From a5bdba69e90827805099e2d495c9f01b83f22e35 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:06:51 -0700 Subject: [PATCH 01/18] AB#29460 - Hotfix - Remove statement overwriting ApplicantName --- .../GrantApplications/GrantApplicationAppService.cs | 1 - 1 file changed, 1 deletion(-) 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 b90cb53c7..b5332cade 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -580,7 +580,6 @@ public async Task UpdateProjectApplicantInfoAsync(Guid id, applicant.FiscalMonth = input.FiscalMonth ?? ""; applicant.NonRegOrgName = input.NonRegOrgName ?? ""; applicant.ElectoralDistrict = input.ElectoralDistrict ?? ""; - applicant.ApplicantName = input.ApplicantName ?? ""; _ = await _applicantRepository.UpdateAsync(applicant); From 058b6cbb3345a44362dc35f237d4be2e2e5bc87a Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Fri, 11 Jul 2025 14:54:00 -0700 Subject: [PATCH 02/18] AB#28707 - Add Non-Registered Organization and Business Columns --- .../GrantApplications/GrantApplicationDto.cs | 2 ++ .../GrantApplicationAppService.cs | 5 +++- .../Localization/GrantManager/en.json | 2 ++ .../Pages/GrantApplications/Index.js | 30 ++++++++++++++++++- 4 files changed, 37 insertions(+), 2 deletions(-) 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 be0069adb..cd21fd862 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 @@ -61,6 +61,8 @@ public class GrantApplicationDto : AuditedEntityDto public List? ApplicationTag { get; set; } public Guid? OwnerId { get; set; } public string? OrganizationName { get; set; } + public string? NonRegisteredBusinessName { get; set; } + public string? NonRegOrgName { get; set; } public string? OrganizationType { get; set; } public GrantApplicationAssigneeDto Owner { get; set; } = new(); public string? OrgStatus { get; set; } = string.Empty; 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 785acb68d..91b013a1c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -128,6 +128,8 @@ public async Task> GetListAsync(PagedAndSort appDto.ApplicationTag = ObjectMapper.Map, List>(firstApplication.ApplicationTags?.ToList() ?? new List()); appDto.Owner = BuildApplicationOwner(firstApplication.Owner); appDto.OrganizationName = firstApplication.Applicant?.OrgName ?? string.Empty; + appDto.NonRegisteredBusinessName = firstApplication.Applicant?.NonRegisteredBusinessName ?? string.Empty; + appDto.NonRegOrgName = firstApplication.Applicant?.NonRegOrgName ?? string.Empty; appDto.OrganizationType = firstApplication.Applicant?.OrganizationType ?? string.Empty; appDto.Assignees = BuildApplicationAssignees(firstApplication.ApplicationAssignments); appDto.SubStatusDisplayValue = MapSubstatusDisplayValue(appDto.SubStatus); @@ -239,7 +241,8 @@ public async Task GetAsync(Guid id) appDto.OrgNumber = application.Applicant.OrgNumber; appDto.OrganizationSize = application.Applicant.OrganizationSize; appDto.OrgStatus = application.Applicant.OrgStatus; - appDto.OrganizationName = application.Applicant.OrgName; + appDto.NonRegisteredBusinessName = application.Applicant.NonRegisteredBusinessName; + appDto.NonRegOrgName = application.Applicant.NonRegOrgName; appDto.Sector = application.Applicant.Sector; appDto.OrganizationType = application.Applicant.OrganizationType; appDto.SubSector = application.Applicant.SubSector; 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 925b17a5a..cb4854d46 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 @@ -319,6 +319,8 @@ "Summary:Application.SubmissionDate": "Submission Date", "Summary:Application.OrganizationName": "Registered Organization Name", "Summary:Application.OrganizationNumber": "Registered Organization Number", + "Summary:Application.NonRegisteredBusinessName": "Non-Registered Business Name", + "Summary:Application.NonRegOrgName": "Non-Registered Organization Name", "Summary:Application.City": "City", "Summary:Application.Community": "Community", "Summary:Application.RequestedAmount": "Requested Amount", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js index e7050d8e9..777056a05 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js @@ -265,7 +265,9 @@ getFyeDayColumn(columnIndex++), getFyeMonthColumn(columnIndex++), getApplicantIdColumn(columnIndex++), - getPayoutColumn(columnIndex++) + getPayoutColumn(columnIndex++), + getNonRegisteredBusinessNameColumn(columnIndex++), + getNonRegisteredOrganizationNameColumn(columnIndex++), ].map((column) => ({ ...column, targets: [column.index], orderData: [column.index, 0] })) .sort((a, b) => a.index - b.index); return sortedColumns; @@ -859,6 +861,32 @@ index: columnIndex } } + + function getNonRegisteredBusinessNameColumn(columnIndex) { + return { + title: l('Summary:Application.NonRegisteredBusinessName'), + name: 'nonRegisteredBusinessName', + data: 'nonRegisteredBusinessName', + className: 'data-table-header', + render: function (data) { + return data ?? ''; + }, + index: columnIndex + } + } + + function getNonRegisteredOrganizationNameColumn(columnIndex) { + return { + title: l('Summary:Application.NonRegOrgName'), + name: 'nonRegOrgName', + data: 'nonRegOrgName', + className: 'data-table-header', + render: function (data) { + return data ?? ''; + }, + index: columnIndex + } + } function getDueDiligenceStatusColumn(columnIndex) { return { title: 'Due Diligence Status', From 417ffd5e019d315a757403f37a5e80cfb31d8986 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:30:18 -0700 Subject: [PATCH 03/18] AB#28585 - Add Tag Assignment Permission Definitions --- .../PaymentsPermissionDefinitionProvider.cs | 7 +++++++ .../Localization/Payments/en.json | 5 ++++- .../Constants/UnitySelector.cs | 14 ++++++++++++++ ...ApplicationPermissionDefinitionProvider.cs | 19 ++++++++++++------- .../Localization/GrantManager/en.json | 4 ++++ 5 files changed, 41 insertions(+), 8 deletions(-) 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 4794cd169..f3778f936 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,13 @@ public override void Define(IPermissionDefinitionContext context) //-- PAYMENT INFO PERMISSIONS grantApplicationPermissionsGroup.Add_PaymentInfo_Permissions(); + + var tagsPermissionsGroup = context.GetGroupOrNull("Tags"); + if (tagsPermissionsGroup != null) + { + tagsPermissionsGroup.AddPermission(UnitySelector.Payment.Tags.Create, L(UnitySelector.Payment.Tags.Create)); + tagsPermissionsGroup.AddPermission(UnitySelector.Payment.Tags.Delete, L(UnitySelector.Payment.Tags.Delete)); + } } private static LocalizableString L(string name) 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 cb0629455..d689e50dc 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 @@ -139,6 +139,9 @@ "Unity.GrantManager.ApplicationManagement.Payment.Summary": "Payment Summary", "Unity.GrantManager.ApplicationManagement.Payment.Supplier": "Supplier Info", "Unity.GrantManager.ApplicationManagement.Payment.Supplier.Update": "Edit Supplier Info", - "Unity.GrantManager.ApplicationManagement.Payment.PaymentList": "Payment List" + "Unity.GrantManager.ApplicationManagement.Payment.PaymentList": "Payment List", + + "Unity.Payments.Tags.Create": "Assign Tag to Payments", + "Unity.Payments.Tags.Delete": "Remove Tag from Payments" } } \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs index 6c0f80fe0..6c67ae7db 100644 --- a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs +++ b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs @@ -62,6 +62,7 @@ public static partial class Scoresheet public const string Update = "Unity.GrantManager.ApplicationManagement.Application.Scoresheet.Update"; public const string Delete = "Unity.GrantManager.ApplicationManagement.Application.Scoresheet.Delete"; } + public static partial class Summary { public const string Default = "Unity.GrantManager.ApplicationManagement.Application.Summary"; @@ -69,7 +70,14 @@ public static partial class Summary public const string Update = "Unity.GrantManager.ApplicationManagement.Application.Summary.Update"; public const string Delete = "Unity.GrantManager.ApplicationManagement.Application.Summary.Delete"; } + + public static partial class Tags + { + public const string Create = "Unity.GrantManager.ApplicationManagement.Application.Tags.Create"; + public const string Delete = "Unity.GrantManager.ApplicationManagement.Application.Tags.Delete"; + } } + public static partial class Review { public const string Default = "Unity.GrantManager.ApplicationManagement.Review"; @@ -207,6 +215,12 @@ public static partial class PaymentList public const string Update = "Unity.GrantManager.ApplicationManagement.Payment.PaymentList.Update"; public const string Delete = "Unity.GrantManager.ApplicationManagement.Payment.PaymentList.Delete"; } + + public static partial class Tags + { + public const string Create = "Unity.Payments.Tags.Create"; + public const string Delete = "Unity.Payments.Tags.Delete"; + } } public static partial class Project diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantApplications/GrantApplicationPermissionDefinitionProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantApplications/GrantApplicationPermissionDefinitionProvider.cs index 2263677df..55a330996 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantApplications/GrantApplicationPermissionDefinitionProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Permissions/GrantApplications/GrantApplicationPermissionDefinitionProvider.cs @@ -79,12 +79,6 @@ public override void Define(IPermissionDefinitionContext context) settingManagement.AddPermission(UnitySettingManagementPermissions.UserInterface, L("Permission:UnitySettingManagementPermissions.UserInterface")); settingManagement.AddPermission(UnitySettingManagementPermissions.BackgroundJobSettings, L("Permission:UnitySettingManagementPermissions.BackgroundJobs")); - // Settings - Tag Management - var tagManagement = settingManagement.AddPermission(UnitySelector.SettingManagement.Tags.Default, L(UnitySelector.SettingManagement.Tags.Default)); - tagManagement.AddChild(UnitySelector.SettingManagement.Tags.Create, L(UnitySelector.SettingManagement.Tags.Create)); - tagManagement.AddChild(UnitySelector.SettingManagement.Tags.Update, L(UnitySelector.SettingManagement.Tags.Update)); - tagManagement.AddChild(UnitySelector.SettingManagement.Tags.Delete, L(UnitySelector.SettingManagement.Tags.Delete)); - var emailingPermission = context.GetPermissionOrNull(SettingManagementPermissions.Emailing); if (emailingPermission != null) { @@ -101,7 +95,18 @@ public override void Define(IPermissionDefinitionContext context) if (timezonePermission != null) { timezonePermission.IsEnabled = false; - } + } + + //-- TAG MANAGEMENT + var tagManagement = settingManagement.AddPermission(UnitySelector.SettingManagement.Tags.Default, L(UnitySelector.SettingManagement.Tags.Default)); + tagManagement.AddChild(UnitySelector.SettingManagement.Tags.Create, L(UnitySelector.SettingManagement.Tags.Create)); + tagManagement.AddChild(UnitySelector.SettingManagement.Tags.Update, L(UnitySelector.SettingManagement.Tags.Update)); + tagManagement.AddChild(UnitySelector.SettingManagement.Tags.Delete, L(UnitySelector.SettingManagement.Tags.Delete)); + + //-- TAG ASSIGNMENT + var tagsPermissionsGroup = context.AddGroup("Tags", L("Permission:Tags")); + tagsPermissionsGroup.AddPermission(UnitySelector.Application.Tags.Create, L(UnitySelector.Application.Tags.Create)); + tagsPermissionsGroup.AddPermission(UnitySelector.Application.Tags.Delete, L(UnitySelector.Application.Tags.Delete)); } private static LocalizableString L(string name) 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 925b17a5a..5c0075c5c 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 @@ -228,6 +228,10 @@ "Unity.GrantManager.SettingManagement.Tags.Update": "Edit Tag", "Unity.GrantManager.SettingManagement.Tags.Delete": "Delete Tag", + "Permission:Tags": "Tags", + "Unity.GrantManager.ApplicationManagement.Application.Tags.Create": "Assign Tag to Applications", + "Unity.GrantManager.ApplicationManagement.Application.Tags.Delete": "Remove Tag from Applications", + "GrantManager:AssessmentUserAssignmentAlreadyExists": "Business Exception: You cannot create two assessments on an application for the same user.", "GrantManager:CantCreateAssessmentForFinalStateApplication": "Business Exception: You cannot create an assessment for an application in final state.", From a9261f5dcbf9e30ce6e16a071a76014aef08d48f Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:40:50 -0700 Subject: [PATCH 04/18] AB#28585 - Add Tag Assignment Permission Data Seeder --- .../Permissions/PermissionGrantsDataSeeder.cs | 618 +++++++++--------- 1 file changed, 317 insertions(+), 301 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs index b28ca1764..d12a94973 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs @@ -9,312 +9,328 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.PermissionManagement; -namespace Unity.GrantManager.Permissions +namespace Unity.GrantManager.Permissions; + +internal class PermissionGrantsDataSeeder : IDataSeedContributor, ITransientDependency { - internal class PermissionGrantsDataSeeder : IDataSeedContributor, ITransientDependency + private readonly IPermissionDataSeeder _permissionDataSeeder; + + public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder) + { + _permissionDataSeeder = permissionDataSeeder; + } + + public readonly List ReviewAndAssessment_CommonPermissions = [ + UnitySelector.Review.Default, + UnitySelector.Review.Approval.Default, + UnitySelector.Review.Approval.Update.Default, + + UnitySelector.Review.AssessmentResults.Default, + UnitySelector.Review.AssessmentResults.Update.Default, + + UnitySelector.Review.AssessmentReviewList.Default, + UnitySelector.Review.AssessmentReviewList.Create, + UnitySelector.Review.AssessmentReviewList.Update.SendBack, + UnitySelector.Review.AssessmentReviewList.Update.Complete + ]; + + public readonly List ApplicantInfo_CommonPermissions = [ + UnitySelector.Applicant.Default, + UnitySelector.Applicant.Summary.Default, + UnitySelector.Applicant.Summary.Update, + UnitySelector.Applicant.Contact.Default, + UnitySelector.Applicant.Contact.Update, + UnitySelector.Applicant.Authority.Default, + UnitySelector.Applicant.Authority.Update, + UnitySelector.Applicant.Location.Default, + UnitySelector.Applicant.Location.Update, + UnitySelector.Applicant.AdditionalContact.Default, + UnitySelector.Applicant.AdditionalContact.Create, + UnitySelector.Applicant.AdditionalContact.Update, + + ]; + + public readonly List ProjectInfo_CommonPermissions = [ + UnitySelector.Project.Default, + UnitySelector.Project.Summary.Default, + UnitySelector.Project.Summary.Update.Default, + UnitySelector.Project.Location.Default, + UnitySelector.Project.Location.Update.Default, + ]; + + public readonly List PaymentInfo_CommonPermissions = [ + UnitySelector.Payment.Default, + UnitySelector.Payment.Summary.Default, + UnitySelector.Payment.Supplier.Default, + UnitySelector.Payment.PaymentList.Default + ]; + + public readonly List Notifications_CommonPermissions = [ + NotificationsPermissions.Email.Default, + NotificationsPermissions.Email.Send, + ]; + + public readonly List Dashboard_CommonPermissions = [ + GrantApplicationPermissions.Dashboard.Default, + GrantApplicationPermissions.Dashboard.ViewDashboard, + GrantApplicationPermissions.Dashboard.ApplicationStatusCount, + GrantApplicationPermissions.Dashboard.EconomicRegionCount, + GrantApplicationPermissions.Dashboard.ApplicationTagsCount, + GrantApplicationPermissions.Dashboard.ApplicationAssigneeCount, + GrantApplicationPermissions.Dashboard.RequestedAmountPerSubsector, + GrantApplicationPermissions.Dashboard.RequestApprovedCount, + ]; + + public readonly List SettingManagement_Tags_CommonPermissions = [ + UnitySelector.SettingManagement.Tags.Default, + UnitySelector.SettingManagement.Tags.Create, + UnitySelector.SettingManagement.Tags.Update, + UnitySelector.SettingManagement.Tags.Delete + ]; + + public readonly List Tags_CommonPermissions = [ + UnitySelector.Application.Tags.Create, + UnitySelector.Application.Tags.Delete, + UnitySelector.Payment.Tags.Create, + UnitySelector.Payment.Tags.Delete, + ]; + + public async Task SeedAsync(DataSeedContext context) { - private readonly IPermissionDataSeeder _permissionDataSeeder; - - public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder) - { - _permissionDataSeeder = permissionDataSeeder; - } - - public readonly List ReviewAndAssessment_CommonPermissions = [ - UnitySelector.Review.Default, - UnitySelector.Review.Approval.Default, - UnitySelector.Review.Approval.Update.Default, - - UnitySelector.Review.AssessmentResults.Default, - UnitySelector.Review.AssessmentResults.Update.Default, - - UnitySelector.Review.AssessmentReviewList.Default, - UnitySelector.Review.AssessmentReviewList.Create, - UnitySelector.Review.AssessmentReviewList.Update.SendBack, - UnitySelector.Review.AssessmentReviewList.Update.Complete - ]; - - public readonly List ApplicantInfo_CommonPermissions = [ - UnitySelector.Applicant.Default, - UnitySelector.Applicant.Summary.Default, - UnitySelector.Applicant.Summary.Update, - UnitySelector.Applicant.Contact.Default, - UnitySelector.Applicant.Contact.Update, - UnitySelector.Applicant.Authority.Default, - UnitySelector.Applicant.Authority.Update, - UnitySelector.Applicant.Location.Default, - UnitySelector.Applicant.Location.Update, - UnitySelector.Applicant.AdditionalContact.Default, - UnitySelector.Applicant.AdditionalContact.Create, - UnitySelector.Applicant.AdditionalContact.Update, - - ]; - - public readonly List ProjectInfo_CommonPermissions = [ - UnitySelector.Project.Default, - UnitySelector.Project.Summary.Default, - UnitySelector.Project.Summary.Update.Default, - UnitySelector.Project.Location.Default, - UnitySelector.Project.Location.Update.Default, - ]; - - public readonly List PaymentInfo_CommonPermissions = [ - UnitySelector.Payment.Default, - UnitySelector.Payment.Summary.Default, - UnitySelector.Payment.Supplier.Default, - UnitySelector.Payment.PaymentList.Default - ]; - - public readonly List Notifications_CommonPermissions = [ - NotificationsPermissions.Email.Default, - NotificationsPermissions.Email.Send, - ]; - - public readonly List Dashboard_CommonPermissions = [ - GrantApplicationPermissions.Dashboard.Default, - GrantApplicationPermissions.Dashboard.ViewDashboard, - GrantApplicationPermissions.Dashboard.ApplicationStatusCount, - GrantApplicationPermissions.Dashboard.EconomicRegionCount, - GrantApplicationPermissions.Dashboard.ApplicationTagsCount, - GrantApplicationPermissions.Dashboard.ApplicationAssigneeCount, - GrantApplicationPermissions.Dashboard.RequestedAmountPerSubsector, - GrantApplicationPermissions.Dashboard.RequestApprovedCount, - ]; - - public readonly List SettingManagement_Tags_CommonPermissions = [ - UnitySelector.SettingManagement.Tags.Default, - UnitySelector.SettingManagement.Tags.Create, - UnitySelector.SettingManagement.Tags.Update, - UnitySelector.SettingManagement.Tags.Delete - ]; - - public async Task SeedAsync(DataSeedContext context) - { - // Default permission grants based on role - - // - Program Manager - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ProgramManager, + // Default permission grants based on role + + // - Program Manager + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ProgramManager, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Assignments.AssignInitial, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + GrantManagerPermissions.Organizations.Default, + GrantManagerPermissions.Organizations.ManageProfiles, + IdentitySeedPermissions.Users.Default, + IdentitySeedPermissions.Users.Create, + IdentitySeedPermissions.Users.Update, + IdentitySeedPermissions.Users.Delete, + IdentitySeedPermissions.Users.ManagePermissions, + IdentitySeedPermissions.Roles.Default, + IdentitySeedPermissions.Roles.Create, + IdentitySeedPermissions.Roles.Update, + IdentitySeedPermissions.Roles.Delete, + IdentitySeedPermissions.Roles.ManagePermissions, + GrantManagerPermissions.Intakes.Default, + GrantManagerPermissions.ApplicationForms.Default, + + .. SettingManagement_Tags_CommonPermissions, + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // - Reviewer + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Reviewer, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // - Assessor + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Assessor, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // - TeamLead + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.TeamLead, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Assignments.AssignInitial, + GrantApplicationPermissions.Applicants.AssignApplicant, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + GrantManagerPermissions.Organizations.Default, + GrantManagerPermissions.Organizations.ManageProfiles, + GrantApplicationPermissions.Approvals.BulkApplicationApproval, + GrantApplicationPermissions.Approvals.DeferAfterApproval, + + .. SettingManagement_Tags_CommonPermissions, + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions, + + // Role Specific Permissions + UnitySelector.Project.Summary.Update.UpdateFinalStateFields, + UnitySelector.Project.Location.Update.UpdateFinalStateFields, + ], context.TenantId); + + // - Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Approvals.Complete, + GrantApplicationPermissions.Approvals.DeferAfterApproval, + GrantApplicationPermissions.Comments.Add, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // - SystemAdmin + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.SystemAdmin, + [ + GrantManagerPermissions.Default, + UnitySettingManagementPermissions.UserInterface, + GrantManagerPermissions.Organizations.Default, + GrantManagerPermissions.Organizations.ManageProfiles, + GrantManagerPermissions.Intakes.Default, + GrantManagerPermissions.ApplicationForms.Default, + + + .. SettingManagement_Tags_CommonPermissions, + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, + .. Notifications_CommonPermissions, + NotificationsPermissions.Settings, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions, + + UnitySettingManagementPermissions.BackgroundJobSettings, + ], context.TenantId); + + + // -L1 Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L1Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + PaymentsPermissions.Payments.L1ApproveOrDecline, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // -L2 Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L2Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + PaymentsPermissions.Payments.L2ApproveOrDecline, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // -L3 Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L3Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + PaymentsPermissions.Payments.L3ApproveOrDecline, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // -External Assessor + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ExternalAssessor, [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Assignments.AssignInitial, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - GrantManagerPermissions.Organizations.Default, - GrantManagerPermissions.Organizations.ManageProfiles, - IdentitySeedPermissions.Users.Default, - IdentitySeedPermissions.Users.Create, - IdentitySeedPermissions.Users.Update, - IdentitySeedPermissions.Users.Delete, - IdentitySeedPermissions.Users.ManagePermissions, - IdentitySeedPermissions.Roles.Default, - IdentitySeedPermissions.Roles.Create, - IdentitySeedPermissions.Roles.Update, - IdentitySeedPermissions.Roles.Delete, - IdentitySeedPermissions.Roles.ManagePermissions, - GrantManagerPermissions.Intakes.Default, - GrantManagerPermissions.ApplicationForms.Default, - - .. SettingManagement_Tags_CommonPermissions, - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - UnitySelector.Payment.Supplier.Update, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + + UnitySelector.Review.Default, + UnitySelector.Review.Approval.Default, + UnitySelector.Review.AssessmentResults.Default, + UnitySelector.Review.AssessmentReviewList.Default, + UnitySelector.Review.AssessmentReviewList.Create, + UnitySelector.Review.AssessmentReviewList.Update.SendBack, + UnitySelector.Review.AssessmentReviewList.Update.Complete, + UnitySelector.Review.Worksheet.Default, + + UnitySelector.Applicant.Default, + UnitySelector.Applicant.Summary.Default, + UnitySelector.Applicant.Contact.Default, + UnitySelector.Applicant.Authority.Default, + UnitySelector.Applicant.Location.Default, + UnitySelector.Applicant.AdditionalContact.Default, + + UnitySelector.Project.Default, + UnitySelector.Project.Summary.Default, + UnitySelector.Project.Location.Default, + + UnitySelector.Payment.Default, + UnitySelector.Payment.Summary.Default, + UnitySelector.Payment.Supplier.Default, + UnitySelector.Payment.PaymentList.Default, + + NotificationsPermissions.Email.Default, + .. Tags_CommonPermissions ], context.TenantId); - // - Reviewer - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Reviewer, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions - ], context.TenantId); - - // - Assessor - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Assessor, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions - ], context.TenantId); - - // - TeamLead - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.TeamLead, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Assignments.AssignInitial, - GrantApplicationPermissions.Applicants.AssignApplicant, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - GrantManagerPermissions.Organizations.Default, - GrantManagerPermissions.Organizations.ManageProfiles, - GrantApplicationPermissions.Approvals.BulkApplicationApproval, - GrantApplicationPermissions.Approvals.DeferAfterApproval, - - .. SettingManagement_Tags_CommonPermissions, - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - UnitySelector.Payment.Supplier.Update, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - - // Role Specific Permissions - UnitySelector.Project.Summary.Update.UpdateFinalStateFields, - UnitySelector.Project.Location.Update.UpdateFinalStateFields, - ], context.TenantId); - - // - Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Approvals.Complete, - GrantApplicationPermissions.Approvals.DeferAfterApproval, - GrantApplicationPermissions.Comments.Add, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions - ], context.TenantId); - - // - SystemAdmin - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.SystemAdmin, - [ - GrantManagerPermissions.Default, - UnitySettingManagementPermissions.UserInterface, - GrantManagerPermissions.Organizations.Default, - GrantManagerPermissions.Organizations.ManageProfiles, - GrantManagerPermissions.Intakes.Default, - GrantManagerPermissions.ApplicationForms.Default, - - - .. SettingManagement_Tags_CommonPermissions, - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - UnitySelector.Payment.Supplier.Update, - .. Notifications_CommonPermissions, - NotificationsPermissions.Settings, - .. Dashboard_CommonPermissions, - - UnitySettingManagementPermissions.BackgroundJobSettings, - ], context.TenantId); - - - // -L1 Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L1Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - PaymentsPermissions.Payments.L1ApproveOrDecline, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions - ], context.TenantId); - - // -L2 Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L2Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - PaymentsPermissions.Payments.L2ApproveOrDecline, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions - ], context.TenantId); - - // -L3 Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L3Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - PaymentsPermissions.Payments.L3ApproveOrDecline, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions - ], context.TenantId); - - // -External Assessor - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ExternalAssessor, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - - UnitySelector.Review.Default, - UnitySelector.Review.Approval.Default, - UnitySelector.Review.AssessmentResults.Default, - UnitySelector.Review.AssessmentReviewList.Default, - UnitySelector.Review.AssessmentReviewList.Create, - UnitySelector.Review.AssessmentReviewList.Update.SendBack, - UnitySelector.Review.AssessmentReviewList.Update.Complete, - UnitySelector.Review.Worksheet.Default, - - UnitySelector.Applicant.Default, - UnitySelector.Applicant.Summary.Default, - UnitySelector.Applicant.Contact.Default, - UnitySelector.Applicant.Authority.Default, - UnitySelector.Applicant.Location.Default, - UnitySelector.Applicant.AdditionalContact.Default, - - UnitySelector.Project.Default, - UnitySelector.Project.Summary.Default, - UnitySelector.Project.Location.Default, - - UnitySelector.Payment.Default, - UnitySelector.Payment.Summary.Default, - UnitySelector.Payment.Supplier.Default, - UnitySelector.Payment.PaymentList.Default, - - NotificationsPermissions.Email.Default, - ], context.TenantId); - - } } } From fa47da797ca0870c2c0a5586b5e922d2cf2c2be6 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:49:09 -0700 Subject: [PATCH 05/18] AB#28585 - Update Tag Assignment Permission Data Seeder --- .../PaymentsPermissionDefinitionProvider.cs | 10 +- .../Constants/UnitySelector.cs | 4 +- .../Localization/GrantManager/en.json | 4 +- .../Permissions/PermissionGrantsDataSeeder.cs | 629 +++++++++--------- 4 files changed, 322 insertions(+), 325 deletions(-) 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 f3778f936..62dcc9405 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 @@ -1,6 +1,7 @@ using Unity.Modules.Shared; using Unity.Payments.Localization; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Features; using Volo.Abp.Localization; namespace Unity.Payments.Permissions; @@ -24,8 +25,8 @@ public override void Define(IPermissionDefinitionContext context) var tagsPermissionsGroup = context.GetGroupOrNull("Tags"); if (tagsPermissionsGroup != null) { - tagsPermissionsGroup.AddPermission(UnitySelector.Payment.Tags.Create, L(UnitySelector.Payment.Tags.Create)); - tagsPermissionsGroup.AddPermission(UnitySelector.Payment.Tags.Delete, L(UnitySelector.Payment.Tags.Delete)); + tagsPermissionsGroup.AddPermission(UnitySelector.Payment.Tags.Create, L(UnitySelector.Payment.Tags.Create)).RequireFeatures("Unity.Payments"); + tagsPermissionsGroup.AddPermission(UnitySelector.Payment.Tags.Delete, L(UnitySelector.Payment.Tags.Delete)).RequireFeatures("Unity.Payments"); } } @@ -42,7 +43,8 @@ public static void Add_PaymentInfo_Permissions(this PermissionGroupDefinition gr { #region PAYMENT INFO GRANULAR PERMISSIONS var upx_Payment = grantApplicationPermissionsGroup - .AddPermission(UnitySelector.Payment.Default, LocalizableString.Create(UnitySelector.Payment.Default)); + .AddPermission(UnitySelector.Payment.Default, LocalizableString.Create(UnitySelector.Payment.Default)) + .RequireFeatures("Unity.Payments"); var upx_Payment_Summary = upx_Payment.AddPaymentChild(UnitySelector.Payment.Summary.Default); @@ -57,6 +59,6 @@ public static void Add_PaymentInfo_Permissions(this PermissionGroupDefinition gr public static PermissionDefinition AddPaymentChild(this PermissionDefinition parent, string name) { - return parent.AddChild(name, LocalizableString.Create(name)); + return parent.AddChild(name, LocalizableString.Create(name)).RequireFeatures("Unity.Payments"); } } diff --git a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs index 6c67ae7db..b5d8e44fc 100644 --- a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs +++ b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Constants/UnitySelector.cs @@ -73,8 +73,8 @@ public static partial class Summary public static partial class Tags { - public const string Create = "Unity.GrantManager.ApplicationManagement.Application.Tags.Create"; - public const string Delete = "Unity.GrantManager.ApplicationManagement.Application.Tags.Delete"; + public const string Create = "Unity.Applications.Tags.Create"; + public const string Delete = "Unity.Applications.Tags.Delete"; } } 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 5c0075c5c..494510d56 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 @@ -229,8 +229,8 @@ "Unity.GrantManager.SettingManagement.Tags.Delete": "Delete Tag", "Permission:Tags": "Tags", - "Unity.GrantManager.ApplicationManagement.Application.Tags.Create": "Assign Tag to Applications", - "Unity.GrantManager.ApplicationManagement.Application.Tags.Delete": "Remove Tag from Applications", + "Unity.Applications.Tags.Create": "Assign Tag to Applications", + "Unity.Applications.Tags.Delete": "Remove Tag from Applications", "GrantManager:AssessmentUserAssignmentAlreadyExists": "Business Exception: You cannot create two assessments on an application for the same user.", "GrantManager:CantCreateAssessmentForFinalStateApplication": "Business Exception: You cannot create an assessment for an application in final state.", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs index d12a94973..6cd655128 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs @@ -9,328 +9,323 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.PermissionManagement; -namespace Unity.GrantManager.Permissions; - -internal class PermissionGrantsDataSeeder : IDataSeedContributor, ITransientDependency +namespace Unity.GrantManager.Permissions { - private readonly IPermissionDataSeeder _permissionDataSeeder; - - public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder) - { - _permissionDataSeeder = permissionDataSeeder; - } - - public readonly List ReviewAndAssessment_CommonPermissions = [ - UnitySelector.Review.Default, - UnitySelector.Review.Approval.Default, - UnitySelector.Review.Approval.Update.Default, - - UnitySelector.Review.AssessmentResults.Default, - UnitySelector.Review.AssessmentResults.Update.Default, - - UnitySelector.Review.AssessmentReviewList.Default, - UnitySelector.Review.AssessmentReviewList.Create, - UnitySelector.Review.AssessmentReviewList.Update.SendBack, - UnitySelector.Review.AssessmentReviewList.Update.Complete - ]; - - public readonly List ApplicantInfo_CommonPermissions = [ - UnitySelector.Applicant.Default, - UnitySelector.Applicant.Summary.Default, - UnitySelector.Applicant.Summary.Update, - UnitySelector.Applicant.Contact.Default, - UnitySelector.Applicant.Contact.Update, - UnitySelector.Applicant.Authority.Default, - UnitySelector.Applicant.Authority.Update, - UnitySelector.Applicant.Location.Default, - UnitySelector.Applicant.Location.Update, - UnitySelector.Applicant.AdditionalContact.Default, - UnitySelector.Applicant.AdditionalContact.Create, - UnitySelector.Applicant.AdditionalContact.Update, - - ]; - - public readonly List ProjectInfo_CommonPermissions = [ - UnitySelector.Project.Default, - UnitySelector.Project.Summary.Default, - UnitySelector.Project.Summary.Update.Default, - UnitySelector.Project.Location.Default, - UnitySelector.Project.Location.Update.Default, - ]; - - public readonly List PaymentInfo_CommonPermissions = [ - UnitySelector.Payment.Default, - UnitySelector.Payment.Summary.Default, - UnitySelector.Payment.Supplier.Default, - UnitySelector.Payment.PaymentList.Default - ]; - - public readonly List Notifications_CommonPermissions = [ - NotificationsPermissions.Email.Default, - NotificationsPermissions.Email.Send, - ]; - - public readonly List Dashboard_CommonPermissions = [ - GrantApplicationPermissions.Dashboard.Default, - GrantApplicationPermissions.Dashboard.ViewDashboard, - GrantApplicationPermissions.Dashboard.ApplicationStatusCount, - GrantApplicationPermissions.Dashboard.EconomicRegionCount, - GrantApplicationPermissions.Dashboard.ApplicationTagsCount, - GrantApplicationPermissions.Dashboard.ApplicationAssigneeCount, - GrantApplicationPermissions.Dashboard.RequestedAmountPerSubsector, - GrantApplicationPermissions.Dashboard.RequestApprovedCount, - ]; - - public readonly List SettingManagement_Tags_CommonPermissions = [ - UnitySelector.SettingManagement.Tags.Default, - UnitySelector.SettingManagement.Tags.Create, - UnitySelector.SettingManagement.Tags.Update, - UnitySelector.SettingManagement.Tags.Delete - ]; - - public readonly List Tags_CommonPermissions = [ - UnitySelector.Application.Tags.Create, - UnitySelector.Application.Tags.Delete, - UnitySelector.Payment.Tags.Create, - UnitySelector.Payment.Tags.Delete, - ]; - - public async Task SeedAsync(DataSeedContext context) + internal class PermissionGrantsDataSeeder : IDataSeedContributor, ITransientDependency { - // Default permission grants based on role - - // - Program Manager - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ProgramManager, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Assignments.AssignInitial, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - GrantManagerPermissions.Organizations.Default, - GrantManagerPermissions.Organizations.ManageProfiles, - IdentitySeedPermissions.Users.Default, - IdentitySeedPermissions.Users.Create, - IdentitySeedPermissions.Users.Update, - IdentitySeedPermissions.Users.Delete, - IdentitySeedPermissions.Users.ManagePermissions, - IdentitySeedPermissions.Roles.Default, - IdentitySeedPermissions.Roles.Create, - IdentitySeedPermissions.Roles.Update, - IdentitySeedPermissions.Roles.Delete, - IdentitySeedPermissions.Roles.ManagePermissions, - GrantManagerPermissions.Intakes.Default, - GrantManagerPermissions.ApplicationForms.Default, - - .. SettingManagement_Tags_CommonPermissions, - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - UnitySelector.Payment.Supplier.Update, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions - ], context.TenantId); - - // - Reviewer - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Reviewer, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions - ], context.TenantId); - - // - Assessor - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Assessor, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions - ], context.TenantId); - - // - TeamLead - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.TeamLead, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Assignments.AssignInitial, - GrantApplicationPermissions.Applicants.AssignApplicant, - GrantApplicationPermissions.Reviews.StartInitial, - GrantApplicationPermissions.Reviews.CompleteInitial, - GrantApplicationPermissions.Comments.Add, - GrantManagerPermissions.Organizations.Default, - GrantManagerPermissions.Organizations.ManageProfiles, - GrantApplicationPermissions.Approvals.BulkApplicationApproval, - GrantApplicationPermissions.Approvals.DeferAfterApproval, - - .. SettingManagement_Tags_CommonPermissions, - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - UnitySelector.Payment.Supplier.Update, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions, - - // Role Specific Permissions - UnitySelector.Project.Summary.Update.UpdateFinalStateFields, - UnitySelector.Project.Location.Update.UpdateFinalStateFields, - ], context.TenantId); - - // - Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - GrantApplicationPermissions.Approvals.Complete, - GrantApplicationPermissions.Approvals.DeferAfterApproval, - GrantApplicationPermissions.Comments.Add, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions - ], context.TenantId); - - // - SystemAdmin - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.SystemAdmin, - [ - GrantManagerPermissions.Default, - UnitySettingManagementPermissions.UserInterface, - GrantManagerPermissions.Organizations.Default, - GrantManagerPermissions.Organizations.ManageProfiles, - GrantManagerPermissions.Intakes.Default, - GrantManagerPermissions.ApplicationForms.Default, - - - .. SettingManagement_Tags_CommonPermissions, - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - UnitySelector.Payment.Supplier.Update, - .. Notifications_CommonPermissions, - NotificationsPermissions.Settings, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions, - - UnitySettingManagementPermissions.BackgroundJobSettings, - ], context.TenantId); - - - // -L1 Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L1Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - PaymentsPermissions.Payments.L1ApproveOrDecline, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions - ], context.TenantId); - - // -L2 Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L2Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - PaymentsPermissions.Payments.L2ApproveOrDecline, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions - ], context.TenantId); - - // -L3 Approver - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L3Approver, - [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - PaymentsPermissions.Payments.L3ApproveOrDecline, - - .. ReviewAndAssessment_CommonPermissions, - .. ApplicantInfo_CommonPermissions, - .. ProjectInfo_CommonPermissions, - .. PaymentInfo_CommonPermissions, - .. Notifications_CommonPermissions, - .. Dashboard_CommonPermissions, - .. Tags_CommonPermissions - ], context.TenantId); - - // -External Assessor - await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ExternalAssessor, + private readonly IPermissionDataSeeder _permissionDataSeeder; + + public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder) + { + _permissionDataSeeder = permissionDataSeeder; + } + + public readonly List ReviewAndAssessment_CommonPermissions = [ + UnitySelector.Review.Default, + UnitySelector.Review.Approval.Default, + UnitySelector.Review.Approval.Update.Default, + + UnitySelector.Review.AssessmentResults.Default, + UnitySelector.Review.AssessmentResults.Update.Default, + + UnitySelector.Review.AssessmentReviewList.Default, + UnitySelector.Review.AssessmentReviewList.Create, + UnitySelector.Review.AssessmentReviewList.Update.SendBack, + UnitySelector.Review.AssessmentReviewList.Update.Complete + ]; + + public readonly List ApplicantInfo_CommonPermissions = [ + UnitySelector.Applicant.Default, + UnitySelector.Applicant.Summary.Default, + UnitySelector.Applicant.Summary.Update, + UnitySelector.Applicant.Contact.Default, + UnitySelector.Applicant.Contact.Update, + UnitySelector.Applicant.Authority.Default, + UnitySelector.Applicant.Authority.Update, + UnitySelector.Applicant.Location.Default, + UnitySelector.Applicant.Location.Update, + UnitySelector.Applicant.AdditionalContact.Default, + UnitySelector.Applicant.AdditionalContact.Create, + UnitySelector.Applicant.AdditionalContact.Update, + + ]; + + public readonly List ProjectInfo_CommonPermissions = [ + UnitySelector.Project.Default, + UnitySelector.Project.Summary.Default, + UnitySelector.Project.Summary.Update.Default, + UnitySelector.Project.Location.Default, + UnitySelector.Project.Location.Update.Default, + ]; + + public readonly List PaymentInfo_CommonPermissions = [ + UnitySelector.Payment.Default, + UnitySelector.Payment.Summary.Default, + UnitySelector.Payment.Supplier.Default, + UnitySelector.Payment.PaymentList.Default + ]; + + public readonly List Notifications_CommonPermissions = [ + NotificationsPermissions.Email.Default, + NotificationsPermissions.Email.Send, + ]; + + public readonly List Dashboard_CommonPermissions = [ + GrantApplicationPermissions.Dashboard.Default, + GrantApplicationPermissions.Dashboard.ViewDashboard, + GrantApplicationPermissions.Dashboard.ApplicationStatusCount, + GrantApplicationPermissions.Dashboard.EconomicRegionCount, + GrantApplicationPermissions.Dashboard.ApplicationTagsCount, + GrantApplicationPermissions.Dashboard.ApplicationAssigneeCount, + GrantApplicationPermissions.Dashboard.RequestedAmountPerSubsector, + GrantApplicationPermissions.Dashboard.RequestApprovedCount, + ]; + + public readonly List SettingManagement_Tags_CommonPermissions = [ + UnitySelector.SettingManagement.Tags.Default, + UnitySelector.SettingManagement.Tags.Create, + UnitySelector.SettingManagement.Tags.Update, + UnitySelector.SettingManagement.Tags.Delete + ]; + + public readonly List Tags_CommonPermissions = [ + UnitySelector.Application.Tags.Create, + UnitySelector.Application.Tags.Delete, + UnitySelector.Payment.Tags.Create, + UnitySelector.Payment.Tags.Delete, + ]; + + public async Task SeedAsync(DataSeedContext context) + { + // Default permission grants based on role + + // - Program Manager + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ProgramManager, [ - GrantManagerPermissions.Default, - GrantApplicationPermissions.Applications.Default, - PaymentsPermissions.Payments.Default, - - UnitySelector.Review.Default, - UnitySelector.Review.Approval.Default, - UnitySelector.Review.AssessmentResults.Default, - UnitySelector.Review.AssessmentReviewList.Default, - UnitySelector.Review.AssessmentReviewList.Create, - UnitySelector.Review.AssessmentReviewList.Update.SendBack, - UnitySelector.Review.AssessmentReviewList.Update.Complete, - UnitySelector.Review.Worksheet.Default, - - UnitySelector.Applicant.Default, - UnitySelector.Applicant.Summary.Default, - UnitySelector.Applicant.Contact.Default, - UnitySelector.Applicant.Authority.Default, - UnitySelector.Applicant.Location.Default, - UnitySelector.Applicant.AdditionalContact.Default, - - UnitySelector.Project.Default, - UnitySelector.Project.Summary.Default, - UnitySelector.Project.Location.Default, - - UnitySelector.Payment.Default, - UnitySelector.Payment.Summary.Default, - UnitySelector.Payment.Supplier.Default, - UnitySelector.Payment.PaymentList.Default, - - NotificationsPermissions.Email.Default, - .. Tags_CommonPermissions + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Assignments.AssignInitial, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + GrantManagerPermissions.Organizations.Default, + GrantManagerPermissions.Organizations.ManageProfiles, + IdentitySeedPermissions.Users.Default, + IdentitySeedPermissions.Users.Create, + IdentitySeedPermissions.Users.Update, + IdentitySeedPermissions.Users.Delete, + IdentitySeedPermissions.Users.ManagePermissions, + IdentitySeedPermissions.Roles.Default, + IdentitySeedPermissions.Roles.Create, + IdentitySeedPermissions.Roles.Update, + IdentitySeedPermissions.Roles.Delete, + IdentitySeedPermissions.Roles.ManagePermissions, + GrantManagerPermissions.Intakes.Default, + GrantManagerPermissions.ApplicationForms.Default, + + .. SettingManagement_Tags_CommonPermissions, + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions ], context.TenantId); + // - Reviewer + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Reviewer, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions + ], context.TenantId); + + // - Assessor + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Assessor, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions + ], context.TenantId); + + // - TeamLead + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.TeamLead, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Assignments.AssignInitial, + GrantApplicationPermissions.Applicants.AssignApplicant, + GrantApplicationPermissions.Reviews.StartInitial, + GrantApplicationPermissions.Reviews.CompleteInitial, + GrantApplicationPermissions.Comments.Add, + GrantManagerPermissions.Organizations.Default, + GrantManagerPermissions.Organizations.ManageProfiles, + GrantApplicationPermissions.Approvals.BulkApplicationApproval, + GrantApplicationPermissions.Approvals.DeferAfterApproval, + + .. SettingManagement_Tags_CommonPermissions, + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions, + + // Role Specific Permissions + UnitySelector.Project.Summary.Update.UpdateFinalStateFields, + UnitySelector.Project.Location.Update.UpdateFinalStateFields, + ], context.TenantId); + + // - Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + GrantApplicationPermissions.Approvals.Complete, + GrantApplicationPermissions.Approvals.DeferAfterApproval, + GrantApplicationPermissions.Comments.Add, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions + ], context.TenantId); + + // - SystemAdmin + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.SystemAdmin, + [ + GrantManagerPermissions.Default, + UnitySettingManagementPermissions.UserInterface, + GrantManagerPermissions.Organizations.Default, + GrantManagerPermissions.Organizations.ManageProfiles, + GrantManagerPermissions.Intakes.Default, + GrantManagerPermissions.ApplicationForms.Default, + + + .. SettingManagement_Tags_CommonPermissions, + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, + .. Notifications_CommonPermissions, + NotificationsPermissions.Settings, + .. Dashboard_CommonPermissions, + .. Tags_CommonPermissions, + + UnitySettingManagementPermissions.BackgroundJobSettings, + ], context.TenantId); + + + // -L1 Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L1Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + PaymentsPermissions.Payments.L1ApproveOrDecline, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions + ], context.TenantId); + + // -L2 Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L2Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + PaymentsPermissions.Payments.L2ApproveOrDecline, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions + ], context.TenantId); + + // -L3 Approver + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.L3Approver, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + PaymentsPermissions.Payments.L3ApproveOrDecline, + + .. ReviewAndAssessment_CommonPermissions, + .. ApplicantInfo_CommonPermissions, + .. ProjectInfo_CommonPermissions, + .. PaymentInfo_CommonPermissions, + .. Notifications_CommonPermissions, + .. Dashboard_CommonPermissions + ], context.TenantId); + + // -External Assessor + await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, UnityRoles.ExternalAssessor, + [ + GrantManagerPermissions.Default, + GrantApplicationPermissions.Applications.Default, + PaymentsPermissions.Payments.Default, + + UnitySelector.Review.Default, + UnitySelector.Review.Approval.Default, + UnitySelector.Review.AssessmentResults.Default, + UnitySelector.Review.AssessmentReviewList.Default, + UnitySelector.Review.AssessmentReviewList.Create, + UnitySelector.Review.AssessmentReviewList.Update.SendBack, + UnitySelector.Review.AssessmentReviewList.Update.Complete, + UnitySelector.Review.Worksheet.Default, + + UnitySelector.Applicant.Default, + UnitySelector.Applicant.Summary.Default, + UnitySelector.Applicant.Contact.Default, + UnitySelector.Applicant.Authority.Default, + UnitySelector.Applicant.Location.Default, + UnitySelector.Applicant.AdditionalContact.Default, + + UnitySelector.Project.Default, + UnitySelector.Project.Summary.Default, + UnitySelector.Project.Location.Default, + + UnitySelector.Payment.Default, + UnitySelector.Payment.Summary.Default, + UnitySelector.Payment.Supplier.Default, + UnitySelector.Payment.PaymentList.Default, + + NotificationsPermissions.Email.Default + ], context.TenantId); + + } } } From 1d11f1c49770338f465d4cd1a7d9f8c2b57adf11 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 29 Jul 2025 13:08:24 -0700 Subject: [PATCH 06/18] AB#28585 - Tag Permissions - Add Application Tag Modal Permission Constraints --- .../wwwroot/themes/ux2/layout.css | 9 +- .../ApplicationTagsAppService.cs | 24 ++--- .../Pages/ApplicationTags/ApplicationTags.js | 92 +++++++------------ .../ApplicationTagsSelectionModal.cshtml | 20 +++- .../ApplicationTagsSelectionModal.cshtml.cs | 16 +--- .../Components/ActionBar/Default.cshtml | 46 +++++----- 6 files changed, 103 insertions(+), 104 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/layout.css b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/layout.css index 3dbd816a3..31ea5ec6a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/layout.css +++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/layout.css @@ -571,7 +571,8 @@ abp-date-picker .btn { background: transparent; padding: 10px; border-radius: 4px; - border: 1px solid #ccc + border: 1px solid #ccc; + min-height: 3em; } .tags-input-wrapper input { @@ -591,6 +592,12 @@ abp-date-picker .btn { margin-bottom: 5px; } +.tags-input-disabled { + background-color: var(--bc-colors-grey-hover) !important; + opacity: var(--bs-btn-disabled-opacity); + background-blend-mode: difference; +} + .tags-uncommon { background-color: #013366; color: white; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationTagsAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationTagsAppService.cs index 504314ed6..2512b3684 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationTagsAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationTagsAppService.cs @@ -13,8 +13,6 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.EventBus.Local; -using Volo.Abp.ObjectMapping; -using static Unity.GrantManager.Permissions.GrantApplicationPermissions; namespace Unity.GrantManager.GrantApplications; @@ -45,7 +43,7 @@ public async Task> GetListWithApplicationIdsAsync(List< var tags = await queryable .Where(x => ids.Contains(x.ApplicationId)) - .Include(x => x.Tag) + .Include(x => x.Tag) .ToListAsync(); return ObjectMapper.Map, List>(tags.OrderBy(t => t.Id).ToList()); @@ -54,7 +52,7 @@ public async Task> GetListWithApplicationIdsAsync(List< public async Task> GetApplicationTagsAsync(Guid id) { var tags = await (await _applicationTagsRepository - .WithDetailsAsync(x => x.Tag)) + .WithDetailsAsync(x => x.Tag)) .Where(e => e.ApplicationId == id) .ToListAsync(); @@ -66,6 +64,7 @@ public async Task> AssignTagsAsync(AssignApplicationTag var existingApplicationTags = await _applicationTagsRepository.GetListAsync(e => e.ApplicationId == input.ApplicationId); var existingTagIds = existingApplicationTags.Select(t => t.TagId).ToHashSet(); var inputTagIds = input.Tags?.Select(t => t.Id).ToHashSet() ?? new HashSet(); + var newTagsToAdd = input.Tags? .Where(tag => !existingTagIds.Contains(tag.Id)) .Select(tag => new ApplicationTags @@ -74,16 +73,17 @@ public async Task> AssignTagsAsync(AssignApplicationTag TagId = tag.Id }) .ToList(); - var tagsToRemove = existingApplicationTags - .Where(et => !inputTagIds.Contains(et.TagId)) - .ToList(); + var tagsToRemove = existingApplicationTags + .Where(et => !inputTagIds.Contains(et.TagId)) + .ToList(); - if (tagsToRemove.Count > 0) + if (tagsToRemove.Count > 0 && await AuthorizationService.IsGrantedAsync(UnitySelector.Application.Tags.Delete)) { await _applicationTagsRepository.DeleteManyAsync(tagsToRemove, autoSave: true); } - if (newTagsToAdd?.Count > 0) + + if (newTagsToAdd?.Count > 0 && await AuthorizationService.IsGrantedAsync(UnitySelector.Application.Tags.Create)) { await _applicationTagsRepository.InsertManyAsync(newTagsToAdd, autoSave: true); @@ -98,7 +98,7 @@ public async Task> AssignTagsAsync(AssignApplicationTag } else { - return new List(); + return []; } } @@ -204,9 +204,9 @@ public async Task DeleteTagWithTagIdAsync(Guid id) var existingApplicationTags = await _applicationTagsRepository.GetListAsync(e => e.Tag.Id == id); var idsToDelete = existingApplicationTags.Select(x => x.Id).ToList(); await _applicationTagsRepository.DeleteManyAsync(idsToDelete, autoSave: true); - - + + } [Authorize(UnitySelector.SettingManagement.Tags.Delete)] diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js index 742bf71a3..3b473293a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js @@ -2,12 +2,11 @@ $(function () { let suggestionsArray = []; - let TagsInput = function (opts) { this.options = Object.assign(TagsInput.defaults, opts); this.init(); } - + TagsInput.prototype.init = function (opts) { this.options = opts ? Object.assign(this.options, opts) : this.options; @@ -24,24 +23,28 @@ $(function () { this.wrapper = document.createElement('div'); this.input = document.createElement('input'); + this.input.Id = "tags-input-control"; init(this); initEvents(this); + // Disable the input if user doesn't have create permission + if (!abp.auth.isGranted('Unity.Applications.Tags.Create')) { + this.input.disabled = true; + this.input.type = "hidden"; + this.wrapper.classList.add('tags-input-disabled'); + } + this.initialized = true; return this; } - - TagsInput.prototype.addTag = function (tagData) { let defaultClass = 'tags-common'; - let id,tagText, tagClass; - - id = tagData.id; - tagText = tagData.name || ''; - tagClass = tagData.class || defaultClass; + let id, tagText, tagClass; - + id = tagData.id; + tagText = tagData.name || ''; + tagClass = tagData.class || defaultClass; if (this.anyErrors(tagText)) return; @@ -54,38 +57,41 @@ $(function () { tag.className = this.options.tagClass + ' ' + tagClass; tag.innerText = tagText; - let closeIcon = document.createElement('a'); - closeIcon.innerHTML = '×'; + if (abp.auth.isGranted('Unity.Applications.Tags.Delete')) { + let closeIcon = document.createElement('a'); + closeIcon.innerHTML = '×'; - - closeIcon.addEventListener('click', function (e) { - e.preventDefault(); - let tag = this.parentNode; + closeIcon.addEventListener('click', function (e) { + e.preventDefault(); + console.log("Delete Tag"); + let tag = this.parentNode; - for (let i = 0; i < tagInput.wrapper.childNodes.length; i++) { - if (tagInput.wrapper.childNodes[i] == tag) - tagInput.deleteTag(tag, i); - } - }) + let tagIndex = Array.from(tagInput.wrapper.childNodes).indexOf(tag); + if (tagIndex !== -1) { + tagInput.deleteTag(tag, tagIndex); + } + }) + + tag.appendChild(closeIcon); + } - tag.appendChild(closeIcon); this.wrapper.insertBefore(tag, this.input); this.orignal_input.value = JSON.stringify(this.arr); updateSelectedTagsInput(this.arr) return this; } - TagsInput.prototype.deleteTag = function (tag, i) { let self = this; - if (this.arr[i].name === 'Uncommon Tags') { + if (this.arr[i] && this.arr[i].Name === 'Uncommon Tags') { abp.message.confirm('Are you sure you want to delete all the uncommon tags?') .then(function (confirmed) { if (confirmed) { tag.remove(); self.arr.splice(i, 1); self.orignal_input.value = JSON.stringify(self.arr); + updateSelectedTagsInput(self.arr); return self; } }); @@ -93,11 +99,11 @@ $(function () { tag.remove(); this.arr.splice(i, 1); this.orignal_input.value = JSON.stringify(this.arr); + updateSelectedTagsInput(this.arr); return this; } } - TagsInput.prototype.anyErrors = function (string) { if (this.options.max != null && this.arr.length >= this.options.max) { console.log('max tags limit reached'); @@ -115,7 +121,6 @@ $(function () { return false; } - TagsInput.prototype.addData = function (array) { let plugin = this; @@ -125,16 +130,14 @@ $(function () { return this; } - TagsInput.prototype.getInputString = function () { return this.arr.join(','); } + TagsInput.prototype.setSuggestions = function (sugArray) { suggestionsArray = sugArray; } - - TagsInput.prototype.destroy = function () { this.orignal_input.removeAttribute('hidden'); @@ -152,7 +155,6 @@ $(function () { this.initialized = false; } - function init(tags) { tags.wrapper.append(tags.input); tags.wrapper.classList.add(tags.options.wrapperClass); @@ -161,45 +163,35 @@ $(function () { tags.input.addEventListener('input', function () { const inputValue = tags.input.value.trim().toLowerCase(); - if (inputValue.length > 1) { const suggestions = suggestionsArray.filter(tag => (tag.name.toLowerCase()).includes(inputValue)); - if (suggestions.length) { displaySuggestions(tags, suggestions); } else { removeSuggestions(tags); } - } else { - removeSuggestions(tags); } }); } - function displaySuggestions(tags, suggestions) { - + removeSuggestions(tags); - const suggestionContainer = document.createElement('div'); suggestionContainer.classList.add('tags-suggestion-container'); const suggestionTitleElement = document.createElement('div'); suggestionTitleElement.className = 'tags-suggestion-title'; suggestionTitleElement.innerText = 'ALL TAGS'; suggestionContainer.appendChild(suggestionTitleElement); - - suggestions.forEach(suggestion => { const suggestionElement = document.createElement('div'); suggestionElement.className = 'tags-suggestion-element'; suggestionElement.innerText = typeof suggestion === 'string' ? suggestion : suggestion.name; - - suggestionElement.addEventListener('click', function () { tags.addTag(suggestion); removeSuggestions(tags); @@ -209,11 +201,9 @@ $(function () { suggestionContainer.appendChild(suggestionElement); }); - tags.wrapper.appendChild(suggestionContainer); } - function removeSuggestions(tags) { const suggestionContainer = tags.wrapper.querySelector('.tags-suggestion-container'); if (suggestionContainer) { @@ -221,33 +211,27 @@ $(function () { } } - function initEvents(tags) { tags.wrapper.addEventListener('click', function () { tags.input.focus(); }); - tags.input.addEventListener('focusout', function () { $('#assignTagsModelSaveBtn').click(function () { trimAndAddTag(tags); }) }); - tags.input.addEventListener('keydown', function (e) { - if (~[9, 13, 188, 32].indexOf(e.keyCode)) { e.preventDefault(); trimAndAddTag(tags); removeSuggestions(tags); } - }); } - function trimAndAddTag(tags) { let str = tags.input.value.trim(); if (!str) { @@ -255,10 +239,8 @@ $(function () { return; } - const matched = suggestionsArray.find(s => - - s.name.toLowerCase() === str.toLowerCase() + s.name.toLowerCase() === str.toLowerCase() ); if (matched) { @@ -271,17 +253,14 @@ $(function () { } function updateSelectedTagsInput(tagsArray) { - let jsonValue = JSON.stringify(tagsArray); $('#SelectedTagsJson').val(jsonValue); - } TagsInput.prototype.getTags = function () { - return this.arr.slice(); + return this.arr.slice(); } - TagsInput.defaults = { selector: '', wrapperClass: 'tags-input-wrapper', @@ -291,5 +270,4 @@ $(function () { } window.TagsInput = TagsInput; - }); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml index 501cf5ff9..cda2a779a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml @@ -1,10 +1,16 @@ @page -@model Unity.GrantManager.Web.Pages.ApplicationTags.ApplicationTagsModalModel +@using Newtonsoft.Json +@using Unity.Modules.Shared @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Abp.Authorization.Permissions + +@model Unity.GrantManager.Web.Pages.ApplicationTags.ApplicationTagsModalModel + @{ Layout = null; } -@using Newtonsoft.Json + +@inject IPermissionChecker PermissionChecker
@@ -13,6 +19,16 @@
+ @if (!await PermissionChecker.IsGrantedAsync(UnitySelector.Application.Tags.Create)) + { +
Note: The current user does not have permission to assign application tags.
+ } + + @if (!await PermissionChecker.IsGrantedAsync(UnitySelector.Application.Tags.Delete)) + { +
Note: The current user does not have permission to remove application tags.
+ } + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml.cs index 96a14a971..b0a8c405f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTagsSelectionModal.cshtml.cs @@ -38,7 +38,6 @@ public class ApplicationTagsModalModel : AbpPageModel public string? ActionType { get; set; } = string.Empty; private readonly IApplicationTagsService _applicationTagsService; - private readonly ITagsService _tagsService; [BindProperty] [DisplayName("Common Tags")] @@ -53,15 +52,14 @@ public class ApplicationTagsModalModel : AbpPageModel public List Tags { get; set; } = new(); [BindProperty] - public string? SelectedTagsJson { get; set; } + public string? SelectedTagsJson { get; set; } [BindProperty] public string? TagsJson { get; set; } - public ApplicationTagsModalModel(IApplicationTagsService applicationTagsService, ITagsService tagsService) + public ApplicationTagsModalModel(IApplicationTagsService applicationTagsService) { _applicationTagsService = applicationTagsService ?? throw new ArgumentNullException(nameof(applicationTagsService)); - _tagsService = tagsService ?? throw new ArgumentNullException(nameof(tagsService)); } public Task OnGetAsync(string applicationIds, string actionType) @@ -84,9 +82,9 @@ public async Task OnPostAsync() if (SelectedTags != null && applicationIds != null && applicationIds.Count > 0) { var selectedTagList = DeserializeJson>(SelectedTags) ?? []; - var tagItems = string.IsNullOrWhiteSpace(TagsJson)? null : DeserializeJson>(TagsJson); + var tagItems = string.IsNullOrWhiteSpace(TagsJson) ? null : DeserializeJson>(TagsJson); await ProcessTagsAsync(uncommonTags, selectedTagList, applicationIds.ToArray(), tagItems); - + } } catch (Exception ex) @@ -127,7 +125,6 @@ private async Task ProcessTagsAsync(string uncommonTagsLabel, List selec try { - await _applicationTagsService.AssignTagsAsync(new AssignApplicationTagsDto { ApplicationId = item, @@ -137,12 +134,9 @@ await _applicationTagsService.AssignTagsAsync(new AssignApplicationTagsDto catch (Exception ex) { Console.WriteLine($"Error processing ApplicationId {item}: {ex.Message}"); - + } } - - - } private static T? DeserializeJson(string jsonString) where T : class { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml index e34a33c80..c3cebf163 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml @@ -3,6 +3,7 @@ @using Microsoft.Extensions.Localization; @using Unity.GrantManager.Permissions; @using Unity.GrantManager.Payments; +@using Unity.Modules.Shared @using Unity.Payments.Permissions @using Volo.Abp.Authorization.Permissions @using Volo.Abp.Features; @@ -20,40 +21,43 @@
+ text="@L["ApplicationList:OpenButton"].Value" + data-selector="applications-table-actions" + class="custom-table-btn flex-none btn btn-secondary action-bar-btn-unavailable" + button-type="Secondary" /> + data-selector="applications-table-actions" + button-type="Secondary" + class="custom-table-btn flex-none btn btn-secondary action-bar-btn-unavailable" + text="@L["ApplicationList:AssignButton"].Value" /> @if (await PermissionChecker.IsGrantedAsync(GrantApplicationPermissions.Approvals.BulkApplicationApproval)) { + data-selector="applications-table-actions" + button-type="Secondary" + class="custom-table-btn flex-none btn btn-secondary action-bar-btn-unavailable" + text="@L["ApplicationList:ApproveButton"].Value" /> } + @if(await PermissionChecker.IsGrantedAsync(UnitySelector.Application.Tags.Create) || await PermissionChecker.IsGrantedAsync(UnitySelector.Application.Tags.Delete)) + { + data-selector="applications-table-actions" + text="@L["ApplicationList:TagButton"].Value" + class="custom-table-btn flex-none btn btn-secondary action-bar-btn-unavailable" + button-type="Secondary" /> + } @if (await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature) && await PermissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.RequestPayment)) { - + } From 10b995118bab1bb50bb7bd5e213b6dac09313eb2 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:27:58 -0700 Subject: [PATCH 07/18] AB#28585 - Tag Permissions - Add Payment Tag Modal Permission Constraints --- .../PaymentTags/PaymentTagAppService.cs | 32 ++++---- .../Pages/PaymentTags/PaymentTags.js | 80 +++++++------------ .../PaymentTagsSelectionModal.cshtml | 20 ++++- .../PaymentTagsSelectionModal.cshtml.cs | 30 +++---- .../PaymentActionBar/Default.cshtml | 17 ++-- .../Pages/ApplicationTags/ApplicationTags.js | 3 +- 6 files changed, 83 insertions(+), 99 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentTags/PaymentTagAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentTags/PaymentTagAppService.cs index 2e0eb04c4..50188c4ff 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentTags/PaymentTagAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentTags/PaymentTagAppService.cs @@ -6,12 +6,12 @@ using System.Threading.Tasks; using Unity.Modules.Shared; using Unity.Payments.Domain.PaymentTags; +using Unity.Payments.Events; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Repositories; -using Volo.Abp.Features; using Volo.Abp.EventBus.Local; -using Unity.Payments.Events; +using Volo.Abp.Features; namespace Unity.Payments.PaymentTags @@ -51,13 +51,11 @@ public async Task> GetListWithPaymentRequestIdsAsync(List(paymentTags); } - + public async Task> AssignTagsAsync(AssignPaymentTagDto input) { var existingApplicationTags = await _paymentTagRepository.GetListAsync(e => e.PaymentRequestId == input.PaymentRequestId); - - var existingTagIds = existingApplicationTags.Select(t => t.TagId).ToHashSet(); var inputTagIds = input.Tags?.Select(t => t.Id).ToHashSet() ?? new HashSet(); var newTagsToAdd = input.Tags? @@ -68,17 +66,17 @@ public async Task> AssignTagsAsync(AssignPaymentTagDto input TagId = tag.Id }) .ToList(); + var tagsToRemove = existingApplicationTags - .Where(et => !inputTagIds.Contains(et.TagId)) - .ToList(); - + .Where(et => !inputTagIds.Contains(et.TagId)) + .ToList(); - if (tagsToRemove.Count > 0) + if (tagsToRemove.Count > 0 && await AuthorizationService.IsGrantedAsync(UnitySelector.Payment.Tags.Delete)) { await _paymentTagRepository.DeleteManyAsync(tagsToRemove, autoSave: true); } - - if (newTagsToAdd?.Count > 0) + + if (newTagsToAdd?.Count > 0 && await AuthorizationService.IsGrantedAsync(UnitySelector.Payment.Tags.Create)) { await _paymentTagRepository.InsertManyAsync(newTagsToAdd, autoSave: true); var tagIds = newTagsToAdd.Select(x => x.TagId).ToList(); @@ -92,7 +90,7 @@ public async Task> AssignTagsAsync(AssignPaymentTagDto input } else { - return new List(); + return []; } } @@ -161,12 +159,12 @@ public async Task> RenameTagAsync(string originalTag, string replacem /// /// String of tag to be deleted. [Authorize(UnitySelector.SettingManagement.Tags.Delete)] - public async Task DeleteTagAsync(Guid id ) + public async Task DeleteTagAsync(Guid id) { - await _paymentTagRepository.DeleteAsync(id); - } - - + await _paymentTagRepository.DeleteAsync(id); + } + + [Authorize(UnitySelector.SettingManagement.Tags.Delete)] public async Task DeleteTagWithTagIdAsync(Guid tagId) { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js index 70ab08e94..93d9a21ff 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js @@ -2,12 +2,11 @@ $(function () { let suggestionsArray = []; - let TagsInput = function (opts) { this.options = Object.assign(TagsInput.defaults, opts); this.init(); } - + TagsInput.prototype.init = function (opts) { this.options = opts ? Object.assign(this.options, opts) : this.options; @@ -24,15 +23,21 @@ $(function () { this.wrapper = document.createElement('div'); this.input = document.createElement('input'); + this.input.id = "tags-input-control"; init(this); initEvents(this); + // Disable the input if user doesn't have create permission + if (!abp.auth.isGranted('Unity.Payments.Tags.Create')) { + this.input.disabled = true; + this.input.type = "hidden"; + this.wrapper.classList.add('tags-input-disabled'); + } + this.initialized = true; return this; } - - TagsInput.prototype.addTag = function (tagData) { let defaultClass = 'tags-common'; let id, tagText, tagClass; @@ -41,8 +46,6 @@ $(function () { tagText = tagData.name || ''; tagClass = tagData.class || defaultClass; - - if (this.anyErrors(tagText)) return; @@ -54,38 +57,40 @@ $(function () { tag.className = this.options.tagClass + ' ' + tagClass; tag.innerText = tagText; - let closeIcon = document.createElement('a'); - closeIcon.innerHTML = '×'; + if (abp.auth.isGranted('Unity.Payments.Tags.Delete')) { + let closeIcon = document.createElement('a'); + closeIcon.innerHTML = '×'; + + closeIcon.addEventListener('click', function (e) { + e.preventDefault(); + let tag = this.parentNode; - - closeIcon.addEventListener('click', function (e) { - e.preventDefault(); - let tag = this.parentNode; + let tagIndex = Array.from(tagInput.wrapper.childNodes).indexOf(tag); + if (tagIndex !== -1) { + tagInput.deleteTag(tag, tagIndex); + } + }) - for (let i = 0; i < tagInput.wrapper.childNodes.length; i++) { - if (tagInput.wrapper.childNodes[i] == tag) - tagInput.deleteTag(tag, i); - } - }) + tag.appendChild(closeIcon); + } - tag.appendChild(closeIcon); this.wrapper.insertBefore(tag, this.input); this.orignal_input.value = JSON.stringify(this.arr); updateSelectedTagsInput(this.arr) return this; } - TagsInput.prototype.deleteTag = function (tag, i) { let self = this; - if (this.arr[i].name === 'Uncommon Tags') { + if (this.arr[i] && this.arr[i].Name === 'Uncommon Tags') { abp.message.confirm('Are you sure you want to delete all the uncommon tags?') .then(function (confirmed) { if (confirmed) { tag.remove(); self.arr.splice(i, 1); self.orignal_input.value = JSON.stringify(self.arr); + updateSelectedTagsInput(self.arr); return self; } }); @@ -93,11 +98,11 @@ $(function () { tag.remove(); this.arr.splice(i, 1); this.orignal_input.value = JSON.stringify(this.arr); + updateSelectedTagsInput(this.arr); return this; } } - TagsInput.prototype.anyErrors = function (string) { if (this.options.max != null && this.arr.length >= this.options.max) { console.log('max tags limit reached'); @@ -115,7 +120,6 @@ $(function () { return false; } - TagsInput.prototype.addData = function (array) { let plugin = this; @@ -125,17 +129,14 @@ $(function () { return this; } - TagsInput.prototype.getInputString = function () { return this.arr.join(','); } - TagsInput.prototype.setSuggestions = function (sugArray) { + TagsInput.prototype.setSuggestions = function (sugArray) { suggestionsArray = sugArray; } - - TagsInput.prototype.destroy = function () { this.orignal_input.removeAttribute('hidden'); @@ -153,7 +154,6 @@ $(function () { this.initialized = false; } - function init(tags) { tags.wrapper.append(tags.input); tags.wrapper.classList.add(tags.options.wrapperClass); @@ -162,45 +162,35 @@ $(function () { tags.input.addEventListener('input', function () { const inputValue = tags.input.value.trim().toLowerCase(); - if (inputValue.length > 1) { const suggestions = suggestionsArray.filter(tag => (tag.name.toLowerCase()).includes(inputValue)); - if (suggestions.length) { displaySuggestions(tags, suggestions); } else { removeSuggestions(tags); } - } else { - removeSuggestions(tags); } }); } - function displaySuggestions(tags, suggestions) { - + removeSuggestions(tags); - const suggestionContainer = document.createElement('div'); suggestionContainer.classList.add('tags-suggestion-container'); const suggestionTitleElement = document.createElement('div'); suggestionTitleElement.className = 'tags-suggestion-title'; suggestionTitleElement.innerText = 'ALL TAGS'; suggestionContainer.appendChild(suggestionTitleElement); - - suggestions.forEach(suggestion => { const suggestionElement = document.createElement('div'); suggestionElement.className = 'tags-suggestion-element'; suggestionElement.innerText = typeof suggestion === 'string' ? suggestion : suggestion.name; - - suggestionElement.addEventListener('click', function () { tags.addTag(suggestion); removeSuggestions(tags); @@ -210,11 +200,9 @@ $(function () { suggestionContainer.appendChild(suggestionElement); }); - tags.wrapper.appendChild(suggestionContainer); } - function removeSuggestions(tags) { const suggestionContainer = tags.wrapper.querySelector('.tags-suggestion-container'); if (suggestionContainer) { @@ -222,33 +210,27 @@ $(function () { } } - // initialize the Events function initEvents(tags) { tags.wrapper.addEventListener('click', function () { tags.input.focus(); }); - tags.input.addEventListener('focusout', function () { $('#assignTagsModelSaveBtn').click(function () { trimAndAddTag(tags); }) }); - tags.input.addEventListener('keydown', function (e) { - if (~[9, 13, 188, 32].indexOf(e.keyCode)) { e.preventDefault(); trimAndAddTag(tags); removeSuggestions(tags); } - }); } - function trimAndAddTag(tags) { let str = tags.input.value.trim(); if (!str) { @@ -256,9 +238,7 @@ $(function () { return; } - const matched = suggestionsArray.find(s => - s.name.toLowerCase() === str.toLowerCase() ); @@ -272,17 +252,14 @@ $(function () { } function updateSelectedTagsInput(tagsArray) { - let jsonValue = JSON.stringify(tagsArray); $('#SelectedTagsJson').val(jsonValue); - } TagsInput.prototype.getTags = function () { return this.arr.slice(); // Return a copy of the array to prevent external modification } - TagsInput.defaults = { selector: '', wrapperClass: 'tags-input-wrapper', @@ -292,5 +269,4 @@ $(function () { } window.TagsInput = TagsInput; - }); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml index fe9adc773..1bac0ad24 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml @@ -1,10 +1,16 @@ @page -@model Unity.Payments.Web.Pages.PaymentTags.PaymentTagsSelectionModalModel +@using Newtonsoft.Json +@using Unity.Modules.Shared @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Abp.Authorization.Permissions + +@model Unity.Payments.Web.Pages.PaymentTags.PaymentTagsSelectionModalModel + @{ Layout = null; } -@using Newtonsoft.Json + +@inject IPermissionChecker PermissionChecker @@ -12,6 +18,16 @@
+ @if (!await PermissionChecker.IsGrantedAsync(UnitySelector.Payment.Tags.Create)) + { +
Note: The current user does not have permission to assign payment tags.
+ } + + @if (!await PermissionChecker.IsGrantedAsync(UnitySelector.Payment.Tags.Delete)) + { +
Note: The current user does not have permission to remove payment tags.
+ } + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml.cs index 2df0bdbe5..f76115591 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTagsSelectionModal.cshtml.cs @@ -1,11 +1,11 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Unity.GrantManager.GlobalTag; using Unity.Payments.PaymentTags; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; @@ -38,8 +38,6 @@ public class PaymentTagsSelectionModalModel : AbpPageModel public string? ActionType { get; set; } = string.Empty; private readonly IPaymentTagAppService _paymentTagsService; - private readonly ITagsService _tagsService; - [BindProperty] [DisplayName("Common Tags")] @@ -54,28 +52,22 @@ public class PaymentTagsSelectionModalModel : AbpPageModel public List Tags { get; set; } = new(); [BindProperty] - public string? SelectedTagsJson { get; set; } + public string? SelectedTagsJson { get; set; } [BindProperty] public string? TagsJson { get; set; } - - public PaymentTagsSelectionModalModel(IPaymentTagAppService paymentTagAppService, ITagsService tagsService) + public PaymentTagsSelectionModalModel(IPaymentTagAppService paymentTagAppService) { _paymentTagsService = paymentTagAppService ?? throw new ArgumentNullException(nameof(paymentTagAppService)); - _tagsService = tagsService ?? throw new ArgumentNullException(nameof(tagsService)); - } - public Task OnGetAsync(string paymentRequestIds, string actionType) + public Task OnGetAsync(string paymentRequestIds, string actionType) { - SelectedPaymentRequestIds = paymentRequestIds; ActionType = actionType; - return Task.CompletedTask; - } public async Task OnPostAsync() @@ -88,7 +80,7 @@ public async Task OnPostAsync() var paymentRequestIds = JsonConvert.DeserializeObject>(SelectedPaymentRequestIds); if (SelectedTags != null) { - + var selectedTagList = DeserializeJson>(SelectedTags) ?? []; if (null != paymentRequestIds) { @@ -118,8 +110,8 @@ private async Task ProcessTagsAsync(string uncommonTagsLabel, List selec for (int i = 0; i < selectedPaymentRequestIds.Length; i++) { var item = selectedPaymentRequestIds[i]; - - var tagList = new List(); + + var tagList = new List(); if (tags != null && tags.Count > 0 && selectedTags != null @@ -130,7 +122,7 @@ private async Task ProcessTagsAsync(string uncommonTagsLabel, List selec if (paymentTag?.UncommonTags != null) { - + tagList.AddRange(paymentTag.UncommonTags); } } @@ -158,7 +150,7 @@ await _paymentTagsService.AssignTagsAsync(new AssignPaymentTagDto } } - + private static T? DeserializeJson(string jsonString) where T : class { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/PaymentActionBar/Default.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/PaymentActionBar/Default.cshtml index 87df724af..5e8eb59e5 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/PaymentActionBar/Default.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/PaymentActionBar/Default.cshtml @@ -1,20 +1,23 @@ -
+@using Unity.Modules.Shared +@using Volo.Abp.Authorization.Permissions + +@inject IPermissionChecker PermissionChecker + +
- + @if(await PermissionChecker.IsGrantedAsync(UnitySelector.Payment.Tags.Create) || await PermissionChecker.IsGrantedAsync(UnitySelector.Payment.Tags.Delete)) + { - + }
-
- - -
+
\ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js index 3b473293a..7f604c947 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js @@ -23,7 +23,7 @@ $(function () { this.wrapper = document.createElement('div'); this.input = document.createElement('input'); - this.input.Id = "tags-input-control"; + this.input.id = "tags-input-control"; init(this); initEvents(this); @@ -63,7 +63,6 @@ $(function () { closeIcon.addEventListener('click', function (e) { e.preventDefault(); - console.log("Delete Tag"); let tag = this.parentNode; let tagIndex = Array.from(tagInput.wrapper.childNodes).indexOf(tag); From 1376a817e9c081c4f8765612d041719810dd54d6 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:38:48 -0700 Subject: [PATCH 08/18] AB#28585 - Code Quality Improvements --- .../src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js | 2 +- .../Permissions/PermissionGrantsDataSeeder.cs | 2 +- .../Pages/ApplicationTags/ApplicationTags.js | 2 +- .../Views/Shared/Components/ActionBar/Default.cshtml | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js index 93d9a21ff..1982933b0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentTags/PaymentTags.js @@ -83,7 +83,7 @@ $(function () { TagsInput.prototype.deleteTag = function (tag, i) { let self = this; - if (this.arr[i] && this.arr[i].Name === 'Uncommon Tags') { + if (this.arr[i] && this.arr[i].name === 'Uncommon Tags') { abp.message.confirm('Are you sure you want to delete all the uncommon tags?') .then(function (confirmed) { if (confirmed) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs index 7b693ed57..a4e280e48 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs @@ -237,7 +237,7 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, NotificationsPermissions.Settings, .. Dashboard_CommonPermissions, .. Tags_CommonPermissions, - UnitySettingManagementPermissions.ConfigurePayments, + UnitySettingManagementPermissions.ConfigurePayments, UnitySettingManagementPermissions.BackgroundJobSettings, ], context.TenantId); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js index 7f604c947..1f6632be2 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationTags/ApplicationTags.js @@ -83,7 +83,7 @@ $(function () { TagsInput.prototype.deleteTag = function (tag, i) { let self = this; - if (this.arr[i] && this.arr[i].Name === 'Uncommon Tags') { + if (this.arr[i] && this.arr[i].name === 'Uncommon Tags') { abp.message.confirm('Are you sure you want to delete all the uncommon tags?') .then(function (confirmed) { if (confirmed) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml index c3cebf163..187c23567 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ActionBar/Default.cshtml @@ -3,9 +3,9 @@ @using Microsoft.Extensions.Localization; @using Unity.GrantManager.Permissions; @using Unity.GrantManager.Payments; -@using Unity.Modules.Shared -@using Unity.Payments.Permissions -@using Volo.Abp.Authorization.Permissions +@using Unity.Modules.Shared; +@using Unity.Payments.Permissions; +@using Volo.Abp.Authorization.Permissions; @using Volo.Abp.Features; @inject IStringLocalizer L From eebb12789b76b1d869f1a3a897af5545aaf6a068 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:44:36 -0700 Subject: [PATCH 09/18] AB#28707 - Remove display of unused Non-Registered Business Name Columns --- .../GrantApplications/GrantApplicationDto.cs | 1 - .../GrantApplicationAppService.cs | 2062 ++++++++--------- .../Localization/GrantManager/en.json | 1 - .../Pages/GrantApplications/Index.js | 14 - 4 files changed, 1030 insertions(+), 1048 deletions(-) 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 cd21fd862..6be96816b 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 @@ -61,7 +61,6 @@ public class GrantApplicationDto : AuditedEntityDto public List? ApplicationTag { get; set; } public Guid? OwnerId { get; set; } public string? OrganizationName { get; set; } - public string? NonRegisteredBusinessName { get; set; } public string? NonRegOrgName { get; set; } public string? OrganizationType { get; set; } public GrantApplicationAssigneeDto Owner { get; set; } = new(); 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 c1c01a68a..1aac29ab8 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -1,161 +1,160 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Authorization.Infrastructure; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Unity.Flex.WorksheetInstances; -using Unity.Flex.Worksheets; -using Unity.GrantManager.Applicants; -using Unity.GrantManager.ApplicationForms; -using Unity.GrantManager.Applications; -using Unity.GrantManager.Comments; -using Unity.GrantManager.Events; -using Unity.GrantManager.Exceptions; -using Unity.GrantManager.Flex; -using Unity.GrantManager.Identity; -using Unity.GrantManager.Payments; -using Unity.GrantManager.Permissions; -using Unity.GrantManager.Zones; -using Unity.Modules.Shared; -using Unity.Modules.Shared.Correlation; -using Unity.Payments.Domain.PaymentRequests; -using Unity.Payments.Enums; -using Unity.Payments.PaymentRequests; -using Unity.Payments.Permissions; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Authorization; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.EventBus.Local; - -namespace Unity.GrantManager.GrantApplications; - -[Authorize] -[Dependency(ReplaceServices = true)] -[ExposeServices(typeof(GrantApplicationAppService), typeof(IGrantApplicationAppService))] -public class GrantApplicationAppService : GrantManagerAppService, IGrantApplicationAppService -{ - - private readonly IApplicationRepository _applicationRepository; - private readonly IApplicationManager _applicationManager; - private readonly IApplicationStatusRepository _applicationStatusRepository; - private readonly IApplicationFormSubmissionRepository _applicationFormSubmissionRepository; - private readonly IApplicationAssignmentRepository _applicationAssignmentRepository; - private readonly IApplicantRepository _applicantRepository; - private readonly ICommentsManager _commentsManager; - private readonly IApplicationFormRepository _applicationFormRepository; - private readonly IPersonRepository _personRepository; - private readonly IApplicantAgentRepository _applicantAgentRepository; - private readonly IApplicantAddressRepository _applicantAddressRepository; - private readonly ILocalEventBus _localEventBus; - private readonly IApplicantSupplierAppService _applicantSupplierService; - private readonly IPaymentRequestAppService _paymentRequestService; - private readonly IPaymentRequestRepository _paymentRequestsRepository; - private readonly IZoneChecker _zoneChecker; - - public GrantApplicationAppService( - IApplicationManager applicationManager, - IApplicationRepository applicationRepository, - IApplicationStatusRepository applicationStatusRepository, - IApplicationAssignmentRepository applicationAssignmentRepository, - IApplicationFormSubmissionRepository applicationFormSubmissionRepository, - IApplicantRepository applicantRepository, - ICommentsManager commentsManager, - IApplicationFormRepository applicationFormRepository, - IPersonRepository personRepository, - IApplicantAgentRepository applicantAgentRepository, - IApplicantAddressRepository applicantAddressRepository, - ILocalEventBus localEventBus, - IApplicantSupplierAppService applicantSupplierService, - IPaymentRequestAppService paymentRequestService, - IPaymentRequestRepository paymentRequestsRepository, - IZoneChecker zoneChecker) - { - _applicationRepository = applicationRepository; - _applicationManager = applicationManager; - _applicationStatusRepository = applicationStatusRepository; - _applicationAssignmentRepository = applicationAssignmentRepository; - _applicationFormSubmissionRepository = applicationFormSubmissionRepository; - _applicantRepository = applicantRepository; - _commentsManager = commentsManager; - _applicationFormRepository = applicationFormRepository; - _personRepository = personRepository; - _applicantAgentRepository = applicantAgentRepository; - _applicantAddressRepository = applicantAddressRepository; - _applicantSupplierService = applicantSupplierService; - _localEventBus = localEventBus; - _paymentRequestService = paymentRequestService; - _paymentRequestsRepository = paymentRequestsRepository; - _zoneChecker = zoneChecker; - } - - public async Task> GetListAsync(PagedAndSortedResultRequestDto input) - { - var groupedResult = await _applicationRepository.WithFullDetailsGroupedAsync(input.SkipCount, input.MaxResultCount, input.Sorting); - - // Pre-fetch payment requests for all applications in a single query to reduce database calls - var applicationIds = groupedResult.SelectMany(g => g).Select(a => a.Id).ToList(); - - bool paymentsFeatureEnabled = await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature); - - List paymentRequests = new List(); - if (paymentsFeatureEnabled) - { - paymentRequests = await _paymentRequestService.GetListByApplicationIdsAsync(applicationIds); - } - - - // Map applications to DTOs - var appDtos = groupedResult.Select(grouping => - { - var firstApplication = grouping.First(); - var appDto = ObjectMapper.Map(firstApplication); - - // Map additional properties - appDto.Status = firstApplication.ApplicationStatus.InternalStatus; - appDto.Applicant = ObjectMapper.Map(firstApplication.Applicant); - appDto.Category = firstApplication.ApplicationForm.Category ?? string.Empty; - appDto.ApplicationTag = ObjectMapper.Map, List>(firstApplication.ApplicationTags?.ToList() ?? new List()); - appDto.Owner = BuildApplicationOwner(firstApplication.Owner); - appDto.OrganizationName = firstApplication.Applicant?.OrgName ?? string.Empty; - appDto.NonRegisteredBusinessName = firstApplication.Applicant?.NonRegisteredBusinessName ?? string.Empty; - appDto.NonRegOrgName = firstApplication.Applicant?.NonRegOrgName ?? string.Empty; - appDto.OrganizationType = firstApplication.Applicant?.OrganizationType ?? string.Empty; - appDto.Assignees = BuildApplicationAssignees(firstApplication.ApplicationAssignments); - appDto.SubStatusDisplayValue = MapSubstatusDisplayValue(appDto.SubStatus); - appDto.DeclineRational = MapDeclineRationalDisplayValue(appDto.DeclineRational); - appDto.ContactFullName = firstApplication.ApplicantAgent?.Name; - appDto.ContactEmail = firstApplication.ApplicantAgent?.Email; - appDto.ContactTitle = firstApplication.ApplicantAgent?.Title; - appDto.ContactBusinessPhone = firstApplication.ApplicantAgent?.Phone; - appDto.ContactCellPhone = firstApplication.ApplicantAgent?.Phone2; - - //Payment request info if the feature is enabled - - if (paymentsFeatureEnabled && paymentRequests != null && paymentRequests is { Count: > 0 }) - { - var paymentInfo = new PaymentInfoDto - { - ApprovedAmount = firstApplication.ApprovedAmount, - TotalPaid = paymentRequests - .Where(pr => pr.CorrelationId == firstApplication.Id && pr.Status.Equals(PaymentRequestStatus.Submitted)) - .Sum(pr => pr.Amount) - }; - appDto.PaymentInfo = paymentInfo; - } - - return appDto; - }).ToList(); +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization.Infrastructure; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Unity.Flex.WorksheetInstances; +using Unity.Flex.Worksheets; +using Unity.GrantManager.Applicants; +using Unity.GrantManager.ApplicationForms; +using Unity.GrantManager.Applications; +using Unity.GrantManager.Comments; +using Unity.GrantManager.Events; +using Unity.GrantManager.Exceptions; +using Unity.GrantManager.Flex; +using Unity.GrantManager.Identity; +using Unity.GrantManager.Payments; +using Unity.GrantManager.Permissions; +using Unity.GrantManager.Zones; +using Unity.Modules.Shared; +using Unity.Modules.Shared.Correlation; +using Unity.Payments.Domain.PaymentRequests; +using Unity.Payments.Enums; +using Unity.Payments.PaymentRequests; +using Unity.Payments.Permissions; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Authorization; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.EventBus.Local; + +namespace Unity.GrantManager.GrantApplications; + +[Authorize] +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(GrantApplicationAppService), typeof(IGrantApplicationAppService))] +public class GrantApplicationAppService : GrantManagerAppService, IGrantApplicationAppService +{ + + private readonly IApplicationRepository _applicationRepository; + private readonly IApplicationManager _applicationManager; + private readonly IApplicationStatusRepository _applicationStatusRepository; + private readonly IApplicationFormSubmissionRepository _applicationFormSubmissionRepository; + private readonly IApplicationAssignmentRepository _applicationAssignmentRepository; + private readonly IApplicantRepository _applicantRepository; + private readonly ICommentsManager _commentsManager; + private readonly IApplicationFormRepository _applicationFormRepository; + private readonly IPersonRepository _personRepository; + private readonly IApplicantAgentRepository _applicantAgentRepository; + private readonly IApplicantAddressRepository _applicantAddressRepository; + private readonly ILocalEventBus _localEventBus; + private readonly IApplicantSupplierAppService _applicantSupplierService; + private readonly IPaymentRequestAppService _paymentRequestService; + private readonly IPaymentRequestRepository _paymentRequestsRepository; + private readonly IZoneChecker _zoneChecker; + + public GrantApplicationAppService( + IApplicationManager applicationManager, + IApplicationRepository applicationRepository, + IApplicationStatusRepository applicationStatusRepository, + IApplicationAssignmentRepository applicationAssignmentRepository, + IApplicationFormSubmissionRepository applicationFormSubmissionRepository, + IApplicantRepository applicantRepository, + ICommentsManager commentsManager, + IApplicationFormRepository applicationFormRepository, + IPersonRepository personRepository, + IApplicantAgentRepository applicantAgentRepository, + IApplicantAddressRepository applicantAddressRepository, + ILocalEventBus localEventBus, + IApplicantSupplierAppService applicantSupplierService, + IPaymentRequestAppService paymentRequestService, + IPaymentRequestRepository paymentRequestsRepository, + IZoneChecker zoneChecker) + { + _applicationRepository = applicationRepository; + _applicationManager = applicationManager; + _applicationStatusRepository = applicationStatusRepository; + _applicationAssignmentRepository = applicationAssignmentRepository; + _applicationFormSubmissionRepository = applicationFormSubmissionRepository; + _applicantRepository = applicantRepository; + _commentsManager = commentsManager; + _applicationFormRepository = applicationFormRepository; + _personRepository = personRepository; + _applicantAgentRepository = applicantAgentRepository; + _applicantAddressRepository = applicantAddressRepository; + _applicantSupplierService = applicantSupplierService; + _localEventBus = localEventBus; + _paymentRequestService = paymentRequestService; + _paymentRequestsRepository = paymentRequestsRepository; + _zoneChecker = zoneChecker; + } + + public async Task> GetListAsync(PagedAndSortedResultRequestDto input) + { + var groupedResult = await _applicationRepository.WithFullDetailsGroupedAsync(input.SkipCount, input.MaxResultCount, input.Sorting); + + // Pre-fetch payment requests for all applications in a single query to reduce database calls + var applicationIds = groupedResult.SelectMany(g => g).Select(a => a.Id).ToList(); + + bool paymentsFeatureEnabled = await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature); + + List paymentRequests = new List(); + if (paymentsFeatureEnabled) + { + paymentRequests = await _paymentRequestService.GetListByApplicationIdsAsync(applicationIds); + } + + + // Map applications to DTOs + var appDtos = groupedResult.Select(grouping => + { + var firstApplication = grouping.First(); + var appDto = ObjectMapper.Map(firstApplication); + + // Map additional properties + appDto.Status = firstApplication.ApplicationStatus.InternalStatus; + appDto.Applicant = ObjectMapper.Map(firstApplication.Applicant); + appDto.Category = firstApplication.ApplicationForm.Category ?? string.Empty; + appDto.ApplicationTag = ObjectMapper.Map, List>(firstApplication.ApplicationTags?.ToList() ?? new List()); + appDto.Owner = BuildApplicationOwner(firstApplication.Owner); + appDto.OrganizationName = firstApplication.Applicant?.OrgName ?? string.Empty; + appDto.NonRegOrgName = firstApplication.Applicant?.NonRegOrgName ?? string.Empty; + appDto.OrganizationType = firstApplication.Applicant?.OrganizationType ?? string.Empty; + appDto.Assignees = BuildApplicationAssignees(firstApplication.ApplicationAssignments); + appDto.SubStatusDisplayValue = MapSubstatusDisplayValue(appDto.SubStatus); + appDto.DeclineRational = MapDeclineRationalDisplayValue(appDto.DeclineRational); + appDto.ContactFullName = firstApplication.ApplicantAgent?.Name; + appDto.ContactEmail = firstApplication.ApplicantAgent?.Email; + appDto.ContactTitle = firstApplication.ApplicantAgent?.Title; + appDto.ContactBusinessPhone = firstApplication.ApplicantAgent?.Phone; + appDto.ContactCellPhone = firstApplication.ApplicantAgent?.Phone2; + + //Payment request info if the feature is enabled + + if (paymentsFeatureEnabled && paymentRequests != null && paymentRequests is { Count: > 0 }) + { + var paymentInfo = new PaymentInfoDto + { + ApprovedAmount = firstApplication.ApprovedAmount, + TotalPaid = paymentRequests + .Where(pr => pr.CorrelationId == firstApplication.Id && pr.Status.Equals(PaymentRequestStatus.Submitted)) + .Sum(pr => pr.Amount) + }; + appDto.PaymentInfo = paymentInfo; + } + + return appDto; + }).ToList(); long totalCount = 0; try @@ -166,408 +165,407 @@ public async Task> GetListAsync(PagedAndSort Logger.LogError(ex, "An exception occurred GetCountAsync: {ExceptionMessage}", ex.Message); } - return new PagedResultDto(totalCount, appDtos); - } - - - private static string MapSubstatusDisplayValue(string subStatus) - { - if (subStatus == null) { return string.Empty; } - var hasKey = AssessmentResultsOptionsList.SubStatusActionList.TryGetValue(subStatus, out string? subStatusValue); - if (hasKey) - return subStatusValue ?? string.Empty; - else - return string.Empty; - } - private static string MapDeclineRationalDisplayValue(string value) - { - if (value == null) { return string.Empty; } - var hasKey = AssessmentResultsOptionsList.DeclineRationalActionList.TryGetValue(value, out string? subStatusValue); - if (hasKey) - return subStatusValue ?? string.Empty; - else - return string.Empty; - } - - private static List BuildApplicationAssignees(IEnumerable? applicationAssignments) - { - var appAssignmentDtos = new List(); - if (applicationAssignments != null) - { - foreach (var assignment in applicationAssignments) - { - appAssignmentDtos.Add(new GrantApplicationAssigneeDto() - { - ApplicationId = assignment.ApplicationId, - AssigneeId = assignment.AssigneeId, - FullName = assignment.Assignee?.FullName ?? string.Empty, - Id = assignment.Id, - Duty = assignment.Duty - }); - } - } - return appAssignmentDtos; - } - - private static GrantApplicationAssigneeDto BuildApplicationOwner(Person? applicationOwner) - { - if (applicationOwner != null) - { - return new GrantApplicationAssigneeDto() - { - Id = applicationOwner.Id, - FullName = applicationOwner.FullName - }; - } - return new GrantApplicationAssigneeDto(); - } - - public async Task GetAsync(Guid id) - { - var application = await _applicationRepository.GetWithFullDetailsByIdAsync(id); - - if (application == null) return new GrantApplicationDto(); - - var appDto = ObjectMapper.Map(application); - - appDto.StatusCode = application.ApplicationStatus.StatusCode; - appDto.Status = application.ApplicationStatus.InternalStatus; - - if (application.ApplicantAgent != null) - { - appDto.ContactFullName = application.ApplicantAgent.Name; - appDto.ContactEmail = application.ApplicantAgent.Email; - appDto.ContactTitle = application.ApplicantAgent.Title; - appDto.ContactBusinessPhone = application.ApplicantAgent.Phone; - appDto.ContactCellPhone = application.ApplicantAgent.Phone2; - } - - if (application.Applicant != null) - { - appDto.OrganizationName = application.Applicant.OrgName; - appDto.OrgNumber = application.Applicant.OrgNumber; - appDto.OrganizationSize = application.Applicant.OrganizationSize; - appDto.OrgStatus = application.Applicant.OrgStatus; - appDto.NonRegisteredBusinessName = application.Applicant.NonRegisteredBusinessName; - appDto.NonRegOrgName = application.Applicant.NonRegOrgName; - appDto.Sector = application.Applicant.Sector; - appDto.OrganizationType = application.Applicant.OrganizationType; - appDto.SubSector = application.Applicant.SubSector; - appDto.SectorSubSectorIndustryDesc = application.Applicant.SectorSubSectorIndustryDesc; - } - - return appDto; - } - - public async Task GetApplicationFormAsync(Guid applicationFormId) - { - return await (await _applicationFormRepository.GetQueryableAsync()).FirstOrDefaultAsync(s => s.Id == applicationFormId); - } - - public async Task GetSummaryAsync(Guid applicationId) - { - var query = from application in await _applicationRepository.GetQueryableAsync() - join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id - join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id - where application.Id == applicationId - select new GetSummaryDto - { - Category = applicationForm == null ? string.Empty : applicationForm.Category, - SubmissionDate = application.SubmissionDate, - OrganizationName = applicant.OrgName, - OrganizationNumber = applicant.OrgNumber, - EconomicRegion = application.EconomicRegion, - City = application.City, - RequestedAmount = application.RequestedAmount, - ProjectBudget = application.TotalProjectBudget, - Sector = applicant.Sector, - Community = application.Community, - Status = application.ApplicationStatus.InternalStatus, - LikelihoodOfFunding = application.LikelihoodOfFunding != null && application.LikelihoodOfFunding != "" ? AssessmentResultsOptionsList.FundingList[application.LikelihoodOfFunding] : "", - AssessmentStartDate = string.Format("{0:yyyy/MM/dd}", application.AssessmentStartDate), - FinalDecisionDate = string.Format("{0:yyyy/MM/dd}", application.FinalDecisionDate), - TotalScore = application.TotalScore.ToString(), - AssessmentResult = application.AssessmentResultStatus != null && application.AssessmentResultStatus != "" ? AssessmentResultsOptionsList.AssessmentResultStatusList[application.AssessmentResultStatus] : "", - RecommendedAmount = application.RecommendedAmount, - ApprovedAmount = application.ApprovedAmount, - Batch = "", // to-do: ask BA for the implementation of Batch field, - RegionalDistrict = application.RegionalDistrict, - OwnerId = application.OwnerId, - - }; - - var queryResult = await AsyncExecuter.FirstOrDefaultAsync(query); - if (queryResult != null) - { - var ownerId = queryResult.OwnerId ?? Guid.Empty; - queryResult.Owner = await GetOwnerAsync(ownerId); - queryResult.Assignees = await GetAssigneesAsync(applicationId); - - return queryResult; - } - else - { - return await Task.FromResult(new GetSummaryDto()); - } - - } - - [Authorize(UnitySelector.Review.AssessmentResults.Update.Default)] - public async Task UpdateAssessmentResultsAsync(Guid id, CreateUpdateAssessmentResultsDto input) - { - var application = await _applicationRepository.GetAsync(id); - - await SanitizeApprovalZoneInputs(input, application); - await SanitizeAssessmentResultsZoneInputs(input, application); - - application.ValidateAndSetDueDate(input.DueDate); - application.UpdateAlwaysChangeableFields(input.Notes, input.SubStatus, input.LikelihoodOfFunding, input.TotalProjectBudget, input.NotificationDate, input.RiskRanking); - - if (application.IsInFinalDecisionState()) - { - if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.Approval.Update.UpdateFinalStateFields)) - { - application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); - } - - if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.UpdateFinalStateFields)) // User allowed to edit specific fields past approval - { - application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); - } - } - else - { - if (await CurrentUserCanUpdateAssessmentFieldsAsync()) - { - application.ValidateAndSetFinalDecisionDate(input.FinalDecisionDate); - application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); - application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); - application.UpdateFieldsOnlyForPreFinalDecision(input.DueDiligenceStatus, - input.RecommendedAmount, - input.DeclineRational); - - application.UpdateAssessmentResultStatus(input.AssessmentResultStatus); - } - } - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.AssessmentInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - return ObjectMapper.Map(application); - } - - private async Task SanitizeApprovalZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) - { - // Approval Zone Fields - Disabled Inputs - input.ApprovedAmount ??= application.ApprovedAmount; - - // Sanitize if zone is disabled - if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.Approval.Default, application.ApplicationFormId)) - { - input.SubStatus ??= application.SubStatus; - input.FinalDecisionDate ??= application.FinalDecisionDate; - input.Notes ??= application.Notes; - } - else - { - // Sanitize if zone is enabled but fields are disabled - if (application.IsInFinalDecisionState()) - { - input.FinalDecisionDate ??= application.FinalDecisionDate; - } - } - } - - private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) - { - // Approval Zone Fields - Disabled Inputs - input.RequestedAmount ??= application.RequestedAmount; - input.TotalProjectBudget ??= application.TotalProjectBudget; - input.RecommendedAmount ??= application.RecommendedAmount; - input.TotalScore ??= application.TotalScore; - - // Sanitize if zone is disabled - if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.AssessmentResults.Default, application.ApplicationFormId)) - { - input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; - input.RiskRanking ??= application.RiskRanking; - input.DueDiligenceStatus ??= application.DueDiligenceStatus; - input.AssessmentResultStatus ??= application.AssessmentResultStatus; - input.DeclineRational ??= application.DeclineRational; - - input.NotificationDate ??= application.NotificationDate; - input.DueDate ??= application.DueDate; - } - else - { - // Sanitize if zone is enabled but fields are disabled - if (application.IsInFinalDecisionState()) - { - input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; - input.RiskRanking ??= application.RiskRanking; - input.DueDiligenceStatus ??= application.DueDiligenceStatus; - input.AssessmentResultStatus ??= application.AssessmentResultStatus; - input.DeclineRational ??= application.DeclineRational; - } - } - } - - private async Task CurrentUserCanUpdateAssessmentFieldsAsync() - { - return await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.Default); - } - - [Authorize(UnitySelector.Project.UpdatePolicy)] - public async Task UpdateProjectInfoAsync(Guid id, CreateUpdateProjectInfoDto input) - { - // Check if the user has the required permissions to update Project Info for either fieldset zone - var hasSummaryPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Summary.Update.Default); - var hasLocationPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Location.Update.Default); - - if (!hasSummaryPermission || !hasLocationPermission) - { - throw new AbpAuthorizationException("The user doesn't have the required permissions to update Project Info."); - } - - var application = await _applicationRepository.GetAsync(id); - - var hasSummaryZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Summary.Default, application.ApplicationFormId); - var hasLocationZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Location.Default, application.ApplicationFormId); - - if (!hasSummaryZone || !hasLocationZone) - { - throw new BusinessException("The Project Info zones are not enabled for this application form."); - } - - SanitizeProjectInfoDisabledInputs(input, application); - - var percentageTotalProjectBudget = (input.TotalProjectBudget == 0 || input.TotalProjectBudget == null) ? 0 : decimal.Multiply(decimal.Divide(input.RequestedAmount ?? 0, input.TotalProjectBudget ?? 0), 100).To(); - - if (application != null) - { - application.ProjectSummary = input.ProjectSummary; - application.ProjectName = input.ProjectName ?? string.Empty; - application.RequestedAmount = input.RequestedAmount ?? 0; - application.TotalProjectBudget = input.TotalProjectBudget ?? 0; - application.ProjectStartDate = input.ProjectStartDate; - application.ProjectEndDate = input.ProjectEndDate; - application.PercentageTotalProjectBudget = Math.Round(percentageTotalProjectBudget, 2); - application.ProjectFundingTotal = input.ProjectFundingTotal; - application.Community = input.Community; - application.CommunityPopulation = input.CommunityPopulation; - application.Acquisition = input.Acquisition; - application.Forestry = input.Forestry; - application.ForestryFocus = input.ForestryFocus; - application.EconomicRegion = input.EconomicRegion; - application.ElectoralDistrict = input.ElectoralDistrict; - application.RegionalDistrict = input.RegionalDistrict; - application.Place = input.Place; - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - return ObjectMapper.Map(application); - } - else - { - throw new EntityNotFoundException(); - } - } - private static void SanitizeProjectInfoDisabledInputs(CreateUpdateProjectInfoDto input, Application application) - { - // Cater for disabled fields that are not serialized with post - fall back to the previous value, these should be 0 from the API call - input.TotalProjectBudget ??= application.TotalProjectBudget; - input.RequestedAmount ??= application.RequestedAmount; - input.ProjectFundingTotal ??= application.ProjectFundingTotal; - } - - [Authorize(UnitySelector.Project.UpdatePolicy)] - public async Task UpdatePartialProjectInfoAsync(Guid id, PartialUpdateDto input) - { - // Only update the fields we need to update based on the modified fields - // This is required to handle controls like the date picker that do not send null values for unchanged fields - var application = await _applicationRepository.GetAsync(id) ?? throw new EntityNotFoundException($"Application with ID {id} not found."); - ObjectMapper.Map(input.Data, application); - - // Explicitly handle properties that are null but listed in ModifiedFields - var dtoProperties = typeof(UpdateProjectInfoDto).GetProperties(); - var appProperties = typeof(Application).GetProperties().ToDictionary(p => p.Name, p => p); - - foreach (var fieldName in input.ModifiedFields) - { - if (dtoProperties.FirstOrDefault(p => - string.Equals(p.Name, fieldName, StringComparison.OrdinalIgnoreCase)) is { } dtoProperty) - { - var value = dtoProperty.GetValue(input.Data); - if (value == null && appProperties.TryGetValue(dtoProperty.Name, out var appProperty) && appProperty.CanWrite) - { - appProperty.SetValue(application, appProperty.PropertyType.IsValueType - && Nullable.GetUnderlyingType(appProperty.PropertyType) == null - ? Activator.CreateInstance(appProperty.PropertyType) - : null); - } - } - } - - // Calculate the percentage of the total project budget based on - // the requested amount and total project budget. Percentage total has to be - // updated whenever RequestedAmount or TotalProjectBudget changes - application.UpdatePercentageTotalProjectBudget(); - - // Add custom worksheet data - if (input.Data.CustomFields is not null && input.Data.WorksheetId != Guid.Empty && input.Data.CorrelationId != Guid.Empty) - { - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input.Data); - } - - await _applicationRepository.UpdateAsync(application); - return ObjectMapper.Map(application); - } - - public async Task UpdateFundingAgreementInfoAsync(Guid id, CreateUpdateFundingAgreementInfoDto input) - { - var application = await _applicationRepository.GetAsync(id); - - if (application != null) - { - application.ContractNumber = input.ContractNumber; - application.ContractExecutionDate = input.ContractExecutionDate; - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.FundingAgreementInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - return ObjectMapper.Map(application); - } - else - { - throw new EntityNotFoundException(); - } - } - + return new PagedResultDto(totalCount, appDtos); + } + + + private static string MapSubstatusDisplayValue(string subStatus) + { + if (subStatus == null) { return string.Empty; } + var hasKey = AssessmentResultsOptionsList.SubStatusActionList.TryGetValue(subStatus, out string? subStatusValue); + if (hasKey) + return subStatusValue ?? string.Empty; + else + return string.Empty; + } + private static string MapDeclineRationalDisplayValue(string value) + { + if (value == null) { return string.Empty; } + var hasKey = AssessmentResultsOptionsList.DeclineRationalActionList.TryGetValue(value, out string? subStatusValue); + if (hasKey) + return subStatusValue ?? string.Empty; + else + return string.Empty; + } + + private static List BuildApplicationAssignees(IEnumerable? applicationAssignments) + { + var appAssignmentDtos = new List(); + if (applicationAssignments != null) + { + foreach (var assignment in applicationAssignments) + { + appAssignmentDtos.Add(new GrantApplicationAssigneeDto() + { + ApplicationId = assignment.ApplicationId, + AssigneeId = assignment.AssigneeId, + FullName = assignment.Assignee?.FullName ?? string.Empty, + Id = assignment.Id, + Duty = assignment.Duty + }); + } + } + return appAssignmentDtos; + } + + private static GrantApplicationAssigneeDto BuildApplicationOwner(Person? applicationOwner) + { + if (applicationOwner != null) + { + return new GrantApplicationAssigneeDto() + { + Id = applicationOwner.Id, + FullName = applicationOwner.FullName + }; + } + return new GrantApplicationAssigneeDto(); + } + + public async Task GetAsync(Guid id) + { + var application = await _applicationRepository.GetWithFullDetailsByIdAsync(id); + + if (application == null) return new GrantApplicationDto(); + + var appDto = ObjectMapper.Map(application); + + appDto.StatusCode = application.ApplicationStatus.StatusCode; + appDto.Status = application.ApplicationStatus.InternalStatus; + + if (application.ApplicantAgent != null) + { + appDto.ContactFullName = application.ApplicantAgent.Name; + appDto.ContactEmail = application.ApplicantAgent.Email; + appDto.ContactTitle = application.ApplicantAgent.Title; + appDto.ContactBusinessPhone = application.ApplicantAgent.Phone; + appDto.ContactCellPhone = application.ApplicantAgent.Phone2; + } + + if (application.Applicant != null) + { + appDto.OrganizationName = application.Applicant.OrgName; + appDto.OrgNumber = application.Applicant.OrgNumber; + appDto.OrganizationSize = application.Applicant.OrganizationSize; + appDto.OrgStatus = application.Applicant.OrgStatus; + appDto.NonRegOrgName = application.Applicant.NonRegOrgName; + appDto.Sector = application.Applicant.Sector; + appDto.OrganizationType = application.Applicant.OrganizationType; + appDto.SubSector = application.Applicant.SubSector; + appDto.SectorSubSectorIndustryDesc = application.Applicant.SectorSubSectorIndustryDesc; + } + + return appDto; + } + + public async Task GetApplicationFormAsync(Guid applicationFormId) + { + return await (await _applicationFormRepository.GetQueryableAsync()).FirstOrDefaultAsync(s => s.Id == applicationFormId); + } + + public async Task GetSummaryAsync(Guid applicationId) + { + var query = from application in await _applicationRepository.GetQueryableAsync() + join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id + join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id + where application.Id == applicationId + select new GetSummaryDto + { + Category = applicationForm == null ? string.Empty : applicationForm.Category, + SubmissionDate = application.SubmissionDate, + OrganizationName = applicant.OrgName, + OrganizationNumber = applicant.OrgNumber, + EconomicRegion = application.EconomicRegion, + City = application.City, + RequestedAmount = application.RequestedAmount, + ProjectBudget = application.TotalProjectBudget, + Sector = applicant.Sector, + Community = application.Community, + Status = application.ApplicationStatus.InternalStatus, + LikelihoodOfFunding = application.LikelihoodOfFunding != null && application.LikelihoodOfFunding != "" ? AssessmentResultsOptionsList.FundingList[application.LikelihoodOfFunding] : "", + AssessmentStartDate = string.Format("{0:yyyy/MM/dd}", application.AssessmentStartDate), + FinalDecisionDate = string.Format("{0:yyyy/MM/dd}", application.FinalDecisionDate), + TotalScore = application.TotalScore.ToString(), + AssessmentResult = application.AssessmentResultStatus != null && application.AssessmentResultStatus != "" ? AssessmentResultsOptionsList.AssessmentResultStatusList[application.AssessmentResultStatus] : "", + RecommendedAmount = application.RecommendedAmount, + ApprovedAmount = application.ApprovedAmount, + Batch = "", // to-do: ask BA for the implementation of Batch field, + RegionalDistrict = application.RegionalDistrict, + OwnerId = application.OwnerId, + + }; + + var queryResult = await AsyncExecuter.FirstOrDefaultAsync(query); + if (queryResult != null) + { + var ownerId = queryResult.OwnerId ?? Guid.Empty; + queryResult.Owner = await GetOwnerAsync(ownerId); + queryResult.Assignees = await GetAssigneesAsync(applicationId); + + return queryResult; + } + else + { + return await Task.FromResult(new GetSummaryDto()); + } + + } + + [Authorize(UnitySelector.Review.AssessmentResults.Update.Default)] + public async Task UpdateAssessmentResultsAsync(Guid id, CreateUpdateAssessmentResultsDto input) + { + var application = await _applicationRepository.GetAsync(id); + + await SanitizeApprovalZoneInputs(input, application); + await SanitizeAssessmentResultsZoneInputs(input, application); + + application.ValidateAndSetDueDate(input.DueDate); + application.UpdateAlwaysChangeableFields(input.Notes, input.SubStatus, input.LikelihoodOfFunding, input.TotalProjectBudget, input.NotificationDate, input.RiskRanking); + + if (application.IsInFinalDecisionState()) + { + if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.Approval.Update.UpdateFinalStateFields)) + { + application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); + } + + if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.UpdateFinalStateFields)) // User allowed to edit specific fields past approval + { + application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); + } + } + else + { + if (await CurrentUserCanUpdateAssessmentFieldsAsync()) + { + application.ValidateAndSetFinalDecisionDate(input.FinalDecisionDate); + application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); + application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); + application.UpdateFieldsOnlyForPreFinalDecision(input.DueDiligenceStatus, + input.RecommendedAmount, + input.DeclineRational); + + application.UpdateAssessmentResultStatus(input.AssessmentResultStatus); + } + } + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.AssessmentInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + return ObjectMapper.Map(application); + } + + private async Task SanitizeApprovalZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) + { + // Approval Zone Fields - Disabled Inputs + input.ApprovedAmount ??= application.ApprovedAmount; + + // Sanitize if zone is disabled + if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.Approval.Default, application.ApplicationFormId)) + { + input.SubStatus ??= application.SubStatus; + input.FinalDecisionDate ??= application.FinalDecisionDate; + input.Notes ??= application.Notes; + } + else + { + // Sanitize if zone is enabled but fields are disabled + if (application.IsInFinalDecisionState()) + { + input.FinalDecisionDate ??= application.FinalDecisionDate; + } + } + } + + private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) + { + // Approval Zone Fields - Disabled Inputs + input.RequestedAmount ??= application.RequestedAmount; + input.TotalProjectBudget ??= application.TotalProjectBudget; + input.RecommendedAmount ??= application.RecommendedAmount; + input.TotalScore ??= application.TotalScore; + + // Sanitize if zone is disabled + if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.AssessmentResults.Default, application.ApplicationFormId)) + { + input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; + input.RiskRanking ??= application.RiskRanking; + input.DueDiligenceStatus ??= application.DueDiligenceStatus; + input.AssessmentResultStatus ??= application.AssessmentResultStatus; + input.DeclineRational ??= application.DeclineRational; + + input.NotificationDate ??= application.NotificationDate; + input.DueDate ??= application.DueDate; + } + else + { + // Sanitize if zone is enabled but fields are disabled + if (application.IsInFinalDecisionState()) + { + input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; + input.RiskRanking ??= application.RiskRanking; + input.DueDiligenceStatus ??= application.DueDiligenceStatus; + input.AssessmentResultStatus ??= application.AssessmentResultStatus; + input.DeclineRational ??= application.DeclineRational; + } + } + } + + private async Task CurrentUserCanUpdateAssessmentFieldsAsync() + { + return await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.Default); + } + + [Authorize(UnitySelector.Project.UpdatePolicy)] + public async Task UpdateProjectInfoAsync(Guid id, CreateUpdateProjectInfoDto input) + { + // Check if the user has the required permissions to update Project Info for either fieldset zone + var hasSummaryPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Summary.Update.Default); + var hasLocationPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Location.Update.Default); + + if (!hasSummaryPermission || !hasLocationPermission) + { + throw new AbpAuthorizationException("The user doesn't have the required permissions to update Project Info."); + } + + var application = await _applicationRepository.GetAsync(id); + + var hasSummaryZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Summary.Default, application.ApplicationFormId); + var hasLocationZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Location.Default, application.ApplicationFormId); + + if (!hasSummaryZone || !hasLocationZone) + { + throw new BusinessException("The Project Info zones are not enabled for this application form."); + } + + SanitizeProjectInfoDisabledInputs(input, application); + + var percentageTotalProjectBudget = (input.TotalProjectBudget == 0 || input.TotalProjectBudget == null) ? 0 : decimal.Multiply(decimal.Divide(input.RequestedAmount ?? 0, input.TotalProjectBudget ?? 0), 100).To(); + + if (application != null) + { + application.ProjectSummary = input.ProjectSummary; + application.ProjectName = input.ProjectName ?? string.Empty; + application.RequestedAmount = input.RequestedAmount ?? 0; + application.TotalProjectBudget = input.TotalProjectBudget ?? 0; + application.ProjectStartDate = input.ProjectStartDate; + application.ProjectEndDate = input.ProjectEndDate; + application.PercentageTotalProjectBudget = Math.Round(percentageTotalProjectBudget, 2); + application.ProjectFundingTotal = input.ProjectFundingTotal; + application.Community = input.Community; + application.CommunityPopulation = input.CommunityPopulation; + application.Acquisition = input.Acquisition; + application.Forestry = input.Forestry; + application.ForestryFocus = input.ForestryFocus; + application.EconomicRegion = input.EconomicRegion; + application.ElectoralDistrict = input.ElectoralDistrict; + application.RegionalDistrict = input.RegionalDistrict; + application.Place = input.Place; + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + return ObjectMapper.Map(application); + } + else + { + throw new EntityNotFoundException(); + } + } + private static void SanitizeProjectInfoDisabledInputs(CreateUpdateProjectInfoDto input, Application application) + { + // Cater for disabled fields that are not serialized with post - fall back to the previous value, these should be 0 from the API call + input.TotalProjectBudget ??= application.TotalProjectBudget; + input.RequestedAmount ??= application.RequestedAmount; + input.ProjectFundingTotal ??= application.ProjectFundingTotal; + } + + [Authorize(UnitySelector.Project.UpdatePolicy)] + public async Task UpdatePartialProjectInfoAsync(Guid id, PartialUpdateDto input) + { + // Only update the fields we need to update based on the modified fields + // This is required to handle controls like the date picker that do not send null values for unchanged fields + var application = await _applicationRepository.GetAsync(id) ?? throw new EntityNotFoundException($"Application with ID {id} not found."); + ObjectMapper.Map(input.Data, application); + + // Explicitly handle properties that are null but listed in ModifiedFields + var dtoProperties = typeof(UpdateProjectInfoDto).GetProperties(); + var appProperties = typeof(Application).GetProperties().ToDictionary(p => p.Name, p => p); + + foreach (var fieldName in input.ModifiedFields) + { + if (dtoProperties.FirstOrDefault(p => + string.Equals(p.Name, fieldName, StringComparison.OrdinalIgnoreCase)) is { } dtoProperty) + { + var value = dtoProperty.GetValue(input.Data); + if (value == null && appProperties.TryGetValue(dtoProperty.Name, out var appProperty) && appProperty.CanWrite) + { + appProperty.SetValue(application, appProperty.PropertyType.IsValueType + && Nullable.GetUnderlyingType(appProperty.PropertyType) == null + ? Activator.CreateInstance(appProperty.PropertyType) + : null); + } + } + } + + // Calculate the percentage of the total project budget based on + // the requested amount and total project budget. Percentage total has to be + // updated whenever RequestedAmount or TotalProjectBudget changes + application.UpdatePercentageTotalProjectBudget(); + + // Add custom worksheet data + if (input.Data.CustomFields is not null && input.Data.WorksheetId != Guid.Empty && input.Data.CorrelationId != Guid.Empty) + { + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input.Data); + } + + await _applicationRepository.UpdateAsync(application); + return ObjectMapper.Map(application); + } + + public async Task UpdateFundingAgreementInfoAsync(Guid id, CreateUpdateFundingAgreementInfoDto input) + { + var application = await _applicationRepository.GetAsync(id); + + if (application != null) + { + application.ContractNumber = input.ContractNumber; + application.ContractExecutionDate = input.ContractExecutionDate; + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.FundingAgreementInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + return ObjectMapper.Map(application); + } + else + { + throw new EntityNotFoundException(); + } + } + /// /// Update the supplier number for the applicant associated with the application. - /// - [Authorize(UnitySelector.Payment.Supplier.Update)] + /// + [Authorize(UnitySelector.Payment.Supplier.Update)] public async Task UpdateSupplierNumberAsync(Guid applicationId, string supplierNumber) { // Could be moved to payments module but dependency on ApplicationId - // Integrate with payments module to update / insert supplier + // Integrate with payments module to update / insert supplier var application = await _applicationRepository.GetAsync(applicationId); - if (await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature) && application != null && !string.IsNullOrEmpty(supplierNumber)) - { - var pendingPayments = await _paymentRequestsRepository.GetPaymentPendingListByCorrelationIdAsync(applicationId); - if (pendingPayments != null && pendingPayments.Count > 0) - { - throw new UserFriendlyException("There are outstanding payment requests with the current Supplier. Please decline or approve the outstanding payments before changing the Supplier Number"); - } - - await _applicantSupplierService.UpdateApplicantSupplierNumberAsync(application.ApplicantId, supplierNumber); + if (await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature) && application != null && !string.IsNullOrEmpty(supplierNumber)) + { + var pendingPayments = await _paymentRequestsRepository.GetPaymentPendingListByCorrelationIdAsync(applicationId); + if (pendingPayments != null && pendingPayments.Count > 0) + { + throw new UserFriendlyException("There are outstanding payment requests with the current Supplier. Please decline or approve the outstanding payments before changing the Supplier Number"); + } + + await _applicantSupplierService.UpdateApplicantSupplierNumberAsync(application.ApplicantId, supplierNumber); } - } - + } + protected internal async Task CreateOrUpdateApplicantAgentAsync(Application application, ContactInfoDto? input) { if (input == null @@ -596,82 +594,82 @@ public async Task UpdateSupplierNumberAsync(Guid applicationId, string supplierN } return await _applicantAgentRepository.UpdateAsync(applicantAgent); - } - - [Obsolete("Use ApplicationApplicantAppService.UpdatePartialApplicantInfoAsync instead.")] - [Authorize(UnitySelector.Applicant.UpdatePolicy)] - public async Task UpdateProjectApplicantInfoAsync(Guid id, CreateUpdateApplicantInfoDto input) - { - var application = await _applicationRepository.GetAsync(id); - - var applicant = await _applicantRepository - .FirstOrDefaultAsync(a => a.Id == application.ApplicantId) ?? throw new EntityNotFoundException(); - - applicant.OrganizationType = input.OrganizationType ?? ""; - applicant.OrgName = input.OrgName ?? ""; - applicant.OrgNumber = input.OrgNumber ?? ""; - applicant.OrgStatus = input.OrgStatus ?? ""; - applicant.OrganizationSize = input.OrganizationSize ?? ""; - applicant.Sector = input.Sector ?? ""; - applicant.SubSector = input.SubSector ?? ""; - applicant.SectorSubSectorIndustryDesc = input.SectorSubSectorIndustryDesc ?? ""; - applicant.IndigenousOrgInd = input.IndigenousOrgInd ?? ""; - applicant.UnityApplicantId = input.UnityApplicantId ?? ""; - applicant.FiscalDay = input.FiscalDay; - applicant.FiscalMonth = input.FiscalMonth ?? ""; - applicant.NonRegOrgName = input.NonRegOrgName ?? ""; - applicant.ElectoralDistrict = input.ElectoralDistrict ?? ""; - applicant.ApplicantName = input.ApplicantName ?? ""; - - _ = await _applicantRepository.UpdateAsync(applicant); - - var applicantAgent = await _applicantAgentRepository.FirstOrDefaultAsync(agent => agent.ApplicantId == application.ApplicantId); - if (applicantAgent == null) - { - applicantAgent = await _applicantAgentRepository.InsertAsync(new ApplicantAgent - { - ApplicantId = application.ApplicantId, - ApplicationId = application.Id, - Name = input.ContactFullName ?? "", - Phone = input.ContactBusinessPhone ?? "", - Phone2 = input.ContactCellPhone ?? "", - Email = input.ContactEmail ?? "", - Title = input.ContactTitle ?? "" - }); - } - else - { - applicantAgent.Name = input.ContactFullName ?? ""; - applicantAgent.Phone = input.ContactBusinessPhone ?? ""; - applicantAgent.Phone2 = input.ContactCellPhone ?? ""; - applicantAgent.Email = input.ContactEmail ?? ""; - applicantAgent.Title = input.ContactTitle ?? ""; - applicantAgent = await _applicantAgentRepository.UpdateAsync(applicantAgent); - } - + } + + [Obsolete("Use ApplicationApplicantAppService.UpdatePartialApplicantInfoAsync instead.")] + [Authorize(UnitySelector.Applicant.UpdatePolicy)] + public async Task UpdateProjectApplicantInfoAsync(Guid id, CreateUpdateApplicantInfoDto input) + { + var application = await _applicationRepository.GetAsync(id); + + var applicant = await _applicantRepository + .FirstOrDefaultAsync(a => a.Id == application.ApplicantId) ?? throw new EntityNotFoundException(); + + applicant.OrganizationType = input.OrganizationType ?? ""; + applicant.OrgName = input.OrgName ?? ""; + applicant.OrgNumber = input.OrgNumber ?? ""; + applicant.OrgStatus = input.OrgStatus ?? ""; + applicant.OrganizationSize = input.OrganizationSize ?? ""; + applicant.Sector = input.Sector ?? ""; + applicant.SubSector = input.SubSector ?? ""; + applicant.SectorSubSectorIndustryDesc = input.SectorSubSectorIndustryDesc ?? ""; + applicant.IndigenousOrgInd = input.IndigenousOrgInd ?? ""; + applicant.UnityApplicantId = input.UnityApplicantId ?? ""; + applicant.FiscalDay = input.FiscalDay; + applicant.FiscalMonth = input.FiscalMonth ?? ""; + applicant.NonRegOrgName = input.NonRegOrgName ?? ""; + applicant.ElectoralDistrict = input.ElectoralDistrict ?? ""; + applicant.ApplicantName = input.ApplicantName ?? ""; + + _ = await _applicantRepository.UpdateAsync(applicant); + + var applicantAgent = await _applicantAgentRepository.FirstOrDefaultAsync(agent => agent.ApplicantId == application.ApplicantId); + if (applicantAgent == null) + { + applicantAgent = await _applicantAgentRepository.InsertAsync(new ApplicantAgent + { + ApplicantId = application.ApplicantId, + ApplicationId = application.Id, + Name = input.ContactFullName ?? "", + Phone = input.ContactBusinessPhone ?? "", + Phone2 = input.ContactCellPhone ?? "", + Email = input.ContactEmail ?? "", + Title = input.ContactTitle ?? "" + }); + } + else + { + applicantAgent.Name = input.ContactFullName ?? ""; + applicantAgent.Phone = input.ContactBusinessPhone ?? ""; + applicantAgent.Phone2 = input.ContactCellPhone ?? ""; + applicantAgent.Email = input.ContactEmail ?? ""; + applicantAgent.Title = input.ContactTitle ?? ""; + applicantAgent = await _applicantAgentRepository.UpdateAsync(applicantAgent); + } + await UpdateApplicantAddresses(application.Id, input); - - application.SigningAuthorityFullName = input.SigningAuthorityFullName ?? ""; - application.SigningAuthorityTitle = input.SigningAuthorityTitle ?? ""; - application.SigningAuthorityEmail = input.SigningAuthorityEmail ?? ""; - application.SigningAuthorityBusinessPhone = input.SigningAuthorityBusinessPhone ?? ""; - application.SigningAuthorityCellPhone = input.SigningAuthorityCellPhone ?? ""; - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ApplicantInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - var appDto = ObjectMapper.Map(application); - - appDto.ContactFullName = applicantAgent.Name; - appDto.ContactEmail = applicantAgent.Email; - appDto.ContactTitle = applicantAgent.Title; - appDto.ContactBusinessPhone = applicantAgent.Phone; - appDto.ContactCellPhone = applicantAgent.Phone2; - - return appDto; - } - + + application.SigningAuthorityFullName = input.SigningAuthorityFullName ?? ""; + application.SigningAuthorityTitle = input.SigningAuthorityTitle ?? ""; + application.SigningAuthorityEmail = input.SigningAuthorityEmail ?? ""; + application.SigningAuthorityBusinessPhone = input.SigningAuthorityBusinessPhone ?? ""; + application.SigningAuthorityCellPhone = input.SigningAuthorityCellPhone ?? ""; + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ApplicantInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + var appDto = ObjectMapper.Map(application); + + appDto.ContactFullName = applicantAgent.Name; + appDto.ContactEmail = applicantAgent.Email; + appDto.ContactTitle = applicantAgent.Title; + appDto.ContactBusinessPhone = applicantAgent.Phone; + appDto.ContactCellPhone = applicantAgent.Phone2; + + return appDto; + } + [Authorize(UnitySelector.Applicant.UpdatePolicy)] public async Task UpdateMergedApplicantAsync(Guid applicationId, CreateUpdateApplicantInfoDto input) { @@ -698,342 +696,342 @@ public async Task UpdateMergedApplicantAsync(Guid applicationId, CreateUpdateApp _ = await _applicantRepository.UpdateAsync(applicant); } - protected virtual async Task PublishCustomFieldUpdatesAsync(Guid applicationId, - string uiAnchor, - CustomDataFieldDto input) - { - if (await FeatureChecker.IsEnabledAsync("Unity.Flex")) - { - if (input.CorrelationId != Guid.Empty) - { - await _localEventBus.PublishAsync(new PersistWorksheetIntanceValuesEto() - { - InstanceCorrelationId = applicationId, - InstanceCorrelationProvider = CorrelationConsts.Application, - SheetCorrelationId = input.CorrelationId, - SheetCorrelationProvider = CorrelationConsts.FormVersion, - UiAnchor = uiAnchor, - CustomFields = input.CustomFields, - WorksheetId = input.WorksheetId - }); - } - else - { - Logger.LogError("Unable to resolve for version"); - } - } - } - + protected virtual async Task PublishCustomFieldUpdatesAsync(Guid applicationId, + string uiAnchor, + CustomDataFieldDto input) + { + if (await FeatureChecker.IsEnabledAsync("Unity.Flex")) + { + if (input.CorrelationId != Guid.Empty) + { + await _localEventBus.PublishAsync(new PersistWorksheetIntanceValuesEto() + { + InstanceCorrelationId = applicationId, + InstanceCorrelationProvider = CorrelationConsts.Application, + SheetCorrelationId = input.CorrelationId, + SheetCorrelationProvider = CorrelationConsts.FormVersion, + UiAnchor = uiAnchor, + CustomFields = input.CustomFields, + WorksheetId = input.WorksheetId + }); + } + else + { + Logger.LogError("Unable to resolve for version"); + } + } + } + protected virtual async Task UpdateApplicantAddresses(Guid applicationId, CreateUpdateApplicantInfoDto input) - { + { List applicantAddresses = await _applicantAddressRepository.FindByApplicantIdAndApplicationIdAsync(input.ApplicantId, applicationId); - if (applicantAddresses != null) - { + if (applicantAddresses != null) + { await UpsertAddress(input, applicantAddresses, AddressType.MailingAddress, input.ApplicantId, applicationId); await UpsertAddress(input, applicantAddresses, AddressType.PhysicalAddress, input.ApplicantId, applicationId); - } - } - + } + } + protected virtual async Task UpsertAddress(CreateUpdateApplicantInfoDto input, List applicantAddresses, AddressType applicantAddressType, Guid applicantId, Guid applicationId) - { + { ApplicantAddress? dbAddress = applicantAddresses.Find(address => address.AddressType == applicantAddressType && address.ApplicationId == applicationId); - - if (dbAddress != null) - { - MapApplicantAddress(input, applicantAddressType, dbAddress); - await _applicantAddressRepository.UpdateAsync(dbAddress); - } - else - { + + if (dbAddress != null) + { + MapApplicantAddress(input, applicantAddressType, dbAddress); + await _applicantAddressRepository.UpdateAsync(dbAddress); + } + else + { var newAddress = new ApplicantAddress() { AddressType = applicantAddressType, ApplicantId = applicantId, ApplicationId = applicationId }; - MapApplicantAddress(input, applicantAddressType, newAddress); - await _applicantAddressRepository.InsertAsync(newAddress); - } - } - - private static void MapApplicantAddress(CreateUpdateApplicantInfoDto input, AddressType applicantAddressType, ApplicantAddress address) - { - switch (applicantAddressType) - { - case AddressType.MailingAddress: - address.AddressType = AddressType.MailingAddress; - address.Street = input.MailingAddressStreet ?? ""; - address.Street2 = input.MailingAddressStreet2 ?? ""; - address.Unit = input.MailingAddressUnit ?? ""; - address.City = input.MailingAddressCity ?? ""; - address.Province = input.MailingAddressProvince ?? ""; - address.Postal = input.MailingAddressPostalCode ?? ""; - break; - case AddressType.PhysicalAddress: - address.AddressType = AddressType.PhysicalAddress; - address.Street = input.PhysicalAddressStreet ?? ""; - address.Street2 = input.PhysicalAddressStreet2 ?? ""; - address.Unit = input.PhysicalAddressUnit ?? ""; - address.City = input.PhysicalAddressCity ?? ""; - address.Province = input.PhysicalAddressProvince ?? ""; - address.Postal = input.PhysicalAddressPostalCode ?? ""; - break; - } - } - - public async Task> GetAssigneesAsync(Guid applicationId) - { - var query = from userAssignment in await _applicationAssignmentRepository.GetQueryableAsync() - join user in await _personRepository.GetQueryableAsync() on userAssignment.AssigneeId equals user.Id - where userAssignment.ApplicationId == applicationId - select new GrantApplicationAssigneeDto - { - Id = userAssignment.Id, - AssigneeId = userAssignment.AssigneeId, - FullName = user.FullName, - Duty = userAssignment.Duty, - ApplicationId = applicationId - }; - - return await query.ToListAsync(); - } - - public async Task GetOwnerAsync(Guid ownerId) - { - var owner = await _personRepository.FindAsync(ownerId); - - if (owner != null) - { - return new GrantApplicationAssigneeDto - { - Id = owner.Id, - FullName = owner.FullName - }; - } - else - return new GrantApplicationAssigneeDto(); - } - - public async Task GetFormSubmissionByApplicationId(Guid applicationId) - { - ApplicationFormSubmission applicationFormSubmission = new(); - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - IQueryable queryableFormSubmissions = await _applicationFormSubmissionRepository.GetQueryableAsync(); - if (queryableFormSubmissions != null) - { - var dbResult = await queryableFormSubmissions - .FirstOrDefaultAsync(a => a.ApplicationId.Equals(applicationId)); - - if (dbResult != null) - { - applicationFormSubmission = dbResult; - } - } - } - return applicationFormSubmission; - } - - public async Task UpdateApplicationStatus(Guid[] applicationIds, Guid statusId) - { - foreach (Guid applicationId in applicationIds) - { - try - { - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - application.ApplicationStatusId = statusId; - await _applicationRepository.UpdateAsync(application); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - } - - public async Task InsertAssigneeAsync(Guid applicationId, Guid assigneeId, string? duty) - { - try - { - var assignees = await GetAssigneesAsync(applicationId); - if (assignees == null || assignees.FindIndex(a => a.AssigneeId == assigneeId) == -1) - { - await _applicationManager.AssignUserAsync(applicationId, assigneeId, duty); - } - else - { - await _applicationManager.UpdateAssigneeAsync(applicationId, assigneeId, duty); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - public async Task DeleteAssigneeAsync(Guid applicationId, Guid assigneeId) - { - try - { - await _applicationManager.RemoveAssigneeAsync(applicationId, assigneeId); - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - public async Task> GetApplicationListAsync(List applicationIds) - { - var applications = await - (await _applicationRepository.WithDetailsAsync()) - .OrderBy(s => s.Id) - .Where(s => applicationIds.Contains(s.Id)) - .ToListAsync(); - - return ObjectMapper.Map, List>(applications); - } - - public async Task> GetApplicationDetailsListAsync(List applicationIds) - { - var query = from application in await _applicationRepository.GetQueryableAsync() - join appStatus in await _applicationStatusRepository.GetQueryableAsync() on application.ApplicationStatusId equals appStatus.Id - join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id - join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id - where applicationIds.Contains(application.Id) - select new - { - application, - appStatus, - applicant, - applicationForm - }; - - var result = query - - .OrderBy(s => s.application.Id) - .GroupBy(s => s.application.Id) - .AsEnumerable() - .ToList(); - - var appDtos = new List(); - - foreach (var grouping in result) - { - var appDto = ObjectMapper.Map(grouping.First().application); - appDto.Status = grouping.First().appStatus.InternalStatus; - appDto.StatusCode = grouping.First().appStatus.StatusCode; - appDto.Applicant = ObjectMapper.Map(grouping.First().applicant); - appDto.ApplicationForm = ObjectMapper.Map(grouping.First().applicationForm); - appDtos.Add(appDto); - } - - return new List(appDtos); - } - - public async Task InsertOwnerAsync(Guid applicationId, Guid? assigneeId) - { - try - { - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - application.OwnerId = assigneeId; - await _applicationRepository.UpdateAsync(application); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - public async Task DeleteOwnerAsync(Guid applicationId) - { - try - { - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - application.OwnerId = null; - await _applicationRepository.UpdateAsync(application); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - [HttpPut] - public async Task UpdateAssigneesAsync(dynamic modifiedAssignees) - { - var dynamicObject = JsonConvert.DeserializeObject(modifiedAssignees); - if (dynamicObject is IEnumerable) - { - Guid previousApplicationId = Guid.Empty; - foreach (JProperty item in dynamicObject) - { - Guid currentApplicationId = Guid.Parse(item.Name); - if (currentApplicationId != previousApplicationId) - { - var assignees = new List<(Guid? assigneeId, string? fullName)>(); - - foreach (JToken assigneeToken in item.Value.Children()) - { - string? assigneeId = assigneeToken.Value("assigneeId") ?? null; - string? fullName = assigneeToken.Value("fullName") ?? null; - assignees.Add(new(assigneeId != null ? Guid.Parse(assigneeId) : null, fullName)); - } - - await _applicationManager.SetAssigneesAsync(currentApplicationId, assignees); - } - - previousApplicationId = currentApplicationId; - } - } - } - - public async Task CreateCommentAsync(Guid id, CreateCommentDto dto) - { - return ObjectMapper.Map((ApplicationComment) - await _commentsManager.CreateCommentAsync(id, dto.Comment, CommentType.ApplicationComment)); - } - - public async Task> GetCommentsAsync(Guid id) - { - return ObjectMapper.Map, IReadOnlyList>((IReadOnlyList) - await _commentsManager.GetCommentsAsync(id, CommentType.ApplicationComment)); - } - - public async Task UpdateCommentAsync(Guid id, UpdateCommentDto dto) - { - try - { - return ObjectMapper.Map((ApplicationComment) - await _commentsManager.UpdateCommentAsync(id, dto.CommentId, dto.Comment, CommentType.ApplicationComment)); - - } - catch (EntityNotFoundException) - { - throw new InvalidCommentParametersException(); - } - } - - public async Task GetCommentAsync(Guid id, Guid commentId) - { - var comment = await _commentsManager.GetCommentAsync(id, commentId, CommentType.ApplicationComment); - - return comment == null - ? throw new InvalidCommentParametersException() - : ObjectMapper.Map((ApplicationComment)comment); - } - - public async Task GetApplicationStatusAsync(Guid id) - { - var application = await _applicationRepository.GetAsync(id, true); - return ObjectMapper.Map(await _applicationStatusRepository.GetAsync(application.ApplicationStatusId)); - } - + MapApplicantAddress(input, applicantAddressType, newAddress); + await _applicantAddressRepository.InsertAsync(newAddress); + } + } + + private static void MapApplicantAddress(CreateUpdateApplicantInfoDto input, AddressType applicantAddressType, ApplicantAddress address) + { + switch (applicantAddressType) + { + case AddressType.MailingAddress: + address.AddressType = AddressType.MailingAddress; + address.Street = input.MailingAddressStreet ?? ""; + address.Street2 = input.MailingAddressStreet2 ?? ""; + address.Unit = input.MailingAddressUnit ?? ""; + address.City = input.MailingAddressCity ?? ""; + address.Province = input.MailingAddressProvince ?? ""; + address.Postal = input.MailingAddressPostalCode ?? ""; + break; + case AddressType.PhysicalAddress: + address.AddressType = AddressType.PhysicalAddress; + address.Street = input.PhysicalAddressStreet ?? ""; + address.Street2 = input.PhysicalAddressStreet2 ?? ""; + address.Unit = input.PhysicalAddressUnit ?? ""; + address.City = input.PhysicalAddressCity ?? ""; + address.Province = input.PhysicalAddressProvince ?? ""; + address.Postal = input.PhysicalAddressPostalCode ?? ""; + break; + } + } + + public async Task> GetAssigneesAsync(Guid applicationId) + { + var query = from userAssignment in await _applicationAssignmentRepository.GetQueryableAsync() + join user in await _personRepository.GetQueryableAsync() on userAssignment.AssigneeId equals user.Id + where userAssignment.ApplicationId == applicationId + select new GrantApplicationAssigneeDto + { + Id = userAssignment.Id, + AssigneeId = userAssignment.AssigneeId, + FullName = user.FullName, + Duty = userAssignment.Duty, + ApplicationId = applicationId + }; + + return await query.ToListAsync(); + } + + public async Task GetOwnerAsync(Guid ownerId) + { + var owner = await _personRepository.FindAsync(ownerId); + + if (owner != null) + { + return new GrantApplicationAssigneeDto + { + Id = owner.Id, + FullName = owner.FullName + }; + } + else + return new GrantApplicationAssigneeDto(); + } + + public async Task GetFormSubmissionByApplicationId(Guid applicationId) + { + ApplicationFormSubmission applicationFormSubmission = new(); + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + IQueryable queryableFormSubmissions = await _applicationFormSubmissionRepository.GetQueryableAsync(); + if (queryableFormSubmissions != null) + { + var dbResult = await queryableFormSubmissions + .FirstOrDefaultAsync(a => a.ApplicationId.Equals(applicationId)); + + if (dbResult != null) + { + applicationFormSubmission = dbResult; + } + } + } + return applicationFormSubmission; + } + + public async Task UpdateApplicationStatus(Guid[] applicationIds, Guid statusId) + { + foreach (Guid applicationId in applicationIds) + { + try + { + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + application.ApplicationStatusId = statusId; + await _applicationRepository.UpdateAsync(application); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + } + + public async Task InsertAssigneeAsync(Guid applicationId, Guid assigneeId, string? duty) + { + try + { + var assignees = await GetAssigneesAsync(applicationId); + if (assignees == null || assignees.FindIndex(a => a.AssigneeId == assigneeId) == -1) + { + await _applicationManager.AssignUserAsync(applicationId, assigneeId, duty); + } + else + { + await _applicationManager.UpdateAssigneeAsync(applicationId, assigneeId, duty); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public async Task DeleteAssigneeAsync(Guid applicationId, Guid assigneeId) + { + try + { + await _applicationManager.RemoveAssigneeAsync(applicationId, assigneeId); + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public async Task> GetApplicationListAsync(List applicationIds) + { + var applications = await + (await _applicationRepository.WithDetailsAsync()) + .OrderBy(s => s.Id) + .Where(s => applicationIds.Contains(s.Id)) + .ToListAsync(); + + return ObjectMapper.Map, List>(applications); + } + + public async Task> GetApplicationDetailsListAsync(List applicationIds) + { + var query = from application in await _applicationRepository.GetQueryableAsync() + join appStatus in await _applicationStatusRepository.GetQueryableAsync() on application.ApplicationStatusId equals appStatus.Id + join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id + join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id + where applicationIds.Contains(application.Id) + select new + { + application, + appStatus, + applicant, + applicationForm + }; + + var result = query + + .OrderBy(s => s.application.Id) + .GroupBy(s => s.application.Id) + .AsEnumerable() + .ToList(); + + var appDtos = new List(); + + foreach (var grouping in result) + { + var appDto = ObjectMapper.Map(grouping.First().application); + appDto.Status = grouping.First().appStatus.InternalStatus; + appDto.StatusCode = grouping.First().appStatus.StatusCode; + appDto.Applicant = ObjectMapper.Map(grouping.First().applicant); + appDto.ApplicationForm = ObjectMapper.Map(grouping.First().applicationForm); + appDtos.Add(appDto); + } + + return new List(appDtos); + } + + public async Task InsertOwnerAsync(Guid applicationId, Guid? assigneeId) + { + try + { + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + application.OwnerId = assigneeId; + await _applicationRepository.UpdateAsync(application); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public async Task DeleteOwnerAsync(Guid applicationId) + { + try + { + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + application.OwnerId = null; + await _applicationRepository.UpdateAsync(application); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + [HttpPut] + public async Task UpdateAssigneesAsync(dynamic modifiedAssignees) + { + var dynamicObject = JsonConvert.DeserializeObject(modifiedAssignees); + if (dynamicObject is IEnumerable) + { + Guid previousApplicationId = Guid.Empty; + foreach (JProperty item in dynamicObject) + { + Guid currentApplicationId = Guid.Parse(item.Name); + if (currentApplicationId != previousApplicationId) + { + var assignees = new List<(Guid? assigneeId, string? fullName)>(); + + foreach (JToken assigneeToken in item.Value.Children()) + { + string? assigneeId = assigneeToken.Value("assigneeId") ?? null; + string? fullName = assigneeToken.Value("fullName") ?? null; + assignees.Add(new(assigneeId != null ? Guid.Parse(assigneeId) : null, fullName)); + } + + await _applicationManager.SetAssigneesAsync(currentApplicationId, assignees); + } + + previousApplicationId = currentApplicationId; + } + } + } + + public async Task CreateCommentAsync(Guid id, CreateCommentDto dto) + { + return ObjectMapper.Map((ApplicationComment) + await _commentsManager.CreateCommentAsync(id, dto.Comment, CommentType.ApplicationComment)); + } + + public async Task> GetCommentsAsync(Guid id) + { + return ObjectMapper.Map, IReadOnlyList>((IReadOnlyList) + await _commentsManager.GetCommentsAsync(id, CommentType.ApplicationComment)); + } + + public async Task UpdateCommentAsync(Guid id, UpdateCommentDto dto) + { + try + { + return ObjectMapper.Map((ApplicationComment) + await _commentsManager.UpdateCommentAsync(id, dto.CommentId, dto.Comment, CommentType.ApplicationComment)); + + } + catch (EntityNotFoundException) + { + throw new InvalidCommentParametersException(); + } + } + + public async Task GetCommentAsync(Guid id, Guid commentId) + { + var comment = await _commentsManager.GetCommentAsync(id, commentId, CommentType.ApplicationComment); + + return comment == null + ? throw new InvalidCommentParametersException() + : ObjectMapper.Map((ApplicationComment)comment); + } + + public async Task GetApplicationStatusAsync(Guid id) + { + var application = await _applicationRepository.GetAsync(id, true); + return ObjectMapper.Map(await _applicationStatusRepository.GetAsync(application.ApplicationStatusId)); + } + public async Task GetAccountCodingIdFromFormIdAsync(Guid formId) { ApplicationForm? form = await _applicationFormRepository.GetAsync(formId, true); @@ -1045,79 +1043,79 @@ public async Task GetApplicationStatusAsync(Guid id) return form.AccountCodingId; } - #region APPLICATION WORKFLOW - /// - /// Fetches the list of actions and their status context for a given application. - /// - /// The application - /// A list of application actions with their state machine permitted and authorization status. - public async Task> GetActions(Guid applicationId, bool includeInternal = false) - { - var actionList = await _applicationManager.GetActions(applicationId); - var application = await _applicationRepository.GetAsync(applicationId, true); - - // Note: Remove internal state change actions that are side-effects of domain events - var externalActionsList = actionList.Where(a => includeInternal || !a.IsInternal).ToList(); - var actionDtos = ObjectMapper.Map< - List, - List>(externalActionsList); - - // NOTE: Authorization is applied on the AppService layer and is false by default - // TODO: Replace placeholder loop with authorization handler mapped to permissions - // AUTHORIZATION HANDLING - actionDtos.ForEach(async item => - { - item.IsPermitted = item.IsPermitted && (await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(item.ApplicationAction))); - item.IsAuthorized = true; - }); - - return new ListResultDto(actionDtos); - } - - private static OperationAuthorizationRequirement GetActionAuthorizationRequirement(GrantApplicationAction triggerAction) - { - return new OperationAuthorizationRequirement { Name = triggerAction.ToString() }; - } - - /// - /// Transitions the Application workflow state machine given an action. - /// - /// The application - /// The action to be invoked on an Application - public async Task TriggerAction(Guid applicationId, GrantApplicationAction triggerAction) - { - // AUTHORIZATION HANDLING - var application = await _applicationRepository.GetAsync(applicationId, true); - if (!await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(triggerAction))) - { - throw new UnauthorizedAccessException(); - } - - application = await _applicationManager.TriggerAction(applicationId, triggerAction); - - await _localEventBus.PublishAsync( - new ApplicationChangedEvent - { - Action = triggerAction, - ApplicationId = applicationId - } - ); - - return ObjectMapper.Map(application); - } - #endregion APPLICATION WORKFLOW - - public async Task> GetAllApplicationsAsync() - { - - var query = from applications in await _applicationRepository.GetQueryableAsync() - select new GrantApplicationLiteDto - { - Id = applications.Id, - ProjectName = applications.ProjectName, - ReferenceNo = applications.ReferenceNo - }; - - return await query.ToListAsync(); + #region APPLICATION WORKFLOW + /// + /// Fetches the list of actions and their status context for a given application. + /// + /// The application + /// A list of application actions with their state machine permitted and authorization status. + public async Task> GetActions(Guid applicationId, bool includeInternal = false) + { + var actionList = await _applicationManager.GetActions(applicationId); + var application = await _applicationRepository.GetAsync(applicationId, true); + + // Note: Remove internal state change actions that are side-effects of domain events + var externalActionsList = actionList.Where(a => includeInternal || !a.IsInternal).ToList(); + var actionDtos = ObjectMapper.Map< + List, + List>(externalActionsList); + + // NOTE: Authorization is applied on the AppService layer and is false by default + // TODO: Replace placeholder loop with authorization handler mapped to permissions + // AUTHORIZATION HANDLING + actionDtos.ForEach(async item => + { + item.IsPermitted = item.IsPermitted && (await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(item.ApplicationAction))); + item.IsAuthorized = true; + }); + + return new ListResultDto(actionDtos); + } + + private static OperationAuthorizationRequirement GetActionAuthorizationRequirement(GrantApplicationAction triggerAction) + { + return new OperationAuthorizationRequirement { Name = triggerAction.ToString() }; + } + + /// + /// Transitions the Application workflow state machine given an action. + /// + /// The application + /// The action to be invoked on an Application + public async Task TriggerAction(Guid applicationId, GrantApplicationAction triggerAction) + { + // AUTHORIZATION HANDLING + var application = await _applicationRepository.GetAsync(applicationId, true); + if (!await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(triggerAction))) + { + throw new UnauthorizedAccessException(); + } + + application = await _applicationManager.TriggerAction(applicationId, triggerAction); + + await _localEventBus.PublishAsync( + new ApplicationChangedEvent + { + Action = triggerAction, + ApplicationId = applicationId + } + ); + + return ObjectMapper.Map(application); + } + #endregion APPLICATION WORKFLOW + + public async Task> GetAllApplicationsAsync() + { + + var query = from applications in await _applicationRepository.GetQueryableAsync() + select new GrantApplicationLiteDto + { + Id = applications.Id, + ProjectName = applications.ProjectName, + ReferenceNo = applications.ReferenceNo + }; + + return await query.ToListAsync(); } -} +} 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 723842760..6ba2ae434 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 @@ -321,7 +321,6 @@ "Summary:Application.SubmissionDate": "Submission Date", "Summary:Application.OrganizationName": "Registered Organization Name", "Summary:Application.OrganizationNumber": "Registered Organization Number", - "Summary:Application.NonRegisteredBusinessName": "Non-Registered Business Name", "Summary:Application.NonRegOrgName": "Non-Registered Organization Name", "Summary:Application.City": "City", "Summary:Application.Community": "Community", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js index 4ecb4095a..3a1cdeac0 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js @@ -269,7 +269,6 @@ getFyeMonthColumn(columnIndex++), getApplicantIdColumn(columnIndex++), getPayoutColumn(columnIndex++), - getNonRegisteredBusinessNameColumn(columnIndex++), getNonRegisteredOrganizationNameColumn(columnIndex++), ].map((column) => ({ ...column, targets: [column.index], orderData: [column.index, 0] })) .sort((a, b) => a.index - b.index); @@ -866,19 +865,6 @@ } } - function getNonRegisteredBusinessNameColumn(columnIndex) { - return { - title: l('Summary:Application.NonRegisteredBusinessName'), - name: 'nonRegisteredBusinessName', - data: 'nonRegisteredBusinessName', - className: 'data-table-header', - render: function (data) { - return data ?? ''; - }, - index: columnIndex - } - } - function getNonRegisteredOrganizationNameColumn(columnIndex) { return { title: l('Summary:Application.NonRegOrgName'), From 93a35bf5dd5c2bb58de24d2f272f8916b9a7ac75 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 29 Jul 2025 16:05:16 -0700 Subject: [PATCH 10/18] AB#28707 - Map IntakeMapping.NonRegisteredBusinessName to Applicant.NonRegOrgName --- .../Applicants/ApplicantAppService.cs | 6 ++++-- .../Intakes/Mapping/IntakeMapping.cs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs index 35aed3ef1..920670030 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs @@ -46,7 +46,8 @@ public async Task CreateOrRetrieveApplicantAsync(IntakeMapping intake } else { applicant.ApplicantName = MappingUtil.ResolveAndTruncateField(600, string.Empty, intakeMap.ApplicantName) ?? applicant.ApplicantName; applicant.ElectoralDistrict = intakeMap.ElectoralDistrict ?? applicant.ElectoralDistrict; - applicant.NonRegisteredBusinessName = intakeMap.NonRegisteredBusinessName ?? applicant.NonRegisteredBusinessName; + // Intake map uses NonRegisteredBusinessName for non-registered organizations to support legacy mappings + applicant.NonRegOrgName = intakeMap.NonRegisteredBusinessName ?? applicant.NonRegOrgName; applicant.OrgName = intakeMap.OrgName ?? applicant.OrgName; applicant.OrgNumber = intakeMap.OrgNumber ?? applicant.OrgNumber; applicant.OrganizationType = intakeMap.OrganizationType ?? applicant.OrganizationType; @@ -283,7 +284,8 @@ private async Task CreateNewApplicantAsync(IntakeMapping intakeMap) { ApplicantName = MappingUtil.ResolveAndTruncateField(600, string.Empty, intakeMap.ApplicantName), ElectoralDistrict = intakeMap.ElectoralDistrict, - NonRegisteredBusinessName = intakeMap.NonRegisteredBusinessName, + // Intake map uses NonRegisteredBusinessName for non-registered organizations to support legacy mappings + NonRegOrgName = intakeMap.NonRegisteredBusinessName, OrgName = intakeMap.OrgName, OrgNumber = intakeMap.OrgNumber, OrganizationType = intakeMap.OrganizationType, diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Intakes/Mapping/IntakeMapping.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Intakes/Mapping/IntakeMapping.cs index 52cadba16..9731a46ef 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Intakes/Mapping/IntakeMapping.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Intakes/Mapping/IntakeMapping.cs @@ -141,7 +141,7 @@ public class IntakeMapping [Browsable(true)] public string? MailingUnit { get; set; } - [DisplayName("Non-Registered Business Name")] + [DisplayName("Non-Registered Organization Name")] [MapFieldType("String")] [Browsable(true)] public string? NonRegisteredBusinessName { get; set; } From 38ed4eaf074ab9ce9fcebe54931a6a0ee90a2af9 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Tue, 29 Jul 2025 16:48:47 -0700 Subject: [PATCH 11/18] AB#29683: Remove note below the applicant merge screen --- .../Views/Shared/Components/ApplicantInfo/Default.cshtml | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml index d61d2ac77..04f967339 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml @@ -647,7 +647,6 @@
- Note: If a different principal is selected, the existing contact information and address will be passed over to the chosen principal.
From 653ceee752199b296d7eddc77979b43442532519 Mon Sep 17 00:00:00 2001 From: Sam Saravillo <7529759+samsaravillo@users.noreply.github.com> Date: Wed, 30 Jul 2025 08:29:00 -0700 Subject: [PATCH 12/18] bugfix/AB#29438 Fix dropdown alignment for column visibility option - Add logic to shift the DataTables column visibility dropdown to the right when 'Other Sector/Sub/Industry Description' is selected, addressing alignment issues. --- .../Pages/GrantApplications/Index.css | 5 +++++ .../Pages/GrantApplications/Index.js | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.css b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.css index d2aa2837b..ed6ddb589 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.css +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.css @@ -124,4 +124,9 @@ table.dataTable tbody tr { border-radius:inherit; } +.dt-button-collection.shift-left { + left: unset !important; + right: 0px !important; +} + /**end**/ \ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js index 3a1cdeac0..49a710276 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Index.js @@ -1258,6 +1258,25 @@ dataTable.rows({ 'page': 'current' }).deselect(); } }); + + + /* Fix when selecting option 'Other Sector/Sub/Industry Description' in the dropdown column list */ + $(document).on('click', '.dt-button-collection .buttons-columnVisibilitynull span', function () { + if ($(this).text().trim() === 'Other Sector/Sub/Industry Description') { + // Add a custom class to the open dropdown + $('.dt-button-collection').addClass('shift-left'); + } else { + // Optionally remove the class if another button is clicked + $('.dt-button-collection').removeClass('shift-left'); + } + }); + + $(document).on('click', function (e) { + if (!$(e.target).closest('.dt-button-collection').length) { + $('.dt-button-collection').removeClass('shift-left'); + } + }); + }); function payoutDefinition(approvedAmount, totalPaid) { if ((approvedAmount > 0 && totalPaid > 0) && (approvedAmount === totalPaid)) { From ae717fb5fe6d809c9951a4ea3a8ba47fcdf79b34 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Wed, 30 Jul 2025 08:35:32 -0700 Subject: [PATCH 13/18] AB#29460 - Add Recover Applicant Names DataFix Migration Script --- ..._AB29460_ApplicantInfo_Datafix.Designer.cs | 4220 +++++++++++++++++ ...730153058_AB29460_ApplicantInfo_Datafix.cs | 44 + 2 files changed, 4264 insertions(+) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.cs diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.Designer.cs new file mode 100644 index 000000000..468e0a5ee --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.Designer.cs @@ -0,0 +1,4220 @@ +// +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("20250730153058_AB29460_ApplicantInfo_Datafix")] + partial class AB29460_ApplicantInfo_Datafix + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("ScoresheetInstanceId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.HasIndex("ScoresheetInstanceId"); + + b.ToTable("Answers", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("Questions", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Scoresheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CustomFieldId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetInstanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetInstanceId"); + + b.ToTable("CustomFieldValues", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetCorrelationId") + .HasColumnType("uuid"); + + b.Property("WorksheetCorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("WorksheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetLinks", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("CustomFields", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Worksheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantName") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("character varying(600)"); + + b.Property("ApproxNumberOfEmployees") + .HasColumnType("text"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MatchPercentage") + .HasColumnType("numeric"); + + b.Property("NonRegOrgName") + .HasColumnType("text"); + + b.Property("NonRegisteredBusinessName") + .HasColumnType("text"); + + b.Property("OrgName") + .HasColumnType("text"); + + b.Property("OrgNumber") + .HasColumnType("text"); + + b.Property("OrgStatus") + .HasColumnType("text"); + + b.Property("OrganizationSize") + .HasColumnType("text"); + + b.Property("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("StartedOperatingDate") + .HasColumnType("date"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SubSector") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UnityApplicantId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantName"); + + b.ToTable("Applicants", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AddressType") + .HasColumnType("integer"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Postal") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("Street2") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Unit") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicantAddresses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("BceidBusinessGuid") + .HasColumnType("uuid"); + + b.Property("BceidBusinessName") + .HasColumnType("text"); + + b.Property("BceidUserGuid") + .HasColumnType("uuid"); + + b.Property("BceidUserName") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactOrder") + .HasColumnType("integer"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IdentityEmail") + .HasColumnType("text"); + + b.Property("IdentityName") + .HasColumnType("text"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSubUser") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("Phone2") + .HasColumnType("text"); + + b.Property("Phone2Extension") + .HasColumnType("text"); + + b.Property("PhoneExtension") + .HasColumnType("text"); + + b.Property("RoleForApplicant") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId") + .IsUnique(); + + b.HasIndex("OidcSubUser"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Acquisition") + .HasColumnType("text"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationStatusId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + b.Property("AssessmentResultDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AssessmentResultStatus") + .HasColumnType("text"); + + b.Property("AssessmentStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Community") + .HasColumnType("text"); + + b.Property("CommunityPopulation") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractExecutionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ContractNumber") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeclineRational") + .HasColumnType("text"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DueDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DueDiligenceStatus") + .HasColumnType("text"); + + b.Property("EconomicRegion") + .HasColumnType("text"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinalDecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Forestry") + .HasColumnType("text"); + + b.Property("ForestryFocus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LikelihoodOfFunding") + .HasColumnType("text"); + + b.Property("Notes") + .HasColumnType("text"); + + b.Property("NotificationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("Payload") + .HasColumnType("jsonb"); + + b.Property("PercentageTotalProjectBudget") + .HasColumnType("double precision"); + + b.Property("Place") + .HasColumnType("text"); + + b.Property("ProjectEndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectFundingTotal") + .HasColumnType("numeric"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ProjectStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectSummary") + .HasColumnType("text"); + + b.Property("ProposalDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RecommendedAmount") + .HasColumnType("numeric"); + + b.Property("ReferenceNo") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrict") + .HasColumnType("text"); + + b.Property("RequestedAmount") + .HasColumnType("numeric"); + + b.Property("RiskRanking") + .HasColumnType("text"); + + b.Property("SigningAuthorityBusinessPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityCellPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityEmail") + .HasColumnType("text"); + + b.Property("SigningAuthorityFullName") + .HasColumnType("text"); + + b.Property("SigningAuthorityTitle") + .HasColumnType("text"); + + b.Property("SubStatus") + .HasColumnType("text"); + + b.Property("SubmissionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalProjectBudget") + .HasColumnType("numeric"); + + b.Property("TotalScore") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.HasIndex("ApplicationStatusId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Applications", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Duty") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssigneeId"); + + b.ToTable("ApplicationAssignments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsFileId") + .HasColumnType("text"); + + b.Property("ChefsSumbissionId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationChefsFileAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactEmail") + .HasColumnType("text"); + + b.Property("ContactFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactMobilePhone") + .HasColumnType("text"); + + b.Property("ContactTitle") + .HasColumnType("text"); + + b.Property("ContactType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactWorkPhone") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationContact", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountCodingId") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasColumnType("text"); + + b.Property("ApplicationFormDescription") + .HasColumnType("text"); + + b.Property("ApplicationFormName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AttemptedConnectionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("Category") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsCriteriaFormGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConnectionHttpStatus") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("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("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("Payable") + .HasColumnType("boolean"); + + b.Property("PaymentApprovalThreshold") + .HasColumnType("numeric"); + + b.Property("PreventPayment") + .HasColumnType("boolean"); + + b.Property("RenderFormIoToHtml") + .HasColumnType("boolean"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IntakeId"); + + b.ToTable("ApplicationForms", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormVersionId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsSubmissionGuid") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormVersionId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("RenderedHTML") + .HasColumnType("text"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Submission") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormSubmissions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsFormVersionGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormSchema") + .HasColumnType("jsonb"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubmissionHeaderMapping") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormVersion", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LinkedApplicationId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationLinks", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StatusCode") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("StatusCode") + .IsUnique(); + + b.ToTable("ApplicationStatuses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("TagId"); + + b.ToTable("ApplicationTags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.ToTable("AssessmentAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ApprovalRecommended") + .HasColumnType("boolean"); + + b.Property("AssessorId") + .HasColumnType("uuid"); + + b.Property("CleanGrowth") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicImpact") + .HasColumnType("integer"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinancialAnalysis") + .HasColumnType("integer"); + + b.Property("InclusiveGrowth") + .HasColumnType("integer"); + + b.Property("IsComplete") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssessorId"); + + b.ToTable("Assessments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("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("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.HasIndex("CommenterId"); + + b.ToTable("AssessmentComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.GlobalTag.Tag", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Tags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Identity.Person", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Badge") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcDisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("OidcSub"); + + b.ToTable("Persons", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Intakes.Intake", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Budget") + .HasColumnType("double precision"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Intakes", (string)null); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.ToTable("EmailGroupUsers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("BCC") + .IsRequired() + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyType") + .IsRequired() + .HasColumnType("text"); + + b.Property("CC") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesMsgId") + .HasColumnType("uuid"); + + b.Property("ChesResponse") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FromAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Priority") + .IsRequired() + .HasColumnType("text"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("SendOnDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SentDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("text"); + + b.Property("TemplateName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ToAddress") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailLogs", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.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("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.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("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("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.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.HasIndex("TagId"); + + b.ToTable("PaymentTags", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentThresholds.PaymentThreshold", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Threshold") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("PaymentThresholds", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressLine1") + .HasColumnType("text"); + + b.Property("AddressLine2") + .HasColumnType("text"); + + b.Property("AddressLine3") + .HasColumnType("text"); + + b.Property("BankAccount") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EFTAdvicePref") + .HasColumnType("text"); + + b.Property("EmailAddress") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCas") + .HasColumnType("timestamp without time zone"); + + b.Property("MarkDeletedInUse") + .HasColumnType("boolean"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentGroup") + .HasColumnType("integer"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SiteProtected") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Sites", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCAS") + .HasColumnType("timestamp without time zone"); + + b.Property("MailingAddress") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SIN") + .HasColumnType("text"); + + b.Property("StandardIndustryClassification") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("Subcategory") + .HasColumnType("text"); + + b.Property("SupplierProtected") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Suppliers", "Payments"); + }); + + modelBuilder.Entity("Unity.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.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("OidcSubUser") + .HasPrincipalKey("OidcSub"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", "ApplicationForm") + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationStatus", "ApplicationStatus") + .WithMany("Applications") + .HasForeignKey("ApplicationStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Applicant"); + + b.Navigation("ApplicationForm"); + + b.Navigation("ApplicationStatus"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationAssignments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Assignee") + .WithMany() + .HasForeignKey("AssigneeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Assignee"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.HasOne("Unity.GrantManager.Intakes.Intake", null) + .WithMany() + .HasForeignKey("IntakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationTags") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("Assessments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("AssessorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) + .WithMany() + .HasForeignKey("GroupId") + .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.Suppliers.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", null) + .WithMany("PaymentTags") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Supplier", "Supplier") + .WithMany("Sites") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Navigation("Instances"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Navigation("Links"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Navigation("ApplicantAddresses"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Navigation("ApplicantAddresses"); + + b.Navigation("ApplicantAgent"); + + b.Navigation("ApplicationAssignments"); + + b.Navigation("ApplicationTags"); + + b.Navigation("Assessments"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Navigation("Applications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Navigation("ExpenseApprovals"); + + b.Navigation("PaymentTags"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Navigation("Sites"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.cs new file mode 100644 index 000000000..df28fd79f --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250730153058_AB29460_ApplicantInfo_Datafix.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class AB29460_ApplicantInfo_Datafix : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.Sql(@" + UPDATE public.""Applicants"" AS app + SET ""ApplicantName"" = LEFT(sub.""MappedApplicantName"", 600) + FROM ( + SELECT + afs.""ApplicantId"", + afs.""Submission""->'submission'->'submission'->'data'->> + (afv.""SubmissionHeaderMapping""::json->>'ApplicantName') AS ""MappedApplicantName"" + FROM + public.""ApplicationFormVersion"" AS afv + JOIN + public.""ApplicationFormSubmissions"" AS afs + ON afv.""Id"" = afs.""ApplicationFormVersionId"" + ) AS sub + WHERE + app.""Id"" = sub.""ApplicantId"" + AND ( + app.""ApplicantName"" IS NULL + OR TRIM(app.""ApplicantName"") = '' + ) + AND sub.""MappedApplicantName"" IS NOT NULL + AND TRIM(sub.""MappedApplicantName"") <> ''; + "); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} From fbf2c51ac78de0c0d67b12d0e7e86cb1b045c734 Mon Sep 17 00:00:00 2001 From: jpasta Date: Wed, 30 Jul 2025 12:15:41 -0700 Subject: [PATCH 14/18] bugfix/AB#29607-FixAmounts --- .../Scoresheets/QuestionDto.cs | 60 ++++++++++++- .../Enums/PaymentRequestStatus.cs | 7 +- .../PaymentRequests/AccountCodingDto.cs | 23 +++++ .../PaymentRequests/PaymentRequestDto.cs | 2 + .../Domain/PaymentRequests/PaymentRequest.cs | 3 +- .../Domain/Services/IPaymentsManager.cs | 2 + .../Domain/Services/PaymentsManager.cs | 88 +++++++++++-------- ...aymentsDbContextModelCreatingExtensions.cs | 5 ++ .../PaymentRequestAppService.cs | 57 ++++++++---- .../PaymentsApplicationAutoMapperProfile.cs | 4 +- .../Localization/Payments/en.json | 1 + .../Pages/AccountCoding/UpdateModal.cshtml.cs | 1 + .../UpdatePaymentRequestStatus.cshtml.cs | 50 +++++++---- .../UpdatePaymentRequestStatusModal.js | 4 +- .../Pages/PaymentRequests/Index.js | 19 +++- .../IApplicationFormAppService.cs | 1 + .../Payments/AccountCodingDto.cs | 14 --- .../Payments/IAccountCodingAppService.cs | 1 + .../ApplicationFormAppService.cs | 9 ++ ...rantManagerApplicationAutoMapperProfile.cs | 2 +- .../Payments/AccountCodingAppService.cs | 1 + .../PaymentConfiguration/Default.cshtml | 13 +-- 22 files changed, 262 insertions(+), 105 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/AccountCodingDto.cs delete mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/QuestionDto.cs b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/QuestionDto.cs index 3708cad7c..4b13baea0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/QuestionDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Flex/src/Unity.Flex.Application.Contracts/Scoresheets/QuestionDto.cs @@ -22,22 +22,74 @@ public class QuestionDto : ExtensibleEntityDto public string? GetMin() { - return JsonSerializer.Deserialize(Definition ?? "{}")?.Min.ToString(); + try + { + var def = JsonSerializer.Deserialize(Definition ?? "{}"); + if (def?.Min == null) + return null; + // Only allow Int64 values + if (long.TryParse(def.Min.ToString(), out var minValue)) + return minValue.ToString(); + return null; + } + catch + { + return null; + } } public string? GetMax() { - return JsonSerializer.Deserialize(Definition ?? "{}")?.Max.ToString(); + try + { + var def = JsonSerializer.Deserialize(Definition ?? "{}"); + if (def?.Max == null) + return null; + // Only allow Int64 values + if (long.TryParse(def.Max.ToString(), out var maxValue)) + return maxValue.ToString(); + return null; + } + catch + { + return null; + } } public string? GetMinLength() { - return JsonSerializer.Deserialize(Definition ?? "{}")?.MinLength.ToString(); + try + { + var def = JsonSerializer.Deserialize(Definition ?? "{}"); + if (def?.MinLength == null) + return null; + // Only allow Int64 values + if (long.TryParse(def.MinLength.ToString(), out var minLength)) + return minLength.ToString(); + return null; + } + catch + { + return null; + } } public string? GetMaxLength() { - return JsonSerializer.Deserialize(Definition ?? "{}")?.MaxLength.ToString(); + try + { + var def = JsonSerializer.Deserialize(Definition ?? "{}"); + if (def?.MaxLength == null) + return null; + // Only allow Int64 values + if (long.TryParse(def.MaxLength.ToString(), out var maxLength)) + return maxLength.ToString(); + return null; + } + catch + { + return null; + } } public string? GetYesValue() 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 6d066a23c..16d557583 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 @@ -9,13 +9,14 @@ public enum PaymentRequestStatus L1Pending = 1, L1Declined = 2, L2Pending = 3, - L2Declined = 4, - L3Pending = 5, + L2Declined = 4, + L3Pending = 5, L3Declined = 6, Submitted = 7, Validated = 8, NotValidated = 9, Paid = 10, - Failed = 11, + Failed = 11, + FSB = 12, // Financial Services Branch - Prevent CAS Payment } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/AccountCodingDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/AccountCodingDto.cs new file mode 100644 index 000000000..be11613b4 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/AccountCodingDto.cs @@ -0,0 +1,23 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Unity.Payments.PaymentRequests +{ + [Serializable] + public class AccountCodingDto : AuditedEntityDto + { + public string MinistryClient { get; private set; } + public string Responsibility { get; private set; } + public string ServiceLine { get; private set; } + public string Stob { get; private set; } + public string ProjectNumber { get; private set; } + public AccountCodingDto() + { + MinistryClient = string.Empty; + Responsibility = string.Empty; + ServiceLine = string.Empty; + Stob = string.Empty; + ProjectNumber = string.Empty; + } + } +} \ No newline at end of file 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 c9f6d72bc..e782f3f36 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 @@ -35,6 +35,8 @@ public class PaymentRequestDto : AuditedEntityDto public string? Note { get; set; } public string? ErrorSummary { get; set; } public Guid? AccountCodingId { get; set; } + public AccountCodingDto? AccountCoding { get; set; } + public string AccountCodingDisplay { get; set; } = string.Empty; public PaymentUserDto? CreatorUser { get; set; } public Collection PaymentTags { get; set; } public Collection ExpenseApprovals { get; set; } 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 94f53c92e..4ea6b8752 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 @@ -10,6 +10,7 @@ using Unity.Payments.Domain.Exceptions; using Unity.Payments.PaymentRequests; using Unity.Payments.Domain.PaymentTags; +using Unity.Payments.Domain.AccountCodings; namespace Unity.Payments.Domain.PaymentRequests { @@ -60,7 +61,7 @@ public virtual Site Site public virtual int? CasHttpStatusCode { get; private set; } = null; public virtual string? CasResponse { get; private set; } = string.Empty; public virtual Guid? AccountCodingId { get; private set; } - + public virtual AccountCoding? AccountCoding { get; set; } = null; public virtual string? Note { get; private set; } = null; protected PaymentRequest() { 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 f98e10420..bccb0910c 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 @@ -7,5 +7,7 @@ namespace Unity.Payments.Domain.Services public interface IPaymentsManager { Task UpdatePaymentStatusAsync(Guid paymentRequestId, PaymentApprovalAction triggerAction); + Task GetFormPreventPaymentStatusByPaymentRequestId(Guid paymentRequestId); + 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 46dde4749..d53a2defe 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 @@ -1,8 +1,10 @@ -using Stateless; +using Microsoft.EntityFrameworkCore; +using Stateless; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Unity.GrantManager.Applications; using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Domain.Shared; using Unity.Payments.Domain.Workflow; @@ -16,28 +18,15 @@ namespace Unity.Payments.Domain.Services { - public class PaymentsManager : DomainService, IPaymentsManager - { - /* To be implemented */ - private readonly IPaymentRequestRepository _paymentRequestRepository; - private readonly IUnitOfWorkManager _unitOfWorkManager; - private readonly IPermissionChecker _permissionChecker; - private readonly CasPaymentRequestCoordinator _casPaymentRequestCoordinator; - private readonly ICurrentUser _currentUser; - - public PaymentsManager( + public class PaymentsManager( + IApplicationRepository applicationRepository, + IApplicationFormRepository applicationFormRepository, CasPaymentRequestCoordinator casPaymentRequestCoordinator, IPaymentRequestRepository paymentRequestRepository, IUnitOfWorkManager unitOfWorkManager, IPermissionChecker permissionChecker, - ICurrentUser currentUser) - { - _casPaymentRequestCoordinator = casPaymentRequestCoordinator; - _paymentRequestRepository = paymentRequestRepository; - _unitOfWorkManager = unitOfWorkManager; - _permissionChecker = permissionChecker; - _currentUser = currentUser; - } + ICurrentUser currentUser) : DomainService, IPaymentsManager + { private void ConfigureWorkflow(StateMachine paymentStateMachine) { @@ -67,13 +56,12 @@ private void ConfigureWorkflow(StateMachine> GetActions(Guid paymentRequestsId) { - var paymentRequest = await _paymentRequestRepository.GetAsync(paymentRequestsId, true); + var paymentRequest = await paymentRequestRepository.GetAsync(paymentRequestsId, true); var Workflow = new PaymentsWorkflow( () => paymentRequest.Status, @@ -98,8 +86,8 @@ public async Task> GetActions(Guid paymentRequests public async Task TriggerAction(Guid paymentRequestsId, PaymentApprovalAction triggerAction) { - var paymentRequest = await _paymentRequestRepository.GetAsync(paymentRequestsId, true); - var currentUserId = _currentUser.GetId(); + var paymentRequest = await paymentRequestRepository.GetAsync(paymentRequestsId, true); + var currentUserId = currentUser.GetId(); var statusChange = paymentRequest.Status; @@ -114,33 +102,33 @@ public async Task TriggerAction(Guid paymentRequestsId, PaymentA if (triggerAction == PaymentApprovalAction.L1Approve) { - var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == Enums.ExpenseApprovalType.Level1); + var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == ExpenseApprovalType.Level1); paymentRequest.ExpenseApprovals[index].Approve(currentUserId); statusChangedTo = PaymentRequestStatus.L2Pending; } else if (triggerAction == PaymentApprovalAction.L1Decline) { - var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == Enums.ExpenseApprovalType.Level1); + var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == ExpenseApprovalType.Level1); paymentRequest.ExpenseApprovals[index].Decline(currentUserId); statusChangedTo = PaymentRequestStatus.L1Declined; } else if (triggerAction == PaymentApprovalAction.L2Approve) { - var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == Enums.ExpenseApprovalType.Level2); + var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == ExpenseApprovalType.Level2); paymentRequest.ExpenseApprovals[index].Approve(currentUserId); statusChangedTo = PaymentRequestStatus.L3Pending; } else if (triggerAction == PaymentApprovalAction.L2Decline) { - var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == Enums.ExpenseApprovalType.Level2); + var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == ExpenseApprovalType.Level2); paymentRequest.ExpenseApprovals[index].Decline(currentUserId); statusChangedTo = PaymentRequestStatus.L2Declined; } else if (triggerAction == PaymentApprovalAction.L3Decline) { - var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == Enums.ExpenseApprovalType.Level3); + var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == ExpenseApprovalType.Level3); paymentRequest.ExpenseApprovals[index].Decline(currentUserId); statusChangedTo = PaymentRequestStatus.L3Declined; } @@ -149,26 +137,56 @@ public async Task TriggerAction(Guid paymentRequestsId, PaymentA { if (HasPermission(PaymentsPermissions.Payments.L2ApproveOrDecline)) { - var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == Enums.ExpenseApprovalType.Level2); + var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == ExpenseApprovalType.Level2); paymentRequest.ExpenseApprovals[index].Approve(currentUserId); } else if (HasPermission(PaymentsPermissions.Payments.L3ApproveOrDecline)) { - var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == Enums.ExpenseApprovalType.Level3); + var index = paymentRequest.ExpenseApprovals.FindIndex(i => i.Type == ExpenseApprovalType.Level3); paymentRequest.ExpenseApprovals[index].Approve(currentUserId); } + bool preventPayment = await GetFormPreventPaymentStatusByApplicationId(paymentRequest.CorrelationId); - statusChangedTo = PaymentRequestStatus.Submitted; - await _casPaymentRequestCoordinator.AddPaymentRequestsToInvoiceQueue(paymentRequest); + if (preventPayment) + { + statusChangedTo = PaymentRequestStatus.FSB; + } + else + { + statusChangedTo = PaymentRequestStatus.Submitted; + await casPaymentRequestCoordinator.AddPaymentRequestsToInvoiceQueue(paymentRequest); + } + + } paymentRequest.SetPaymentRequestStatus(statusChangedTo); - return await _paymentRequestRepository.UpdateAsync(paymentRequest); + return await paymentRequestRepository.UpdateAsync(paymentRequest); + } + + public async Task GetFormPreventPaymentStatusByPaymentRequestId(Guid paymentRequestId) + { + PaymentRequest paymentRequest = await paymentRequestRepository.GetAsync(paymentRequestId); + Guid applicationId = paymentRequest.CorrelationId; + var applicationQueryable = await applicationRepository.GetQueryableAsync(); + var applicationWithIncludes = await applicationQueryable.Where(a => a.Id == applicationId) + .Include(a => a.ApplicationForm).ToListAsync(); + + var appForm = applicationWithIncludes.FirstOrDefault()?.ApplicationForm; + return appForm != null && appForm.PreventPayment; } + + public async Task GetFormPreventPaymentStatusByApplicationId(Guid applicationId) + { + Application application = await applicationRepository.GetAsync(applicationId); + Guid formId = application.ApplicationForm.Id; + ApplicationForm appForm = await applicationFormRepository.GetAsync(formId); + return appForm.PreventPayment; + } public async Task UpdatePaymentStatusAsync(Guid paymentRequestId, PaymentApprovalAction triggerAction) { - using var uow = _unitOfWorkManager.Begin(); + using var uow = unitOfWorkManager.Begin(); await TriggerAction(paymentRequestId, triggerAction); 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 d33e05d2e..9d41429a1 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 @@ -34,6 +34,11 @@ public static void ConfigurePayments( .WithMany() .HasForeignKey(x => x.SiteId) .OnDelete(DeleteBehavior.NoAction); + + b.HasOne(e => e.AccountCoding) + .WithMany() + .HasForeignKey(x => x.AccountCodingId) + .OnDelete(DeleteBehavior.NoAction); b.HasIndex(e => e.ReferenceNumber).IsUnique(); }); 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 59974d29d..9cfbc292a 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 @@ -25,17 +25,19 @@ namespace Unity.Payments.PaymentRequests { [RequiresFeature("Unity.Payments")] [Authorize] - public class PaymentRequestAppService( - ICurrentUser currentUser, - IDataFilter dataFilter, - IExternalUserLookupServiceProvider externalUserLookupServiceProvider, - IPaymentConfigurationRepository paymentConfigurationRepository, - IPaymentsManager paymentsManager, - IPaymentRequestRepository paymentRequestsRepository, - IPaymentThresholdRepository paymentThresholdRepository, - IPermissionChecker permissionChecker) : PaymentsAppService, IPaymentRequestAppService - - { + #pragma warning disable S107 // Suppress "Constructor has too many parameters" + public class PaymentRequestAppService( + ICurrentUser currentUser, + IDataFilter dataFilter, + IExternalUserLookupServiceProvider externalUserLookupServiceProvider, + IPaymentConfigurationRepository paymentConfigurationRepository, + IPaymentsManager paymentsManager, + IPaymentRequestRepository paymentRequestsRepository, + IPaymentThresholdRepository paymentThresholdRepository, + IPermissionChecker permissionChecker) : PaymentsAppService, IPaymentRequestAppService + #pragma warning restore S107 + + { public async Task GetDefaultAccountCodingId() { Guid? accountCodingId = null; @@ -55,12 +57,9 @@ public virtual async Task> CreateAsync(List pr.AccountCoding) .Include(pr => pr.PaymentTags) .ThenInclude(pt => pt.Tag) .ToListAsync(); #pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. - var mappedPayments = await MapToDtoAndLoadDetailsAsync(paymentsWithTags); + var mappedPayments = await MapToDtoAndLoadDetailsAsync(paymentWithIncludes); ApplyErrorSummary(mappedPayments); @@ -366,6 +366,7 @@ protected internal async Task> MapToDtoAndLoadDetailsAsy { paymentRequestDto.CreatorUser = paymentRequestUserDto; } + paymentRequestDto.AccountCodingDisplay = GetAccountDistributionCode(paymentRequestDto.AccountCoding).Result; foreach (var expenseApproval in paymentRequestDto.ExpenseApprovals) { @@ -380,6 +381,26 @@ protected internal async Task> MapToDtoAndLoadDetailsAsy return paymentDtos; } + public virtual Task GetAccountDistributionCode(AccountCodingDto? accountCoding) + { + string accountDistributionCode = ""; + if (accountCoding == null) return Task.FromResult(accountDistributionCode); + + if (accountCoding != null + && accountCoding.Responsibility != null + && accountCoding.ServiceLine != null + && accountCoding.Stob != null + && accountCoding.MinistryClient != null + && accountCoding.ProjectNumber != null) + { + string accountDistributionPostFix = "000000.0000"; + accountDistributionCode = + $"{accountCoding.MinistryClient}.{accountCoding.Responsibility}.{accountCoding.ServiceLine}.{accountCoding.Stob}.{accountCoding.ProjectNumber}.{accountDistributionPostFix}"; + } + + return Task.FromResult(accountDistributionCode); + } + private static void ApplyErrorSummary(List mappedPayments) { mappedPayments.ForEach(mappedPayment => diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs index 19c00f440..f437fd146 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs @@ -23,7 +23,9 @@ public class PaymentsApplicationAutoMapperProfile : Profile public PaymentsApplicationAutoMapperProfile() { CreateMap() - .ForMember(dest => dest.ErrorSummary, options => options.Ignore()) + .ForMember(dest => dest.ErrorSummary, opt => opt.Ignore()) + .ForMember(dest => dest.AccountCoding, opt => opt.MapFrom(src => src.AccountCoding)) + .ForMember(dest => dest.AccountCodingDisplay, opt => opt.Ignore()) .ForMember(dest => dest.Site, opt => opt.MapFrom(src => src.Site)) .ForMember(dest => dest.CreatorUser, opt => opt.Ignore()) .ForMember(dest => dest.PaymentTags, opt => opt.MapFrom(src => src.PaymentTags)); 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 f069ee75b..6d2d0da0b 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 @@ -129,6 +129,7 @@ "Enum:PaymentRequestStatus.L3Approved": "L3 Approved", "Enum:PaymentRequestStatus.L3Declined": "L3 Declined", "Enum:PaymentRequestStatus.Submitted": "Submitted to CAS", + "Enum:PaymentRequestStatus.FSB": "Sent to Accounts Payable", "Enum:PaymentRequestStatus.Validated": "Validated", "Enum:PaymentRequestStatus.NotValidated": "Not Validated", "Enum:PaymentRequestStatus.Paid": "Paid", diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs index 8376e5f1d..58a57638f 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Unity.GrantManager.Payments; +using Unity.Payments.PaymentRequests; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; namespace Unity.Payments.Web.Pages.AccountCoding; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs index c4cbd61a5..c4a2fc1b3 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Unity.GrantManager.ApplicationForms; using Unity.Payments.Domain.PaymentRequests; +using Unity.Payments.Domain.Services; using Unity.Payments.Domain.Shared; using Unity.Payments.Enums; using Unity.Payments.PaymentConfigurations; @@ -24,6 +25,7 @@ public class PaymentGrouping } public class UpdatePaymentRequestStatus( + IPaymentsManager paymentsManager, IPaymentRequestAppService paymentRequestAppService, IApplicationFormAppService applicationFormAppService, IPaymentRequestRepository paymentRepository, @@ -73,8 +75,6 @@ private async Task InitializeStateAsync(string paymentIds, bool isApprove) HasPaymentConfiguration = await paymentConfigurationAppService.GetAsync() != null; } - - private async Task> BuildPaymentApprovalsAsync(List payments) { var paymentApprovals = new List(); @@ -137,13 +137,11 @@ private async Task UpdateExpenseApprovalsAsync(PaymentDetailsDto payment, bool i { if (payment.Status == PaymentRequestStatus.L2Pending) { - var l3Approval = payment.ExpenseApprovals.FirstOrDefault(x => x.Type == ExpenseApprovalType.Level3); PaymentRequest paymentEntity = await paymentRepository.GetAsync(payment.Id); if (isL3ApprovalRequired && l3Approval == null) { paymentEntity.ExpenseApprovals.Add(new ExpenseApproval(Guid.NewGuid(), ExpenseApprovalType.Level3)); - } else if (!isL3ApprovalRequired && l3Approval != null) { @@ -174,30 +172,45 @@ private void ValidateApprovalModel(PaymentsApprovalModel request) private async Task VerifyPermissionsAsync(PaymentRequestStatus status, PaymentsApprovalModel request) { - if (status == PaymentRequestStatus.L2Pending && IsApproval) - { - request.ToStatus = request.IsL3ApprovalRequired ? PaymentRequestStatus.L3Pending : PaymentRequestStatus.Submitted; - } - else + bool preventPayment = await paymentsManager.GetFormPreventPaymentStatusByPaymentRequestId(request.Id); + request.ToStatus = GetNextStatus(status, request, preventPayment, IsApproval); + var permission = GetRequiredPermission(status); + return permission != null && await permissionCheckerService.IsGrantedAsync(permission); + } + + private static PaymentRequestStatus GetNextStatus(PaymentRequestStatus status, PaymentsApprovalModel request, bool preventPayment, bool isApproval) + { + if (status == PaymentRequestStatus.L2Pending && isApproval) { - request.ToStatus = status switch + if (request.IsL3ApprovalRequired) { - PaymentRequestStatus.L1Pending => IsApproval ? PaymentRequestStatus.L2Pending : PaymentRequestStatus.L1Declined, - PaymentRequestStatus.L2Pending => PaymentRequestStatus.L2Declined, - PaymentRequestStatus.L3Pending => IsApproval ? PaymentRequestStatus.Submitted : PaymentRequestStatus.L3Declined, - _ => request.ToStatus - }; + return PaymentRequestStatus.L3Pending; + } + if (preventPayment) + { + return PaymentRequestStatus.FSB; + } + return PaymentRequestStatus.Submitted; } - var permission = status switch + return status switch + { + PaymentRequestStatus.L1Pending => isApproval ? PaymentRequestStatus.L2Pending : PaymentRequestStatus.L1Declined, + PaymentRequestStatus.L2Pending => PaymentRequestStatus.L2Declined, + PaymentRequestStatus.L3Pending => isApproval ? PaymentRequestStatus.Submitted : PaymentRequestStatus.L3Declined, + _ => request.ToStatus + }; + } + + private static string? GetRequiredPermission(PaymentRequestStatus status) + { + return status switch { PaymentRequestStatus.L1Pending => PaymentsPermissions.Payments.L1ApproveOrDecline, PaymentRequestStatus.L2Pending => PaymentsPermissions.Payments.L2ApproveOrDecline, PaymentRequestStatus.L3Pending => PaymentsPermissions.Payments.L3ApproveOrDecline, _ => null }; - - return permission != null && await permissionCheckerService.IsGrantedAsync(permission); } public async Task OnPostAsync() @@ -249,6 +262,7 @@ public static string GetStatusText(PaymentRequestStatus status) "L3Approved" => "L3 Approved", "L3Declined" => "L3 Declined", "Submitted" => "Submitted to CAS", + "FSB" => "Sent to Accounts Payable", "Paid" => "Paid", "PaymentFailed" => "Payment Failed", _ => "L1 Pending", diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js index 8026351fd..f1fe8946b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js @@ -94,6 +94,9 @@ function getStatusText(data) { case "Submitted": return "Submitted"; + + case "FSB": + return "Sent to Accounts Payable"; case "Paid": return "Paid"; @@ -101,7 +104,6 @@ function getStatusText(data) { case "PaymentFailed": return "Payment Failed" - default: return "Created"; } 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 eacb87611..c1953c5c2 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 @@ -25,7 +25,8 @@ $(function () { 'l1ApprovalDate', 'l2ApprovalDate', 'l3ApprovalDate', - 'CASResponse' + 'CASResponse', + 'accountCodingDisplay' ]; let paymentRequestStatusModal = new abp.ModalManager({ @@ -293,7 +294,8 @@ $(function () { getPaymentStatusColumn(columnIndex++), getCASResponseColumn(columnIndex++), getTagsColumn(columnIndex++), - getNoteColumn(columnIndex++) + getNoteColumn(columnIndex++), + getAccountDistributionColumn(columnIndex++), ] return columns.map((column) => ({ ...column, targets: [column.index], orderData: [column.index, 0] })); @@ -531,7 +533,7 @@ $(function () { } function formatName(userData) { - return userData !== null ? `${userData?.name} ${userData?.surname}` : null; + return userData+"" != "undefined" && userData !== null ? `${userData?.name} ${userData?.surname}` : ""; } function getApprovalDateColumn(columnIndex, level) { @@ -637,6 +639,17 @@ $(function () { }; } + function getAccountDistributionColumn(columnIndex) { + return { + title: 'Account Code', + name: 'accountCodingDisplay', + data: 'accountCodingDisplay', + className: 'data-table-header', + index: columnIndex + + }; + } + function getExpenseApprovalsDetails(expenseApprovals, type) { return expenseApprovals.find(x => x.type == type); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs index 0550e005e..285357a88 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs @@ -19,5 +19,6 @@ public interface IApplicationFormAppService : ICrudAppService< Task> GetPublishedVersionsAsync(Guid id); Task PatchOtherConfig(Guid id, OtherConfigDto config); Task GetFormPaymentApprovalThresholdByApplicationIdAsync(Guid applicationId); + Task GetFormPreventPaymentStatusByApplicationId(Guid applicationId); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs deleted file mode 100644 index 0e277d2ff..000000000 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Volo.Abp.Application.Dtos; - -namespace Unity.GrantManager.Payments -{ - public class AccountCodingDto : AuditedEntityDto -{ - public string? MinistryClient { get; private set; } = string.Empty; - public string? Responsibility { get; private set; } = string.Empty; - public string? ServiceLine { get; private set; } = string.Empty; - public string? Stob { get; private set; } = string.Empty; - public string? ProjectNumber { get; private set; } = string.Empty; - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs index df1da44a5..1c4deb4cf 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs @@ -1,4 +1,5 @@ using System; +using Unity.Payments.PaymentRequests; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index 18897a819..afb6b1cf3 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -162,6 +162,15 @@ public async Task PatchOtherConfig(Guid id, OtherConfigDto config) } [Authorize(PaymentsPermissions.Payments.EditFormPaymentConfiguration)] + public async Task GetFormPreventPaymentStatusByApplicationId(Guid applicationId) + { + // Get the payment threshold for the application + GrantApplicationDto grantApplicationDto = await _applicationService.GetAsync(applicationId); + Guid formId = grantApplicationDto.ApplicationForm.Id; + ApplicationForm appForm = await _applicationFormRepository.GetAsync(formId); + return appForm.PreventPayment; + } + public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) { ApplicationForm appForm = await _applicationFormRepository.GetAsync(dto.ApplicationFormId); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs index dd89fa432..77a47ff1b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs @@ -12,9 +12,9 @@ using Unity.GrantManager.Identity; using Unity.GrantManager.Intakes; using Unity.GrantManager.Locality; -using Unity.GrantManager.Payments; using Unity.GrantManager.Zones; using Unity.Payments.Domain.AccountCodings; +using Unity.Payments.PaymentRequests; namespace Unity.GrantManager; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs index 4a0e75f0d..4bd9de87b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs @@ -1,5 +1,6 @@ using System; using Unity.Payments.Domain.AccountCodings; +using Unity.Payments.PaymentRequests; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml index 9d82c4834..525bb92e8 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -24,7 +24,7 @@ - +
$ @@ -35,24 +35,25 @@ data-val-range="The field Payment Threshold Amount must be 0 or greater." data-val-range-max="1.7976931348623157E+308" data-val-range-min="0" - placeholder="0.00" id="PaymentApprovalThreshold" name="PaymentApprovalThreshold" value="@Model.PaymentApprovalThreshold" class="form-control-currency text-end rounded-end">
- +

Note: The selected Account Code for this form will only apply to payments made within this specific intake form. It will not impact the global Account Code settings.

+
+

- Note: Set the Approval Payment Threshold here only if this intake form requires a unique threshold. + Note: Set the Approval Payment Threshold here only if this intake form requires a unique threshold.
The individual Approval Thresholds assigned to each l2_approver will still take precedence if they are lower - than the threshold specified in this form. This form's threshold will not override the l2_approver's existing thresholds. + than the threshold specified in this form.

-
+

From 9fa60cf6bf7590f08e1bcbb3018c70c8503ca493 Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:43:14 -0700 Subject: [PATCH 15/18] Update applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/Unity.Payments.Web/Pages/PaymentRequests/Index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c1953c5c2..83d814a23 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 @@ -533,7 +533,7 @@ $(function () { } function formatName(userData) { - return userData+"" != "undefined" && userData !== null ? `${userData?.name} ${userData?.surname}` : ""; + return typeof userData !== 'undefined' && userData !== null ? `${userData?.name} ${userData?.surname}` : ""; } function getApprovalDateColumn(columnIndex, level) { From 75d6e6ee4eff7045d6215dd78f2a10bd16463b5c Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:44:15 -0700 Subject: [PATCH 16/18] Update applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../PaymentRequests/PaymentRequestAppService.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 9cfbc292a..4b68645ed 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 @@ -386,8 +386,7 @@ public virtual Task GetAccountDistributionCode(AccountCodingDto? account string accountDistributionCode = ""; if (accountCoding == null) return Task.FromResult(accountDistributionCode); - if (accountCoding != null - && accountCoding.Responsibility != null + if (accountCoding.Responsibility != null && accountCoding.ServiceLine != null && accountCoding.Stob != null && accountCoding.MinistryClient != null From e09d9156ddf35de6381c760c4401cd067816b986 Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:44:30 -0700 Subject: [PATCH 17/18] Update applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../PaymentRequests/PaymentRequestAppService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4b68645ed..b78566d35 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 @@ -366,7 +366,7 @@ protected internal async Task> MapToDtoAndLoadDetailsAsy { paymentRequestDto.CreatorUser = paymentRequestUserDto; } - paymentRequestDto.AccountCodingDisplay = GetAccountDistributionCode(paymentRequestDto.AccountCoding).Result; + paymentRequestDto.AccountCodingDisplay = await GetAccountDistributionCode(paymentRequestDto.AccountCoding); foreach (var expenseApproval in paymentRequestDto.ExpenseApprovals) { From 4873a2db7cbde3cf7030827f8f389ae58b7ed217 Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:44:49 -0700 Subject: [PATCH 18/18] Update applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../PaymentRequests/PaymentRequestAppService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b78566d35..421acc35e 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 @@ -392,9 +392,9 @@ public virtual Task GetAccountDistributionCode(AccountCodingDto? account && accountCoding.MinistryClient != null && accountCoding.ProjectNumber != null) { - string accountDistributionPostFix = "000000.0000"; + const string DefaultAccountDistributionPostfix = "000000.0000"; accountDistributionCode = - $"{accountCoding.MinistryClient}.{accountCoding.Responsibility}.{accountCoding.ServiceLine}.{accountCoding.Stob}.{accountCoding.ProjectNumber}.{accountDistributionPostFix}"; + $"{accountCoding.MinistryClient}.{accountCoding.Responsibility}.{accountCoding.ServiceLine}.{accountCoding.Stob}.{accountCoding.ProjectNumber}.{DefaultAccountDistributionPostfix}"; } return Task.FromResult(accountDistributionCode);