From 53da46da2cc5eb448c9426c9342aecc419de891c Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 5 Aug 2025 14:43:30 -0700 Subject: [PATCH 1/6] AB#29664 code QL suggestions # Conflicts: # applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs --- .../DetermineElectoralDistrictHandler.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs index 118fa2ad3..487a6bac1 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs @@ -14,7 +14,7 @@ public class DetermineElectoralDistrictHandler(IGeocoderApiService geocoderApiSe : ILocalEventHandler, ITransientDependency { /// - /// Determines the Electoral Distrct based on the Address. + /// Determines the Electoral District based on the Address. /// /// /// @@ -30,31 +30,39 @@ public async Task HandleEventAsync(ApplicationProcessEvent eventData) if (eventData.FormVersion == null) { - logger.LogWarning("Application data is null in DetermineElectoralDistrictHandler."); + logger.LogWarning("Form version data is null in DetermineElectoralDistrictHandler."); return; } // Check if the electoral district is already mapped for the form submission, if so then no work to be done if (eventData.FormVersion.HasSubmissionHeaderMapping("ApplicantElectoralDistrict")) + { + logger.LogInformation("Electoral district already determined for application {ApplicationId}. No further action required.", + eventData.Application.Id); return; + } + + // Use local variable to avoid modifying the entity property + var addressType = eventData.Application.ApplicationForm.ElectoralDistrictAddressType ?? GrantApplications.AddressType.PhysicalAddress; + logger.LogInformation("Using electoral district address type: {AddressType} for electoral determination", addressType); - var electoralDistrictAddressType = eventData.Application.ApplicationForm.ElectoralDistrictAddressType; var applicantAddresses = eventData.Application.Applicant.ApplicantAddresses; if (applicantAddresses == null || applicantAddresses.Count == 0) { - logger.LogWarning("Application data is null in DetermineElectoralDistrictHandler."); + logger.LogWarning("Applicant addresses are null or empty in DetermineElectoralDistrictHandler for application {ApplicationId}.", + eventData.Application.Id); return; } // Find the related address type var matchedAddressType = applicantAddresses - .FirstOrDefault(a => a.AddressType == electoralDistrictAddressType); + .FirstOrDefault(a => a.AddressType == addressType); if (matchedAddressType == null) { logger.LogWarning("No address of type {AddressType} found for application {ApplicationId}.", - electoralDistrictAddressType, eventData.Application.Id); + addressType, eventData.Application.Id); return; } From ec92302f9bd73caf964743371697e1b8ba440376 Mon Sep 17 00:00:00 2001 From: jpasta Date: Tue, 5 Aug 2025 14:50:24 -0700 Subject: [PATCH 2/6] hotfix/AB#29603-AddressIssue --- .../ApplicantInfoViewComponent.cs | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs index 1ff68758d..705fb1bad 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs @@ -30,44 +30,44 @@ public async Task InvokeAsync(Guid applicationId, Guid app var applicantInfoDto = await applicationAppicantService.GetApplicantInfoTabAsync(applicationId); var electoralDistrictAddressType = await applicationFormAppService.GetElectoralDistrictAddressTypeAsync(applicantInfoDto.ApplicationFormId); - if (applicantInfoDto == null) - { - throw new InvalidOperationException("Applicant information could not be retrieved."); + if (applicantInfoDto == null) + { + throw new InvalidOperationException("Applicant information could not be retrieved."); } - ApplicantInfoViewModel viewModel = new() - { - ApplicationId = applicationId, - ApplicationFormId = applicantInfoDto.ApplicationFormId, - ApplicationFormVersionId = applicationFormVersionId, - ApplicantId = applicantInfoDto.ApplicantId, - ApplicantSummary = ObjectMapper.Map(applicantInfoDto.ApplicantSummary ?? new ApplicantSummaryDto()), - ContactInfo = ObjectMapper.Map(applicantInfoDto.ContactInfo ?? new ContactInfoDto()), - SigningAuthority = ObjectMapper.Map(applicantInfoDto.SigningAuthority ?? new SigningAuthorityDto()), - ApplicantElectoralAddressType = electoralDistrictAddressType, + ApplicantInfoViewModel viewModel = new() + { + ApplicationId = applicationId, + ApplicationFormId = applicantInfoDto.ApplicationFormId, + ApplicationFormVersionId = applicationFormVersionId, + ApplicantId = applicantInfoDto.ApplicantId, + ApplicantSummary = ObjectMapper.Map(applicantInfoDto.ApplicantSummary ?? new ApplicantSummaryDto()), + ContactInfo = ObjectMapper.Map(applicantInfoDto.ContactInfo ?? new ContactInfoDto()), + SigningAuthority = ObjectMapper.Map(applicantInfoDto.SigningAuthority ?? new SigningAuthorityDto()), + ApplicantElectoralAddressType = electoralDistrictAddressType, }; viewModel.ApplicantSummary.ApplicantId = applicantInfoDto.ApplicantId; await PopulateSectorsAndSubSectorsAsync(viewModel); - await PopulateElectoralDistrictsAsync(viewModel); - - // MAPADDRESSES - if (applicantInfoDto.ApplicantAddresses?.Count > 0) - { - // Map physical address - var physicalAddress = FindMostRecentAddress(applicantInfoDto.ApplicantAddresses, AddressType.PhysicalAddress); - if (physicalAddress is not null) - { - viewModel.PhysicalAddress = ObjectMapper.Map(physicalAddress); + await PopulateElectoralDistrictsAsync(viewModel); + + // MAPADDRESSES + if (applicantInfoDto.ApplicantAddresses?.Count > 0) + { + // Map physical address + var physicalAddress = FindMostRecentAddress(applicantInfoDto.ApplicantAddresses, AddressType.PhysicalAddress); + if (physicalAddress is not null) + { + viewModel.PhysicalAddress = ObjectMapper.Map(physicalAddress); } - // Map mailing address - var mailingAddress = FindMostRecentAddress(applicantInfoDto.ApplicantAddresses, AddressType.MailingAddress); - if (mailingAddress is not null) - { - viewModel.MailingAddress = ObjectMapper.Map(mailingAddress); - } + // Map mailing address + var mailingAddress = FindMostRecentAddress(applicantInfoDto.ApplicantAddresses, AddressType.MailingAddress); + if (mailingAddress is not null) + { + viewModel.MailingAddress = ObjectMapper.Map(mailingAddress); + } } return View(viewModel); @@ -76,12 +76,10 @@ public async Task InvokeAsync(Guid applicationId, Guid app private static ApplicantAddressDto? FindMostRecentAddress(List applicantAddresses, AddressType addressType) { return applicantAddresses - .Where(address => address.AddressType == addressType) - .OrderByDescending(address => - address.CreationTime < address.LastModificationTime.GetValueOrDefault(DateTime.MinValue) - ? address.CreationTime - : address.LastModificationTime.GetValueOrDefault(DateTime.MinValue)) - .FirstOrDefault(); + .Where(address => address.AddressType == addressType) + .OrderByDescending(address => + address.LastModificationTime.GetValueOrDefault(address.CreationTime)) + .FirstOrDefault(); } private async Task PopulateElectoralDistrictsAsync(ApplicantInfoViewModel model) From 6898919d23fdf1647cd151bf71d75d1c1b283c57 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Wed, 6 Aug 2025 09:45:45 -0700 Subject: [PATCH 3/6] AB#29664 code QL suggestions # Conflicts: # applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs --- .../DetermineElectoralDistrictHandler.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs index 118fa2ad3..487a6bac1 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/DetermineElectoralDistrictHandler.cs @@ -14,7 +14,7 @@ public class DetermineElectoralDistrictHandler(IGeocoderApiService geocoderApiSe : ILocalEventHandler, ITransientDependency { /// - /// Determines the Electoral Distrct based on the Address. + /// Determines the Electoral District based on the Address. /// /// /// @@ -30,31 +30,39 @@ public async Task HandleEventAsync(ApplicationProcessEvent eventData) if (eventData.FormVersion == null) { - logger.LogWarning("Application data is null in DetermineElectoralDistrictHandler."); + logger.LogWarning("Form version data is null in DetermineElectoralDistrictHandler."); return; } // Check if the electoral district is already mapped for the form submission, if so then no work to be done if (eventData.FormVersion.HasSubmissionHeaderMapping("ApplicantElectoralDistrict")) + { + logger.LogInformation("Electoral district already determined for application {ApplicationId}. No further action required.", + eventData.Application.Id); return; + } + + // Use local variable to avoid modifying the entity property + var addressType = eventData.Application.ApplicationForm.ElectoralDistrictAddressType ?? GrantApplications.AddressType.PhysicalAddress; + logger.LogInformation("Using electoral district address type: {AddressType} for electoral determination", addressType); - var electoralDistrictAddressType = eventData.Application.ApplicationForm.ElectoralDistrictAddressType; var applicantAddresses = eventData.Application.Applicant.ApplicantAddresses; if (applicantAddresses == null || applicantAddresses.Count == 0) { - logger.LogWarning("Application data is null in DetermineElectoralDistrictHandler."); + logger.LogWarning("Applicant addresses are null or empty in DetermineElectoralDistrictHandler for application {ApplicationId}.", + eventData.Application.Id); return; } // Find the related address type var matchedAddressType = applicantAddresses - .FirstOrDefault(a => a.AddressType == electoralDistrictAddressType); + .FirstOrDefault(a => a.AddressType == addressType); if (matchedAddressType == null) { logger.LogWarning("No address of type {AddressType} found for application {ApplicationId}.", - electoralDistrictAddressType, eventData.Application.Id); + addressType, eventData.Application.Id); return; } From fa08b6b19ec0fb6d0299e4c0459724dd84396d92 Mon Sep 17 00:00:00 2001 From: jpasta Date: Wed, 6 Aug 2025 13:32:44 -0700 Subject: [PATCH 4/6] hotfix/AB#29603-AddressIssue-RevertToWorkingAddress --- .../ApplicantInfo/ApplicantInfoViewComponent.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs index 705fb1bad..585dfde18 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs @@ -76,10 +76,12 @@ public async Task InvokeAsync(Guid applicationId, Guid app private static ApplicantAddressDto? FindMostRecentAddress(List applicantAddresses, AddressType addressType) { return applicantAddresses - .Where(address => address.AddressType == addressType) - .OrderByDescending(address => - address.LastModificationTime.GetValueOrDefault(address.CreationTime)) - .FirstOrDefault(); + .Where(address => address.AddressType == addressType) + .OrderByDescending(address => + address.CreationTime < address.LastModificationTime.GetValueOrDefault(DateTime.MinValue) + ? address.CreationTime + : address.LastModificationTime.GetValueOrDefault(DateTime.MinValue)) + .FirstOrDefault(); } private async Task PopulateElectoralDistrictsAsync(ApplicantInfoViewModel model) From 2ba3cdcabb34e38063f6a2bb4f7c94a6fb9c3d5f Mon Sep 17 00:00:00 2001 From: jpasta Date: Wed, 6 Aug 2025 14:28:23 -0700 Subject: [PATCH 5/6] hotfix/AB#29603-AddressIssue-RevertToWorkingAddress --- .../ApplicantInfo/ApplicantInfoViewComponent.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs index 585dfde18..705fb1bad 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs @@ -76,12 +76,10 @@ public async Task InvokeAsync(Guid applicationId, Guid app private static ApplicantAddressDto? FindMostRecentAddress(List applicantAddresses, AddressType addressType) { return applicantAddresses - .Where(address => address.AddressType == addressType) - .OrderByDescending(address => - address.CreationTime < address.LastModificationTime.GetValueOrDefault(DateTime.MinValue) - ? address.CreationTime - : address.LastModificationTime.GetValueOrDefault(DateTime.MinValue)) - .FirstOrDefault(); + .Where(address => address.AddressType == addressType) + .OrderByDescending(address => + address.LastModificationTime.GetValueOrDefault(address.CreationTime)) + .FirstOrDefault(); } private async Task PopulateElectoralDistrictsAsync(ApplicantInfoViewModel model) From 8164eb4c2cb3c4a8effacf5d3f6354a2c6b1f117 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Wed, 6 Aug 2025 15:56:56 -0700 Subject: [PATCH 6/6] AB#29664 fix the electoral district mapping --- .../GrantApplications/UpdateApplicantSummaryDto.cs | 3 +-- .../GrantApplications/ApplicationApplicantAppService.cs | 9 +++++++++ .../GrantManagerApplicationAutoMapperProfile.cs | 3 ++- .../ApplicantInfo/ApplicantInfoViewComponent.cs | 2 ++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs index cbe79cc0d..52350304e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs @@ -16,6 +16,5 @@ public class UpdateApplicantSummaryDto public bool? IndigenousOrgInd { get; set; } public string? UnityApplicantId { get; set; } public string? FiscalDay { get; set; } - public string? FiscalMonth { get; set; } - public string? ElectoralDistrict { get; set; } + public string? FiscalMonth { get; set; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs index 52c9bf819..61a4b6883 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs @@ -151,6 +151,7 @@ public async Task UpdatePartialApplicantInfoAsync(Guid appl } // Only update the fields we need to update based on the modified + // Automapper mapping ignores the ElectoralDistrict as this is different from the application level electoral district ObjectMapper.Map(input.Data, application); //-- APPLICANT INFO - SUMMARY @@ -190,6 +191,14 @@ public async Task UpdatePartialApplicantInfoAsync(Guid appl await CreateOrUpdateApplicantAddress(application.ApplicantId, input.Data.MailingAddress); } + //-- APPLICANT ELECTORAL DISTRICT + if (input.Data.ElectoralDistrict != null + && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Location.Update)) + { + // Update the electoral district at the applicant level + application.Applicant.ElectoralDistrict = input.Data.ElectoralDistrict; + } + //-- APPLICANT INFO CUSTOM FIELDS if (input.Data.CustomFields?.ValueKind != JsonValueKind.Null && input.Data.WorksheetId != Guid.Empty && input.Data.CorrelationId != Guid.Empty) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs index 436c2efba..d528cf51c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs @@ -103,7 +103,8 @@ public GrantManagerApplicationAutoMapperProfile() CreateMap() .IgnoreNullAndDefaultValues(); CreateMap() - .IgnoreNullAndDefaultValues(); + .IgnoreNullAndDefaultValues() + .ForMember(dest => dest.ElectoralDistrict, opt => opt.Ignore()); // Electoral district is handled separately CreateMap() .IgnoreNullAndDefaultValues(); CreateMap() diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs index 705fb1bad..544ca9480 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/ApplicantInfoViewComponent.cs @@ -45,6 +45,8 @@ public async Task InvokeAsync(Guid applicationId, Guid app ContactInfo = ObjectMapper.Map(applicantInfoDto.ContactInfo ?? new ContactInfoDto()), SigningAuthority = ObjectMapper.Map(applicantInfoDto.SigningAuthority ?? new SigningAuthorityDto()), ApplicantElectoralAddressType = electoralDistrictAddressType, + // This is fixed at the applicant level, we need solution this wrt the recent address logic added below + ElectoralDistrict = applicantInfoDto.ElectoralDistrict }; viewModel.ApplicantSummary.ApplicantId = applicantInfoDto.ApplicantId;