");
dt.columns().every(function () {
- let column = this;
- if (column.visible()) {
- let title = column.header().textContent;
- if (title && title !== 'Actions') {
-
- let filterValue = filterData[title] ? filterData[title] : '';
-
- let input = $("", {
- type: 'text',
- class: 'form-control input-sm custom-filter-input',
- placeholder: title,
- value: filterValue
- });
+ let column = this;
+ if (column.visible()) {
+ let title = column.header().textContent;
+ if (title && title !== 'Actions') {
+ let filterValue = filterData[title] ? filterData[title] : '';
+
+ let input = $('', {
+ type: 'text',
+ class: 'form-control input-sm custom-filter-input',
+ placeholder: title,
+ value: filterValue,
+ });
- let newCell = $("| ").append(input);
+ let newCell = $(' | ').append(input);
- if (column.search() !== filterValue) {
- column.search(filterValue).draw();
- }
+ if (column.search() !== filterValue) {
+ column.search(filterValue).draw();
+ }
- newCell.find("input").on("keyup", function () {
- if (column.search() !== this.value) {
- column.search(this.value).draw();
- updateFilterButton(dt);
- }
- });
+ newCell.find('input').on('keyup', function () {
+ if (column.search() !== this.value) {
+ column.search(this.value).draw();
+ updateFilterButton(dt);
+ }
+ });
- newRow.append(newCell);
- }
- else {
- let newCell = $(" | ");
- newRow.append(newCell);
- }
+ newRow.append(newCell);
+ } else {
+ let newCell = $(' | ');
+ newRow.append(newCell);
}
- });
+ }
+ });
updateFilterButton(dt);
$(`#${dtName} thead`).after(newRow);
if (optionsOpen) {
- $(".tr-toggle-filter").show();
+ $('.tr-toggle-filter').show();
}
}
@@ -530,7 +669,7 @@ function searchFilter(iDt) {
}
if ($('#btn-toggle-filter').text() === FilterDesc.With_Filter) {
- $(".tr-toggle-filter").show();
+ $('.tr-toggle-filter').show();
}
}
@@ -545,52 +684,52 @@ function updateFilterButton(dt) {
});
let hasFilter = columnFiltersApplied || searchValue !== '';
- $('#btn-toggle-filter').text(hasFilter ? FilterDesc.With_Filter : FilterDesc.Default);
+ $('#btn-toggle-filter').text(
+ hasFilter ? FilterDesc.With_Filter : FilterDesc.Default
+ );
}
$('.data-table-select-all').click(function () {
-
- if ($('.data-table-select-all').is(":checked")) {
- PubSub.publish('datatable_select_all',true);
+ if ($('.data-table-select-all').is(':checked')) {
+ PubSub.publish('datatable_select_all', true);
} else {
PubSub.publish('datatable_select_all', false);
}
-
});
function commonTableActionButtons(exportTitle) {
return [
{
text: 'Filter',
- id: "btn-toggle-filter",
+ id: 'btn-toggle-filter',
className: 'btn-secondary custom-table-btn m-0',
- action: function (e, dt, node, config) { },
+ action: function (e, dt, node, config) {},
attr: {
- id: 'btn-toggle-filter'
- }
+ id: 'btn-toggle-filter',
+ },
},
{
extend: 'csv',
text: 'Export',
title: exportTitle,
- className: 'custom-table-btn flex-none btn btn-secondary hidden-export-btn d-none',
+ className:
+ 'custom-table-btn flex-none btn btn-secondary hidden-export-btn d-none',
exportOptions: {
columns: ':visible:not(.notexport)',
orthogonal: 'fullName',
format: {
body: function (data, row, column, node) {
return data === nullPlaceholder ? '' : data;
- }
- }
- }
- }
+ },
+ },
+ },
+ },
];
}
// Toggle hidden export buttons for Ctrl+Alt+Shift+E globally
$(document).keydown(function (e) {
- if (e.ctrlKey && e.altKey &&
- e.shiftKey && e.key === 'E') {
+ if (e.ctrlKey && e.altKey && e.shiftKey && e.key === 'E') {
// Toggle d-none class on elements with hidden-export class
$('.hidden-export-btn').toggleClass('d-none');
diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/zone-extensions.js b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/zone-extensions.js
index 157690cd2..1003da21f 100644
--- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/zone-extensions.js
+++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/zone-extensions.js
@@ -3,6 +3,29 @@
return;
}
+ /**
+ * Unflatten dot separated JSON objects into nested objects
+ */
+ $.fn.unflattenObject = function(flatObj) {
+ const result = {};
+ for (const flatKey in flatObj) {
+ const value = flatObj[flatKey];
+ if (!flatKey) continue;
+ const keys = flatKey.split('.');
+ let cur = result;
+ for (let i = 0; i < keys.length; i++) {
+ const k = keys[i];
+ if (i === keys.length - 1) {
+ cur[k] = value;
+ } else {
+ cur[k] = cur[k] || {};
+ cur = cur[k];
+ }
+ }
+ }
+ return result;
+ }
+
/**
* @public
* Handles zone fieldset serialization with DTO nesting
@@ -16,7 +39,6 @@
// OPTIONS NOTE: Zones to include
// OPTIONS NOTE: Properties to include
-
// Initialize result object
const resultObject = {};
// Collection phase: Gather all field data in a single pass
@@ -41,8 +63,16 @@
data.push({ name: this.name, value: value });
});
- }
+ } else {
+ // Add only disabled fields marked with data-zone-include="true"
+ $form.find(':disabled[name][data-zone-include="true"]').each(function () {
+ const value = $(this).is(":checkbox") ?
+ $(this).is(':checked') :
+ $(this).val();
+ data.push({ name: this.name, value: value });
+ });
+ }
// Convert field names to camelCase if required
if (camelCase) {
@@ -137,7 +167,7 @@ class UnityChangeTrackingForm {
constructor($form, options = {}) {
this.options = {
- modifiedClass: 'unity-modified-field-marker',
+ modifiedClass: options.modifiedClass || 'unity-modified-field-marker',
saveButtonSelector: options.saveButtonSelector || '#saveButton',
...options
};
@@ -173,6 +203,9 @@ class UnityChangeTrackingForm {
if ($el.prop('checked')) {
this.originalValues[name] = $el.val();
}
+ } else if ($el.attr('data-zone-include') === 'true') {
+ // Store whether this field should be included even when disabled
+ this.originalValues[name] = $el.val();
} else {
this.originalValues[name] = $el.val();
}
@@ -202,12 +235,15 @@ class UnityChangeTrackingForm {
} else {
return; // Skip radio buttons that aren't checked
}
+ } else if ($element.attr('data-zone-include') === 'true') {
+ // Store whether this field should be included even when disabled
+ currentValue = $element.val();
} else {
currentValue = $element.val();
}
const originalValue = this.originalValues[name];
-
+
if (currentValue !== originalValue) {
this.markAsModified($element, name);
} else {
@@ -313,6 +349,14 @@ class UnityZoneForm extends UnityChangeTrackingForm {
this.addSubmitHandler();
}
+ // NOTE Get Zone Status
+ // NOTE Get field by name or id
+ // NOTE Get field value by name or id
+
+ isValid() {
+ return this.form.valid();
+ }
+
initializeNumericFields() {
$('.numeric-mask').maskMoney({ precision: 0 });
$('.percentage-mask').maskMoney();
@@ -334,10 +378,86 @@ class UnityZoneForm extends UnityChangeTrackingForm {
$('.unity-currency-input').maskMoney();
}
+ /**
+ * Extracts the last two segments from a string separated by underscores,
+ * and returns them joined by an underscore (e.g., "Unity_GrantManager_ApplicationManagement_Applicant_Summary" => "Applicant_Summary").
+ * If the input does not have at least two segments, returns the original string.
+ * @private
+ * @param {string} input
+ * @returns {string}
+ */
+ #extractZoneSuffix(input) {
+ if (typeof input !== 'string') return input;
+ const parts = input.split('_');
+ if (parts.length < 2) return input;
+ return parts.slice(-2).join('_');
+ }
+
addSubmitHandler() {
this.form.on('submit', (e) => {
e.preventDefault();
+ // Include submission handler callback
this.resetTracking();
});
}
+
+ reportZones(viewExpanded = false) {
+ let tableData = [];
+ const self = this; // Store reference to the class instance
+
+ this.form.find('fieldset').each(function () {
+ const fieldName = $(this).attr('name');
+
+ $(this).find(':input').each(function () {
+ const $el = $(this);
+ const name = this.name || '(no name)';
+
+ // Get current value based on input type
+ let currentValue;
+ if ($el.is(':checkbox')) {
+ currentValue = $el.prop('checked');
+ } else if ($el.is(':radio')) {
+ if ($el.prop('checked')) {
+ currentValue = $el.val();
+ } else {
+ currentValue = '(unchecked radio)';
+ }
+ } else {
+ currentValue = $el.val() || '(no value)';
+ }
+
+ // Get original value if it exists
+ const originalValue = name !== '(no name)' && self.originalValues.hasOwnProperty(name) ?
+ self.originalValues[name] : '(not tracked)';
+
+ const isModified = self.modifiedFields.has(name);
+
+ let tableOutput = {
+ 'fieldsetName': self.#extractZoneSuffix(fieldName),
+ 'id': this.id
+ }
+
+ if (viewExpanded) {
+ let expandedProperties = {
+ 'name': name,
+ 'tag': this.tagName.toLowerCase(),
+ 'type': this.type
+ };
+
+ tableOutput = { ...tableOutput, ...expandedProperties };
+ }
+
+ let changeProperties = {
+ 'originalValue': originalValue,
+ 'currentValue': currentValue,
+ 'modified': isModified
+ };
+ tableOutput = { ...tableOutput, ...changeProperties };
+
+ tableData.push(tableOutput);
+ });
+ });
+
+ console.table(tableData);
+ }
}
\ No newline at end of file
diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj
index ab63d28b7..3cbf5e2fa 100644
--- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj
+++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/test/Unity.Theme.UX2.Tests/Unity.AspNetCore.Mvc.UI.Theme.UX2.Tests.csproj
@@ -1,7 +1,7 @@
-
+
- net8.0
+ net9.0
enable
enable
@@ -10,16 +10,16 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Emails/CreateEmailDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Emails/CreateEmailDto.cs
index 61949c518..f6ddffba4 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Emails/CreateEmailDto.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Emails/CreateEmailDto.cs
@@ -15,7 +15,7 @@ public class CreateEmailDto
[MaxLength(1023)] // Max for CHES
public string EmailSubject { get; set; } = string.Empty;
- [MaxLength(40000)]
+
[Required]
public string EmailBody { get; set; } = string.Empty;
public Guid ApplicationId { get; set; }
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantAddressDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantAddressDto.cs
index 429f6689d..ff96dd506 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantAddressDto.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantAddressDto.cs
@@ -1,10 +1,11 @@
using System;
using Volo.Abp.Application.Dtos;
+using Volo.Abp.Auditing;
namespace Unity.GrantManager.GrantApplications;
[Serializable]
-public class ApplicantAddressDto : EntityDto
+public class ApplicantAddressDto : EntityDto, IHasCreationTime, IHasModificationTime
{
public Guid ApplicantId { get; set; }
public string Street { get; set; } = string.Empty;
@@ -13,6 +14,8 @@ public class ApplicantAddressDto : EntityDto
public string? City { get; set; }
public string? Province { get; set; }
public string? Postal { get; set; }
+ public AddressType AddressType { get; set; }
+
public DateTime CreationTime { get; set; }
- public AddressType AddressType { get; set; }
+ public DateTime? LastModificationTime { get; set; }
}
\ No newline at end of file
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantInfoDto.cs
new file mode 100644
index 000000000..1d861bcf2
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantInfoDto.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using Unity.Flex.Worksheets;
+
+namespace Unity.GrantManager.GrantApplications;
+
+public class ApplicantInfoDto : CustomDataFieldDto
+{
+ public Guid ApplicationId { get; set; }
+ public Guid ApplicantId { get; set; }
+ public Guid ApplicationFormId { get; set; }
+
+ public string ApplicationReferenceNo { get; set; } = string.Empty;
+ public string ApplicantName { get; set; } = string.Empty;
+ public GrantApplicationState ApplicationStatusCode { get; set; }
+ public string? ElectoralDistrict { get; set; }
+
+ public ApplicantSummaryDto? ApplicantSummary { get; set; }
+ public List? ApplicantAddresses { get; set; }
+ public SigningAuthorityDto? SigningAuthority { get; set; }
+ public ContactInfoDto? ContactInfo { get; set; }
+}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantSummaryDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantSummaryDto.cs
new file mode 100644
index 000000000..885df95bf
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicantSummaryDto.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Unity.GrantManager.GrantApplications;
+
+public class ApplicantSummaryDto
+{
+ public Guid ApplicantId { get; set; }
+ public string? ApplicantName { get; set; }
+ public string? Sector { get; set; }
+ public string? SubSector { get; set; }
+ public string? OrgNumber { get; set; }
+ public string? OrgName { get; set; }
+ public string? NonRegOrgName { get; set; }
+ public string? OrgStatus { get; set; }
+ public string? OrganizationType { get; set; }
+ public string? OrganizationSize { get; set; }
+ public string? SectorSubSectorIndustryDesc { get; set; }
+ public bool? RedStop { get; set; }
+ 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; }
+}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs
index fb0152841..4e29860b0 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ApplicationApplicantInfoDto.cs
@@ -1,28 +1,27 @@
using System;
using System.Collections.Generic;
-namespace Unity.GrantManager.GrantApplications
+namespace Unity.GrantManager.GrantApplications;
+
+[Serializable]
+public class ApplicationApplicantInfoDto : GrantApplicationApplicantDto
{
- [Serializable]
- public class ApplicationApplicantInfoDto : GrantApplicationApplicantDto
- {
- public Guid ApplicantId { get; set; }
- public string ContactFullName { get; set; } = string.Empty;
- public string ContactTitle { get; set; } = string.Empty;
- public string ContactEmail { get; set; } = string.Empty;
- public string ContactBusinessPhone { get; set; } = string.Empty;
- public string ContactCellPhone { get; set; } = string.Empty;
- public string OrganizationName { get; set; } = string.Empty;
- public string SigningAuthorityFullName { get; set; } = string.Empty;
- public string SigningAuthorityTitle { get; set; } = string.Empty;
- public string SigningAuthorityEmail { get; set; } = string.Empty;
- public string SigningAuthorityBusinessPhone { get; set; } = string.Empty;
- public string SigningAuthorityCellPhone { get; set; } = string.Empty;
- public string ApplicationReferenceNo { get; set; } = string.Empty;
- public string ApplicationStatus { get; set; } = string.Empty;
- public GrantApplicationState ApplicationStatusCode { get; set; }
- public List ApplicantAddresses { get; set; } = new List();
- public Guid ApplicationFormId { get; set; }
- public string NonRegOrgName { get; set; } = string.Empty;
- }
+ public Guid ApplicantId { get; set; }
+ public string ContactFullName { get; set; } = string.Empty;
+ public string ContactTitle { get; set; } = string.Empty;
+ public string ContactEmail { get; set; } = string.Empty;
+ public string ContactBusinessPhone { get; set; } = string.Empty;
+ public string ContactCellPhone { get; set; } = string.Empty;
+ public string OrganizationName { get; set; } = string.Empty;
+ public string SigningAuthorityFullName { get; set; } = string.Empty;
+ public string SigningAuthorityTitle { get; set; } = string.Empty;
+ public string SigningAuthorityEmail { get; set; } = string.Empty;
+ public string SigningAuthorityBusinessPhone { get; set; } = string.Empty;
+ public string SigningAuthorityCellPhone { get; set; } = string.Empty;
+ public string ApplicationReferenceNo { get; set; } = string.Empty;
+ public string ApplicationStatus { get; set; } = string.Empty;
+ public GrantApplicationState ApplicationStatusCode { get; set; }
+ public List ApplicantAddresses { get; set; } = [];
+ public Guid ApplicationFormId { get; set; }
+ public string NonRegOrgName { get; set; } = string.Empty;
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/BulkApprovalDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/BulkApprovalDto.cs
index 5e08208af..cd248c606 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/BulkApprovalDto.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/BulkApprovalDto.cs
@@ -25,5 +25,7 @@ public BulkApprovalDto()
public string ApplicantName { get; set; }
public string FormName { get; set; }
public string ApplicationStatus { get; set; }
+ public bool? IsDirectApproval { get; set; }
+ public decimal RecommendedAmount { get; set; }
}
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ContactInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ContactInfoDto.cs
new file mode 100644
index 000000000..f0a1c0209
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/ContactInfoDto.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Unity.GrantManager.GrantApplications;
+
+public class ContactInfoDto
+{
+ public Guid? ApplicantAgentId { get; set; }
+ public Guid? ApplicationId { get; set; }
+
+ public string? Name { get; set; }
+ public string? Title { get; set; }
+ public string? Email { get; set; }
+ public string? Phone { get; set; }
+ public string? Phone2 { get; set; }
+}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicantInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicantInfoDto.cs
index 1439aeab5..92c317d68 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicantInfoDto.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/CreateUpdateApplicantInfoDto.cs
@@ -1,10 +1,13 @@
using System;
+using System.Collections.Generic;
using Unity.Flex.Worksheets;
namespace Unity.GrantManager.GrantApplications
{
public class CreateUpdateApplicantInfoDto : CustomDataFieldDto
{
+ public Guid? ApplicationId { get; set; }
+ public Guid ApplicantId { get; set; }
public string? OrgName { get; set; }
public string? OrgNumber { get; set; }
public string? OrgStatus { get; set; }
@@ -43,9 +46,61 @@ public class CreateUpdateApplicantInfoDto : CustomDataFieldDto
public string? MailingAddressProvince { get; set; }
public string? MailingAddressPostalCode { get; set; }
- public Guid ApplicantId { get; set; }
public string? NonRegOrgName { get; set; }
public string? ElectoralDistrict { get; set; }
public string? ApplicantName { get; set; }
}
+
+ public class UpsertApplicantInfoDto : CustomDataFieldDto
+ {
+ public string ApplicationReferenceNo { get; set; } = string.Empty;
+ public string ApplicantName { get; set; } = string.Empty;
+ public GrantApplicationState ApplicationStatusCode { get; set; }
+
+ public ApplicantSummaryDto? ApplicantSummary { get; set; }
+ public List? ApplicantAddresses { get; set; }
+ public SigningAuthorityDto? SigningAuthority { get; set; }
+ public ContactInfoDto? ContactInfo { get; set; }
+
+ public string? OrgName { get; set; }
+ public string? OrgNumber { get; set; }
+ public string? OrgStatus { get; set; }
+ public string? OrganizationType { get; set; }
+ public string? OrganizationSize { get; set; }
+
+ public string? Sector { get; set; }
+ public string? SubSector { get; set; }
+ public string? SectorSubSectorIndustryDesc { get; set; } = string.Empty;
+ public bool? RedStop { get; set; }
+ public string? IndigenousOrgInd { get; set; }
+ public string? UnityApplicantId { get; set; }
+ public int? FiscalDay { get; set; }
+ public string? FiscalMonth { get; set; }
+ public string? ContactFullName { get; set; }
+ public string? ContactTitle { get; set; }
+ public string? ContactEmail { get; set; }
+ public string? ContactBusinessPhone { get; set; }
+ public string? ContactCellPhone { get; set; }
+ public string? SigningAuthorityFullName { get; set; }
+ public string? SigningAuthorityTitle { get; set; }
+ public string? SigningAuthorityEmail { get; set; }
+ public string? SigningAuthorityBusinessPhone { get; set; }
+ public string? SigningAuthorityCellPhone { get; set; }
+ public string? PhysicalAddressStreet { get; set; }
+ public string? PhysicalAddressStreet2 { get; set; }
+ public string? PhysicalAddressUnit { get; set; }
+ public string? PhysicalAddressCity { get; set; }
+ public string? PhysicalAddressProvince { get; set; }
+ public string? PhysicalAddressPostalCode { get; set; }
+
+ public string? MailingAddressStreet { get; set; }
+ public string? MailingAddressStreet2 { get; set; }
+ public string? MailingAddressUnit { get; set; }
+ public string? MailingAddressCity { get; set; }
+ public string? MailingAddressProvince { get; set; }
+ public string? MailingAddressPostalCode { get; set; }
+
+ public string? NonRegOrgName { get; set; }
+ public string? ElectoralDistrict { get; set; }
+ }
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IApplicationApplicantAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IApplicationApplicantAppService.cs
index aabd77357..e81eaf8af 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IApplicationApplicantAppService.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IApplicationApplicantAppService.cs
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
+using Unity.Modules.Shared;
using Volo.Abp.Application.Services;
namespace Unity.GrantManager.GrantApplications
@@ -7,5 +8,8 @@ namespace Unity.GrantManager.GrantApplications
public interface IApplicationApplicantAppService : IApplicationService
{
Task GetByApplicationIdAsync(Guid applicationId);
+ Task GetApplicantInfoTabAsync(Guid applicationId);
+ Task UpdatePartialApplicantInfoAsync(Guid applicationId, PartialUpdateDto input);
+ Task GetSupplierNameMatchesCheck(Guid applicantId, string? supplierName);
}
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/SigningAuthorityDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/SigningAuthorityDto.cs
new file mode 100644
index 000000000..56ce79819
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/SigningAuthorityDto.cs
@@ -0,0 +1,10 @@
+namespace Unity.GrantManager.GrantApplications;
+
+public class SigningAuthorityDto
+{
+ public string? SigningAuthorityFullName { get; set; }
+ public string? SigningAuthorityTitle { get; set; }
+ public string? SigningAuthorityEmail { get; set; }
+ public string? SigningAuthorityBusinessPhone { get; set; }
+ public string? SigningAuthorityCellPhone { get; set; }
+}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantAddressDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantAddressDto.cs
new file mode 100644
index 000000000..ad283d6fa
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantAddressDto.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Unity.GrantManager.GrantApplications;
+
+public class UpdateApplicantAddressDto
+{
+ public Guid ApplicantId { get; set; }
+ public AddressType AddressType { get; set; }
+
+ public string? Street { get; set; }
+ public string? Street2 { get; set; }
+ public string? Unit { get; set; }
+ public string? City { get; set; }
+ public string? Province { get; set; }
+ public string? PostalCode { get; set; }
+}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantInfoDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantInfoDto.cs
new file mode 100644
index 000000000..a4a626d1e
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantInfoDto.cs
@@ -0,0 +1,19 @@
+using System;
+using Unity.Flex.Worksheets;
+
+namespace Unity.GrantManager.GrantApplications;
+
+public class UpdateApplicantInfoDto : CustomDataFieldDto
+{
+ public Guid ApplicationId { get; set; }
+ public Guid ApplicantId { get; set; }
+ public Guid ApplicationFormId { get; set; }
+
+ public string? ElectoralDistrict { get; set; }
+
+ public UpdateApplicantSummaryDto? ApplicantSummary { get; set; }
+ public UpdateApplicantAddressDto? PhysicalAddress { get; set; }
+ public UpdateApplicantAddressDto? MailingAddress { get; set; }
+ public SigningAuthorityDto? SigningAuthority { get; set; }
+ public ContactInfoDto? ContactInfo { get; set; }
+}
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
new file mode 100644
index 000000000..cbe79cc0d
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/UpdateApplicantSummaryDto.cs
@@ -0,0 +1,21 @@
+namespace Unity.GrantManager.GrantApplications;
+
+public class UpdateApplicantSummaryDto
+{
+ public string? ApplicantName { get; set; }
+ public string? Sector { get; set; }
+ public string? SubSector { get; set; }
+ public string? OrgNumber { get; set; }
+ public string? OrgName { get; set; }
+ public string? NonRegOrgName { get; set; }
+ public string? OrgStatus { get; set; }
+ public string? OrganizationType { get; set; }
+ public string? OrganizationSize { get; set; }
+ public string? SectorSubSectorIndustryDesc { get; set; }
+ public bool? RedStop { get; set; }
+ 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; }
+}
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 3366a7a08..41852b750 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
@@ -3,7 +3,6 @@
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
using Volo.Abp.SettingManagement;
-using static Unity.Modules.Shared.UnitySelector.Review;
namespace Unity.GrantManager.Permissions.GrantApplications
{
@@ -70,12 +69,11 @@ public override void Define(IPermissionDefinitionContext context)
//-- REVIEW & ASSESSMENT PERMISSIONS
grantApplicationPermissionsGroup.AddApplication_ReviewAndAssessment_Permissions();
- // Applicant Info
- var applicantInfoPermissions = grantApplicationPermissionsGroup.AddPermission(GrantApplicationPermissions.ApplicantInfo.Default, L($"Permission:{GrantApplicationPermissions.ApplicantInfo.Default}"));
- applicantInfoPermissions.AddChild(GrantApplicationPermissions.ApplicantInfo.Update, L($"Permission:{GrantApplicationPermissions.ApplicantInfo.Update}"));
+ //-- APPLICANT INFO PERMISSIONS
+ grantApplicationPermissionsGroup.AddApplication_ApplicantInfo_Permissions();
// Project Info
- grantApplicationPermissionsGroup.AddApplication_ProjectInfo_Permissions();
+ grantApplicationPermissionsGroup.AddApplication_ProjectInfo_Permissions();
var settingManagement = context.GetGroup(SettingManagementPermissions.GroupName);
settingManagement.AddPermission(UnitySettingManagementPermissions.UserInterface, L("Permission:UnitySettingManagementPermissions.UserInterface"));
@@ -129,8 +127,8 @@ public static void AddApplication_ReviewAndAssessment_Permissions(this Permissio
var upx_Review_AssessmentResults_UpdateFinalStateFields = upx_Review_AssessmentResults_Update.AddUnityChild(UnitySelector.Review.AssessmentResults.Update.UpdateFinalStateFields);
var upx_Review_AssessmentReviewList = upx_Review.AddUnityChild(UnitySelector.Review.AssessmentReviewList.Default);
- var upx_Review_AssessmentReviewList_Create = upx_Review_AssessmentReviewList.AddUnityChild(UnitySelector.Review.AssessmentReviewList.Create);
-
+ var upx_Review_AssessmentReviewList_Create = upx_Review_AssessmentReviewList.AddUnityChild(UnitySelector.Review.AssessmentReviewList.Create);
+
var upx_Review_AssessmentReviewList_SendBack = upx_Review_AssessmentReviewList.AddUnityChild(UnitySelector.Review.AssessmentReviewList.Update.SendBack);
var upx_Review_AssessmentReviewList_Complete = upx_Review_AssessmentReviewList.AddUnityChild(UnitySelector.Review.AssessmentReviewList.Update.Complete);
#endregion
@@ -139,15 +137,38 @@ public static void AddApplication_ReviewAndAssessment_Permissions(this Permissio
public static void AddApplication_ProjectInfo_Permissions(this PermissionGroupDefinition grantApplicationPermissionsGroup)
{
#region PROJECT INFO GRANULAR PERMISSIONS
- var upx_Project = grantApplicationPermissionsGroup.AddPermission(UnitySelector.Project.Default, L(UnitySelector.Project.Default));
+ var upx_Project = grantApplicationPermissionsGroup.AddPermission(UnitySelector.Project.Default, L(UnitySelector.Project.Default));
- var upx_Project_Summary = upx_Project.AddUnityChild(UnitySelector.Project.Summary.Default);
- var upx_Project_Summary_Update = upx_Project_Summary.AddUnityChild(UnitySelector.Project.Summary.Update.Default);
- var upx_Project_Summary_UpdateFinalStateFields = upx_Project_Summary_Update.AddUnityChild(UnitySelector.Project.Summary.Update.UpdateFinalStateFields);
+ var upx_Project_Summary = upx_Project.AddUnityChild(UnitySelector.Project.Summary.Default);
+ var upx_Project_Summary_Update = upx_Project_Summary.AddUnityChild(UnitySelector.Project.Summary.Update.Default);
+ var upx_Project_Summary_UpdateFinalStateFields = upx_Project_Summary_Update.AddUnityChild(UnitySelector.Project.Summary.Update.UpdateFinalStateFields);
- var upx_Project_Location = upx_Project.AddUnityChild(UnitySelector.Project.Location.Default);
- var upx_Project_Location_Update = upx_Project_Location.AddUnityChild(UnitySelector.Project.Location.Update.Default);
- var upx_Project_Location_UpdateFinalStateFields = upx_Project_Location_Update.AddUnityChild(UnitySelector.Project.Location.Update.UpdateFinalStateFields);
+ var upx_Project_Location = upx_Project.AddUnityChild(UnitySelector.Project.Location.Default);
+ var upx_Project_Location_Update = upx_Project_Location.AddUnityChild(UnitySelector.Project.Location.Update.Default);
+ var upx_Project_Location_UpdateFinalStateFields = upx_Project_Location_Update.AddUnityChild(UnitySelector.Project.Location.Update.UpdateFinalStateFields);
+ #endregion
+ }
+
+ public static void AddApplication_ApplicantInfo_Permissions(this PermissionGroupDefinition grantApplicationPermissionsGroup)
+ {
+ #region APPLICANT INFO GRANULAR PERMISSIONS
+ var upx_Applicant = grantApplicationPermissionsGroup.AddPermission(UnitySelector.Applicant.Default, L(UnitySelector.Applicant.Default));
+
+ var upx_Applicant_Summary = upx_Applicant.AddUnityChild(UnitySelector.Applicant.Summary.Default);
+ var upx_Applicant_Summary_Update = upx_Applicant_Summary.AddUnityChild(UnitySelector.Applicant.Summary.Update);
+
+ var upx_Applicant_Contact = upx_Applicant.AddUnityChild(UnitySelector.Applicant.Contact.Default);
+ var upx_Applicant_Contact_Update = upx_Applicant_Contact.AddUnityChild(UnitySelector.Applicant.Contact.Update);
+
+ var upx_Applicant_Authority = upx_Applicant.AddUnityChild(UnitySelector.Applicant.Authority.Default);
+ var upx_Applicant_Authority_Update = upx_Applicant_Authority.AddUnityChild(UnitySelector.Applicant.Authority.Update);
+
+ var upx_Applicant_Location = upx_Applicant.AddUnityChild(UnitySelector.Applicant.Location.Default);
+ var upx_Applicant_Location_Update = upx_Applicant_Location.AddUnityChild(UnitySelector.Applicant.Location.Update);
+
+ var upx_Applicant_AdditionalContact = upx_Applicant.AddUnityChild(UnitySelector.Applicant.AdditionalContact.Default);
+ var upx_Applicant_AdditionalContact_Create = upx_Applicant_AdditionalContact.AddUnityChild(UnitySelector.Applicant.AdditionalContact.Create);
+ var upx_Applicant_AdditionalContact_Update = upx_Applicant_AdditionalContact.AddUnityChild(UnitySelector.Applicant.AdditionalContact.Update);
#endregion
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj
index 679591692..4f76fb8d6 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Unity.GrantManager.Application.Contracts.csproj
@@ -1,9 +1,9 @@
-
+
- net8.0
+ net9.0
enable
Unity.GrantManager
@@ -17,16 +17,16 @@
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
**/Assessments/AssessmentListItemDto.cs, **/Assessments/AssessmentScoresDto.cs
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormVersionAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormVersionAppService.cs
index 71db731c3..de58359ed 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormVersionAppService.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormVersionAppService.cs
@@ -270,28 +270,45 @@ private async Task UpdateApplicationFormVersionFields(ApplicationFormVersion app
public async Task GetFormVersionByApplicationIdAsync(Guid applicationId)
{
var formSubmission = await _formSubmissionRepository.GetByApplicationAsync(applicationId);
+
if (formSubmission.FormVersionId == null)
{
- try
- {
- var submissionJson = JObject.Parse(formSubmission.Submission);
- var tokenFormVersionId = submissionJson?.SelectToken("submission.formVersionId")?.ToString();
- if (tokenFormVersionId == null) return 0;
-
- var formVersionId = Guid.Parse(tokenFormVersionId);
- formSubmission.FormVersionId = formVersionId;
- await _formSubmissionRepository.UpdateAsync(formSubmission);
- return await GetVersion(formVersionId);
- }
- catch
- {
- return 0;
- }
+ return await HandleEmptyFormVersionIdAsync(formSubmission);
}
return await GetVersion(formSubmission.FormVersionId ?? Guid.Empty);
}
+ ///
+ /// Handles the case where the form version ID is empty or null in the form submission.
+ /// This method is for backward compatibility with legacy submissions that may not have the form version ID set.
+ /// This method should be reviewed later as it can be removed once all submissions have been migrated to include the form version ID.
+ ///
+ ///
+ ///
+ private async Task HandleEmptyFormVersionIdAsync(ApplicationFormSubmission formSubmission)
+ {
+ try
+ {
+ var submissionJson = JObject.Parse(formSubmission.Submission);
+ var legacyTokenFormVersionId = submissionJson?.SelectToken("submission.formVersionId")?.ToString();
+ var newTokenFormVersionId = submissionJson?.SelectToken("formVersionId")?.ToString();
+
+ var formVersionIdString = legacyTokenFormVersionId ?? newTokenFormVersionId;
+ if (formVersionIdString == null)
+ return 0;
+
+ var formVersionId = Guid.Parse(formVersionIdString);
+ formSubmission.FormVersionId = formVersionId;
+ await _formSubmissionRepository.UpdateAsync(formSubmission);
+ return await GetVersion(formVersionId);
+ }
+ catch
+ {
+ return 0;
+ }
+ }
+
public async Task DeleteWorkSheetMappingByFormName(string formName, Guid formVersionId)
{
var applicationFormVersion = await _formVersionRepository.GetAsync(formVersionId);
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 a80515735..52c9bf819 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/ApplicationApplicantAppService.cs
@@ -1,67 +1,353 @@
using Microsoft.AspNetCore.Authorization;
+using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json;
using System.Threading.Tasks;
+using Unity.Flex.WorksheetInstances;
+using Unity.Flex.Worksheets;
using Unity.GrantManager.Applications;
+using Unity.GrantManager.Flex;
+using Unity.Modules.Shared;
+using Unity.Modules.Shared.Correlation;
+using Unity.Modules.Shared.Utils;
+using Volo.Abp.Domain.Entities;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.EventBus.Local;
-namespace Unity.GrantManager.GrantApplications
-{
- [Authorize]
- public class ApplicationApplicantAppService : GrantManagerAppService, IApplicationApplicantAppService
+namespace Unity.GrantManager.GrantApplications;
+
+[Authorize]
+public class ApplicationApplicantAppService(
+ IApplicantRepository applicantRepository,
+ IApplicationRepository applicationRepository,
+ IApplicantAgentRepository applicantAgentRepository,
+ IApplicantAddressRepository applicantAddressRepository,
+ ILocalEventBus localEventBus) : GrantManagerAppService, IApplicationApplicantAppService
+{
+ [Authorize(UnitySelector.Applicant.Default)]
+ public async Task GetApplicantInfoTabAsync(Guid applicationId)
+ {
+ var application = await applicationRepository.WithBasicDetailsAsync(applicationId);
+ if (application == null || !await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Default))
+ {
+ return new ApplicantInfoDto();
+ }
+
+ var applicantInfoDto = ObjectMapper.Map(application);
+
+ applicantInfoDto.ApplicationId = application.Id;
+ applicantInfoDto.ApplicantId = application.ApplicantId;
+ applicantInfoDto.ApplicationFormId = application.ApplicationFormId;
+
+ applicantInfoDto.ApplicationReferenceNo = application.ReferenceNo;
+ applicantInfoDto.ApplicantName = application.Applicant?.ApplicantName ?? string.Empty;
+
+ applicantInfoDto.ApplicationStatusCode = application.ApplicationStatus.StatusCode;
+ applicantInfoDto.ElectoralDistrict = application.Applicant?.ElectoralDistrict ?? string.Empty;
+
+ //-- APPLICANT INFO SUMMARY
+ if (application.Applicant != null && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Summary.Default))
+ {
+ applicantInfoDto.ApplicantSummary = ObjectMapper.Map(application.Applicant);
+ applicantInfoDto.ApplicantSummary.FiscalDay = application.Applicant?.FiscalDay.ToString() ?? string.Empty;
+ }
+ else
+ {
+ applicantInfoDto.ApplicantSummary = new ApplicantSummaryDto();
+ }
+
+ //-- APPLICANT INFO CONTACT
+ if (application?.ApplicantAgent != null && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Contact.Default))
+ {
+ applicantInfoDto.ContactInfo = ObjectMapper.Map(application.ApplicantAgent);
+ }
+ else
+ {
+ applicantInfoDto.ContactInfo = new ContactInfoDto();
+ }
+
+ //-- SIGNING AUTHORITY
+ if (application != null && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Authority.Default))
+ {
+ applicantInfoDto.SigningAuthority = ObjectMapper.Map(application);
+ }
+ else
+ {
+ applicantInfoDto.SigningAuthority = new SigningAuthorityDto();
+ }
+
+ //-- APPLICANT INFO ADDRESS
+ if (await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Location.Default))
+ {
+ applicantInfoDto.ApplicantAddresses = ObjectMapper.Map, List>(application?.Applicant?.ApplicantAddresses?.ToList() ?? []);
+ }
+ else
+ {
+ applicantInfoDto.ApplicantAddresses = [];
+ }
+
+ return applicantInfoDto;
+ }
+
+ [Obsolete("Use GetApplicantInfoTabAsync instead.")]
+ [Authorize]
+ public async Task GetByApplicationIdAsync(Guid applicationId)
{
- private readonly IApplicationRepository _applicationRepository;
+ var applicantInfo = await applicationRepository.WithBasicDetailsAsync(applicationId);
+ if (applicantInfo == null) return new ApplicationApplicantInfoDto();
- public ApplicationApplicantAppService(IApplicationRepository applicationRepository)
+ return new ApplicationApplicantInfoDto()
{
- _applicationRepository = applicationRepository;
- }
+ ApplicantId = applicantInfo.Applicant.Id,
+ ApplicationFormId = applicantInfo.ApplicationFormId,
+ ApplicantName = applicantInfo.Applicant?.ApplicantName ?? string.Empty,
+ ApplicationReferenceNo = applicantInfo.ReferenceNo,
+ ApplicationStatus = applicantInfo.ApplicationStatus.InternalStatus,
+ ApplicationStatusCode = applicantInfo.ApplicationStatus.StatusCode,
- public async Task GetByApplicationIdAsync(Guid applicationId)
- {
- var applicantInfo = await _applicationRepository.WithBasicDetailsAsync(applicationId);
- if (applicantInfo == null) return new ApplicationApplicantInfoDto();
+ OrganizationName = applicantInfo.Applicant?.OrgName ?? string.Empty,
+ OrganizationSize = applicantInfo.Applicant?.OrganizationSize ?? string.Empty,
+ OrganizationType = applicantInfo.Applicant?.OrganizationType ?? string.Empty,
+ OrgNumber = applicantInfo.Applicant?.OrgNumber ?? string.Empty,
+ OrgStatus = applicantInfo.Applicant?.OrgStatus ?? string.Empty,
+ NonRegOrgName = applicantInfo.Applicant?.NonRegOrgName ?? string.Empty,
+
+ Sector = applicantInfo.Applicant?.Sector ?? string.Empty,
+ SectorSubSectorIndustryDesc = applicantInfo.Applicant?.SectorSubSectorIndustryDesc ?? string.Empty,
+ SubSector = applicantInfo.Applicant?.SubSector ?? string.Empty,
+ RedStop = applicantInfo.Applicant?.RedStop ?? false,
+ IndigenousOrgInd = applicantInfo.Applicant?.IndigenousOrgInd ?? string.Empty,
+ UnityApplicantId = applicantInfo.Applicant?.UnityApplicantId ?? string.Empty,
+ FiscalDay = applicantInfo.Applicant?.FiscalDay.ToString() ?? string.Empty,
+ FiscalMonth = applicantInfo.Applicant?.FiscalMonth ?? string.Empty,
- return new ApplicationApplicantInfoDto()
- {
- ApplicantId = applicantInfo.Applicant.Id,
- ApplicationFormId = applicantInfo.ApplicationFormId,
- ApplicantName = applicantInfo.Applicant?.ApplicantName ?? string.Empty,
- ApplicationReferenceNo = applicantInfo.ReferenceNo,
- ApplicationStatus = applicantInfo.ApplicationStatus.InternalStatus,
- ApplicationStatusCode = applicantInfo.ApplicationStatus.StatusCode,
+ SigningAuthorityBusinessPhone = applicantInfo.SigningAuthorityBusinessPhone ?? string.Empty,
+ SigningAuthorityCellPhone = applicantInfo.SigningAuthorityCellPhone ?? string.Empty,
+ SigningAuthorityEmail = applicantInfo.SigningAuthorityEmail ?? string.Empty,
+ SigningAuthorityFullName = applicantInfo.SigningAuthorityFullName ?? string.Empty,
+ SigningAuthorityTitle = applicantInfo.SigningAuthorityTitle ?? string.Empty,
- OrganizationName = applicantInfo.Applicant?.OrgName ?? string.Empty,
- OrganizationSize = applicantInfo.Applicant?.OrganizationSize ?? string.Empty,
- OrganizationType = applicantInfo.Applicant?.OrganizationType ?? string.Empty,
- OrgNumber = applicantInfo.Applicant?.OrgNumber ?? string.Empty,
- OrgStatus = applicantInfo.Applicant?.OrgStatus ?? string.Empty,
- NonRegOrgName = applicantInfo.Applicant?.NonRegOrgName ?? string.Empty,
+ ContactFullName = applicantInfo.ApplicantAgent?.Name ?? string.Empty,
+ ContactTitle = applicantInfo.ApplicantAgent?.Title ?? string.Empty,
+ ContactEmail = applicantInfo.ApplicantAgent?.Email ?? string.Empty,
+ ContactBusinessPhone = applicantInfo.ApplicantAgent?.Phone ?? string.Empty,
+ ContactCellPhone = applicantInfo.ApplicantAgent?.Phone2 ?? string.Empty,
- Sector = applicantInfo.Applicant?.Sector ?? string.Empty,
- SectorSubSectorIndustryDesc = applicantInfo.Applicant?.SectorSubSectorIndustryDesc ?? string.Empty,
- SubSector = applicantInfo.Applicant?.SubSector ?? string.Empty,
- RedStop = applicantInfo.Applicant?.RedStop ?? false,
- IndigenousOrgInd = applicantInfo.Applicant?.IndigenousOrgInd ?? string.Empty,
- UnityApplicantId = applicantInfo.Applicant?.UnityApplicantId ?? string.Empty,
- FiscalDay = applicantInfo.Applicant?.FiscalDay.ToString() ?? string.Empty,
- FiscalMonth = applicantInfo.Applicant?.FiscalMonth ?? string.Empty,
+ ApplicantAddresses = ObjectMapper.Map, List>(applicantInfo.Applicant?.ApplicantAddresses?.ToList() ?? []),
+ ElectoralDistrict = applicantInfo.Applicant?.ElectoralDistrict ?? string.Empty
+ };
+ }
- SigningAuthorityBusinessPhone = applicantInfo.SigningAuthorityBusinessPhone ?? string.Empty,
- SigningAuthorityCellPhone = applicantInfo.SigningAuthorityCellPhone ?? string.Empty,
- SigningAuthorityEmail = applicantInfo.SigningAuthorityEmail ?? string.Empty,
- SigningAuthorityFullName = applicantInfo.SigningAuthorityFullName ?? string.Empty,
- SigningAuthorityTitle = applicantInfo.SigningAuthorityTitle ?? string.Empty,
+ [Authorize(UnitySelector.Applicant.UpdatePolicy)]
+ public async Task UpdatePartialApplicantInfoAsync(Guid applicationId, PartialUpdateDto input)
+ {
+ var application = await applicationRepository.GetAsync(applicationId) ?? throw new EntityNotFoundException();
+
+ if (input == null || input.Data == null)
+ {
+ throw new ArgumentNullException(nameof(input), "Input data cannot be null.");
+ }
+
+ // Only update the fields we need to update based on the modified
+ ObjectMapper.Map(input.Data, application);
+
+ //-- APPLICANT INFO - SUMMARY
+ if (input.Data.ApplicantSummary != null
+ && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Summary.Update))
+ {
+ await InternalPartialUpdateApplicantSummaryInfoAsync(application.Applicant, input.Data.ApplicantSummary, input.ModifiedFields);
+ }
+
+ //-- APPLICANT INFO - CONTACT (APPLICANT AGENT)
+ if (input.Data.ContactInfo != null
+ && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Contact.Update))
+ {
+ await CreateOrUpdateContactInfoAsync(application.ApplicantId, input.Data.ContactInfo);
+ }
+
+ //-- APPLICANT INFO - SIGNING AUTHORITY (APPLICATION)
+ if (input.Data.SigningAuthority != null
+ && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Authority.Update))
+ {
+ // Move to applicaiton service
+ ObjectMapper.Map(input.Data.SigningAuthority, application);
+ }
+
+ //-- APPLICANT INFO - ADDRESS
+ if (input.Data.PhysicalAddress != null
+ && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Location.Update))
+ {
+ input.Data.PhysicalAddress.AddressType = AddressType.PhysicalAddress;
+ await CreateOrUpdateApplicantAddress(application.ApplicantId, input.Data.PhysicalAddress);
+ }
+
+ if (input.Data.MailingAddress != null
+ && await AuthorizationService.IsGrantedAsync(UnitySelector.Applicant.Location.Update))
+ {
+ input.Data.MailingAddress.AddressType = AddressType.MailingAddress;
+ await CreateOrUpdateApplicantAddress(application.ApplicantId, input.Data.MailingAddress);
+ }
+
+ //-- APPLICANT INFO CUSTOM FIELDS
+ if (input.Data.CustomFields?.ValueKind != JsonValueKind.Null && input.Data.WorksheetId != Guid.Empty && input.Data.CorrelationId != Guid.Empty)
+ {
+ await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ApplicantInfoUiAnchor, input.Data);
+ }
+
+ var updatedApplication = await applicationRepository.UpdateAsync(application);
+ return ObjectMapper.Map(updatedApplication);
+ }
+
+ ///
+ /// Updates the Applicant Summary information for the given applicant while ignoring null values unless explicitly specified in modifiedFields.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Authorize(UnitySelector.Applicant.Summary.Update)]
+ protected internal async Task PartialUpdateApplicantSummaryInfoAsync(Guid applicantId, UpdateApplicantSummaryDto applicantSummary, List? modifiedFields = default)
+ {
+ var applicant = await applicantRepository.GetAsync(applicantId) ?? throw new EntityNotFoundException();
+ return await InternalPartialUpdateApplicantSummaryInfoAsync(applicant, applicantSummary, modifiedFields);
+ }
+
+ ///
+ /// Updates the Applicant Summary information for the given applicant while ignoring null values unless explicitly specified in modifiedFields.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task InternalPartialUpdateApplicantSummaryInfoAsync(Applications.Applicant applicant, UpdateApplicantSummaryDto applicantSummary, List? modifiedFields = default)
+ {
+ ObjectMapper.Map(applicantSummary, applicant);
- ContactFullName = applicantInfo.ApplicantAgent?.Name ?? string.Empty,
- ContactTitle = applicantInfo.ApplicantAgent?.Title ?? string.Empty,
- ContactEmail = applicantInfo.ApplicantAgent?.Email ?? string.Empty,
- ContactBusinessPhone = applicantInfo.ApplicantAgent?.Phone ?? string.Empty,
- ContactCellPhone = applicantInfo.ApplicantAgent?.Phone2 ?? string.Empty,
+ var modifiedSummaryFields = modifiedFields?
+ .Where(f => f.StartsWith("ApplicantSummary.", StringComparison.Ordinal))
+ .Select(f => f["ApplicantSummary.".Length..]).ToList() ?? [];
- ApplicantAddresses = ObjectMapper.Map, List>(applicantInfo.Applicant?.ApplicantAddresses?.ToList() ?? []),
- ElectoralDistrict = applicantInfo.Applicant?.ElectoralDistrict ?? string.Empty
- };
+ if (modifiedSummaryFields != null && modifiedSummaryFields.Count > 0) // Ensure modifiedFields is not null
+ {
+ // Handle null values for changed fields
+ PropertyHelper.ApplyNullValuesFromDto(
+ applicantSummary,
+ applicant,
+ modifiedSummaryFields ?? []); // Provide a fallback for null
}
+
+ return await applicantRepository.UpdateAsync(applicant);
+ }
+
+ ///
+ /// Creates or updates the appicant agent (contact info) for the given applicant. Ignores null values unless explicitly specified in modifiedFields.
+ ///
+ ///
+ ///
+ ///
+ [Authorize(UnitySelector.Applicant.Contact.Update)]
+ protected internal async Task CreateOrUpdateContactInfoAsync(Guid applicantId, ContactInfoDto contactInfo)
+ {
+ var applicantAgent = await applicantAgentRepository.FirstOrDefaultAsync(a => a.ApplicantId == applicantId)
+ ?? new ApplicantAgent
+ {
+ ApplicantId = applicantId,
+ ApplicationId = contactInfo.ApplicationId,
+ };
+
+ ObjectMapper.Map(contactInfo, applicantAgent);
+
+ if (applicantAgent.Id == Guid.Empty)
+ {
+ return await applicantAgentRepository.InsertAsync(applicantAgent);
+ }
+ else
+ {
+ return await applicantAgentRepository.UpdateAsync(applicantAgent);
+ }
+ }
+
+ ///
+ /// Creates or updates the applicant addresses for the given applicant. Ignores null values unless explicitly specified in modifiedFields.
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Authorize(UnitySelector.Applicant.Location.Update)]
+ protected internal async Task CreateOrUpdateApplicantAddress(Guid applicantId, UpdateApplicantAddressDto updatedAddress)
+ {
+ var applicantAddresses = await applicantAddressRepository.FindByApplicantIdAsync(applicantId);
+
+ ApplicantAddress? dbAddress = applicantAddresses.FirstOrDefault(a => a.AddressType == updatedAddress.AddressType)
+ ?? new ApplicantAddress
+ {
+ ApplicantId = applicantId,
+ AddressType = updatedAddress.AddressType,
+ };
+
+ ObjectMapper.Map(updatedAddress, dbAddress);
+
+ if (dbAddress.Id == Guid.Empty)
+ {
+ await applicantAddressRepository.InsertAsync(dbAddress);
+ }
+ else
+ {
+ await applicantAddressRepository.UpdateAsync(dbAddress);
+ }
+ }
+
+ 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");
+ }
+ }
+ }
+
+ public async Task GetSupplierNameMatchesCheck(Guid applicantId, string? supplierName)
+ {
+ if (string.IsNullOrWhiteSpace(supplierName))
+ {
+ return true; // If supplierName is null or empty, there is nothing to warn about
+ }
+
+ var applicant = await applicantRepository.GetAsync(applicantId) ?? throw new EntityNotFoundException();
+
+ var normalizedSupplierName = supplierName?.Trim();
+ var organizationName = applicant.OrgName?.Trim();
+ var nonRegisteredOrganizationName = applicant.NonRegOrgName?.Trim();
+
+ // Match if either orgName or nonRegisteredOrgName matches supplierName
+ // - If both orgName and nonRegisteredOrgName are null or empty, return true
+ // - Otherwise, return true if supplierName matches either orgName or nonRegisteredOrgName (case-insensitive)
+ if (string.IsNullOrEmpty(organizationName) && string.IsNullOrEmpty(nonRegisteredOrganizationName))
+ {
+ return true;
+ }
+
+ return string.Equals(normalizedSupplierName, organizationName, StringComparison.OrdinalIgnoreCase)
+ || string.Equals(normalizedSupplierName, nonRegisteredOrganizationName, StringComparison.OrdinalIgnoreCase);
}
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/BulkApprovalsAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/BulkApprovalsAppService.cs
index 86dcece18..8153e606f 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/BulkApprovalsAppService.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/BulkApprovalsAppService.cs
@@ -42,9 +42,10 @@ public async Task BulkApproveApplications(List> ValidateBulkApplications(Application[]
foreach (var application in applications)
{
- List<(bool, string)> validationMessages = await RunValidations(application);
-
- applicationsForApproval.Add(new BulkApprovalDto()
- {
- ApplicationId = application.Id,
- ApprovedAmount = application.ApprovedAmount,
- RequestedAmount = application.RequestedAmount,
- FinalDecisionDate = application.FinalDecisionDate,
- ReferenceNo = application.ReferenceNo,
- ValidationMessages = validationMessages.Select(s => s.Item2).ToList(),
- ApplicantName = application.Applicant.ApplicantName ?? string.Empty,
- ApplicationStatus = application.ApplicationStatus.InternalStatus,
- FormName = application.ApplicationForm?.ApplicationFormName ?? string.Empty,
- IsValid = !validationMessages.Exists(s => s.Item1)
- });
+ applicationsForApproval
+ .Add(MapBulkApproval(application, await RunValidations(application)));
}
return applicationsForApproval;
}
+
+ ///
+ /// Map the application to a BulkApprovalDto with validation messages
+ ///
+ ///
+ ///
+ ///
+ private static BulkApprovalDto MapBulkApproval(Application application, List<(bool, string)> validationMessages)
+ {
+ return new BulkApprovalDto()
+ {
+ ApplicationId = application.Id,
+ ApprovedAmount = application.ApprovedAmount,
+ RequestedAmount = application.RequestedAmount,
+ FinalDecisionDate = application.FinalDecisionDate,
+ ReferenceNo = application.ReferenceNo,
+ ValidationMessages = validationMessages.Select(s => s.Item2).ToList(),
+ ApplicantName = application.Applicant.ApplicantName ?? string.Empty,
+ ApplicationStatus = application.ApplicationStatus.InternalStatus,
+ FormName = application.ApplicationForm?.ApplicationFormName ?? string.Empty,
+ IsValid = !validationMessages.Exists(s => s.Item1),
+ IsDirectApproval = application.ApplicationForm?.IsDirectApproval,
+ RecommendedAmount = application.RecommendedAmount
+ };
+ }
+
///
/// Run the validations for the application
///
@@ -139,6 +153,29 @@ private async Task> ValidateBulkApplications(Application[]
if (!authorized)
validationMessages.Add(new(true, "INVALID_PERMISSIONS"));
+ // If this application belongs to a direct approval form, we default to RequestedAmount if the ApprovedAmount is 0.00
+ if (application.ApplicationForm?.IsDirectApproval == true)
+ {
+ application.ApprovedAmount = application.ApprovedAmount == 0m ? application.RequestedAmount : application.ApprovedAmount;
+ }
+ else
+ {
+ // If this application does not belong to a direct approval form, ensure that RecommendedAmount is not 0.00.
+ if (application.RecommendedAmount == 0m)
+ {
+ validationMessages.Add(new(false, "INVALID_RECOMMENDED_AMOUNT"));
+ }
+
+ // If ApprovedAmount is 0.00, we default it to RecommendedAmount
+ application.ApprovedAmount = application.ApprovedAmount == 0m ? application.RecommendedAmount : application.ApprovedAmount;
+ }
+
+ // If approved amount is still 0.00 after default sets then it is an error
+ if (application.ApprovedAmount == 0m)
+ {
+ validationMessages.Add(new(false, "INVALID_APPROVED_AMOUNT"));
+ }
+
return validationMessages;
}
@@ -154,8 +191,15 @@ private static bool MeetsWorkflowRequirement(Application application, GrantAppli
{
return false;
}
- if(application.ApplicationForm.IsDirectApproval)
+
+ // Specific ruleset for the Is Direct Approval flow
+ if (application.ApplicationForm.IsDirectApproval)
{
+ if (application.ApplicationStatus.StatusCode == GrantApplicationState.GRANT_APPROVED)
+ {
+ return false;
+ }
+
return true;
}
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..e7388a434 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs
@@ -310,7 +310,7 @@ public async Task UpdateAssessmentResultsAsync(Guid id, Cre
await SanitizeApprovalZoneInputs(input, application);
await SanitizeAssessmentResultsZoneInputs(input, application);
- application.ValidateAndChangeDueDate(input.DueDate);
+ application.ValidateAndSetDueDate(input.DueDate);
application.UpdateAlwaysChangeableFields(input.Notes, input.SubStatus, input.LikelihoodOfFunding, input.TotalProjectBudget, input.NotificationDate, input.RiskRanking);
if (application.IsInFinalDecisionState())
@@ -329,7 +329,7 @@ public async Task UpdateAssessmentResultsAsync(Guid id, Cre
{
if (await CurrentUserCanUpdateAssessmentFieldsAsync())
{
- application.ValidateAndChangeFinalDecisionDate(input.FinalDecisionDate);
+ application.ValidateAndSetFinalDecisionDate(input.FinalDecisionDate);
application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount);
application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore);
application.UpdateFieldsOnlyForPreFinalDecision(input.DueDiligenceStatus,
@@ -558,7 +558,38 @@ public async Task UpdateSupplierNumberAsync(Guid applicationId, string supplierN
}
}
- [Authorize(GrantApplicationPermissions.ApplicantInfo.Update)]
+ protected internal async Task CreateOrUpdateApplicantAgentAsync(Application application, ContactInfoDto? input)
+ {
+ if (input == null
+ || !await AuthorizationService.IsGrantedAnyAsync(UnitySelector.Applicant.Contact.Create, UnitySelector.Applicant.Contact.Update))
+ {
+ return null;
+ }
+
+ var applicantAgent = await _applicantAgentRepository
+ .FirstOrDefaultAsync(a => a.ApplicantId == application.ApplicantId)
+ ?? new ApplicantAgent
+ {
+ ApplicantId = application.ApplicantId,
+ ApplicationId = application.Id
+ };
+
+ applicantAgent.Name = input?.Name ?? string.Empty;
+ applicantAgent.Phone = input?.Phone ?? string.Empty;
+ applicantAgent.Phone2 = input?.Phone2 ?? string.Empty;
+ applicantAgent.Email = input?.Email ?? string.Empty;
+ applicantAgent.Title = input?.Title ?? string.Empty;
+
+ if (applicantAgent.Id == Guid.Empty)
+ {
+ return await _applicantAgentRepository.InsertAsync(applicantAgent);
+ }
+
+ 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);
@@ -1041,5 +1072,5 @@ public async Task> GetAllApplicationsAsync()
};
return await query.ToListAsync();
- }
+ }
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs
index f49ad72c2..c97bfde6d 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs
@@ -49,6 +49,7 @@ public GrantManagerApplicationAutoMapperProfile()
CreateMap();
CreateMap();
CreateMap();
+ CreateMap();
CreateMap();
CreateMap();
CreateMap();
@@ -78,17 +79,74 @@ public GrantManagerApplicationAutoMapperProfile()
CreateMap();
+ //-- PROJECT INFO
CreateMap()
- .ForAllMembers(opts =>
- {
- opts.AllowNull(); // Ignore Null Values for Lists and Collections
- opts.Condition((src, dest, srcMember) // Ignore Null and Default Values for Properties
- => srcMember != null
- && !IsDefault(srcMember));
- });
+ .IgnoreNullAndDefaultValues();
+
+ //-- APPLICANT INFO - OUTBOUND MAPS
+ CreateMap();
+ CreateMap();
+ CreateMap()
+ .ForMember(dest => dest.IndigenousOrgInd,
+ opt => opt.MapFrom(src =>
+ src.IndigenousOrgInd == "Yes" ? true :
+ src.IndigenousOrgInd == "No" ? false : (bool?)null));
+ CreateMap();
+ CreateMap();
+
+ //-- APPLICANT INFO - INBOUND MAPS
+ CreateMap()
+ .IgnoreNullAndDefaultValues();
+ CreateMap()
+ .IgnoreNullAndDefaultValues();
+ CreateMap()
+ .IgnoreNullAndDefaultValues();
+ CreateMap()
+ .ForMember(dest => dest.IndigenousOrgInd,
+ opt => opt.MapFrom(src =>
+ src.IndigenousOrgInd == true ? "Yes" :
+ src.IndigenousOrgInd == false ? "No" : null))
+ .IgnoreNullAndDefaultValues();
+ CreateMap()
+ .IgnoreNullAndDefaultValues();
+ CreateMap()
+ .ForMember(dest => dest.Postal, opt => opt.MapFrom(src => src.PostalCode))
+ .IgnoreNullAndDefaultValues();
+ }
+}
+
+// Extension methods for reusable mapping configurations
+public static class MappingExtensions
+{
+ ///
+ /// Configures the mapping to ignore null and default values for all members.
+ /// Useful for patch/update scenarios where only non-default values should be mapped.
+ ///
+ /// The source type.
+ /// The destination type.
+ /// The mapping expression.
+ /// The updated mapping expression.
+ public static IMappingExpression IgnoreNullAndDefaultValues(
+ this IMappingExpression expression)
+ {
+ expression.ForAllMembers(opts =>
+ {
+ opts.AllowNull(); // Ignore Null Values for Lists and Collections
+ opts.Condition((src, dest, srcMember) =>
+ srcMember != null && !IsValueDefault(srcMember)); // Ignore Null and Default Values for Properties
+ });
+
+ return expression;
}
- private static bool IsDefault(object value)
+ ///
+ /// Determines whether the provided value is the default value for its type.
+ ///
+ /// The value to check.
+ ///
+ /// true if the value is null or the default for its type; otherwise, false.
+ ///
+ public static bool IsValueDefault(object value)
{
if (value == null)
return true;
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/GenerateReportDataHandler.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/GenerateReportDataHandler.cs
index 19082af34..189441218 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/GenerateReportDataHandler.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/Handlers/GenerateReportDataHandler.cs
@@ -41,7 +41,7 @@ public async Task HandleEventAsync(ApplicationProcessEvent eventData)
eventData.ApplicationFormSubmission.ReportData = reportingDataGenerator
.Generate(eventData.RawSubmission,
eventData.FormVersion?.ReportKeys,
- eventData.ApplicationFormSubmission.Id);
+ eventData.ApplicationFormSubmission.Id) ?? "{}";
}
}
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/IntakeFormSubmissionManager.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/IntakeFormSubmissionManager.cs
index 3b02dad6a..09f2e6d06 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/IntakeFormSubmissionManager.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/IntakeFormSubmissionManager.cs
@@ -67,18 +67,20 @@ public async Task ProcessFormSubmissionAsync(ApplicationForm applicationFo
ApplicationFormId = applicationForm.Id,
ChefsSubmissionGuid = intakeMap.SubmissionId ?? $"{Guid.Empty}",
ApplicationId = application.Id,
- Submission = dataNode?.ToString() ?? string.Empty
+ Submission = dataNode?.ToString() ?? string.Empty
};
_ = await _applicationFormSubmissionRepository.InsertAsync(newSubmission);
ApplicationFormVersion? localFormVersion = await _applicationFormVersionRepository.GetByChefsFormVersionAsync(Guid.Parse(formVersionId));
+
await _customFieldsIntakeSubmissionMapper.MapAndPersistCustomFields(application.Id,
localFormVersion?.Id ?? Guid.Empty,
formSubmission,
formVersionSubmissionHeaderMapping);
newSubmission.ApplicationFormVersionId = localFormVersion?.Id;
+ newSubmission.FormVersionId = string.IsNullOrWhiteSpace(localFormVersion?.ChefsFormVersionGuid) ? null : Guid.Parse(localFormVersion.ChefsFormVersionGuid);
// Extend any further processing of the application here through local event bus and handlers
await localEventBus.PublishAsync(new ApplicationProcessEvent
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/SubmissionAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/SubmissionAppService.cs
index aa77546fd..6e99e114c 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/SubmissionAppService.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Intakes/SubmissionAppService.cs
@@ -142,9 +142,17 @@ join applicationForm in await applicationFormRepository.GetQueryableAsync() on a
public async Task> GetSubmissionsList(bool allSubmissions)
{
- List chefsSubmissions = new List();
+ var chefsSubmissions = new List();
+ var serializerOptions = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ ReadCommentHandling = JsonCommentHandling.Skip,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
+ };
var tenants = await tenantRepository.GetListAsync();
+ var unityRefNos = new HashSet();
+ var checkedForms = new HashSet();
foreach (var tenant in tenants)
{
using (CurrentTenant.Change(tenant.Id))
@@ -153,76 +161,63 @@ public async Task> GetSubmissionsList(b
var appDtos = new List();
var rowCounter = 0;
- List checkedForms = new List();
-
foreach (var grouping in groupedResult)
{
var appDto = ObjectMapper.Map(grouping.First());
- appDto.RowCount = rowCounter;
+ appDto.RowCount = rowCounter++;
appDtos.Add(appDto);
- rowCounter++;
// Chef's API call to get submissions
- if (!checkedForms.Contains(appDto.ApplicationForm.ChefsApplicationFormGuid ?? string.Empty))
- {
+ var formGuid = appDto.ApplicationForm.ChefsApplicationFormGuid ?? string.Empty;
+ if (!checkedForms.Add(formGuid)) continue; // already queried this form
- var id = appDto.ApplicationForm.ChefsApplicationFormGuid;
- var apiKey = stringEncryptionService.Decrypt(appDto.ApplicationForm.ApiKey! ?? string.Empty);
- var request = new RestRequest($"/forms/{id}/submissions", Method.Get)
- .AddParameter("fields", "applicantAgent.name");
- request.Authenticator = new HttpBasicAuthenticator(id ?? "ID", apiKey ?? "no api key given");
- RestResponse? response = null;
- try
- {
- response = await restClient.GetAsync(request);
- var submissionOptions = new JsonSerializerOptions
- {
- WriteIndented = true,
- PropertyNameCaseInsensitive = true,
- ReadCommentHandling = JsonCommentHandling.Skip,
- DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
- };
-
- var submissions = JsonSerializer.Deserialize>(response.Content ?? string.Empty, submissionOptions);
- if (submissions != null)
- {
- foreach (var submission in submissions)
- {
- submission.tenant = tenant.Name;
- submission.form = appDto.ApplicationForm.ApplicationFormName ?? string.Empty;
- submission.category = appDto.ApplicationForm.Category ?? string.Empty;
- }
- chefsSubmissions.AddRange(submissions);
- }
- }
- catch (Exception ex)
+ var apiKey = stringEncryptionService.Decrypt(appDto.ApplicationForm.ApiKey!);
+ var request = new RestRequest($"/forms/{formGuid}/submissions", Method.Get)
+ .AddParameter("fields", "applicantAgent.name");
+ request.Authenticator = new HttpBasicAuthenticator(formGuid, apiKey ?? string.Empty);
+
+ try
+ {
+ var response = await restClient.GetAsync(request);
+ var submissions = JsonSerializer.Deserialize>(
+ response.Content ?? "[]",
+ serializerOptions) ?? [];
+
+ foreach (var s in submissions)
{
- var ExceptionMessage = ex.Message;
- logger.LogError(ex, "GetSubmissionsList Exception: {ExceptionMessage}", ExceptionMessage);
+ s.tenant = tenant.Name;
+ s.form = appDto.ApplicationForm.ApplicationFormName ?? string.Empty;
+ s.category = appDto.ApplicationForm.Category ?? string.Empty;
}
- checkedForms.Add(id ?? string.Empty);
+ chefsSubmissions.AddRange(submissions);
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "GetSubmissionsList Exception: {Message}", ex.Message);
}
}
- // Set inUnity property for each submission based on whether it exists in appDtos
- foreach (var submission in chefsSubmissions)
- {
- submission.inUnity = appDtos.Any(appDto => submission.ConfirmationId.ToString() == appDto.ReferenceNo);
- }
-
-
- // Remove chef's submissions if Unity has an application with the same reference number
- if (!allSubmissions)
- {
- chefsSubmissions.RemoveAll(r => appDtos.Any(appDto => r.ConfirmationId.ToString() == appDto.ReferenceNo));
- }
+ unityRefNos.UnionWith(appDtos
+ .Select(a => a.ReferenceNo)
+ .Where(r => !string.IsNullOrWhiteSpace(r))
+ .ToHashSet(StringComparer.OrdinalIgnoreCase));
}
}
- // Remove all deleted submissions
- chefsSubmissions.RemoveAll(r => r.Deleted);
+ // Set inUnity flag
+ foreach (var submission in chefsSubmissions)
+ {
+ submission.inUnity = unityRefNos.Contains(submission.ConfirmationId.ToString());
+ }
+
+ // Remove duplicates unless caller asked for *all* submissions
+ if (!allSubmissions)
+ {
+ chefsSubmissions.RemoveAll(s => unityRefNos.Contains(s.ConfirmationId.ToString()));
+ }
+
return new PagedResultDto(chefsSubmissions.Count, chefsSubmissions);
}
}
\ No newline at end of file
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj
index 924c2244f..78d607b83 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Unity.GrantManager.Application.csproj
@@ -3,7 +3,7 @@
- net8.0
+ net9.0
enable
Unity.GrantManager
@@ -25,23 +25,23 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile
index 35ab54ff7..a8bc24a33 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Dockerfile
@@ -1,7 +1,7 @@
-FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
-FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["NuGet.Config", "."]
COPY ["src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj", "src/Unity.GrantManager.DbMigrator/"]
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj
index d4cfa81e8..d260179b5 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.DbMigrator/Unity.GrantManager.DbMigrator.csproj
@@ -1,10 +1,10 @@
-
+
Exe
- net8.0
+ net9.0
enable
@@ -18,24 +18,24 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
+
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AddressType.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AddressType.cs
index e140b5d28..cd1e957d9 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AddressType.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/GrantApplications/AddressType.cs
@@ -1,9 +1,11 @@
-namespace Unity.GrantManager.GrantApplications
+using System.Text.Json.Serialization;
+
+namespace Unity.GrantManager.GrantApplications;
+
+[JsonConverter(typeof(JsonStringEnumConverter))]
+public enum AddressType
{
- public enum AddressType
- {
- PhysicalAddress = 1,
- MailingAddress = 2,
- BusinessAddress = 3
- }
+ PhysicalAddress = 1,
+ MailingAddress = 2,
+ BusinessAddress = 3
}
\ No newline at end of file
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 66bd19064..415b3f886 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
@@ -205,6 +205,9 @@
"Unity.GrantManager.ApplicationManagement.Applicant.Authority.Update": "Edit Signing Authority",
"Unity.GrantManager.ApplicationManagement.Applicant.Location": "Address",
"Unity.GrantManager.ApplicationManagement.Applicant.Location.Update": "Edit Address",
+ "Unity.GrantManager.ApplicationManagement.Applicant.AdditionalContact": "Additional Contact(s)",
+ "Unity.GrantManager.ApplicationManagement.Applicant.AdditionalContact.Create": "Add Additional Contact(s)",
+ "Unity.GrantManager.ApplicationManagement.Applicant.AdditionalContact.Update": "Edit Additional Contact(s)",
"Unity.GrantManager.ApplicationManagement.Funding": "Funding",
"Unity.GrantManager.ApplicationManagement.Funding.Agreement": "Funding Agreement",
@@ -213,6 +216,8 @@
"Unity.GrantManager.ApplicationManagement.Payment": "Payment",
"Unity.GrantManager.ApplicationManagement.Payment.Summary": "Payment Summary",
"Unity.GrantManager.ApplicationManagement.Payment.Summary.Update": "Edit 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",
"Permission:GrantApplicationManagement.ProjectInfo": "Project Info",
@@ -363,9 +368,6 @@
"ProjectInfoView:ProjectInfo.ContactBusinessPhone": "Contact Business Phone",
"ProjectInfoView:ProjectInfo.ContactCellPhone": "Contact Cell Phone",
- "Permission:GrantApplicationManagement.ApplicantInfo": "Applicant Info",
- "Permission:GrantApplicationManagement.ApplicantInfo.Update": "Applicant Info Update",
-
"ApplicantInfoView:ApplicantInfoContactInfo": "Contact Info",
"ApplicantInfoView:SigningAuthorityTitle": "Signing Authority",
"ApplicantInfoView:PhysicalAddress": "Physical Address",
@@ -446,6 +448,7 @@
"ApplicationBatchApprovalRequest:InvalidStatus": "The assessment for the selected item is not in the Assessment Completed state",
"ApplicationBatchApprovalRequest:InvalidPermissions": "Invalid permissions",
"ApplicationBatchApprovalRequest:InvalidApprovedAmount": "Invalid Approved Amount, it must be greater than 0.00",
- "ApplicationBatchApprovalRequest:MaxCountExceeded": "You have exceeded the maximum number of items for bulk approval. Please reduce the number to {0} or fewer"
+ "ApplicationBatchApprovalRequest:MaxCountExceeded": "You have exceeded the maximum number of items for bulk approval. Please reduce the number to {0} or fewer",
+ "ApplicationBatchApprovalRequest:InvalidRecommendedAmount": "Invalid Recommended Amount, it must be greater than 0.00"
}
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj
index ace8f0ab8..a6dc6a7f5 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Unity.GrantManager.Domain.Shared.csproj
@@ -1,27 +1,27 @@
-
+
- net8.0
+ net9.0
enable
Unity.GrantManager
true
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -34,7 +34,7 @@
-
+
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs
index ac0da0ec4..c83cf9326 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/Application.cs
@@ -181,7 +181,12 @@ public void UpdateFieldsOnlyForPreFinalDecision(string? dueDiligenceStatus, deci
DeclineRational = declineRational;
}
- public void ValidateAndChangeDueDate(DateTime? dueDate)
+ ///
+ /// Validates and sets the DueDate property.
+ ///
+ ///
+ ///
+ public void ValidateAndSetDueDate(DateTime? dueDate)
{
if ((DueDate != dueDate) && dueDate != null && dueDate.Value < DateTime.Now.AddDays(-1))
{
@@ -193,7 +198,12 @@ public void ValidateAndChangeDueDate(DateTime? dueDate)
}
}
- public void ValidateAndChangeFinalDecisionDate(DateTime? finalDecisionDate)
+ ///
+ /// Validates and sets the FinalDecisionDate property.
+ ///
+ ///
+ ///
+ public void ValidateAndSetFinalDecisionDate(DateTime? finalDecisionDate)
{
if ((FinalDecisionDate != finalDecisionDate) && finalDecisionDate != null && finalDecisionDate.Value > DateTime.Now)
{
@@ -205,12 +215,35 @@ public void ValidateAndChangeFinalDecisionDate(DateTime? finalDecisionDate)
}
}
- public void ValidateMinAndChangeApprovedAmount(decimal approvedAmount)
+ ///
+ /// Validates and sets the ApprovedAmount property.
+ ///
+ ///
+ ///
+ public void ValidateAndSetApprovedAmount(decimal approvedAmount)
{
if ((ApprovedAmount != approvedAmount) && approvedAmount <= 0m)
{
throw new BusinessException("Approved amount cannot be 0.");
}
+ else
+ {
+ ApprovedAmount = approvedAmount;
+ }
+ }
+
+ ///
+ /// Validates the recommended amount for direct approval.
+ ///
+ ///
+ ///
+ ///
+ public void ValidateDirectApprovalRecommendedAmount(decimal recommendedAmount, bool? isDirectApproval)
+ {
+ if (isDirectApproval != true && (RecommendedAmount != recommendedAmount) && recommendedAmount <= 0m)
+ {
+ throw new BusinessException("Recommended amount cannot be 0.");
+ }
}
///
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 45c9caea5..856de9e42 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs
@@ -35,8 +35,19 @@ public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder)
];
public readonly List ApplicantInfo_CommonPermissions = [
- GrantApplicationPermissions.ApplicantInfo.Default,
- GrantApplicationPermissions.ApplicantInfo.Update,
+ 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 = [
@@ -47,6 +58,13 @@ public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder)
UnitySelector.Project.Location.Update.Default,
];
+ public readonly List PaymentInfo_CommonPermissions = [
+ UnitySelector.Payment.Summary.Default,
+ UnitySelector.Payment.Supplier.Default,
+ UnitySelector.Payment.Supplier.Update,
+ UnitySelector.Payment.PaymentList.Default
+ ];
+
public readonly List Notifications_CommonPermissions = [
NotificationsPermissions.Email.Default,
NotificationsPermissions.Email.Send,
@@ -63,6 +81,12 @@ public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder)
GrantApplicationPermissions.Dashboard.RequestApprovedCount,
];
+ public readonly List SettingManagement_Tags_CommonPermissions = [
+ UnitySelector.SettingManagement.Tags.Default,
+ UnitySelector.SettingManagement.Tags.Update,
+ UnitySelector.SettingManagement.Tags.Delete
+ ];
+
public async Task SeedAsync(DataSeedContext context)
{
// Default permission grants based on role
@@ -91,6 +115,7 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName,
GrantManagerPermissions.Intakes.Default,
GrantManagerPermissions.ApplicationForms.Default,
+ .. SettingManagement_Tags_CommonPermissions,
.. ReviewAndAssessment_CommonPermissions,
.. ApplicantInfo_CommonPermissions,
.. ProjectInfo_CommonPermissions,
@@ -144,10 +169,8 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName,
GrantManagerPermissions.Organizations.ManageProfiles,
GrantApplicationPermissions.Approvals.BulkApplicationApproval,
GrantApplicationPermissions.Approvals.DeferAfterApproval,
- UnitySelector.SettingManagement.Tags.Default,
- UnitySelector.SettingManagement.Tags.Update,
- UnitySelector.SettingManagement.Tags.Delete,
+ .. SettingManagement_Tags_CommonPermissions,
.. ReviewAndAssessment_CommonPermissions,
.. ApplicantInfo_CommonPermissions,
.. ProjectInfo_CommonPermissions,
@@ -186,6 +209,7 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName,
GrantManagerPermissions.ApplicationForms.Default,
+ .. SettingManagement_Tags_CommonPermissions,
.. ReviewAndAssessment_CommonPermissions,
.. ApplicantInfo_CommonPermissions,
.. ProjectInfo_CommonPermissions,
@@ -194,9 +218,6 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName,
.. Dashboard_CommonPermissions,
UnitySettingManagementPermissions.BackgroundJobSettings,
- UnitySelector.SettingManagement.Tags.Default,
- UnitySelector.SettingManagement.Tags.Update,
- UnitySelector.SettingManagement.Tags.Delete
], context.TenantId);
@@ -261,8 +282,13 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName,
UnitySelector.Review.AssessmentReviewList.Update.Complete,
UnitySelector.Review.Worksheet.Default,
- GrantApplicationPermissions.ApplicantInfo.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,
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj
index 64cf6154c..096adad34 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Unity.GrantManager.Domain.csproj
@@ -1,9 +1,9 @@
-
+
- net8.0
+ net9.0
enable
Unity.GrantManager
@@ -14,20 +14,20 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
**/Assessments/Assessment.cs, **/Assessments/AssessmentWithAssessorQueryResultItem.cs
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Zones/DefaultZoneDefinition.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Zones/DefaultZoneDefinition.cs
index 924c617ef..dea377698 100644
--- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Zones/DefaultZoneDefinition.cs
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Zones/DefaultZoneDefinition.cs
@@ -68,23 +68,25 @@ public static class DefaultZoneDefinition
Name = UnitySelector.Applicant.Contact.Default,
ViewComponentType = "ApplicantContactInfoViewComponent",
IsEnabled = true,
- IsConfigurationDisabled = true,
SortOrder = 2
},
new ZoneDefinition {
Name = UnitySelector.Applicant.Authority.Default,
ViewComponentType = "ApplicantSigningAuthorityViewComponent",
IsEnabled = true,
- IsConfigurationDisabled = true,
SortOrder = 3
},
new ZoneDefinition {
Name = UnitySelector.Applicant.Location.Default,
ViewComponentType = "ApplicantPhysicalAddressViewComponent",
IsEnabled = true,
- IsConfigurationDisabled = true,
SortOrder = 4
},
+ new ZoneDefinition {
+ Name = UnitySelector.Applicant.AdditionalContact.Default,
+ IsEnabled = true,
+ SortOrder = 5
+ },
]
},
new ZoneTabDefinition {
@@ -111,14 +113,22 @@ public static class DefaultZoneDefinition
Name = UnitySelector.Payment.Summary.Default,
ViewComponentType = "PaymentInfoViewComponent",
IsEnabled = true,
+ IsConfigurationDisabled = true,
SortOrder = 1
},
- new ZoneDefinition {
+ new ZoneDefinition {
+ Name = UnitySelector.Payment.Supplier.Default,
+ ViewComponentType = "SupplierInfoViewComponent",
+ IsEnabled = true,
+ IsConfigurationDisabled = true,
+ SortOrder = 2
+ },
+ new ZoneDefinition {
Name = UnitySelector.Payment.PaymentList.Default,
ViewComponentType = "PaymentListViewComponent",
IsEnabled = true,
IsConfigurationDisabled = true,
- SortOrder = 2
+ SortOrder = 3
}
]
}
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20250520195822_Abp9_1_Upgrade.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20250520195822_Abp9_1_Upgrade.Designer.cs
new file mode 100644
index 000000000..915d8dad8
--- /dev/null
+++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/HostMigrations/20250520195822_Abp9_1_Upgrade.Designer.cs
@@ -0,0 +1,2549 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Unity.GrantManager.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore;
+
+#nullable disable
+
+namespace Unity.GrantManager.Migrations.HostMigrations
+{
+ [DbContext(typeof(GrantManagerDbContext))]
+ [Migration("20250520195822_Abp9_1_Upgrade")]
+ partial class Abp9_1_Upgrade
+ {
+ ///
+ 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("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzBlobTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("trigger_name");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("trigger_group");
+
+ b.Property("BlobData")
+ .HasColumnType("bytea")
+ .HasColumnName("blob_data");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("qrtz_blob_triggers", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCalendar", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("CalendarName")
+ .HasColumnType("text")
+ .HasColumnName("calendar_name");
+
+ b.Property("Calendar")
+ .IsRequired()
+ .HasColumnType("bytea")
+ .HasColumnName("calendar");
+
+ b.HasKey("SchedulerName", "CalendarName");
+
+ b.ToTable("qrtz_calendars", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzCronTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("trigger_name");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("trigger_group");
+
+ b.Property("CronExpression")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("cron_expression");
+
+ b.Property("TimeZoneId")
+ .HasColumnType("text")
+ .HasColumnName("time_zone_id");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("qrtz_cron_triggers", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzFiredTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("EntryId")
+ .HasColumnType("text")
+ .HasColumnName("entry_id");
+
+ b.Property("FiredTime")
+ .HasColumnType("bigint")
+ .HasColumnName("fired_time");
+
+ b.Property("InstanceName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("instance_name");
+
+ b.Property("IsNonConcurrent")
+ .HasColumnType("bool")
+ .HasColumnName("is_nonconcurrent");
+
+ b.Property("JobGroup")
+ .HasColumnType("text")
+ .HasColumnName("job_group");
+
+ b.Property("JobName")
+ .HasColumnType("text")
+ .HasColumnName("job_name");
+
+ b.Property("Priority")
+ .HasColumnType("integer")
+ .HasColumnName("priority");
+
+ b.Property("RequestsRecovery")
+ .HasColumnType("bool")
+ .HasColumnName("requests_recovery");
+
+ b.Property("ScheduledTime")
+ .HasColumnType("bigint")
+ .HasColumnName("sched_time");
+
+ b.Property("State")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("state");
+
+ b.Property("TriggerGroup")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("trigger_group");
+
+ b.Property("TriggerName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("trigger_name");
+
+ b.HasKey("SchedulerName", "EntryId");
+
+ b.HasIndex("InstanceName")
+ .HasDatabaseName("idx_qrtz_ft_trig_inst_name");
+
+ b.HasIndex("JobGroup")
+ .HasDatabaseName("idx_qrtz_ft_job_group");
+
+ b.HasIndex("JobName")
+ .HasDatabaseName("idx_qrtz_ft_job_name");
+
+ b.HasIndex("RequestsRecovery")
+ .HasDatabaseName("idx_qrtz_ft_job_req_recovery");
+
+ b.HasIndex("TriggerGroup")
+ .HasDatabaseName("idx_qrtz_ft_trig_group");
+
+ b.HasIndex("TriggerName")
+ .HasDatabaseName("idx_qrtz_ft_trig_name");
+
+ b.HasIndex("SchedulerName", "TriggerName", "TriggerGroup")
+ .HasDatabaseName("idx_qrtz_ft_trig_nm_gp");
+
+ b.ToTable("qrtz_fired_triggers", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzJobDetail", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("JobName")
+ .HasColumnType("text")
+ .HasColumnName("job_name");
+
+ b.Property("JobGroup")
+ .HasColumnType("text")
+ .HasColumnName("job_group");
+
+ b.Property("Description")
+ .HasColumnType("text")
+ .HasColumnName("description");
+
+ b.Property("IsDurable")
+ .HasColumnType("bool")
+ .HasColumnName("is_durable");
+
+ b.Property("IsNonConcurrent")
+ .HasColumnType("bool")
+ .HasColumnName("is_nonconcurrent");
+
+ b.Property("IsUpdateData")
+ .HasColumnType("bool")
+ .HasColumnName("is_update_data");
+
+ b.Property("JobClassName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("job_class_name");
+
+ b.Property("JobData")
+ .HasColumnType("bytea")
+ .HasColumnName("job_data");
+
+ b.Property("RequestsRecovery")
+ .HasColumnType("bool")
+ .HasColumnName("requests_recovery");
+
+ b.HasKey("SchedulerName", "JobName", "JobGroup");
+
+ b.HasIndex("RequestsRecovery")
+ .HasDatabaseName("idx_qrtz_j_req_recovery");
+
+ b.ToTable("qrtz_job_details", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzLock", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("LockName")
+ .HasColumnType("text")
+ .HasColumnName("lock_name");
+
+ b.HasKey("SchedulerName", "LockName");
+
+ b.ToTable("qrtz_locks", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzPausedTriggerGroup", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("trigger_group");
+
+ b.HasKey("SchedulerName", "TriggerGroup");
+
+ b.ToTable("qrtz_paused_trigger_grps", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSchedulerState", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("InstanceName")
+ .HasColumnType("text")
+ .HasColumnName("instance_name");
+
+ b.Property("CheckInInterval")
+ .HasColumnType("bigint")
+ .HasColumnName("checkin_interval");
+
+ b.Property("LastCheckInTime")
+ .HasColumnType("bigint")
+ .HasColumnName("last_checkin_time");
+
+ b.HasKey("SchedulerName", "InstanceName");
+
+ b.ToTable("qrtz_scheduler_state", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimplePropertyTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("trigger_name");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("trigger_group");
+
+ b.Property("BooleanProperty1")
+ .HasColumnType("bool")
+ .HasColumnName("bool_prop_1");
+
+ b.Property("BooleanProperty2")
+ .HasColumnType("bool")
+ .HasColumnName("bool_prop_2");
+
+ b.Property("DecimalProperty1")
+ .HasColumnType("numeric")
+ .HasColumnName("dec_prop_1");
+
+ b.Property("DecimalProperty2")
+ .HasColumnType("numeric")
+ .HasColumnName("dec_prop_2");
+
+ b.Property("IntegerProperty1")
+ .HasColumnType("integer")
+ .HasColumnName("int_prop_1");
+
+ b.Property("IntegerProperty2")
+ .HasColumnType("integer")
+ .HasColumnName("int_prop_2");
+
+ b.Property("LongProperty1")
+ .HasColumnType("bigint")
+ .HasColumnName("long_prop_1");
+
+ b.Property("LongProperty2")
+ .HasColumnType("bigint")
+ .HasColumnName("long_prop_2");
+
+ b.Property("StringProperty1")
+ .HasColumnType("text")
+ .HasColumnName("str_prop_1");
+
+ b.Property("StringProperty2")
+ .HasColumnType("text")
+ .HasColumnName("str_prop_2");
+
+ b.Property("StringProperty3")
+ .HasColumnType("text")
+ .HasColumnName("str_prop_3");
+
+ b.Property("TimeZoneId")
+ .HasColumnType("text")
+ .HasColumnName("time_zone_id");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("qrtz_simprop_triggers", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzSimpleTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("trigger_name");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("trigger_group");
+
+ b.Property("RepeatCount")
+ .HasColumnType("bigint")
+ .HasColumnName("repeat_count");
+
+ b.Property("RepeatInterval")
+ .HasColumnType("bigint")
+ .HasColumnName("repeat_interval");
+
+ b.Property("TimesTriggered")
+ .HasColumnType("bigint")
+ .HasColumnName("times_triggered");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.ToTable("qrtz_simple_triggers", (string)null);
+ });
+
+ modelBuilder.Entity("AppAny.Quartz.EntityFrameworkCore.Migrations.QuartzTrigger", b =>
+ {
+ b.Property("SchedulerName")
+ .HasColumnType("text")
+ .HasColumnName("sched_name");
+
+ b.Property("TriggerName")
+ .HasColumnType("text")
+ .HasColumnName("trigger_name");
+
+ b.Property("TriggerGroup")
+ .HasColumnType("text")
+ .HasColumnName("trigger_group");
+
+ b.Property("CalendarName")
+ .HasColumnType("text")
+ .HasColumnName("calendar_name");
+
+ b.Property("Description")
+ .HasColumnType("text")
+ .HasColumnName("description");
+
+ b.Property("EndTime")
+ .HasColumnType("bigint")
+ .HasColumnName("end_time");
+
+ b.Property("JobData")
+ .HasColumnType("bytea")
+ .HasColumnName("job_data");
+
+ b.Property("JobGroup")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("job_group");
+
+ b.Property("JobName")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("job_name");
+
+ b.Property("MisfireInstruction")
+ .HasColumnType("smallint")
+ .HasColumnName("misfire_instr");
+
+ b.Property("NextFireTime")
+ .HasColumnType("bigint")
+ .HasColumnName("next_fire_time");
+
+ b.Property("PreviousFireTime")
+ .HasColumnType("bigint")
+ .HasColumnName("prev_fire_time");
+
+ b.Property("Priority")
+ .HasColumnType("integer")
+ .HasColumnName("priority");
+
+ b.Property("StartTime")
+ .HasColumnType("bigint")
+ .HasColumnName("start_time");
+
+ b.Property("TriggerState")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("trigger_state");
+
+ b.Property("TriggerType")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("trigger_type");
+
+ b.HasKey("SchedulerName", "TriggerName", "TriggerGroup");
+
+ b.HasIndex("NextFireTime")
+ .HasDatabaseName("idx_qrtz_t_next_fire_time");
+
+ b.HasIndex("TriggerState")
+ .HasDatabaseName("idx_qrtz_t_state");
+
+ b.HasIndex("NextFireTime", "TriggerState")
+ .HasDatabaseName("idx_qrtz_t_nft_st");
+
+ b.HasIndex("SchedulerName", "JobName", "JobGroup");
+
+ b.ToTable("qrtz_triggers", (string)null);
+ });
+
+ modelBuilder.Entity("Unity.GrantManager.Intakes.ChefsMissedSubmission", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ChefsApplicationFormGuid")
+ .HasColumnType("text");
+
+ b.Property("ChefsSubmissionGuids")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.ToTable("ChefsMissedSubmissions", (string)null);
+ });
+
+ modelBuilder.Entity("Unity.GrantManager.Locality.Community", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RegionalDistrictCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Communities", (string)null);
+ });
+
+ modelBuilder.Entity("Unity.GrantManager.Locality.EconomicRegion", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("EconomicRegionCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EconomicRegionName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.HasKey("Id");
+
+ b.ToTable("EconomicRegions", (string)null);
+ });
+
+ modelBuilder.Entity("Unity.GrantManager.Locality.ElectoralDistrict", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ElectoralDistrictCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ElectoralDistrictName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.HasKey("Id");
+
+ b.ToTable("ElectoralDistricts", (string)null);
+ });
+
+ modelBuilder.Entity("Unity.GrantManager.Locality.RegionalDistrict", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("EconomicRegionCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("RegionalDistrictCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RegionalDistrictName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("RegionalDistricts", (string)null);
+ });
+
+ modelBuilder.Entity("Unity.GrantManager.Locality.Sector", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property |