From ca6aefbf5d2bfbc78e0683ff8dcf19347f415abf Mon Sep 17 00:00:00 2001 From: jpasta Date: Mon, 14 Apr 2025 15:43:39 -0700 Subject: [PATCH 01/30] feature/AB#28691-AccountCoding-FirstDraft --- .../AccountCoding.cs | 56 +- .../PaymentConfiguration.cs | 1 + .../EntityFrameworkCore/IPaymentsDbContext.cs | 3 +- .../EntityFrameworkCore/PaymentsDbContext.cs | 11 +- ...aymentsDbContextModelCreatingExtensions.cs | 9 + .../PaymentConfigurationAppService.cs | 2 + .../Pages/PaymentConfigurations/Index.cshtml | 18 + .../Pages/PaymentConfigurations/Index.js | 137 + .../Payments/AccountCodingDto.cs | 14 + .../Payments/CreateUpdateAccountCodingDto.cs | 20 + .../Payments/IAccountCodingAppService.cs | 14 + ...ApplicationPermissionDefinitionProvider.cs | 1 + ...rantManagerApplicationAutoMapperProfile.cs | 3 + .../Localization/GrantManager/en.json | 2 + .../UnitySettingManagementPermissions.cs | 2 + .../Permissions/PermissionGrantsDataSeeder.cs | 3 +- .../20250409224221_AccountCoding.Designer.cs | 3384 +++++++++++++++++ .../20250409224221_AccountCoding.cs | 50 + 18 files changed, 3702 insertions(+), 28 deletions(-) rename applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/{PaymentConfigurations => AccountCodings}/AccountCoding.cs (51%) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/AccountCoding.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs similarity index 51% rename from applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/AccountCoding.cs rename to applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs index 1bdd38696..de9842e44 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/AccountCoding.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs @@ -2,22 +2,35 @@ using System.Linq; using Unity.Payments.Domain.Exceptions; using Volo.Abp; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; -namespace Unity.Payments.Domain.PaymentConfigurations + +namespace Unity.Payments.Domain.AccountCodings { - public record AccountCoding + public class AccountCoding : FullAuditedAggregateRoot, IMultiTenant { - public string MinistryClient { get; private set; } = string.Empty; - public string Responsibility { get; private set; } = string.Empty; - public string ServiceLine { get; private set; } = string.Empty; - public string Stob { get; private set; } = string.Empty; - public string ProjectNumber { get; private set; } = string.Empty; - - private AccountCoding(string ministryClient, - string responsibility, - string serviceLine, - string stob, - string projectNumber) + public Guid? TenantId { get; set; } + + // Account Coding Fields + public virtual string? MinistryClient { get; private set; } = string.Empty; + public virtual string? Responsibility { get; private set; } = string.Empty; + public virtual string? ServiceLine { get; private set; } = string.Empty; + public virtual string? Stob { get; private set; } = string.Empty; + public virtual string? ProjectNumber { get; private set; } = string.Empty; + + // Constructor for ORM + protected AccountCoding() + { + + } + + public AccountCoding( + string? ministryClient, + string? responsibility, + string? serviceLine, + string? stob, + string? projectNumber) { MinistryClient = ministryClient; Responsibility = responsibility; @@ -33,7 +46,7 @@ public static AccountCoding Create( string stob, string projectNumber) { - ValidateField(ministryClient, 3, nameof(MinistryClient), false); + ValidateField(ministryClient, 3, nameof(MinistryClient), false); ValidateField(responsibility, 5, nameof(Responsibility), false); ValidateField(serviceLine, 5, nameof(serviceLine)); ValidateField(stob, 4, nameof(stob)); @@ -42,20 +55,21 @@ public static AccountCoding Create( return new AccountCoding(ministryClient, responsibility, serviceLine, stob, projectNumber); } - private static void ValidateField(string field, uint length, string fieldName, bool validateNumeric = true) + private static void ValidateField(string field, uint length, string fieldName, bool validAlphanumeric = true) { - - bool validNumeric = true; - if (validateNumeric) { - validNumeric = field.All(char.IsDigit); + + if (validAlphanumeric) + { + validAlphanumeric = field.All(char.IsLetterOrDigit); } - if (field.Length != length || !validNumeric) + if (field.Length != length || !validAlphanumeric) { throw new BusinessException(ErrorConsts.InvalidAccountCodingField) .WithData("field", fieldName) .WithData("length", length); - } + } } } + } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs index 8de252a10..193d1545f 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs @@ -1,4 +1,5 @@ using System; +using Unity.Payments.Domain.AccountCodings; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs index 7f01a1727..d6e045119 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using Unity.Payments.Domain; +using Unity.Payments.Domain.AccountCodings; using Unity.Payments.Domain.PaymentConfigurations; using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Domain.Suppliers; @@ -11,7 +12,7 @@ namespace Unity.Payments.EntityFrameworkCore; [ConnectionStringName(PaymentsDbProperties.ConnectionStringName)] public interface IPaymentsDbContext : IEfCoreDbContext { - + public DbSet AccountCoding { get; } public DbSet PaymentRequests { get; } public DbSet ExpenseApproval { get; } public DbSet Suppliers { get; } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs index 781f5b4a7..01f567f80 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using Unity.Payments.Domain; +using Unity.Payments.Domain.AccountCodings; using Unity.Payments.Domain.PaymentConfigurations; using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Domain.Suppliers; @@ -10,13 +11,13 @@ namespace Unity.Payments.EntityFrameworkCore; [ConnectionStringName(PaymentsDbProperties.ConnectionStringName)] public class PaymentsDbContext : AbpDbContext, IPaymentsDbContext -{ - - public DbSet PaymentRequests { get; set; } +{ + public DbSet AccountCoding { get; set; } public DbSet ExpenseApproval { get; set; } - public DbSet Suppliers { get;set; } - public DbSet PaymentConfigurations { get;set; } + public DbSet Suppliers { get; set; } + public DbSet PaymentConfigurations { get; set; } public DbSet Sites { get; set; } + public DbSet PaymentRequests { get; set; } public PaymentsDbContext(DbContextOptions options) : base(options) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs index 549ef78eb..184fe6db7 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs @@ -5,6 +5,7 @@ using Unity.Payments.Domain; using Unity.Payments.Domain.Suppliers; using Unity.Payments.Domain.PaymentConfigurations; +using Unity.Payments.Domain.AccountCodings; namespace Unity.Payments.EntityFrameworkCore; @@ -64,6 +65,14 @@ public static void ConfigurePayments( b.ConfigureByConvention(); }); + modelBuilder.Entity(b => + { + b.ToTable(PaymentsDbProperties.DbTablePrefix + "AccountCodings", + PaymentsDbProperties.DbSchema); + + b.ConfigureByConvention(); + }); + modelBuilder.Entity(b => { b.ToTable(PaymentsDbProperties.DbTablePrefix + "PaymentConfigurations", diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs index 41ab4c8ad..aa265cb5b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs @@ -1,4 +1,6 @@ using System.Threading.Tasks; +using Unity.Payments.Domain; +using Unity.Payments.Domain.AccountCodings; using Unity.Payments.Domain.Exceptions; using Unity.Payments.Domain.PaymentConfigurations; using Volo.Abp.Features; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml index 41b208eef..64acc78bf 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml @@ -18,6 +18,24 @@
+
+
+
+

Account Codes

+
+
+ +
+ +
+ +
+
+
+ +
+
+Make this a modal

Account Coding

diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js index e0a61f635..99f8a540e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js @@ -19,6 +19,143 @@ $(function () { bindLimitedInputFields(/^[a-zA-Z0-9]+$/, [UIElements.inputPaymentIdPrefix[0].id]); } + let createModal = new abp.ModalManager(abp.appPath + 'PaymentConfigurations/CreateModal'); + let updateModal = new abp.ModalManager(abp.appPath + 'PaymentConfigurations/UpdateModal'); + const l = abp.localization.getResource('GrantManager'); + /** + * List All + */ + $.fn.dataTable.Buttons.defaults.dom.button.className = 'btn flex-none'; + let actionButtons = [ + { + text: ' ' + l('Common:Command:Create') + '', + titleAttr: l('Common:Command:Create'), + id: 'CreateButton', + className: 'btn-light rounded-1', + action: (e, dt, node, config) => createIntakeBtn(e) + }, + ...commonTableActionButtons(l('Intake')) + ]; + + const listColumns = [ + { + title: 'Ministry Client', + name: "ministryClient", + data: "ministryClient", + index: 0 + }, + { + title: 'Responsibility', + name: "responsibility", + data: "responsibility", + index: 1 + }, + { + title: 'Service Line', + name: "serviceLine", + data: "serviceLine", + index: 2 + }, + { + title: 'Stob', + name: "stob", + data: "stob", + index: 3 + }, + { + title: 'Project #', + name: "projectNumber", + data: "projectNumber", + index: 4 + }, + { + title: 'Default', + orderable: false, + className: 'notexport text-center', + name: 'rowActions', + index: 5, + rowAction: { + items: + [ + { + text: 'Edit', + action: (data) => updateModal.open({ id: data.record.id }) + } + ] + } + }, + { + title: '', + orderable: false, + className: 'notexport text-center', + name: 'defaultRadio', + index: 6, + rowAction: { + items: + [ + { + text: 'Edit', + action: (data) => updateModal.open({ id: data.record.id }) + } + ] + } + } + ]; + + const defaultVisibleColumns = [ + 'ministryClient', + 'responsibility', + 'serviceLine', + 'stob', + 'projectNumber', + 'rowActions', + 'defaultRadio' + ]; + + + let responseCallback = function (result) { + return { + recordsTotal: result.totalCount, + recordsFiltered: result.items.length, + data: result.items + }; + }; + + let dt = $('#AccountCodesDataTable'); + + let dataTable = initializeDataTable({ + dt, + defaultVisibleColumns, + listColumns, + maxRowsPerPage: 25, + defaultSortColumn: 0, + dataEndpoint: unity.grantManager.payments.accountCoding.getList, + data: {}, + responseCallback, + actionButtons, + pagingEnabled: true, + reorderEnabled: false, + languageSetValues: {}, + dataTableName: 'IntakesTable', + dynamicButtonContainerId: 'dynamicButtonContainerId', + useNullPlaceholder: true, + externalSearchId: 'search-intakes' + }); + + createModal.onResult(function () { + dataTable.ajax.reload(); + }); + + updateModal.onResult(function () { + dataTable.ajax.reload(); + }); + + function createIntakeBtn(e) { + e.preventDefault(); + createModal.open(); + }; + + function displayStatusMessage() { let statusMessage = UIElements.statusMessage.val(); if (statusMessage != "") { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs new file mode 100644 index 000000000..468ff56db --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Unity.GrantManager.Payments +{ + public class AccountCodingDto : AuditedEntityDto + { + public string? MinistryClient { get; private set; } = string.Empty; + public string? Responsibility { get; private set; } = string.Empty; + public string? ServiceLine { get; private set; } = string.Empty; + public string? Stob { get; private set; } = string.Empty; + public string? ProjectNumber { get; private set; } = string.Empty; + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs new file mode 100644 index 000000000..b21c2c7ca --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs @@ -0,0 +1,20 @@ +using System.ComponentModel; + +namespace Unity.GrantManager.Payments +{ + public class CreateUpdateAccountCodingDto + { + [DisplayName("Ministry Client")] + public string? MinistryClient { get; private set; } = string.Empty; + + [DisplayName("Responsibility")] + public string? Responsibility { get; private set; } = string.Empty; + + [DisplayName("Service Line")] + public string? ServiceLine { get; private set; } = string.Empty; + [DisplayName("Stob")] + public string? Stob { get; private set; } = string.Empty; + [DisplayName("Project Number")] + public string? ProjectNumber { get; private set; } = string.Empty; + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs new file mode 100644 index 000000000..df1da44a5 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IAccountCodingAppService.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Unity.GrantManager.Payments +{ + public interface IAccountCodingAppService : ICrudAppService< + AccountCodingDto, + Guid, + PagedAndSortedResultRequestDto, + CreateUpdateAccountCodingDto> + { + } +} 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 5b7bfa487..c5935e1a8 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 @@ -85,6 +85,7 @@ public override void Define(IPermissionDefinitionContext context) var settingManagement = context.GetGroup(SettingManagementPermissions.GroupName); settingManagement.AddPermission(UnitySettingManagementPermissions.UserInterface, L("Permission:UnitySettingManagementPermissions.UserInterface")); settingManagement.AddPermission(UnitySettingManagementPermissions.BackgroundJobSettings, L("Permission:UnitySettingManagementPermissions.BackgroundJobs")); + settingManagement.AddPermission(UnitySettingManagementPermissions.ConfigurePayments, L("Permission:UnitySettingManagementPermissions.ConfigurePayments")); var emailingPermission = context.GetPermissionOrNull(SettingManagementPermissions.Emailing); if (emailingPermission != null) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs index 9d67e624b..3d48512e5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationAutoMapperProfile.cs @@ -10,7 +10,9 @@ using Unity.GrantManager.Identity; using Unity.GrantManager.Intakes; using Unity.GrantManager.Locality; +using Unity.GrantManager.Payments; using Unity.GrantManager.Zones; +using Unity.Payments.Domain.AccountCodings; namespace Unity.GrantManager; @@ -71,6 +73,7 @@ public GrantManagerApplicationAutoMapperProfile() CreateMap(); CreateMap(); CreateMap(); + CreateMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); 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 0b3f19f5a..88a40adb9 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Localization/GrantManager/en.json @@ -229,6 +229,8 @@ "Permission:UnitySettingManagementPermissions.BackgroundJobs": "Background Jobs", "Permission:UnitySettingManagementPermissions.UserInterface": "Application Tabs", + "Permission:UnitySettingManagementPermissions.ConfigurePayments": "Configure Payments", + "Setting:GrantManager.UI.PageTitle": "Application Tabs Configuration", "Setting:GrantManager.UI.Tabs.Applicant.Description": "Toggle visibility of the Applicant Info tab for the tenant", "Setting:GrantManager.UI.Tabs.Applicant.DisplayName": "Applicant Info", diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/UnitySettingManagementPermissions.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/UnitySettingManagementPermissions.cs index 1e32e4821..84a8d195c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/UnitySettingManagementPermissions.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain.Shared/Permissions/UnitySettingManagementPermissions.cs @@ -6,4 +6,6 @@ public static class UnitySettingManagementPermissions public const string UserInterface = GroupName + ".UserInterface"; public const string BackgroundJobSettings = "SettingManagement.GrantManager"; + + public const string ConfigurePayments = "SettingManagement.ConfigurePayments"; } 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 0225f382e..1dc3a61fe 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs @@ -251,7 +251,8 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, NotificationsPermissions.Email.Send, NotificationsPermissions.Settings, - UnitySettingManagementPermissions.BackgroundJobSettings + UnitySettingManagementPermissions.BackgroundJobSettings, + UnitySettingManagementPermissions.ConfigurePayments, }, context.TenantId); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.Designer.cs new file mode 100644 index 000000000..ea3e7f3b9 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.Designer.cs @@ -0,0 +1,3384 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Unity.GrantManager.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + [DbContext(typeof(GrantTenantDbContext))] + [Migration("20250409224221_AccountCoding")] + partial class AccountCoding + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("ScoresheetInstanceId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.HasIndex("ScoresheetInstanceId"); + + b.ToTable("Answers", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("Questions", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Scoresheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CustomFieldId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetInstanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetInstanceId"); + + b.ToTable("CustomFieldValues", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetCorrelationId") + .HasColumnType("uuid"); + + b.Property("WorksheetCorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("WorksheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetLinks", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("CustomFields", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Worksheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantName") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("character varying(600)"); + + b.Property("ApproxNumberOfEmployees") + .HasColumnType("text"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MatchPercentage") + .HasColumnType("numeric"); + + b.Property("NonRegOrgName") + .HasColumnType("text"); + + b.Property("NonRegisteredBusinessName") + .HasColumnType("text"); + + b.Property("OrgName") + .HasColumnType("text"); + + b.Property("OrgNumber") + .HasColumnType("text"); + + b.Property("OrgStatus") + .HasColumnType("text"); + + b.Property("OrganizationSize") + .HasColumnType("text"); + + b.Property("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("StartedOperatingDate") + .HasColumnType("date"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SubSector") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UnityApplicantId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantName"); + + b.ToTable("Applicants", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AddressType") + .HasColumnType("integer"); + + b.Property("ApplicantId") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Postal") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("Street2") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Unit") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("ApplicantAddresses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("BceidBusinessGuid") + .HasColumnType("uuid"); + + b.Property("BceidBusinessName") + .HasColumnType("text"); + + b.Property("BceidUserGuid") + .HasColumnType("uuid"); + + b.Property("BceidUserName") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactOrder") + .HasColumnType("integer"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IdentityEmail") + .HasColumnType("text"); + + b.Property("IdentityName") + .HasColumnType("text"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSubUser") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("Phone2") + .HasColumnType("text"); + + b.Property("Phone2Extension") + .HasColumnType("text"); + + b.Property("PhoneExtension") + .HasColumnType("text"); + + b.Property("RoleForApplicant") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId") + .IsUnique(); + + b.HasIndex("OidcSubUser"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Acquisition") + .HasColumnType("text"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationStatusId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + b.Property("AssessmentResultDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AssessmentResultStatus") + .HasColumnType("text"); + + b.Property("AssessmentStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Community") + .HasColumnType("text"); + + b.Property("CommunityPopulation") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractExecutionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ContractNumber") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeclineRational") + .HasColumnType("text"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DueDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DueDiligenceStatus") + .HasColumnType("text"); + + b.Property("EconomicRegion") + .HasColumnType("text"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinalDecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Forestry") + .HasColumnType("text"); + + b.Property("ForestryFocus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LikelihoodOfFunding") + .HasColumnType("text"); + + b.Property("Notes") + .HasColumnType("text"); + + b.Property("NotificationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("Payload") + .HasColumnType("jsonb"); + + b.Property("PercentageTotalProjectBudget") + .HasColumnType("double precision"); + + b.Property("Place") + .HasColumnType("text"); + + b.Property("ProjectEndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectFundingTotal") + .HasColumnType("numeric"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ProjectStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectSummary") + .HasColumnType("text"); + + b.Property("ProposalDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RecommendedAmount") + .HasColumnType("numeric"); + + b.Property("ReferenceNo") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrict") + .HasColumnType("text"); + + b.Property("RequestedAmount") + .HasColumnType("numeric"); + + b.Property("RiskRanking") + .HasColumnType("text"); + + b.Property("SigningAuthorityBusinessPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityCellPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityEmail") + .HasColumnType("text"); + + b.Property("SigningAuthorityFullName") + .HasColumnType("text"); + + b.Property("SigningAuthorityTitle") + .HasColumnType("text"); + + b.Property("SubStatus") + .HasColumnType("text"); + + b.Property("SubmissionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalProjectBudget") + .HasColumnType("numeric"); + + b.Property("TotalScore") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.HasIndex("ApplicationStatusId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Applications", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Duty") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssigneeId"); + + b.ToTable("ApplicationAssignments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsFileId") + .HasColumnType("text"); + + b.Property("ChefsSumbissionId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationChefsFileAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactEmail") + .HasColumnType("text"); + + b.Property("ContactFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactMobilePhone") + .HasColumnType("text"); + + b.Property("ContactTitle") + .HasColumnType("text"); + + b.Property("ContactType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactWorkPhone") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationContact", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasColumnType("text"); + + b.Property("ApplicationFormDescription") + .HasColumnType("text"); + + b.Property("ApplicationFormName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AttemptedConnectionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("Category") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsCriteriaFormGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConnectionHttpStatus") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("RenderFormIoToHtml") + .HasColumnType("boolean"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IntakeId"); + + b.ToTable("ApplicationForms", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormVersionId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsSubmissionGuid") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormVersionId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("RenderedHTML") + .HasColumnType("text"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Submission") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormSubmissions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsFormVersionGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubmissionHeaderMapping") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormVersion", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LinkedApplicationId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationLinks", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StatusCode") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("StatusCode") + .IsUnique(); + + b.ToTable("ApplicationStatuses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationTags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.ToTable("AssessmentAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ApprovalRecommended") + .HasColumnType("boolean"); + + b.Property("AssessorId") + .HasColumnType("uuid"); + + b.Property("CleanGrowth") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicImpact") + .HasColumnType("integer"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinancialAnalysis") + .HasColumnType("integer"); + + b.Property("InclusiveGrowth") + .HasColumnType("integer"); + + b.Property("IsComplete") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssessorId"); + + b.ToTable("Assessments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicationComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.HasIndex("CommenterId"); + + b.ToTable("AssessmentComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Identity.Person", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Badge") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcDisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("OidcSub"); + + b.ToTable("Persons", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Intakes.Intake", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Budget") + .HasColumnType("double precision"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Intakes", (string)null); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("BCC") + .IsRequired() + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyType") + .IsRequired() + .HasColumnType("text"); + + b.Property("CC") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesMsgId") + .HasColumnType("uuid"); + + b.Property("ChesResponse") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FromAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Priority") + .IsRequired() + .HasColumnType("text"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("SendOnDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SentDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ToAddress") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailLogs", "Notifications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentConfigurations.PaymentConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MinistryClient") + .HasColumnType("text"); + + b.Property("PaymentIdPrefix") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentThreshold") + .HasColumnType("numeric"); + + b.Property("ProjectNumber") + .HasColumnType("text"); + + b.Property("Responsibility") + .HasColumnType("text"); + + b.Property("ServiceLine") + .HasColumnType("text"); + + b.Property("Stob") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfigurations", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DecisionUserId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.ToTable("ExpenseApprovals", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("BatchName") + .IsRequired() + .HasColumnType("text"); + + b.Property("BatchNumber") + .HasColumnType("numeric"); + + b.Property("CasHttpStatusCode") + .HasColumnType("integer"); + + b.Property("CasResponse") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InvoiceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("InvoiceStatus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsRecon") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PayeeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentDate") + .HasColumnType("text"); + + b.Property("PaymentNumber") + .HasColumnType("text"); + + b.Property("PaymentStatus") + .HasColumnType("text"); + + b.Property("ReferenceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequesterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("SubmissionConfirmationCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SupplierName") + .HasColumnType("text"); + + b.Property("SupplierNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ReferenceNumber") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("PaymentRequests", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressLine1") + .HasColumnType("text"); + + b.Property("AddressLine2") + .HasColumnType("text"); + + b.Property("AddressLine3") + .HasColumnType("text"); + + b.Property("BankAccount") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EFTAdvicePref") + .HasColumnType("text"); + + b.Property("EmailAddress") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCas") + .HasColumnType("timestamp without time zone"); + + b.Property("MarkDeletedInUse") + .HasColumnType("boolean"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentGroup") + .HasColumnType("integer"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SiteProtected") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Sites", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCAS") + .HasColumnType("timestamp without time zone"); + + b.Property("MailingAddress") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SIN") + .HasColumnType("text"); + + b.Property("StandardIndustryClassification") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("Subcategory") + .HasColumnType("text"); + + b.Property("SupplierProtected") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Suppliers", "Payments"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Instances") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Question", "Question") + .WithMany("Answers") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", null) + .WithMany("Answers") + .HasForeignKey("ScoresheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.ScoresheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Sections") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.HasOne("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", null) + .WithMany("Values") + .HasForeignKey("WorksheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Links") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.WorksheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Sections") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany("ApplicantAddresses") + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Applicant"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithOne("ApplicantAgent") + .HasForeignKey("Unity.GrantManager.Applications.ApplicantAgent", "ApplicationId"); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("OidcSubUser") + .HasPrincipalKey("OidcSub"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", "ApplicationForm") + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationStatus", "ApplicationStatus") + .WithMany("Applications") + .HasForeignKey("ApplicationStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Applicant"); + + b.Navigation("ApplicationForm"); + + b.Navigation("ApplicationStatus"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationAssignments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Assignee") + .WithMany() + .HasForeignKey("AssigneeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Assignee"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.HasOne("Unity.GrantManager.Intakes.Intake", null) + .WithMany() + .HasForeignKey("IntakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationTags") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("Assessments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("AssessorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", "PaymentRequest") + .WithMany("ExpenseApprovals") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PaymentRequest"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Supplier", "Supplier") + .WithMany("Sites") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Navigation("Instances"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Navigation("Links"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Navigation("ApplicantAddresses"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Navigation("ApplicantAgent"); + + b.Navigation("ApplicationAssignments"); + + b.Navigation("ApplicationTags"); + + b.Navigation("Assessments"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Navigation("Applications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Navigation("ExpenseApprovals"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Navigation("Sites"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs new file mode 100644 index 000000000..c16c36fab --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class AccountCoding : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AccountCodings", + schema: "Payments", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + MinistryClient = table.Column(type: "text", nullable: false), + Responsibility = table.Column(type: "text", nullable: false), + ServiceLine = table.Column(type: "text", nullable: false), + Stob = table.Column(type: "text", nullable: false), + ProjectNumber = table.Column(type: "text", nullable: false), + ExtraProperties = table.Column(type: "text", nullable: false), + ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true), + LastModificationTime = table.Column(type: "timestamp without time zone", nullable: true), + LastModifierId = table.Column(type: "uuid", nullable: true), + IsDeleted = table.Column(type: "boolean", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uuid", nullable: true), + DeletionTime = table.Column(type: "timestamp without time zone", nullable: true), + TenantId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AccountCodings", x => x.Id); + table.UniqueConstraint("UK_AccountCodings", x => new { x.MinistryClient, x.Responsibility, x.ServiceLine, x.Stob, x.ProjectNumber }); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AccountCodings"); + } + } +} From 98437c2aa782258ebe59400b860d1f4a207b9d42 Mon Sep 17 00:00:00 2001 From: jpasta Date: Wed, 16 Apr 2025 16:47:21 -0700 Subject: [PATCH 02/30] feature/AB#28691-AccountCodingMulti-Step2 --- .../UpsertPaymentConfigurationDtoBase.cs | 16 -- .../CreatePaymentConfigurationDto.cs | 0 .../IPaymentConfigurationAppService.cs | 11 +- .../PaymentConfigurationDto.cs | 5 - .../UpdatePaymentConfigurationDto.cs | 0 .../UpsertPaymentConfigurationDtoBase.cs | 11 ++ .../Domain/AccountCodings/AccountCoding.cs | 19 ++- .../IAccountCodingRepository.cs | 9 + .../PaymentConfiguration.cs | 22 +-- .../EntityFrameworkCore/PaymentsDbContext.cs | 7 +- .../Integrations/Cas/InvoiceService.cs | 44 +++-- .../PaymentConfigurationAppService.cs | 161 +++++++----------- .../PaymentRequestAppService.cs | 68 +++----- .../PaymentsApplicationAutoMapperProfile.cs | 18 +- .../Pages/AccountCoding/CreateModal.cshtml | 29 ++++ .../Pages/AccountCoding/CreateModal.cshtml.cs | 20 +++ .../Pages/AccountCoding/UpdateModal.cshtml | 24 +++ .../Pages/AccountCoding/UpdateModal.cshtml.cs | 30 ++++ .../Pages/PaymentConfigurations/Index.cshtml | 51 +----- .../PaymentConfigurations/Index.cshtml.cs | 96 +---------- .../Pages/PaymentConfigurations/Index.css | 22 ++- .../Pages/PaymentConfigurations/Index.js | 127 +++++--------- .../PaymentConfigurationViewModel.cs | 55 ------ .../AccountCoding_Tests.cs | 98 ----------- .../PaymentConfigurationAppService_Tests.cs | 113 ------------ .../Payments/AccountCodingDto.cs | 2 +- .../Payments/CreateUpdateAccountCodingDto.cs | 40 ++++- .../Payments/AccountCodingAppService.cs | 23 +++ 28 files changed, 393 insertions(+), 728 deletions(-) delete mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/UpsertPaymentConfigurationDtoBase.cs rename applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/{PaymentConfiguration => PaymentConfigurations}/CreatePaymentConfigurationDto.cs (100%) rename applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/{PaymentConfiguration => PaymentConfigurations}/IPaymentConfigurationAppService.cs (66%) rename applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/{PaymentConfiguration => PaymentConfigurations}/PaymentConfigurationDto.cs (51%) rename applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/{PaymentConfiguration => PaymentConfigurations}/UpdatePaymentConfigurationDto.cs (100%) create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs delete mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/PaymentConfigurationViewModel.cs delete mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs delete mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/PaymentConfigurationAppService_Tests.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/UpsertPaymentConfigurationDtoBase.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/UpsertPaymentConfigurationDtoBase.cs deleted file mode 100644 index cd6a2f37f..000000000 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/UpsertPaymentConfigurationDtoBase.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Unity.Payments.PaymentConfigurations -{ - [Serializable] - public class UpsertPaymentConfigurationDtoBase - { - public decimal PaymentThreshold { get; set; } - public string PaymentIdPrefix { get; set; } = string.Empty; - public string MinistryClient { get; set; } = string.Empty; - public string Responsibility { get; set; } = string.Empty; - public string ServiceLine { get; set; } = string.Empty; - public string Stob { get; set; } = string.Empty; - public string ProjectNumber { get; set; } = string.Empty; - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/CreatePaymentConfigurationDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/CreatePaymentConfigurationDto.cs similarity index 100% rename from applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/CreatePaymentConfigurationDto.cs rename to applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/CreatePaymentConfigurationDto.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/IPaymentConfigurationAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/IPaymentConfigurationAppService.cs similarity index 66% rename from applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/IPaymentConfigurationAppService.cs rename to applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/IPaymentConfigurationAppService.cs index e26fff6d0..6cd6ffcfc 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/IPaymentConfigurationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/IPaymentConfigurationAppService.cs @@ -4,11 +4,8 @@ namespace Unity.Payments.PaymentConfigurations { public interface IPaymentConfigurationAppService { - Task GetAsync(); - - Task CreateAsync(CreatePaymentConfigurationDto createPaymentConfigurationDto); - - Task UpdateAsync(UpdatePaymentConfigurationDto updatePaymentConfigurationDto); - Task GetAccountDistributionCodeAsync(); - } + Task GetAsync(); + Task UpdateAsync(UpdatePaymentConfigurationDto updatePaymentConfigurationDto); + Task CreateAsync(CreatePaymentConfigurationDto createUpdatePaymentConfigurationDto); + } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/PaymentConfigurationDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/PaymentConfigurationDto.cs similarity index 51% rename from applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/PaymentConfigurationDto.cs rename to applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/PaymentConfigurationDto.cs index 0bfeede64..fc91d2973 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/PaymentConfigurationDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/PaymentConfigurationDto.cs @@ -8,10 +8,5 @@ public class PaymentConfigurationDto : ExtensibleFullAuditedEntityDto { public decimal PaymentThreshold { get; set; } public string PaymentIdPrefix { get; set; } = string.Empty; - public string MinistryClient { get; set; } = string.Empty; - public string Responsibility { get; set; } = string.Empty; - public string ServiceLine { get; set; } = string.Empty; - public string Stob { get; set; } = string.Empty; - public string ProjectNumber { get; set; } = string.Empty; } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/UpdatePaymentConfigurationDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpdatePaymentConfigurationDto.cs similarity index 100% rename from applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfiguration/UpdatePaymentConfigurationDto.cs rename to applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpdatePaymentConfigurationDto.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs new file mode 100644 index 000000000..03e428b42 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs @@ -0,0 +1,11 @@ +using System; + +namespace Unity.Payments.PaymentConfigurations +{ + [Serializable] + public class UpsertPaymentConfigurationDtoBase + { + public decimal PaymentThreshold { get; set; } + public string PaymentIdPrefix { get; set; } = string.Empty; + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs index de9842e44..34ea5785a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs @@ -1,4 +1,6 @@ using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; using System.Linq; using Unity.Payments.Domain.Exceptions; using Volo.Abp; @@ -9,15 +11,18 @@ namespace Unity.Payments.Domain.AccountCodings { public class AccountCoding : FullAuditedAggregateRoot, IMultiTenant - { + { public Guid? TenantId { get; set; } - // Account Coding Fields - public virtual string? MinistryClient { get; private set; } = string.Empty; - public virtual string? Responsibility { get; private set; } = string.Empty; - public virtual string? ServiceLine { get; private set; } = string.Empty; - public virtual string? Stob { get; private set; } = string.Empty; - public virtual string? ProjectNumber { get; private set; } = string.Empty; + public string MinistryClient { get; set; } = string.Empty; + + public string Responsibility { get; set; } = string.Empty; + + public string ServiceLine { get; set; } = string.Empty; + + public string Stob { get; set; } = string.Empty; + + public string ProjectNumber { get; set; } = string.Empty; // Constructor for ORM protected AccountCoding() diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs new file mode 100644 index 000000000..10d039f6d --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Domain.Repositories; + +namespace Unity.Payments.Domain.AccountCodings; + +public interface IAccountCodingRepository : IRepository +{ + +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs index 193d1545f..f36505790 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs @@ -1,5 +1,4 @@ using System; -using Unity.Payments.Domain.AccountCodings; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; @@ -10,12 +9,6 @@ public class PaymentConfiguration : FullAuditedAggregateRoot, IMultiTenant public Guid? TenantId { get; set; } public string PaymentIdPrefix { get; set; } = string.Empty; public decimal? PaymentThreshold { get; set; } - public string? MinistryClient { get; private set; } - public string? Responsibility { get; private set; } - public string? ServiceLine { get; private set; } - public string? Stob { get; private set; } - public string? ProjectNumber { get; private set; } - protected PaymentConfiguration() { @@ -24,21 +17,10 @@ protected PaymentConfiguration() public PaymentConfiguration( decimal? paymentThreshold, - string paymentIdPrefix, - AccountCoding accountCoding) + string paymentIdPrefix) { PaymentThreshold = paymentThreshold; - PaymentIdPrefix = paymentIdPrefix; - SetAccountCoding(accountCoding); - } - - public void SetAccountCoding(AccountCoding accountCoding) - { - MinistryClient = accountCoding.MinistryClient; - Responsibility = accountCoding.Responsibility; - ServiceLine = accountCoding.ServiceLine; - Stob = accountCoding.Stob; - ProjectNumber = accountCoding.ProjectNumber; + PaymentIdPrefix = paymentIdPrefix; } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs index 01f567f80..a64451e5e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs @@ -12,12 +12,13 @@ namespace Unity.Payments.EntityFrameworkCore; [ConnectionStringName(PaymentsDbProperties.ConnectionStringName)] public class PaymentsDbContext : AbpDbContext, IPaymentsDbContext { + public DbSet PaymentRequests { get; set; } public DbSet AccountCoding { get; set; } public DbSet ExpenseApproval { get; set; } - public DbSet Suppliers { get; set; } - public DbSet PaymentConfigurations { get; set; } + public DbSet Suppliers { get;set; } + public DbSet PaymentConfigurations { get;set; } public DbSet Sites { get; set; } - public DbSet PaymentRequests { get; set; } + public PaymentsDbContext(DbContextOptions options) : base(options) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs index bd878752e..2caecc5f5 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs @@ -35,10 +35,10 @@ public class InvoiceService : ApplicationService, IInvoiceService private const string CFS_APINVOICE = "cfs/apinvoice"; - private readonly Dictionary CASPaymentGroup = new Dictionary + private readonly Dictionary CASPaymentGroup = new() { - { (int)PaymentGroup.EFT, "GEN EFT" }, - { (int)PaymentGroup.Cheque, "GEN CHQ" } + [(int)PaymentGroup.EFT] = "GEN EFT", + [(int)PaymentGroup.Cheque] = "GEN CHQ" }; public InvoiceService( @@ -62,9 +62,9 @@ public InvoiceService( } protected virtual async Task InitializeCASInvoice(PaymentRequest paymentRequest, - string? accountDistributionCode) + string? accountDistributionCode) { - Invoice? casInvoice = new Invoice(); + Invoice? casInvoice = new(); Site? site = await GetSiteByPaymentRequestAsync(paymentRequest); if (site != null && site.Supplier != null && site.Supplier.Number != null && accountDistributionCode != null) @@ -87,10 +87,12 @@ public InvoiceService( casInvoice.InvoiceBatchName = paymentRequest.BatchName; casInvoice.PaymentAdviceComments = paymentRequest.Description; - InvoiceLineDetail invoiceLineDetail = new InvoiceLineDetail(); - invoiceLineDetail.InvoiceLineNumber = 1; - invoiceLineDetail.InvoiceLineAmount = paymentRequest.Amount; - invoiceLineDetail.DefaultDistributionAccount = accountDistributionCode; // This will be at the tenant level + InvoiceLineDetail invoiceLineDetail = new() + { + InvoiceLineNumber = 1, + InvoiceLineAmount = paymentRequest.Amount, + DefaultDistributionAccount = accountDistributionCode // This will be at the tenant level + }; casInvoice.InvoiceLineDetails = new List { invoiceLineDetail }; } @@ -100,8 +102,11 @@ public InvoiceService( public async Task GetSiteByPaymentRequestAsync(PaymentRequest paymentRequest) { Site? site = await _iSiteRepository.GetAsync(paymentRequest.SiteId, true); - Supplier supplier = await _iSupplierRepository.GetAsync(site.SupplierId); - site.Supplier = supplier; + if (site?.SupplierId != null) + { + Supplier supplier = await _iSupplierRepository.GetAsync(site.SupplierId); + site.Supplier = supplier; + } return site; } @@ -111,26 +116,29 @@ public InvoiceService( try { PaymentRequest? paymentRequest = await _iPaymentRequestRepository.GetPaymentRequestByInvoiceNumber(invoiceNumber); - if (paymentRequest == null) + if (paymentRequest is null) { throw new UserFriendlyException("CreateInvoiceByPaymentRequestAsync: Payment Request not found"); } - string? accountDistributionCode = await _paymentConfigurationAppService.GetAccountDistributionCodeAsync(); - if (accountDistributionCode != null) + string? accountDistributionCode = ""; // Placeholder for actual logic + + if (!string.IsNullOrEmpty(accountDistributionCode)) { Invoice? invoice = await InitializeCASInvoice(paymentRequest, accountDistributionCode); - if (invoice != null) + if (invoice is not null) { invoiceResponse = await CreateInvoiceAsync(invoice); - if (invoiceResponse != null) + if (invoiceResponse is not null) { await UpdatePaymentRequestWithInvoice(paymentRequest.Id, invoiceResponse); } } } - } catch (Exception ex) { + } + catch (Exception ex) + { string ExceptionMessage = ex.Message; Logger.LogError(ex, "CreateInvoiceByPaymentRequestAsync Exception: {ExceptionMessage}", ExceptionMessage); } @@ -222,7 +230,7 @@ public async Task GetCasPaymentAsync(string invoiceNumbe var authToken = await _iTokenService.GetAuthTokenAsync(); var resource = $"{_casClientOptions.Value.CasBaseUrl}/{CFS_APINVOICE}/{invoiceNumber}/{supplierNumber}/{siteNumber}"; var response = await _resilientRestClient.HttpAsync(HttpMethod.Get, resource, authToken); - CasPaymentSearchResult casPaymentSearchResult = new CasPaymentSearchResult(); + CasPaymentSearchResult casPaymentSearchResult = new(); if (response != null && response.Content != null diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs index aa265cb5b..47c57e537 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs @@ -1,100 +1,61 @@ -using System.Threading.Tasks; -using Unity.Payments.Domain; -using Unity.Payments.Domain.AccountCodings; -using Unity.Payments.Domain.Exceptions; -using Unity.Payments.Domain.PaymentConfigurations; -using Volo.Abp.Features; - -namespace Unity.Payments.PaymentConfigurations -{ - [RequiresFeature("Unity.Payments")] - public class PaymentConfigurationAppService : PaymentsAppService, IPaymentConfigurationAppService - { - private readonly IPaymentConfigurationRepository _paymentConfigurationRepository; - - public PaymentConfigurationAppService(IPaymentConfigurationRepository paymentConfigurationRepository) - { - _paymentConfigurationRepository = paymentConfigurationRepository; - } - - public virtual async Task GetAsync() - { - PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); - - if (paymentConfiguration == null) { return null; } - - return ObjectMapper.Map(paymentConfiguration); - } - - public virtual async Task GetAccountDistributionCodeAsync() - { - PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); - string accountDistributionCode = ""; - if (paymentConfiguration != null - && paymentConfiguration.Responsibility != null - && paymentConfiguration.ServiceLine != null - && paymentConfiguration.Stob != null - && paymentConfiguration.MinistryClient != null - && paymentConfiguration.ProjectNumber != null) - { - string accountDistributionPostFix = "000000.0000"; - accountDistributionCode = - $"{paymentConfiguration.MinistryClient}.{paymentConfiguration.Responsibility}.{paymentConfiguration.ServiceLine}.{paymentConfiguration.Stob}.{paymentConfiguration.ProjectNumber}.{accountDistributionPostFix}"; - } - - return accountDistributionCode; - } - - public virtual async Task CreateAsync(CreatePaymentConfigurationDto createPaymentConfigurationDto) - { - PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); - - if (paymentConfiguration != null) - { - throw new ConfigurationExistsException(L[ErrorConsts.ConfigurationExists]); - } - - var newPaymentConfiguration = await _paymentConfigurationRepository.InsertAsync(new PaymentConfiguration - ( - createPaymentConfigurationDto.PaymentThreshold, - createPaymentConfigurationDto.PaymentIdPrefix, - AccountCoding.Create( - createPaymentConfigurationDto.MinistryClient, - createPaymentConfigurationDto.Responsibility, - createPaymentConfigurationDto.ServiceLine, - createPaymentConfigurationDto.Stob, - createPaymentConfigurationDto.ProjectNumber - ) - )); - - return ObjectMapper.Map(newPaymentConfiguration); - } - - public virtual async Task UpdateAsync(UpdatePaymentConfigurationDto updatePaymentConfigurationDto) - { - PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync() ?? - throw new ConfigurationExistsException(L[ErrorConsts.ConfigurationDoesNotExist]); - - paymentConfiguration.PaymentThreshold = updatePaymentConfigurationDto.PaymentThreshold; - paymentConfiguration.PaymentIdPrefix = updatePaymentConfigurationDto.PaymentIdPrefix; - - paymentConfiguration.SetAccountCoding(AccountCoding.Create(updatePaymentConfigurationDto.MinistryClient, - updatePaymentConfigurationDto.Responsibility, - updatePaymentConfigurationDto.ServiceLine, - updatePaymentConfigurationDto.Stob, - updatePaymentConfigurationDto.ProjectNumber)); - - var updatedConfiguration = await _paymentConfigurationRepository.UpdateAsync(paymentConfiguration); - - return ObjectMapper.Map(updatedConfiguration); - } - - - protected virtual async Task FindPaymentConfigurationAsync() - { - var paymentConfigurations = await _paymentConfigurationRepository.GetListAsync(); - var paymentConfiguration = paymentConfigurations.Count > 0 ? paymentConfigurations[0] : null; - return paymentConfiguration; - } - } -} +using System.Threading.Tasks; +using Unity.Payments.Domain.Exceptions; +using Unity.Payments.Domain.PaymentConfigurations; +using Volo.Abp.Features; + +namespace Unity.Payments.PaymentConfigurations +{ + [RequiresFeature("Unity.Payments")] + public class PaymentConfigurationAppService(IPaymentConfigurationRepository paymentConfigurationRepository) : PaymentsAppService, IPaymentConfigurationAppService + { + + + public virtual async Task GetAsync() + { + PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); + + if (paymentConfiguration == null) { return null; } + + return ObjectMapper.Map(paymentConfiguration); + } + + public virtual async Task CreateAsync(CreatePaymentConfigurationDto createPaymentConfigurationDto) + { + PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); + + if (paymentConfiguration != null) + { + throw new ConfigurationExistsException(L[ErrorConsts.ConfigurationExists]); + } + + var newPaymentConfiguration = await paymentConfigurationRepository.InsertAsync(new PaymentConfiguration + ( + createPaymentConfigurationDto.PaymentThreshold, + createPaymentConfigurationDto.PaymentIdPrefix + )); + + return ObjectMapper.Map(newPaymentConfiguration); + } + + public virtual async Task UpdateAsync(UpdatePaymentConfigurationDto updatePaymentConfigurationDto) + { + PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync() ?? + throw new ConfigurationExistsException(L[ErrorConsts.ConfigurationDoesNotExist]); + + paymentConfiguration.PaymentThreshold = updatePaymentConfigurationDto.PaymentThreshold; + paymentConfiguration.PaymentIdPrefix = updatePaymentConfigurationDto.PaymentIdPrefix; + + var updatedConfiguration = await paymentConfigurationRepository.UpdateAsync(paymentConfiguration); + + return ObjectMapper.Map(updatedConfiguration); + } + + + protected virtual async Task FindPaymentConfigurationAsync() + { + var paymentConfigurations = await paymentConfigurationRepository.GetListAsync(); + var paymentConfiguration = paymentConfigurations.Count > 0 ? paymentConfigurations[0] : null; + return paymentConfiguration; + } + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs index a42e2e81b..d00c88f6f 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs @@ -23,37 +23,19 @@ namespace Unity.Payments.PaymentRequests { [RequiresFeature("Unity.Payments")] [Authorize] - public class PaymentRequestAppService : PaymentsAppService, IPaymentRequestAppService - { - private readonly ICurrentUser _currentUser; - private readonly IDataFilter _dataFilter; - private readonly IExternalUserLookupServiceProvider _externalUserLookupServiceProvider; - private readonly IPaymentConfigurationRepository _paymentConfigurationRepository; - private readonly IPaymentsManager _paymentsManager; - private readonly IPaymentRequestRepository _paymentRequestsRepository; - private readonly IPermissionChecker _permissionChecker; - - public PaymentRequestAppService( + public class PaymentRequestAppService( ICurrentUser currentUser, IDataFilter dataFilter, IExternalUserLookupServiceProvider externalUserLookupServiceProvider, IPaymentConfigurationRepository paymentConfigurationRepository, IPaymentsManager paymentsManager, IPaymentRequestRepository paymentRequestsRepository, - IPermissionChecker permissionChecker) - { - _currentUser = currentUser; - _dataFilter = dataFilter; - _externalUserLookupServiceProvider = externalUserLookupServiceProvider; - _paymentConfigurationRepository = paymentConfigurationRepository; - _paymentsManager = paymentsManager; - _paymentRequestsRepository = paymentRequestsRepository; - _permissionChecker = permissionChecker; - } + IPermissionChecker permissionChecker) : PaymentsAppService, IPaymentRequestAppService + { protected virtual async Task<(PaymentConfiguration? Config, decimal Threshold)> GetPaymentConfigurationWithThresholdAsync() { - var paymentConfigs = await _paymentConfigurationRepository.GetListAsync(); + var paymentConfigs = await paymentConfigurationRepository.GetListAsync(); var paymentConfig = paymentConfigs.FirstOrDefault(); if (paymentConfig == null) @@ -106,7 +88,7 @@ public virtual async Task> CreateAsync(List GetMaxBatchNumberAsync() { - var paymentRequestList = await _paymentRequestsRepository.GetListAsync(); + var paymentRequestList = await paymentRequestsRepository.GetListAsync(); decimal batchNumber = 1; // Lookup max plus 1 if (paymentRequestList != null && paymentRequestList.Count > 0) { @@ -176,7 +158,7 @@ private async Task GetMaxBatchNumberAsync() public Task GetPaymentRequestCountBySiteIdAsync(Guid siteId) { - return _paymentRequestsRepository.GetPaymentRequestCountBySiteId(siteId); + return paymentRequestsRepository.GetPaymentRequestCountBySiteId(siteId); } public virtual async Task> UpdateStatusAsync(List paymentRequests) @@ -189,12 +171,12 @@ public virtual async Task> UpdateStatusAsync(List DetermineTriggerActionAsync( private async Task CanPerformLevel1ActionAsync(PaymentRequestStatus status) { List level1Approvals = new() { PaymentRequestStatus.L1Pending, PaymentRequestStatus.L1Declined }; - return await _permissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.L1ApproveOrDecline) && level1Approvals.Contains(status); + return await permissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.L1ApproveOrDecline) && level1Approvals.Contains(status); } private async Task CanPerformLevel2ActionAsync(PaymentRequest payment) { List level2Approvals = new() { PaymentRequestStatus.L2Pending, PaymentRequestStatus.L2Declined }; - return await _permissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.L2ApproveOrDecline) && level2Approvals.Contains(payment.Status); + return await permissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.L2ApproveOrDecline) && level2Approvals.Contains(payment.Status); } private async Task CanPerformLevel3ActionAsync(PaymentRequestStatus status) { List level3Approvals = new() { PaymentRequestStatus.L3Pending, PaymentRequestStatus.L3Declined }; - return await _permissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.L3ApproveOrDecline) && level3Approvals.Contains(status); + return await permissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.L3ApproveOrDecline) && level3Approvals.Contains(status); } private async Task CreatePaymentRequestDtoAsync(Guid paymentRequestId) { - var payment = await _paymentRequestsRepository.GetAsync(paymentRequestId); + var payment = await paymentRequestsRepository.GetAsync(paymentRequestId); return new PaymentRequestDto { Id = payment.Id, @@ -277,10 +259,10 @@ private async Task CreatePaymentRequestDtoAsync(Guid paymentR public async Task> GetListAsync(PagedAndSortedResultRequestDto input) { - var totalCount = await _paymentRequestsRepository.GetCountAsync(); - using (_dataFilter.Disable()) + var totalCount = await paymentRequestsRepository.GetCountAsync(); + using (dataFilter.Disable()) { - var payments = await _paymentRequestsRepository + var payments = await paymentRequestsRepository .GetPagedListAsync(input.SkipCount, input.MaxResultCount, input.Sorting ?? string.Empty, includeDetails: true); var mappedPayments = await MapToDtoAndLoadDetailsAsync(payments); @@ -315,7 +297,7 @@ protected internal async Task> MapToDtoAndLoadDetailsAsy var allUserIds = paymentRequesterIds.Concat(expenseApprovalCreatorIds).Distinct(); foreach (var userId in allUserIds) { - var userInfo = await _externalUserLookupServiceProvider.FindByIdAsync(userId); + var userInfo = await externalUserLookupServiceProvider.FindByIdAsync(userId); if (userInfo != null) { userDictionary[userId] = ObjectMapper.Map(userInfo); @@ -358,9 +340,9 @@ private static void ApplyErrorSummary(List mappedPayments) public async Task> GetListByApplicationIdAsync(Guid applicationId) { - using (_dataFilter.Disable()) + using (dataFilter.Disable()) { - var paymentsQueryable = await _paymentRequestsRepository.GetQueryableAsync(); + var paymentsQueryable = await paymentRequestsRepository.GetQueryableAsync(); var payments = await paymentsQueryable.Include(pr => pr.Site).ToListAsync(); var filteredPayments = payments.Where(e => e.CorrelationId == applicationId).ToList(); @@ -370,7 +352,7 @@ public async Task> GetListByApplicationIdAsync(Guid appl public async Task> GetListByPaymentIdsAsync(List paymentIds) { - var paymentsQueryable = await _paymentRequestsRepository.GetQueryableAsync(); + var paymentsQueryable = await paymentRequestsRepository.GetQueryableAsync(); var payments = await paymentsQueryable .Where(e => paymentIds.Contains(e.Id)) .Include(pr => pr.Site) @@ -381,17 +363,17 @@ public async Task> GetListByPaymentIdsAsync(List p public virtual async Task GetTotalPaymentRequestAmountByCorrelationIdAsync(Guid correlationId) { - return await _paymentRequestsRepository.GetTotalPaymentRequestAmountByCorrelationIdAsync(correlationId); + return await paymentRequestsRepository.GetTotalPaymentRequestAmountByCorrelationIdAsync(correlationId); } protected virtual string GetCurrentRequesterName() { - return $"{_currentUser.Name} {_currentUser.SurName}"; + return $"{currentUser.Name} {currentUser.SurName}"; } protected virtual async Task GetPaymentConfigurationAsync() { - var paymentConfigs = await _paymentConfigurationRepository.GetListAsync(); + var paymentConfigs = await paymentConfigurationRepository.GetListAsync(); if (paymentConfigs.Count > 0) { @@ -404,7 +386,7 @@ protected virtual string GetCurrentRequesterName() protected virtual async Task GetPaymentThresholdAsync() { - var paymentConfigs = await _paymentConfigurationRepository.GetListAsync(); + var paymentConfigs = await paymentConfigurationRepository.GetListAsync(); if (paymentConfigs.Count > 0) { @@ -418,7 +400,7 @@ protected virtual async Task GetPaymentThresholdAsync() private async Task GetNextSequenceNumberAsync(int currentYear) { // Retrieve all payment requests - var payments = await _paymentRequestsRepository.GetListAsync(); + var payments = await paymentRequestsRepository.GetListAsync(); // Filter payments for the current year var filteredPayments = payments diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs index 01c06379b..db1d8dcfd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs @@ -1,11 +1,13 @@ using AutoMapper; using Unity.Payments.PaymentRequests; using Unity.Payments.Domain.PaymentRequests; -using Unity.Payments.Domain.PaymentConfigurations; +using Unity.Payments.Domain.AccountCodings; using Unity.Payments.Domain.Suppliers; using Unity.Payments.PaymentConfigurations; +using Unity.Payments.Domain.PaymentConfigurations; using Unity.Payments.Suppliers; using Volo.Abp.Users; +using Unity.GrantManager.Payments; namespace Unity.Payments; @@ -26,6 +28,20 @@ public PaymentsApplicationAutoMapperProfile() .ForMember(dest => dest.PaymentGroup, opt => opt.MapFrom(s => s.PaymentGroup.ToString())); CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(dest => dest.TenantId, opt => opt.Ignore()) + .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) + .ForMember(dest => dest.DeleterId, opt => opt.Ignore()) + .ForMember(dest => dest.DeletionTime, opt => opt.Ignore()) + .ForMember(dest => dest.LastModificationTime, opt => opt.Ignore()) + .ForMember(dest => dest.LastModifierId, opt => opt.Ignore()) + .ForMember(dest => dest.CreationTime, opt => opt.Ignore()) + .ForMember(dest => dest.CreatorId, opt => opt.Ignore()) + .ForMember(dest => dest.ExtraProperties, opt => opt.Ignore()) + .ForMember(dest => dest.ConcurrencyStamp, opt => opt.Ignore()) + .ForMember(dest => dest.Id, opt => opt.Ignore()); CreateMap(); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml new file mode 100644 index 000000000..6c8dc64fe --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml @@ -0,0 +1,29 @@ +@page +@using Unity.GrantManager.Localization +@using Microsoft.Extensions.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal + +@model Unity.GrantManager.Web.Pages.AccountCoding.CreateModalModel + +@{ + Layout = null; +} + + + + + + + + + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs new file mode 100644 index 000000000..84a3102fd --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Unity.GrantManager.Payments; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Unity.GrantManager.Web.Pages.AccountCoding; + +public class CreateModalModel(IAccountCodingAppService accountCodingAppService) : AbpPageModel +{ + [BindProperty] + public CreateUpdateAccountCodingDto? AccountCoding { get; set; } + + public async Task OnPostAsync() + { + await accountCodingAppService.CreateAsync(AccountCoding!); + return NoContent(); + } +} + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml new file mode 100644 index 000000000..27eadbb7b --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml @@ -0,0 +1,24 @@ +@page +@using Unity.GrantManager.Localization +@using Microsoft.Extensions.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal + +@model Unity.GrantManager.Web.Pages.AccountCoding.UpdateModalModel + +@{ + Layout = null; +} + + + + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs new file mode 100644 index 000000000..752c5a6fd --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Unity.GrantManager.Payments; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Unity.GrantManager.Web.Pages.AccountCoding; + +public class UpdateModalModel(IAccountCodingAppService accountCodingAppService) : AbpPageModel +{ + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid Id { get; set; } + + [BindProperty] + public CreateUpdateAccountCodingDto? AccountCoding { get; set; } + + + public async Task OnGetAsync() + { + var accountCodingDto = await accountCodingAppService.GetAsync(Id); + AccountCoding = ObjectMapper.Map(accountCodingDto); + } + + public async Task OnPostAsync() + { + await accountCodingAppService.UpdateAsync(Id, AccountCoding!); + return NoContent(); + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml index 64acc78bf..6e1b3c43a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml @@ -1,7 +1,7 @@ @page -@model Unity.Payments.Web.Pages.PaymentConfigurations.CreatePaymentConfigurationModel + @{ - ViewBag.PageTitle = "Payment Configuration"; + ViewBag.PageTitle = "Account Codes"; } @section styles { @@ -14,8 +14,6 @@ } - -
@@ -24,7 +22,7 @@

Account Codes

- +
@@ -35,48 +33,5 @@
-Make this a modal - -

Account Coding

- - - - - - - -

Payment Settings

- - - - *
- - $ - - - - -
- - - * - - - - - - - - - -
-
\ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs index 58ef47150..4f4bd8ff4 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs @@ -1,101 +1,11 @@ using System; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Mvc; -using Unity.Payments.PaymentConfigurations; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; -namespace Unity.Payments.Web.Pages.PaymentConfigurations +namespace Unity.Payments.Web.Pages.AccountCoding { - public class CreatePaymentConfigurationModel : AbpPageModel + public class AccountCodingModel : AbpPageModel { - protected IPaymentConfigurationAppService PaymentConfigurationService { get; } - [BindProperty] - public PaymentConfigurationViewModel PaymentConfiguration { get; set; } = new(); - - [BindProperty] - public decimal PaymentThreshold { get; set; } - - [BindProperty] - public string PaymentIdPrefix { get; set; } = string.Empty; - - [TempData] - public string StatusMessage { get; set; } = string.Empty; - - - public CreatePaymentConfigurationModel(IPaymentConfigurationAppService iPaymentConfigurationService) - { - PaymentConfigurationService = iPaymentConfigurationService; - } - - public async Task OnGetAsync() - { - // Grab the current Payent Configuration - var paymentConfigurationDto = await PaymentConfigurationService.GetAsync(); - - if (paymentConfigurationDto != null) - { - PaymentThreshold = paymentConfigurationDto.PaymentThreshold; - PaymentIdPrefix = paymentConfigurationDto.PaymentIdPrefix; - PaymentConfiguration.MinistryClient = paymentConfigurationDto.MinistryClient; - PaymentConfiguration.Responsibility = paymentConfigurationDto.Responsibility; - PaymentConfiguration.Stob = paymentConfigurationDto.Stob; - PaymentConfiguration.ServiceLine = paymentConfigurationDto.ServiceLine; - PaymentConfiguration.ProjectNumber = paymentConfigurationDto.ProjectNumber; - } - } - - public async Task OnPostAsync() - { - if (ModelState.IsValid && PaymentConfiguration != null) - { - try - { - await UpsertPaymentConfigurationAsync(); - StatusMessage = "Successfully Saved Payment Settings."; - } - catch (Exception ex) - { - Logger.LogError(ex, message: "Exception in CreatePaymentConfigurationModel OnPostAsync"); - StatusMessage = "An error occurred while saving Payment Settings."; - } - } - - return Page(); - } - - private async Task UpsertPaymentConfigurationAsync() - { - var existing = await PaymentConfigurationService.GetAsync(); - - if (existing == null) - { - await PaymentConfigurationService.CreateAsync(new CreatePaymentConfigurationDto - { - PaymentThreshold = PaymentThreshold, - PaymentIdPrefix = PaymentIdPrefix, - MinistryClient = PaymentConfiguration.MinistryClient, - Responsibility = PaymentConfiguration.Responsibility, - Stob = PaymentConfiguration.Stob, - ServiceLine = PaymentConfiguration.ServiceLine, - ProjectNumber = PaymentConfiguration.ProjectNumber - }); - } - else - { - await PaymentConfigurationService.UpdateAsync(new UpdatePaymentConfigurationDto - { - PaymentThreshold = PaymentThreshold, - PaymentIdPrefix = PaymentIdPrefix, - MinistryClient = PaymentConfiguration.MinistryClient, - Responsibility = PaymentConfiguration.Responsibility, - Stob = PaymentConfiguration.Stob, - ServiceLine = PaymentConfiguration.ServiceLine, - ProjectNumber = PaymentConfiguration.ProjectNumber - }); - } - } } -} - +} \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css index 9a6808115..ada98d2f1 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css @@ -11,12 +11,6 @@ overflow: scroll; } -.field-validation-error { - float: inline-start; - display: block; - max-width: 332px; - width: 332px; -} .readonly { color: var(--bc-colors-grey-text-500); @@ -75,6 +69,22 @@ align-items: center; } +.field-validation-error { + float: inline-start; + display: block; + max-width: 100%; + width: 100%; +} + +.modal-dialog { + max-width: 850px !important; + min-width: 850px !important; +} + +input.form-control:focus, input.form-control:active, textarea.form-control:focus, textarea.form-control:active, .form-select:focus, .form-select:active { + font-weight: inherit !important; +} + @media only screen and (max-width: 850px) { .field-validation-error { float: none; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js index 99f8a540e..cb2eecfd5 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js @@ -1,26 +1,7 @@ $(function () { - const UIElements = { - inputMinistryClient: $('input[name="PaymentConfiguration.MinistryClient"]'), - inputResponsibility: $('input[name="PaymentConfiguration.Responsibility"]'), - inputServiceLine: $('input[name="PaymentConfiguration.ServiceLine"]'), - inputStob: $('input[name="PaymentConfiguration.Stob"]'), - inputProjectNumber: $('input[name="PaymentConfiguration.ProjectNumber"]'), - readOnlyAccountCoding: $('#account-coding'), - statusMessage: $('#status-message'), - inputPaymentIdPrefix: $('#PaymentIdPrefix') - }; - - init(); - - function init() { - bindUIEvents(); - setAccountCodingDisplay(); - displayStatusMessage(); - bindLimitedInputFields(/^[a-zA-Z0-9]+$/, [UIElements.inputPaymentIdPrefix[0].id]); - } - let createModal = new abp.ModalManager(abp.appPath + 'PaymentConfigurations/CreateModal'); - let updateModal = new abp.ModalManager(abp.appPath + 'PaymentConfigurations/UpdateModal'); + let createModal = new abp.ModalManager(abp.appPath + 'AccountCoding/CreateModal'); + let updateModal = new abp.ModalManager(abp.appPath + 'AccountCoding/UpdateModal'); const l = abp.localization.getResource('GrantManager'); /** * List All @@ -36,44 +17,44 @@ $(function () { }, ...commonTableActionButtons(l('Intake')) ]; - + let index = 0; const listColumns = [ { title: 'Ministry Client', name: "ministryClient", data: "ministryClient", - index: 0 + index: index }, { title: 'Responsibility', name: "responsibility", data: "responsibility", - index: 1 + index: index++ }, { title: 'Service Line', name: "serviceLine", data: "serviceLine", - index: 2 + index: index++ }, { title: 'Stob', name: "stob", data: "stob", - index: 3 + index: index++ }, { title: 'Project #', name: "projectNumber", data: "projectNumber", - index: 4 + index: index++ }, { - title: 'Default', + title: 'Action', orderable: false, className: 'notexport text-center', name: 'rowActions', - index: 5, + index: index++, rowAction: { items: [ @@ -85,11 +66,11 @@ $(function () { } }, { - title: '', + title: 'Default', orderable: false, className: 'notexport text-center', name: 'defaultRadio', - index: 6, + index: index++, rowAction: { items: [ @@ -136,10 +117,10 @@ $(function () { pagingEnabled: true, reorderEnabled: false, languageSetValues: {}, - dataTableName: 'IntakesTable', + dataTableName: 'AccountCodesDataTable', dynamicButtonContainerId: 'dynamicButtonContainerId', useNullPlaceholder: true, - externalSearchId: 'search-intakes' + externalSearchId: 'search-data-table' }); createModal.onResult(function () { @@ -153,60 +134,32 @@ $(function () { function createIntakeBtn(e) { e.preventDefault(); createModal.open(); - }; - - - function displayStatusMessage() { - let statusMessage = UIElements.statusMessage.val(); - if (statusMessage != "") { - if (statusMessage.indexOf('error') > 0) { - abp.notify.error( - UIElements.statusMessage.val(), - 'Error Occurred' - ); - } else { - abp.notify.success( - UIElements.statusMessage.val(), - 'Save Successful' - ); + createModal.onOpen(function () { + + const UIElements = { + inputMinistryClient: $('input[name="AccountCoding.MinistryClient"]'), + inputResponsibility: $('input[name="AccountCoding.Responsibility"]'), + inputServiceLine: $('input[name="AccountCoding.ServiceLine"]'), + inputStob: $('input[name="AccountCoding.Stob"]'), + inputProjectNumber: $('input[name="AccountCoding.ProjectNumber"]'), + readOnlyAccountCoding: $('#account-coding') + }; + + UIElements.inputMinistryClient.on('keyup', setAccountCodingDisplay); + UIElements.inputResponsibility.on('keyup', setAccountCodingDisplay); + UIElements.inputServiceLine.on('keyup', setAccountCodingDisplay); + UIElements.inputStob.on('keyup', setAccountCodingDisplay); + UIElements.inputProjectNumber.on('keyup', setAccountCodingDisplay); + + function setAccountCodingDisplay() { + let currentAccount = $(UIElements.inputMinistryClient).val() + "." + + $(UIElements.inputResponsibility).val() + "." + + $(UIElements.inputServiceLine).val() + "." + + $(UIElements.inputStob).val() + "." + + $(UIElements.inputProjectNumber).val(); + + $(UIElements.readOnlyAccountCoding).val(currentAccount); } - } - } - - function bindUIEvents() { - UIElements.inputMinistryClient.on('keyup', setAccountCodingDisplay); - UIElements.inputResponsibility.on('keyup', setAccountCodingDisplay); - UIElements.inputServiceLine.on('keyup', setAccountCodingDisplay); - UIElements.inputStob.on('keyup', setAccountCodingDisplay); - UIElements.inputProjectNumber.on('keyup', setAccountCodingDisplay); - } - - function bindLimitedInputFields(regex, fieldIds) { - fieldIds.forEach((id) => { - let inputElement = document.getElementById(id); - inputElement.addEventListener('input', function (_) { - let value = inputElement.value; - let lastChar = value.charAt(value.length - 1); - - if (!regex.test(lastChar)) { - inputElement.value = value.slice(0, -1); - } - - inputElement.value = inputElement.value.toUpperCase(); - }); }); - } - - function setAccountCodingDisplay() { - let currentAccount = $(UIElements.inputMinistryClient).val() + "." + - $(UIElements.inputResponsibility).val() + "." + - $(UIElements.inputServiceLine).val() + "." + - $(UIElements.inputStob).val() + "." + - $(UIElements.inputProjectNumber).val(); - $(UIElements.readOnlyAccountCoding).val(currentAccount); - } - $('#resetButton').click(function () { - $('#paymentConfigForm')[0].reset(); - setAccountCodingDisplay(); - }); + }; }); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/PaymentConfigurationViewModel.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/PaymentConfigurationViewModel.cs deleted file mode 100644 index 1d3db92c7..000000000 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/PaymentConfigurationViewModel.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; - -namespace Unity.Payments.Web.Pages.PaymentConfigurations -{ - public class PaymentConfigurationViewModel - { - [DisplayName("Ministry Client")] - [Required] - [RegularExpression("([a-zA-Z0-9]+)", ErrorMessage = "{0} does not match the pattern of only non-special characters.")] - [StringLength(3, MinimumLength = 3, ErrorMessage = "{0} must have a minimum of {1} characters.")] - [MaxLength(3, ErrorMessage = "{0} must have a max of {1} characters.")] - [DisplayOrder(10004)] - public string MinistryClient { get; set; } = string.Empty; - - [DisplayName("Responsibility")] - [Required] - [RegularExpression("([a-zA-Z0-9]+)", ErrorMessage = "{0} does not match the pattern of only non-special characters.")] - [StringLength(5, MinimumLength = 5, ErrorMessage = "{0} must have a minimum of {1} characters.")] - [MaxLength(5, ErrorMessage = "{0} must have a max of {1} characters.")] - [DisplayOrder(10004)] - public string Responsibility { get; set; } = string.Empty; - - [DisplayName("Service Line")] - [Required] - [RegularExpression("([0-9]+)", ErrorMessage = "{0} does not match the pattern of only digits.")] - [StringLength(5, MinimumLength = 5, ErrorMessage = "{0} must have a minimum of {1} digits.")] - [MaxLength(5, ErrorMessage = "{0} must have a minimum of {1} digits.")] - [DisplayOrder(10004)] - public string ServiceLine { get; set; } = string.Empty; - - [DisplayName("Stob")] - [Required] - [RegularExpression("([0-9]+)", ErrorMessage = "{0} does not match the pattern of only digits.")] - [StringLength(4, MinimumLength = 4, ErrorMessage = "{0} must have a minimum of {1} digits.")] - [MaxLength(4, ErrorMessage = "{0} must have a max of {1} digit.s")] - [DisplayOrder(10005)] - public string Stob { get; set; } = string.Empty; - - [DisplayName("Project #")] - [Required] - [RegularExpression("([0-9]+)", ErrorMessage = "{0} does not match the pattern of only digits.")] - [StringLength(7, MinimumLength = 7, ErrorMessage = "{0} must have a minimum of {1} digits.")] - [MaxLength(7, ErrorMessage = "{0} must have a max of {1} digits.")] - [DisplayOrder(10005)] - public string ProjectNumber { get; set; } = string.Empty; - - //Must be a valid and enabled accont combination in CFS. - //Format: XXX.XXXXX.XXXXX.XXXX.XXXXXXX.XXXXXX.XXXX - // 0TW.51OCG.00000.5717.5100000.000000.0000 - // BCGOV_CL.BCGOV_RSP.BCGOV_SRVC.BCGOV_STOB.BCGOV_PROJ + 000000.0000 - } -} - diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs deleted file mode 100644 index 0957412c8..000000000 --- a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs +++ /dev/null @@ -1,98 +0,0 @@ -using Xunit; -using Shouldly; -using Unity.Payments.Domain.PaymentConfigurations; -using System.ComponentModel; - -namespace Unity.Payments.PaymentConfigurations -{ - [Category("Domain")] - public class AccountCoding_Tests : PaymentsApplicationTestBase - { - [Fact] - public void Create_ValidParameters_ShouldNotThrow() - { - // Arrange - // Act - var accountCoding = AccountCoding.Create( - ministryClient: "0TW", - responsibility: "51OCG", - serviceLine: "00000", - stob: "5717", - projectNumber: "5100000" - ); - - // Assert - accountCoding.ShouldNotBeNull(); - } - - [Fact] - public void Create_InvalidMinistryClient_ShouldThrow() - { - // Arrange - // Act - // Assert - Assert.Throws(() => AccountCoding.Create( - ministryClient: "12345", // Invalid - projectNumber: "1234567890", - responsibility: "123", - serviceLine: "123456", - stob: "12345678")); - } - - [Fact] - public void Create_InvalidProjectNumber_ShouldThrow() - { - // Arrange - // Act - // Assert - Assert.Throws(() => AccountCoding.Create( - ministryClient: "1234", - projectNumber: "1234567890123", // Invalid - responsibility: "123", - serviceLine: "123456", - stob: "12345678")); - } - - [Fact] - public void Create_InvalidReposibility_ShouldThrow() - { - // Arrange - // Act - // Assert - Assert.Throws(() => AccountCoding.Create( - ministryClient: "1234", - projectNumber: "1234567890", - responsibility: "1234", // Invalid - serviceLine: "123456", - stob: "12345678")); - } - - [Fact] - public void Create_InvalidServiceLine_ShouldThrow() - { - // Arrange - // Act - // Assert - Assert.Throws(() => AccountCoding.Create( - ministryClient: "1234", - projectNumber: "1234567890", - responsibility: "123", - serviceLine: "1234567", // Invalid - stob: "12345678")); - } - - [Fact] - public void Create_InvalidStob_ShouldThrow() - { - // Arrange - // Act - // Assert - Assert.Throws(() => AccountCoding.Create( - ministryClient: "1234", - projectNumber: "1234567890", - responsibility: "123", - serviceLine: "123456", - stob: "123456789")); // Invalid - } - } -} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/PaymentConfigurationAppService_Tests.cs b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/PaymentConfigurationAppService_Tests.cs deleted file mode 100644 index d3a014a10..000000000 --- a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/PaymentConfigurationAppService_Tests.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Shouldly; -using System.Threading.Tasks; -using Unity.Payments.Domain.PaymentConfigurations; -using Xunit; - -namespace Unity.Payments.PaymentConfigurations -{ - public class PaymentConfigurationAppService_Tests : PaymentsApplicationTestBase - { - private readonly IPaymentConfigurationAppService _paymentConfigurationAppService; - private readonly IPaymentConfigurationRepository _paymentConfigurationRepository; - - public PaymentConfigurationAppService_Tests() - { - _paymentConfigurationAppService = GetRequiredService(); - _paymentConfigurationRepository = GetRequiredService(); - } - - [Fact] - [Trait("Category", "Integration")] - public async Task GetAsync_GetsConfiguration() - { - // Arrange - var inserted = await _paymentConfigurationRepository.InsertAsync(new PaymentConfiguration( - paymentThreshold: 500, - paymentIdPrefix: "CGG", - AccountCoding.Create( - ministryClient: "0TW", - responsibility: "51OCG", - serviceLine: "00000", - stob: "5717", - projectNumber: "5100000" - ) - ), true); - // Act - var result = await _paymentConfigurationAppService.GetAsync(); - - // Assert - result.ShouldNotBeNull(); - result.Id.ShouldBe(inserted.Id); - } - - [Fact] - [Trait("Category", "Integration")] - public async Task CreateAsync_AddsConfiguration() - { - // Arrange - var createPaymentConfigurationDto = new CreatePaymentConfigurationDto() - { - PaymentThreshold = 500, - MinistryClient = "0TW", - ProjectNumber = "5100000", - Responsibility = "51OCG", - ServiceLine = "00000", - Stob = "5717" - }; - - - // Act - var created = await _paymentConfigurationAppService.CreateAsync(createPaymentConfigurationDto); - var result = await _paymentConfigurationRepository.GetAsync(created.Id); - - // Assert - result.ShouldNotBeNull(); - result.MinistryClient.ShouldBe("0TW"); - result.ProjectNumber.ShouldBe("5100000"); - result.Responsibility.ShouldBe("51OCG"); - result.ServiceLine.ShouldBe("00000"); - result.Stob.ShouldBe("5717"); - result.PaymentThreshold.ShouldBe(500); - } - - [Fact] - [Trait("Category", "Integration")] - public async Task UpdateAsync_UpdatesConfiguration() - { - // Arrange - _ = await _paymentConfigurationRepository.InsertAsync(new PaymentConfiguration( - paymentThreshold: 500, - paymentIdPrefix: "CGG", - AccountCoding.Create( - ministryClient: "0TW", - responsibility: "51OCG", - serviceLine: "00000", - stob: "5717", - projectNumber: "5100000" - ) - ), true); - - // Act - var updated = await _paymentConfigurationAppService.UpdateAsync(new UpdatePaymentConfigurationDto() - { - MinistryClient = "0TW", - PaymentThreshold = 1000, - ProjectNumber = "5200000", - Responsibility = "51OCG", - ServiceLine = "00000", - Stob = "5718" - }); - - var result = await _paymentConfigurationRepository.GetAsync(updated.Id); - - // Assert - result.ShouldNotBeNull(); - result.MinistryClient.ShouldBe("0TW"); - result.ProjectNumber.ShouldBe("5200000"); - result.Responsibility.ShouldBe("51OCG"); - result.ServiceLine.ShouldBe("00000"); - result.Stob.ShouldBe("5718"); - result.PaymentThreshold.ShouldBe(1000); - } - } -} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs index 468ff56db..0e277d2ff 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/AccountCodingDto.cs @@ -4,7 +4,7 @@ namespace Unity.GrantManager.Payments { public class AccountCodingDto : AuditedEntityDto - { +{ public string? MinistryClient { get; private set; } = string.Empty; public string? Responsibility { get; private set; } = string.Empty; public string? ServiceLine { get; private set; } = string.Empty; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs index b21c2c7ca..0a5e5f87b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs @@ -1,20 +1,46 @@ -using System.ComponentModel; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Application.Dtos; + namespace Unity.GrantManager.Payments { public class CreateUpdateAccountCodingDto { [DisplayName("Ministry Client")] - public string? MinistryClient { get; private set; } = string.Empty; + [Required] + [RegularExpression("([a-zA-Z0-9]+)", ErrorMessage = "{0} does not match the pattern of only non-special characters.")] + [StringLength(3, MinimumLength = 3, ErrorMessage = "{0} must have a minimum of {1} characters.")] + [MaxLength(3, ErrorMessage = "{0} must have a max of {1} characters.")] + public string? MinistryClient { get; init; } = string.Empty; [DisplayName("Responsibility")] - public string? Responsibility { get; private set; } = string.Empty; + [Required] + [RegularExpression("([a-zA-Z0-9]+)", ErrorMessage = "{0} does not match the pattern of only non-special characters.")] + [StringLength(5, MinimumLength = 5, ErrorMessage = "{0} must have a minimum of {1} characters.")] + [MaxLength(5, ErrorMessage = "{0} must have a max of {1} characters.")] + public string? Responsibility { get; init; } = string.Empty; [DisplayName("Service Line")] - public string? ServiceLine { get; private set; } = string.Empty; + [Required] + [RegularExpression("([a-zA-Z0-9]+)", ErrorMessage = "{0} does not match the pattern of only non-special characters.")] + [StringLength(5, MinimumLength = 5, ErrorMessage = "{0} must have a minimum of {1} characters.")] + [MaxLength(5, ErrorMessage = "{0} must have a minimum of {1} characters.")] + public string? ServiceLine { get; init; } = string.Empty; + [DisplayName("Stob")] - public string? Stob { get; private set; } = string.Empty; - [DisplayName("Project Number")] - public string? ProjectNumber { get; private set; } = string.Empty; + [Required] + [RegularExpression("([a-zA-Z0-9]+)", ErrorMessage = "{0} does not match the pattern of only non-special characters.")] + [StringLength(4, MinimumLength = 4, ErrorMessage = "{0} must have a minimum of {1} characters.")] + [MaxLength(4, ErrorMessage = "{0} must have a max of {1} characters.")] + public string? Stob { get; init; } = string.Empty; + + [DisplayName("Project #")] + [Required] + [RegularExpression("([a-zA-Z0-9]+)", ErrorMessage = "{0} does not match the pattern of only non-special characters.")] + [StringLength(7, MinimumLength = 7, ErrorMessage = "{0} must have a minimum of {1} characters.")] + [MaxLength(7, ErrorMessage = "{0} must have a max of {1} characters.")] + public string? ProjectNumber { get; init; } = string.Empty; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs new file mode 100644 index 000000000..e75d51bce --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading.Tasks; +using Unity.Payments.Domain.AccountCodings; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; +using Volo.Abp.Domain.Repositories; + +namespace Unity.GrantManager.Payments +{ + public class AccountCodingAppService : + CrudAppService< + AccountCoding, + AccountCodingDto, + System.Guid, + PagedAndSortedResultRequestDto, + CreateUpdateAccountCodingDto>, IAccountCodingAppService + { + public AccountCodingAppService(IRepository repository) + : base(repository) + { + } + } +} From 18237b490ecdb83ac46a20eec66e5d1067cb4340 Mon Sep 17 00:00:00 2001 From: jpasta Date: Thu, 24 Apr 2025 13:55:18 -0700 Subject: [PATCH 03/30] feature/AB#28691-AccountCodingOnTab --- .../Domain/AccountCodings/AccountCoding.cs | 12 +-- .../IAccountCodingRepository.cs | 2 +- .../PaymentConfiguration.cs | 1 + .../Repositories/AccountCodingRepository.cs | 15 +++ .../PaymentConfigurationAppService.cs | 25 ++++- .../PaymentsPermissionDefinitionProvider.cs | 1 + .../Localization/Payments/en.json | 3 +- .../Permissions/PaymentsPermissions.cs | 1 + .../Pages/AccountCoding/CreateModal.cshtml | 3 - .../Pages/AccountCoding/UpdateModal.cshtml | 2 - .../Pages/PaymentConfigurations/Index.js | 41 ++++---- .../UX2/Components/Topbar/Default.cshtml | 9 +- .../ApplicationForms/ApplicationFormDto.cs | 2 + .../FormPaymentConfiguration.cs | 13 +++ .../Payments/CreateUpdateAccountCodingDto.cs | 4 +- .../ApplicationFormAppService.cs | 17 +++- .../Payments/AccountCodingAppService.cs | 3 +- .../Applications/ApplicationForm.cs | 4 +- .../20250409224221_AccountCoding.cs | 95 ++++++++++++++++++- .../Pages/ApplicationForms/Mapping.cshtml | 7 +- .../CreateUpdateApplicationFormViewModel.cs | 5 - .../PaymentConfiguration/Default.cshtml | 70 ++++++++++++++ .../PaymentConfiguration/Default.css | 1 + .../PaymentConfiguration/Default.js | 94 ++++++++++++++++++ .../PaymentConfigurationController.cs | 15 +++ .../PaymentConfigurationViewComponent.cs | 76 +++++++++++++++ .../PaymentConfigurationViewModel.cs | 28 ++++++ 27 files changed, 493 insertions(+), 56 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/AccountCodingRepository.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationController.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs index 34ea5785a..70615659d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs @@ -1,6 +1,4 @@ using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; using System.Linq; using Unity.Payments.Domain.Exceptions; using Volo.Abp; @@ -31,11 +29,11 @@ protected AccountCoding() } public AccountCoding( - string? ministryClient, - string? responsibility, - string? serviceLine, - string? stob, - string? projectNumber) + string ministryClient, + string responsibility, + string serviceLine, + string stob, + string projectNumber) { MinistryClient = ministryClient; Responsibility = responsibility; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs index 10d039f6d..ab91c12f1 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/IAccountCodingRepository.cs @@ -3,7 +3,7 @@ namespace Unity.Payments.Domain.AccountCodings; -public interface IAccountCodingRepository : IRepository +public interface IAccountCodingRepository : IBasicRepository { } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs index f36505790..5da3260a6 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs @@ -7,6 +7,7 @@ namespace Unity.Payments.Domain.PaymentConfigurations public class PaymentConfiguration : FullAuditedAggregateRoot, IMultiTenant { public Guid? TenantId { get; set; } + public Guid? DeafaultAccountCodingId { get; set; } public string PaymentIdPrefix { get; set; } = string.Empty; public decimal? PaymentThreshold { get; set; } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/AccountCodingRepository.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/AccountCodingRepository.cs new file mode 100644 index 000000000..436c131f4 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/AccountCodingRepository.cs @@ -0,0 +1,15 @@ +using System; +using Unity.Payments.Domain.AccountCodings; +using Unity.Payments.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Unity.Payments.Repositories +{ + public class AccountCodingRepository : EfCoreRepository, IAccountCodingRepository + { + public AccountCodingRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs index 47c57e537..65d01d7c0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Unity.Payments.Domain.AccountCodings; using Unity.Payments.Domain.Exceptions; using Unity.Payments.Domain.PaymentConfigurations; using Volo.Abp.Features; @@ -19,7 +20,25 @@ public class PaymentConfigurationAppService(IPaymentConfigurationRepository paym return ObjectMapper.Map(paymentConfiguration); } - public virtual async Task CreateAsync(CreatePaymentConfigurationDto createPaymentConfigurationDto) + public virtual Task GetAccountDistributionCode(AccountCoding accountCoding) + { + string accountDistributionCode = ""; + if (accountCoding != null + && accountCoding.Responsibility != null + && accountCoding.ServiceLine != null + && accountCoding.Stob != null + && accountCoding.MinistryClient != null + && accountCoding.ProjectNumber != null) + { + string accountDistributionPostFix = "000000.0000"; + accountDistributionCode = + $"{accountCoding.MinistryClient}.{accountCoding.Responsibility}.{accountCoding.ServiceLine}.{accountCoding.Stob}.{accountCoding.ProjectNumber}.{accountDistributionPostFix}"; + } + + return Task.FromResult(accountDistributionCode); + } + + public virtual async Task CreateAsync(CreatePaymentConfigurationDto createUpdatePaymentConfigurationDto) { PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); @@ -30,8 +49,8 @@ public virtual async Task CreateAsync(CreatePaymentConf var newPaymentConfiguration = await paymentConfigurationRepository.InsertAsync(new PaymentConfiguration ( - createPaymentConfigurationDto.PaymentThreshold, - createPaymentConfigurationDto.PaymentIdPrefix + createUpdatePaymentConfigurationDto.PaymentThreshold, + createUpdatePaymentConfigurationDto.PaymentIdPrefix )); return ObjectMapper.Map(newPaymentConfiguration); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs index 721035dda..e6455c8f5 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs @@ -17,6 +17,7 @@ public override void Define(IPermissionDefinitionContext context) paymentsPermissions.AddChild(PaymentsPermissions.Payments.L3ApproveOrDecline, L("Permission:Payments.L3ApproveOrDecline")); paymentsPermissions.AddChild(PaymentsPermissions.Payments.RequestPayment, L("Permission:Payments.RequestPayment")); paymentsPermissions.AddChild(PaymentsPermissions.Payments.EditSupplierInfo, L("Permission:Payments.EditSupplierInfo")); + paymentsPermissions.AddChild(PaymentsPermissions.Payments.EditFormPaymentConfiguration, L("Permission:Payments.EditFormPaymentConfiguration")); } private static LocalizableString L(string name) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json index 0493edd6f..c30b2d396 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json @@ -109,6 +109,7 @@ "Permission:Payments.L2ApproveOrDecline": "Approve/Decline L2 Payments", "Permission:Payments.L3ApproveOrDecline": "Approve/Decline L3 Payments", "Permission:Payments.RequestPayment": "Request Payment", - "Permission:Payments.EditSupplierInfo": "Update Supplier Info" + "Permission:Payments.EditSupplierInfo": "Update Supplier Info", + "Permission:Payments.EditFormPaymentConfiguration": "Edit Form Payment Configuration" } } \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs index 531c62646..fc2891703 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Permissions/PaymentsPermissions.cs @@ -15,6 +15,7 @@ public static class Payments public const string Decline = Default + ".Decline"; public const string RequestPayment = Default + ".RequestPayment"; public const string EditSupplierInfo = Default + ".EditSupplierInfo"; + public const string EditFormPaymentConfiguration = Default + ".EditFormPaymentConfiguration"; } public static string[] GetAll() diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml index 6c8dc64fe..4b0a22858 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml @@ -1,8 +1,5 @@ @page -@using Unity.GrantManager.Localization -@using Microsoft.Extensions.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal - @model Unity.GrantManager.Web.Pages.AccountCoding.CreateModalModel @{ diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml index 27eadbb7b..6e7cacedc 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml @@ -1,6 +1,4 @@ @page -@using Unity.GrantManager.Localization -@using Microsoft.Extensions.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @model Unity.GrantManager.Web.Pages.AccountCoding.UpdateModalModel diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js index cb2eecfd5..f03167aad 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js @@ -18,58 +18,63 @@ $(function () { ...commonTableActionButtons(l('Intake')) ]; let index = 0; - const listColumns = [ + const listColumns = [ { title: 'Ministry Client', name: "ministryClient", data: "ministryClient", - index: index + visible: true, + index: index++ }, { title: 'Responsibility', name: "responsibility", data: "responsibility", + visible: true, index: index++ }, { title: 'Service Line', name: "serviceLine", data: "serviceLine", + visible: true, index: index++ }, { title: 'Stob', name: "stob", data: "stob", + visible: true, index: index++ }, { title: 'Project #', name: "projectNumber", data: "projectNumber", + visible: true, index: index++ - }, + }, { - title: 'Action', + title: 'Default', orderable: false, + visible: true, className: 'notexport text-center', - name: 'rowActions', + name: 'defaultRadio', index: index++, - rowAction: { - items: - [ - { - text: 'Edit', - action: (data) => updateModal.open({ id: data.record.id }) - } - ] + data: 'id', + render: function (data, type, full, meta) { + let checked = '';//UIElements.siteId.val() == data ? 'checked' : '' -------- '${data}'; + + return ``; } }, { - title: 'Default', + title: 'Action', orderable: false, + data: 'id', className: 'notexport text-center', - name: 'defaultRadio', + name: 'rowActions', + visible: true, index: index++, rowAction: { items: @@ -80,7 +85,7 @@ $(function () { } ] } - } + } ]; const defaultVisibleColumns = [ @@ -89,8 +94,8 @@ $(function () { 'serviceLine', 'stob', 'projectNumber', - 'rowActions', - 'defaultRadio' + 'defaultRadio', + 'rowActions', ]; diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Themes/UX2/Components/Topbar/Default.cshtml b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Themes/UX2/Components/Topbar/Default.cshtml index 78cf044db..d31fa1bcb 100644 --- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Themes/UX2/Components/Topbar/Default.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/Themes/UX2/Components/Topbar/Default.cshtml @@ -32,6 +32,8 @@ bool isAuthorizedForTenantSwitch = false; if (CurrentUser.IsAuthenticated && CurrentUser.FindClaims("tenant").Length > 1) isAuthorizedForTenantSwitch = true; + + bool isAuthorizedForPaymentConfiguration = await PermissionChecker.IsGrantedAsync("SettingManagement.ConfigurePayments"); } @@ -40,11 +42,10 @@ { Switch Grant Programs } - @if (await FeatureChecker.IsEnabledAsync("Unity.Payments")) + @if (await FeatureChecker.IsEnabledAsync("Unity.Payments") && isAuthorizedForPaymentConfiguration) { - /* To be moved to a settings */ - Payments Configuration - } + Payments Configuration + } @if (await FeatureChecker.IsEnabledAsync("Unity.Flex")) { Scoresheets Configuration diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs index 0aa1fbb16..d48f5bd36 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/ApplicationFormDto.cs @@ -20,6 +20,8 @@ public class ApplicationFormDto : EntityDto public string? ConnectionHttpStatus { get; set; } public DateTime? AttemptedConnectionDate { get; set; } public bool Payable { get; set; } + public bool PreventPayment { get; set; } + public Guid AccountCodingId { get; set; } public bool RenderFormIoToHtml { get; set; } public Guid? ScoresheetId { get; set; } public Guid? TenantId { get; set; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs new file mode 100644 index 000000000..0ba115eba --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs @@ -0,0 +1,13 @@ +using System; + +namespace Unity.GrantManager.ApplicationForms +{ + [Serializable] + public class FormPaymentConfigurationDto + { + public Guid ApplicationFormId { get; set; } + public Guid? AccountCodingId { get; set; } + public bool PreventPayment { get; set; } + public bool Payable { get; set; } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs index 0a5e5f87b..e756eee33 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/CreateUpdateAccountCodingDto.cs @@ -1,7 +1,5 @@ -using System; -using System.ComponentModel; +using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using Volo.Abp.Application.Dtos; namespace Unity.GrantManager.Payments diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index eff6ef090..05afb983c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -64,10 +64,10 @@ public override async Task UpdateAsync(Guid id, CreateUpdate if (hasFormGuidChanged || hasFormApiKeyChanged) { return await InitializeFormVersion(id, input); - } - else - { - return await base.UpdateAsync(id, input); + } + else + { + return await base.UpdateAsync(id, input); } } @@ -129,5 +129,14 @@ public async Task SaveApplicationFormScoresheet(FormScoresheetDto dto) appForm.ScoresheetId = dto.ScoresheetId; await _applicationFormRepository.UpdateAsync(appForm); } + + public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) + { + ApplicationForm appForm = await _applicationFormRepository.GetAsync(dto.ApplicationFormId); + appForm.AccountCodingId = dto.AccountCodingId; + appForm.Payable = dto.Payable; + appForm.PreventPayment = dto.PreventPayment; + await _applicationFormRepository.UpdateAsync(appForm); + } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs index e75d51bce..4a0e75f0d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/AccountCodingAppService.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using Unity.Payments.Domain.AccountCodings; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; @@ -11,7 +10,7 @@ public class AccountCodingAppService : CrudAppService< AccountCoding, AccountCodingDto, - System.Guid, + Guid, PagedAndSortedResultRequestDto, CreateUpdateAccountCodingDto>, IAccountCodingAppService { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs index 46289493a..65ce973d5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs @@ -19,7 +19,9 @@ public class ApplicationForm : FullAuditedAggregateRoot, IMultiTenant public string? Category { get; set; } public string? ConnectionHttpStatus { get; set; } public DateTime? AttemptedConnectionDate { get; set; } - public bool Payable { get; set; } + public bool Payable { get; set; } + public bool PreventPayment { get; set; } + public Guid? AccountCodingId { get; set; } public Guid? ScoresheetId { get; set; } public Guid? TenantId { get; set; } public bool RenderFormIoToHtml { get; set; } = false; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs index c16c36fab..61c89b11d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs @@ -37,12 +37,105 @@ protected override void Up(MigrationBuilder migrationBuilder) { table.PrimaryKey("PK_AccountCodings", x => x.Id); table.UniqueConstraint("UK_AccountCodings", x => new { x.MinistryClient, x.Responsibility, x.ServiceLine, x.Stob, x.ProjectNumber }); - }); + }); + + migrationBuilder.AddColumn( + name: "DefaultAccountCodingId", + table: "PaymentConfigurations", + type: "uuid", + nullable: false, + schema: "Payments", + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + migrationBuilder.CreateIndex( + name: "IX_PaymentConfiguration_DefaultAccountCodingId", + schema: "Payments", + table: "PaymentConfigurations", + column: "DefaultAccountCodingId"); + + migrationBuilder.AddForeignKey( + name: "FK_PaymentConfiguration_AccountCodings_Id", + schema: "Payments", + table: "PaymentConfigurations", + column: "DefaultAccountCodingId", + principalSchema: "Payments", + principalTable: "AccountCodings", + principalColumn: "Id"); + + migrationBuilder.AddColumn( + name: "PreventPayment", + table: "ApplicationForms", + type: "bool", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "AccountCodingId", + table: "ApplicationForms", + type: "uuid", + nullable: true, + defaultValue: null); + + migrationBuilder.CreateIndex( + name: "IX_ApplicationForms_AccountCodingId", + table: "ApplicationForms", + column: "AccountCodingId"); + + migrationBuilder.AddForeignKey( + name: "FK_ApplicationForms_AccountCodings_Id", + table: "ApplicationForms", + column: "AccountCodingId", + principalSchema: "Payments", + principalTable: "AccountCodings", + principalColumn: "Id"); + + migrationBuilder.DropColumn( + name: "MinistryClient", + table: "PaymentConfigurations", + schema: "Payments"); + + migrationBuilder.DropColumn( + name: "Responsibility", + table: "PaymentConfigurations", + schema: "Payments"); + + migrationBuilder.DropColumn( + name: "ServiceLine", + table: "PaymentConfigurations", + schema: "Payments"); + + migrationBuilder.DropColumn( + name: "Stob", + table: "PaymentConfigurations", + schema: "Payments"); + + migrationBuilder.DropColumn( + name: "ProjectNumber", + table: "PaymentConfigurations", + schema: "Payments"); + } /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropForeignKey( + name: "FK_ApplicationForms_AccountCodings_Id", + table: "ApplicationForms"); + + migrationBuilder.DropColumn( + name: "PreventPayment", + table: "ApplicationForms"); + + migrationBuilder.DropColumn( + name: "DefaultAccountCodingId", + table: "PaymentConfigurations", + schema: "Payments"); + + migrationBuilder.DropColumn( + name: "AccountCodingId", + table: "ApplicationForms"); + migrationBuilder.DropTable( name: "AccountCodings"); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml index 7bb68ec5d..24aaf2db7 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml @@ -8,6 +8,7 @@ @using Unity.GrantManager.Permissions; @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal; @using Volo.Abp.Authorization.Permissions; +@using Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration; @model MappingModel @inject IAuthorizationService AuthorizationService @@ -198,7 +199,11 @@ - + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/ViewModels/CreateUpdateApplicationFormViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/ViewModels/CreateUpdateApplicationFormViewModel.cs index c50b47476..02f4421f3 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/ViewModels/CreateUpdateApplicationFormViewModel.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/ViewModels/CreateUpdateApplicationFormViewModel.cs @@ -33,10 +33,5 @@ public class CreateUpdateApplicationFormViewModel [DisplayName("ApplicationForms:Category")] public string? Category { get; set; } - [DisplayName("ApplicationForms:Payable")] - public bool Payable { get; set; } - - [DisplayName("ApplicationForms:RenderFormIoToHtml")] - public bool RenderFormIoToHtml { get; set; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml new file mode 100644 index 000000000..510f2ef4b --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -0,0 +1,70 @@ +@using System.Text.Json +@using Unity.GrantManager.Comments; +@using Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration; +@using Volo.Abp.AspNetCore.Mvc.UI.Layout; +@using Unity.GrantManager.Web.Pages.GrantApplications; +@model PaymentConfigurationViewModel + +@{ + Layout = null; +} + + + +
+
+
Configuration
+
+
+ + + + + + + + + + + + + +

+ Note: The Account Code selected for this form will apply exclusively + to payments within this intake form, and will not affect the global settings. +

+
+
+
Settings
+
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+ + Back +
+
+
+
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css new file mode 100644 index 000000000..83ea941a5 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js new file mode 100644 index 000000000..ddf48b5b1 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js @@ -0,0 +1,94 @@ +$(function () { + const UIElements = { + btnSave: $('#btn-save-payment-configuration'), + btnBack: $('#btn-back-payment-configuration'), + appFormId: $('#applicationFormId').val(), + accountCode: $('#AccountCode'), + preventPayment: $('#PreventAutomaticPaymentToCAS'), + payable: $('#Payable'), + hasEditPermission: $('#HasEditFormPaymentConfiguration').val() + }; + + function bindUIEvents() { + UIElements.accountCode.on('change', enableSaveButton); + UIElements.preventPayment.on('change', enableSaveButton); + UIElements.payable.on('change', enableSaveButton); + + UIElements.btnSave.on('click', saveButtonAction); + UIElements.btnBack.on('click', backButtonAction); + } + + init(); + + function init() { + bindUIEvents(); + console.log('wtf'); + toastr.options.positionClass = 'toast-top-center'; + UIElements.btnSave.prop('disabled', true); + } + + function saveButtonAction() { + let applicationFormId = UIElements.appFormId; + let accountCodingId = UIElements.accountCode.val(); + let preventPayment = UIElements.preventPayment.is(':checked'); + let payable = UIElements.payable.is(':checked'); + + unity.grantManager.applicationForms.applicationForm.savePaymentConfiguration( + { + accountCodingId: accountCodingId, + applicationFormId: applicationFormId, + preventPayment: preventPayment, + payable: payable + }) + .then(() => { + UIElements.btnSave.prop('disabled', true); + abp.notify.success( + 'Payment Configuration is successfully saved.', + 'Form Payment Configuration' + ); + + Swal.fire({ + title: "Note", + text: "Please note that any changes made to the payment configuration will not impact payment requests that have already been created.", + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary' + } + }); + }); + } + + function backButtonAction() { + + // If the save is enabled show a sweet alert to confirm the back action + if (UIElements.btnSave.prop('disabled') === false) { + + Swal.fire({ + title: "Are you sure?", + text: "You have unsaved changes.", + showCancelButton: true, + confirmButtonText:'Yes', + customClass: { + confirmButton: 'btn btn-primary', + cancelButton: 'btn btn-secondary' + } + }).then((result) => { + if (result.isConfirmed) { + location.href = '/ApplicationForms'; + } + else { + return; + } + }); + } else { + location.href = '/ApplicationForms'; + } + } + + function enableSaveButton() { + if (UIElements.hasEditPermission === 'True') { + UIElements.btnSave.prop('disabled', false); + } + } +}); + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationController.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationController.cs new file mode 100644 index 000000000..0e81d62ac --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationController.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + + +namespace Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration +{ + [ApiExplorerSettings(IgnoreApi = true)] + [Route("GrantApplications/PaymentConfiguration")] + public class PaymentConfigurationController : AbpController + { + protected ILogger logger => LazyServiceProvider.LazyGetService(provider => LoggerFactory?.CreateLogger(GetType().FullName!) ?? NullLogger.Instance); + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs new file mode 100644 index 000000000..f797f860c --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs @@ -0,0 +1,76 @@ +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Widgets; +using Volo.Abp.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; +using Microsoft.AspNetCore.Mvc.Rendering; +using Unity.Payments.Domain.AccountCodings; +using Unity.Payments.PaymentConfigurations; +using Unity.Payments.Permissions; +using Volo.Abp.Authorization.Permissions; +using Unity.GrantManager.Applications; + +namespace Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration +{ + [Widget( + RefreshUrl = "PaymentConfiguration/Refresh", + ScriptTypes = new[] { typeof(PaymentConfigurationScriptBundleContributor) }, + StyleTypes = new[] { typeof(PaymentConfigurationStyleBundleContributor) }, + AutoInitialize = true)] + public class PaymentConfigurationViewComponent( + IAccountCodingRepository accountCodingRepository, + IApplicationFormRepository applicationFormRepository, + IPermissionChecker permissionChecker, + PaymentConfigurationAppService paymentConfigurationAppService) : AbpViewComponent + { + + public string AccountCodeList { get; set; } = string.Empty; + + public async Task InvokeAsync(Guid formId) + { + ApplicationForm? applicationForm = await applicationFormRepository.GetAsync(formId); + List accountCodings = await accountCodingRepository.GetListAsync(); + PaymentConfigurationViewModel model = new(); + model.HasEditFormPaymentConfiguration = await HasEditPaymentConfiguration(); + model.Payable = applicationForm?.Payable ?? false; + model.PreventAutomaticPaymentToCAS = applicationForm?.PreventPayment ?? false; + model.AccountCode = applicationForm?.AccountCodingId; + model.AccountCodeList = new(); + foreach (var accountCoding in accountCodings) + { + string accountCodingText = await paymentConfigurationAppService.GetAccountDistributionCode(accountCoding); + SelectListItem selectListItem = new SelectListItem { Value = accountCoding.Id.ToString(), Text = accountCodingText}; + model.AccountCodeList.Add(selectListItem); + } + + return View(model); + } + + private async Task HasEditPaymentConfiguration() + { + return await permissionChecker.IsGrantedAsync(PaymentsPermissions.Payments.EditFormPaymentConfiguration); + } + } + + public class PaymentConfigurationStyleBundleContributor : BundleContributor + { + public override void ConfigureBundle(BundleConfigurationContext context) + { + context.Files + .AddIfNotContains("/Views/Shared/Components/PaymentConfiguration/Default.css"); + } + } + + public class PaymentConfigurationScriptBundleContributor : BundleContributor + { + public override void ConfigureBundle(BundleConfigurationContext context) + { + context.Files + .AddIfNotContains("/Views/Shared/Components/PaymentConfiguration/Default.js"); + context.Files + .AddIfNotContains("/libs/pubsub-js/src/pubsub.js"); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs new file mode 100644 index 000000000..f1cbfeca7 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc.Rendering; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; + +namespace Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration +{ + public class PaymentConfigurationViewModel + { + public PaymentConfigurationViewModel() + { + + } + + public List AccountCodeList { get; set; } = new List(); + + [Display(Name = "Account Code")] + [SelectItems(nameof(AccountCodeList))] + public Guid? AccountCode { get; set; } + + public bool Payable { get; set; } + + public bool PreventAutomaticPaymentToCAS { get; set; } + + public bool HasEditFormPaymentConfiguration { get; set; } + } +} From 5a2cb5c62c7139b6d042ac830d68fd7dfeec026b Mon Sep 17 00:00:00 2001 From: jpasta Date: Tue, 29 Apr 2025 17:02:33 -0700 Subject: [PATCH 04/30] feature/AB#28691-AccountCodingMulti Dev --- .../PaymentThresholds/PaymentThresholdDto.cs | 14 + .../PaymentConfiguration.cs | 4 +- .../IPaymentConfigurationRepository.cs | 9 + .../UserPaymentThresholds/PaymentThreshold.cs | 20 + .../EntityFrameworkCore/IPaymentsDbContext.cs | 2 + .../EntityFrameworkCore/PaymentsDbContext.cs | 3 +- ...aymentsDbContextModelCreatingExtensions.cs | 9 + .../UserPaymentThresholdRepository.cs | 15 + .../FinancialSummaryService.cs | 4 +- .../Pages/AccountCoding/CreateModal.cshtml | 2 +- .../Pages/AccountCoding/UpdateModal.cshtml | 8 +- .../Pages/PaymentConfigurations/Index.cshtml | 44 +- .../PaymentConfigurations/Index.cshtml.cs | 93 +++- .../Pages/PaymentConfigurations/Index.css | 25 + .../Pages/PaymentConfigurations/Index.js | 467 ++++++++++++------ .../UserPaymentThresholdModel.cs | 13 + .../wwwroot/themes/ux2/table-utils.js | 2 +- .../FormPaymentConfiguration.cs | 1 + .../ApplicationFormAppService.cs | 1 + .../Payments/IPaymentSettingsAppService.cs | 10 + .../Payments/PaymentSettingsAppService.cs | 75 +++ .../Applications/ApplicationForm.cs | 1 + .../20250409224221_AccountCoding.cs | 45 +- .../GrantTenantDbContextModelSnapshot.cs | 66 +++ .../Pages/ApplicationForms/Mapping.cshtml | 2 +- .../PaymentConfiguration/Default.cshtml | 44 +- .../PaymentConfiguration/Default.css | 15 +- .../PaymentConfiguration/Default.js | 87 ++-- .../PaymentConfigurationViewModel.cs | 2 + 29 files changed, 878 insertions(+), 205 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentThresholds/PaymentThresholdDto.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/IPaymentConfigurationRepository.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/PaymentThreshold.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/UserPaymentThresholdRepository.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/UserPaymentThresholdModel.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentThresholds/PaymentThresholdDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentThresholds/PaymentThresholdDto.cs new file mode 100644 index 000000000..343649578 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentThresholds/PaymentThresholdDto.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Unity.Payments.PaymentThresholds; + +[Serializable] +public class PaymentThresholdDto : AuditedEntityDto +{ + public Guid? TenantId { get; set; } + public Guid? UserId { get; set; } + public string? UserName { get; set; } + public decimal? Threshold { get; set; } + public string? Description { get; set; } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs index 5da3260a6..15a327d8e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs @@ -7,11 +7,11 @@ namespace Unity.Payments.Domain.PaymentConfigurations public class PaymentConfiguration : FullAuditedAggregateRoot, IMultiTenant { public Guid? TenantId { get; set; } - public Guid? DeafaultAccountCodingId { get; set; } + public Guid? DefaultAccountCodingId { get; set; } public string PaymentIdPrefix { get; set; } = string.Empty; public decimal? PaymentThreshold { get; set; } - protected PaymentConfiguration() + public PaymentConfiguration() { /* This constructor is for ORMs to be used while getting the entity from the database. */ } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/IPaymentConfigurationRepository.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/IPaymentConfigurationRepository.cs new file mode 100644 index 000000000..965690780 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/IPaymentConfigurationRepository.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Domain.Repositories; + +namespace Unity.Payments.Domain.PaymentThresholds; + +public interface IPaymentThresholdRepository : IRepository +{ + +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/PaymentThreshold.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/PaymentThreshold.cs new file mode 100644 index 000000000..40d33b942 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/UserPaymentThresholds/PaymentThreshold.cs @@ -0,0 +1,20 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Unity.Payments.Domain.PaymentThresholds +{ + public class PaymentThreshold : FullAuditedAggregateRoot, IMultiTenant + { + public Guid? TenantId { get; set; } + public Guid? UserId { get; set; } + public decimal? Threshold { get; set; } + public string? Description { get; set; } + + public PaymentThreshold() + { + /* This constructor is for ORMs to be used while getting the entity from the database. */ + } + + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs index d6e045119..8fe531767 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/IPaymentsDbContext.cs @@ -4,6 +4,7 @@ using Unity.Payments.Domain.PaymentConfigurations; using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Domain.Suppliers; +using Unity.Payments.Domain.PaymentThresholds; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -18,4 +19,5 @@ public interface IPaymentsDbContext : IEfCoreDbContext public DbSet Suppliers { get; } public DbSet Sites { get; } public DbSet PaymentConfigurations { get; } + public DbSet PaymentThresholds { get; } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs index a64451e5e..08feefa5d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContext.cs @@ -4,6 +4,7 @@ using Unity.Payments.Domain.PaymentConfigurations; using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Domain.Suppliers; +using Unity.Payments.Domain.PaymentThresholds; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -17,9 +18,9 @@ public class PaymentsDbContext : AbpDbContext, IPaymentsDbCon public DbSet ExpenseApproval { get; set; } public DbSet Suppliers { get;set; } public DbSet PaymentConfigurations { get;set; } + public DbSet PaymentThresholds { get; set; } public DbSet Sites { get; set; } - public PaymentsDbContext(DbContextOptions options) : base(options) { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs index 184fe6db7..48cdd3e49 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/PaymentsDbContextModelCreatingExtensions.cs @@ -6,6 +6,7 @@ using Unity.Payments.Domain.Suppliers; using Unity.Payments.Domain.PaymentConfigurations; using Unity.Payments.Domain.AccountCodings; +using Unity.Payments.Domain.PaymentThresholds; namespace Unity.Payments.EntityFrameworkCore; @@ -80,5 +81,13 @@ public static void ConfigurePayments( b.ConfigureByConvention(); }); + + modelBuilder.Entity(b => + { + b.ToTable(PaymentsDbProperties.DbTablePrefix + "PaymentThresholds", + PaymentsDbProperties.DbSchema); + + b.ConfigureByConvention(); + }); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/UserPaymentThresholdRepository.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/UserPaymentThresholdRepository.cs new file mode 100644 index 000000000..e434d425c --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/EntityFrameworkCore/Repositories/UserPaymentThresholdRepository.cs @@ -0,0 +1,15 @@ +using System; +using Unity.Payments.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Unity.Payments.Domain.PaymentThresholds; + +namespace Unity.Payments.Repositories +{ + public class PaymentThresholdRepository : EfCoreRepository, IPaymentThresholdRepository + { + public PaymentThresholdRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/FinancialSummaryService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/FinancialSummaryService.cs index 220c1c4a5..1b21e64e0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/FinancialSummaryService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/FinancialSummaryService.cs @@ -13,6 +13,7 @@ using Unity.Notifications.Events; using System.Text; using Volo.Abp.EventBus.Local; +using Unity.GrantManager.Identity; namespace Unity.Payments.PaymentRequests { @@ -23,7 +24,6 @@ public class FinancialSummaryService : ApplicationService private readonly ICurrentTenant _currentTenant; private readonly IIdentityUserIntegrationService _identityUserLookupAppService; private readonly ILocalEventBus _localEventBus; - public const string FinancialAnalyst = "financial_analyst"; public FinancialSummaryService ( IIdentityUserIntegrationService identityUserIntegrationService, @@ -108,7 +108,7 @@ public async Task> GetFinancialAnalystEmails() foreach (var user in users.Items) { var roles = await _identityUserLookupAppService.GetRoleNamesAsync(user.Id); - if(roles != null && roles.Contains(FinancialAnalyst) ) + if(roles != null && roles.Contains(UnityRoles.FinancialAnalyst) ) { financialAnalystEmails.Add(user.Email); } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml index 4b0a22858..b89b742df 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml @@ -13,7 +13,7 @@ - + Account Coding diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml index 6e7cacedc..f7a8afe2e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml @@ -11,8 +11,14 @@ - + + + Account Coding + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml index 6e1b3c43a..ceee04045 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml @@ -1,4 +1,5 @@ @page +@model Unity.Payments.Web.Pages.PaymentConfifurations.PaymentConfigurationModel; @{ ViewBag.PageTitle = "Account Codes"; @@ -8,14 +9,28 @@ } + @section scripts { } -
+
+
    + + +
+
+ + + +
@@ -33,5 +48,32 @@
+
+
+
+ + +

Payment Settings

+
+
+ + + Payment id Prefix + + + +
+ + +

Approval Threshold

+
+
+
+
+
+
+ +
+
\ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs index 4f4bd8ff4..3e5e49603 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs @@ -1,11 +1,100 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Unity.GrantManager.Identity; +using Unity.Payments.Domain.PaymentConfigurations; +using Unity.Payments.Domain.PaymentThresholds; +using Unity.Payments.Web.Pages.PaymentApprovals; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Integration; +using Volo.Abp.Users; -namespace Unity.Payments.Web.Pages.AccountCoding +namespace Unity.Payments.Web.Pages.PaymentConfifurations { - public class AccountCodingModel : AbpPageModel + public class PaymentConfigurationModel( + IPaymentThresholdRepository paymentThresholdRepository, + IPaymentConfigurationRepository paymentConfigurationRepository, + IIdentityUserIntegrationService identityUserLookupAppService) : AbpPageModel { + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid? AccountCodingId { get; set; } + [HiddenInput] + [BindProperty(SupportsGet = true)] + public List PaymentThresholdList { get; set; } = new List(); + + [BindProperty(SupportsGet = true)] + public string? PaymentIdPrefix { get; set; } + + public async Task OnGetAsync() + { + var paymentConfigurations = await paymentConfigurationRepository.GetListAsync(); + var paymentConfiguration = paymentConfigurations.Count > 0 ? paymentConfigurations[0] : null; + + if (paymentConfiguration != null) + { + AccountCodingId = paymentConfiguration.DefaultAccountCodingId; + PaymentIdPrefix = paymentConfiguration.PaymentIdPrefix; + } + + PaymentThresholdList = await GetL2ApproversThresholds(); + } + + public async Task> GetL2ApproversThresholds() + { + // lookup users with the l2_approval role + List l2UsersData = new List(); + + var userListResult = await identityUserLookupAppService.SearchAsync(new UserLookupSearchInputDto()); + var users = userListResult.Items; + if (users != null) + { + foreach (UserData user in users) + { + var roles = await identityUserLookupAppService.GetRoleNamesAsync(user.Id); + if(roles != null && roles.Contains(UnityRoles.L2Approver) ) + { + PaymentThreshold? paymentThreshold = await paymentThresholdRepository.FirstOrDefaultAsync(x => x.UserId == user.Id); + + if (paymentThreshold != null) + { + l2UsersData.Add(new PaymentThresholdModel() + { + Id = paymentThreshold.Id, + UserId = user.Id, + UserName = user.Name, + PaymentThreshold = paymentThreshold.Threshold, + Description = paymentThreshold.Description + }); + } + else + { + // If the user does not have a payment threshold, create a new one with null values + PaymentThreshold paymentThresholdNew = await paymentThresholdRepository.InsertAsync(new PaymentThreshold() + { + UserId = user.Id, + Threshold = null, + Description = null + }); + + l2UsersData.Add(new PaymentThresholdModel() + { + Id = paymentThresholdNew.Id, + UserId = user.Id, + UserName = user.Name, + PaymentThreshold = null, + Description = null + }); + } + } + } + } + return l2UsersData; + } } } \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css index ada98d2f1..619872f01 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css @@ -85,6 +85,31 @@ input.form-control:focus, input.form-control:active, textarea.form-control:focus font-weight: inherit !important; } +.hide { + display: none; +} + +#PaymentConfigurationSideMenu.side-menu{ + float: left; + position: absolute; + left: 0px; + top: 150px; +} + +#PaymentConfigurationSideMenu ul { + padding-left: 0; +} + +#PaymentConfigurationSideMenu li { + height: 40px; + padding: 10px; + border-radius: 0 100em 100em 0; +} + +#PaymentConfigurationSideMenu .nav-item { + justify-content: left; +} + @media only screen and (max-width: 850px) { .field-validation-error { float: none; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js index f03167aad..0575732af 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js @@ -1,170 +1,333 @@ $(function () { - let createModal = new abp.ModalManager(abp.appPath + 'AccountCoding/CreateModal'); let updateModal = new abp.ModalManager(abp.appPath + 'AccountCoding/UpdateModal'); + const l = abp.localization.getResource('GrantManager'); - /** - * List All - */ - $.fn.dataTable.Buttons.defaults.dom.button.className = 'btn flex-none'; - let actionButtons = [ - { - text: ' ' + l('Common:Command:Create') + '', - titleAttr: l('Common:Command:Create'), - id: 'CreateButton', - className: 'btn-light rounded-1', - action: (e, dt, node, config) => createIntakeBtn(e) - }, - ...commonTableActionButtons(l('Intake')) - ]; - let index = 0; - const listColumns = [ - { - title: 'Ministry Client', - name: "ministryClient", - data: "ministryClient", - visible: true, - index: index++ - }, - { - title: 'Responsibility', - name: "responsibility", - data: "responsibility", - visible: true, - index: index++ - }, - { - title: 'Service Line', - name: "serviceLine", - data: "serviceLine", - visible: true, - index: index++ - }, - { - title: 'Stob', - name: "stob", - data: "stob", - visible: true, - index: index++ - }, - { - title: 'Project #', - name: "projectNumber", - data: "projectNumber", - visible: true, - index: index++ - }, - { - title: 'Default', - orderable: false, - visible: true, - className: 'notexport text-center', - name: 'defaultRadio', - index: index++, - data: 'id', - render: function (data, type, full, meta) { - let checked = '';//UIElements.siteId.val() == data ? 'checked' : '' -------- '${data}'; - - return ``; - } - }, - { - title: 'Action', - orderable: false, - data: 'id', - className: 'notexport text-center', - name: 'rowActions', - visible: true, - index: index++, - rowAction: { - items: - [ - { - text: 'Edit', - action: (data) => updateModal.open({ id: data.record.id }) - } - ] - } - } - ]; - - const defaultVisibleColumns = [ - 'ministryClient', - 'responsibility', - 'serviceLine', - 'stob', - 'projectNumber', - 'defaultRadio', - 'rowActions', - ]; - - - let responseCallback = function (result) { - return { - recordsTotal: result.totalCount, - recordsFiltered: result.items.length, - data: result.items - }; + toastr.options.positionClass = 'toast-top-center'; + let dataTable; + let paymentSettingsDataTable; + + const UIElements = { + accountCodingDataTable: $('#AccountCodesDataTable'), + paymentSettingsDataTable: $('#PaymentSettingsDataTable'), + accountCodingId: $('#AccountCodingId'), + accountCodingMenu: $('#account-coding-menu-item'), + paymentSettingMenu: $('#payment-setting-menu-item'), + accountCodesDiv: $('#account-codes-div'), + paymentSettingsDiv: $('#payment-settings-div'), }; - let dt = $('#AccountCodesDataTable'); - - let dataTable = initializeDataTable({ - dt, - defaultVisibleColumns, - listColumns, - maxRowsPerPage: 25, - defaultSortColumn: 0, - dataEndpoint: unity.grantManager.payments.accountCoding.getList, - data: {}, - responseCallback, - actionButtons, - pagingEnabled: true, - reorderEnabled: false, - languageSetValues: {}, - dataTableName: 'AccountCodesDataTable', - dynamicButtonContainerId: 'dynamicButtonContainerId', - useNullPlaceholder: true, - externalSearchId: 'search-data-table' - }); + init(); + + function init() { + dataTable = initializeAccountCodesDataTable(); + paymentSettingsDataTable = initializePaymentSettingsDataTable(); + bindUIElements(); + + console.log('in here'); + } + + function bindUIElements() { + UIElements.accountCodingMenu.on('click', menuItemClick); + UIElements.paymentSettingMenu.on('click', menuItemClick); + } + + function removeActiveClassFromMenuItems() { + UIElements.accountCodingMenu.removeClass('active'); + UIElements.paymentSettingMenu.removeClass('active'); + } + + function menuItemClick(e) { + removeActiveClassFromMenuItems(); + e.target.classList.add('active'); + UIElements.accountCodesDiv.toggleClass('hide'); + UIElements.paymentSettingsDiv.toggleClass('hide'); + } + + function bindModalElements() { + const UIElements = { + inputMinistryClient: $('input[name="AccountCoding.MinistryClient"]'), + inputResponsibility: $('input[name="AccountCoding.Responsibility"]'), + inputServiceLine: $('input[name="AccountCoding.ServiceLine"]'), + inputStob: $('input[name="AccountCoding.Stob"]'), + inputProjectNumber: $('input[name="AccountCoding.ProjectNumber"]'), + readOnlyAccountCoding: $('#account-coding') + }; + + UIElements.inputMinistryClient.on('keyup', setAccountCodingDisplay); + UIElements.inputResponsibility.on('keyup', setAccountCodingDisplay); + UIElements.inputServiceLine.on('keyup', setAccountCodingDisplay); + UIElements.inputStob.on('keyup', setAccountCodingDisplay); + UIElements.inputProjectNumber.on('keyup', setAccountCodingDisplay); + + function setAccountCodingDisplay() { + let currentAccount = $(UIElements.inputMinistryClient).val() + "." + + $(UIElements.inputResponsibility).val() + "." + + $(UIElements.inputServiceLine).val() + "." + + $(UIElements.inputStob).val() + "." + + $(UIElements.inputProjectNumber).val(); + + $(UIElements.readOnlyAccountCoding).val(currentAccount); + } + + setAccountCodingDisplay(); + } + + function initializePaymentSettingsDataTable() { + let actionButtons = []; + const listColumns = getPaymenSettingsColumns(); + + const defaultVisibleColumns = [ + 'userName', + 'paymentThreshold', + 'description' + ]; + + let responseCallback = function (result) { + return { + recordsTotal: result.length, + recordsFiltered: result.length, + data: result + }; + }; + + let dt = UIElements.paymentSettingsDataTable; + return initializeDataTable({ + dt, + defaultVisibleColumns, + listColumns, + maxRowsPerPage: 25, + defaultSortColumn: 0, + dataEndpoint: unity.grantManager.payments.paymentSettings.getL2ApproversThresholds, + data: {}, + responseCallback, + actionButtons, + pagingEnabled: true, + reorderEnabled: false, + languageSetValues: {}, + dataTableName: 'PaymentSettingsDataTable', + dynamicButtonContainerId: 'dynamicButtonContainerId', + useNullPlaceholder: true, + externalSearchId: 'search-data-table' + }); + + function getPaymenSettingsColumns() { + let index = 0; + return [ + { + title: 'Id', + name: "id", + data: "id", + visible: false, + index: index++ + }, + { + title: 'User Id', + name: "userId", + data: "userId", + visible: false, + index: index++ + }, + { + title: 'Expense Authority', + name: "userName", + data: "userName", + visible: true, + index: index++ + }, + { + title: 'Approval Threshold', + name: "paymentThreshold", + data: "paymentThreshold", + visible: true, + index: index++ + }, + { + title: 'Description', + name: "description", + data: "description", + visible: true, + index: index++ + }, + { + title: 'Action', + orderable: false, + sortable: false, + data: 'id', + className: 'notexport text-center', + name: 'rowActions', + visible: true, + index: index++, + rowAction: { + items: + [ + { + text: 'Edit', + action: (data) => editPaymentSettingsBtn(data.record.id) + } + ] + } + } + ]; + } + } + + function initializeAccountCodesDataTable() { + $.fn.dataTable.Buttons.defaults.dom.button.className = 'btn flex-none'; + let actionButtons = [ + { + text: ' ' + l('Common:Command:Create') + '', + titleAttr: l('Common:Command:Create'), + id: 'CreateButton', + className: 'btn-light rounded-1', + action: (e, dt, node, config) => createAccountCodingBtn(e) + }, + ...commonTableActionButtons(l('Intake')) + ]; + + const listColumns = getAccountCodingColumns(); + + const defaultVisibleColumns = [ + 'ministryClient', + 'responsibility', + 'serviceLine', + 'stob', + 'projectNumber', + 'defaultRadio', + 'rowActions', + ]; + + let responseCallback = function (result) { + return { + recordsTotal: result.totalCount, + recordsFiltered: result.items.length, + data: result.items + }; + }; + + let dt = UIElements.accountCodingDataTable; + return initializeDataTable({ + dt, + defaultVisibleColumns, + listColumns, + maxRowsPerPage: 25, + defaultSortColumn: 0, + dataEndpoint: unity.grantManager.payments.accountCoding.getList, + data: {}, + responseCallback, + actionButtons, + pagingEnabled: true, + reorderEnabled: false, + languageSetValues: {}, + dataTableName: 'AccountCodesDataTable', + dynamicButtonContainerId: 'dynamicButtonContainerId', + useNullPlaceholder: true, + externalSearchId: 'search-data-table' + }); + } + + function getAccountCodingColumns() { + let index = 0; + return [ + { + title: 'Ministry Client', + name: "ministryClient", + data: "ministryClient", + visible: true, + index: index++ + }, + { + title: 'Responsibility', + name: "responsibility", + data: "responsibility", + visible: true, + index: index++ + }, + { + title: 'Service Line', + name: "serviceLine", + data: "serviceLine", + visible: true, + index: index++ + }, + { + title: 'Stob', + name: "stob", + data: "stob", + visible: true, + index: index++ + }, + { + title: 'Project #', + name: "projectNumber", + data: "projectNumber", + visible: true, + index: index++ + }, + { + title: 'Default', + orderable: false, + visible: true, + className: 'notexport text-center', + name: 'defaultRadio', + index: index++, + data: 'id', + render: function (data, type, full, meta) { + let checked = UIElements.accountCodingId.val() == data ? 'checked' : ''; + return ``; + } + }, + { + title: 'Action', + orderable: false, + sortable: false, + data: 'id', + className: 'notexport text-center', + name: 'rowActions', + visible: true, + index: index++, + rowAction: { + items: + [ + { + text: 'Edit', + action: (data) => editAccountCodingBtn(data.record.id) + } + ] + } + } + ]; + + } createModal.onResult(function () { - dataTable.ajax.reload(); + accountCodingDataTable.ajax.reload(); }); updateModal.onResult(function () { - dataTable.ajax.reload(); + accountCodingDataTable.ajax.reload(); }); - - function createIntakeBtn(e) { + + function editAccountCodingBtn(id) { + updateModal.open({ id: id }); + updateModal.onOpen(function () { + bindModalElements(); + }); + }; + + function createAccountCodingBtn(e) { e.preventDefault(); createModal.open(); createModal.onOpen(function () { - - const UIElements = { - inputMinistryClient: $('input[name="AccountCoding.MinistryClient"]'), - inputResponsibility: $('input[name="AccountCoding.Responsibility"]'), - inputServiceLine: $('input[name="AccountCoding.ServiceLine"]'), - inputStob: $('input[name="AccountCoding.Stob"]'), - inputProjectNumber: $('input[name="AccountCoding.ProjectNumber"]'), - readOnlyAccountCoding: $('#account-coding') - }; - - UIElements.inputMinistryClient.on('keyup', setAccountCodingDisplay); - UIElements.inputResponsibility.on('keyup', setAccountCodingDisplay); - UIElements.inputServiceLine.on('keyup', setAccountCodingDisplay); - UIElements.inputStob.on('keyup', setAccountCodingDisplay); - UIElements.inputProjectNumber.on('keyup', setAccountCodingDisplay); - - function setAccountCodingDisplay() { - let currentAccount = $(UIElements.inputMinistryClient).val() + "." + - $(UIElements.inputResponsibility).val() + "." + - $(UIElements.inputServiceLine).val() + "." + - $(UIElements.inputStob).val() + "." + - $(UIElements.inputProjectNumber).val(); - - $(UIElements.readOnlyAccountCoding).val(currentAccount); - } + bindModalElements(); }); }; }); + +function handleDefaultAccountCodeRadioClick(id) { + unity.grantManager.payments.paymentConfiguration.setDefaultAccountCode(id).done(function () { + toastr.success('Successfully set default account code.'); + }).fail(function () { + toastr.error('Failed to set default account code.'); + }); +}; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/UserPaymentThresholdModel.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/UserPaymentThresholdModel.cs new file mode 100644 index 000000000..4fbd726ed --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/UserPaymentThresholdModel.cs @@ -0,0 +1,13 @@ +using System; + +namespace Unity.Payments.Web.Pages.PaymentApprovals +{ + public class PaymentThresholdModel + { + public Guid Id { get; set; } + public Guid? UserId { get; set; } + public decimal? PaymentThreshold { get; set; } + public string? Description { get; set; } + public string? UserName { get; set; } + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js index 3f7aaa9f2..ef9745ed0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js +++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js @@ -437,7 +437,7 @@ function updateFilter(dt, dtName, filterData) { let column = this; if (column.visible()) { let title = column.header().textContent; - if (title && title !== 'Actions') { + if (title && title !== 'Actions' && title !== 'Action' && title !== 'Default') { let filterValue = filterData[title] ? filterData[title] : ''; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs index 0ba115eba..dba5f9447 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/FormPaymentConfiguration.cs @@ -9,5 +9,6 @@ public class FormPaymentConfigurationDto public Guid? AccountCodingId { get; set; } public bool PreventPayment { get; set; } public bool Payable { get; set; } + public decimal? PaymentApprovalThreshold { get; set; } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index 05afb983c..9665ead91 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -136,6 +136,7 @@ public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) appForm.AccountCodingId = dto.AccountCodingId; appForm.Payable = dto.Payable; appForm.PreventPayment = dto.PreventPayment; + appForm.PaymentApprovalThreshold = dto.PaymentApprovalThreshold; await _applicationFormRepository.UpdateAsync(appForm); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs new file mode 100644 index 000000000..e45632021 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Unity.Payments.PaymentThresholds; + +namespace Unity.GrantManager.Payments; + +public interface IPaymentSettingsAppService +{ + Task> GetL2ApproversThresholds(); +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs new file mode 100644 index 000000000..9e53add6a --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using Volo.Abp.DependencyInjection; +using System; +using System.Linq; +using System.Threading.Tasks; +using Unity.GrantManager.Identity; +using Unity.Payments.Domain.PaymentThresholds; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Integration; +using Unity.Payments.PaymentThresholds; +using Volo.Abp.Users; + +namespace Unity.GrantManager.Payments; + + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(PaymentSettingsAppService), typeof(IPaymentSettingsAppService))] +public class PaymentSettingsAppService( + IPaymentThresholdRepository paymentThresholdRepository, + IIdentityUserIntegrationService identityUserLookupAppService) : GrantManagerAppService, IPaymentSettingsAppService +{ + +public async Task> GetL2ApproversThresholds() + { + // lookup users with the l2_approval role + List l2UsersData = new List(); + + var userListResult = await identityUserLookupAppService.SearchAsync(new UserLookupSearchInputDto()); + var users = userListResult.Items; + if (users != null) + { + foreach (UserData user in users) + { + var roles = await identityUserLookupAppService.GetRoleNamesAsync(user.Id); + if(roles != null && roles.Contains(UnityRoles.L2Approver) ) + { + PaymentThreshold? paymentThreshold = await paymentThresholdRepository.FirstOrDefaultAsync(x => x.UserId == user.Id); + + if (paymentThreshold != null) + { + l2UsersData.Add(new PaymentThresholdDto() + { + Id = paymentThreshold.Id, + UserId = user.Id, + UserName = user.Name, + Threshold = paymentThreshold.Threshold, + Description = paymentThreshold.Description + }); + } + else + { + // If the user does not have a payment threshold, create a new one with null values + PaymentThreshold paymentThresholdNew = await paymentThresholdRepository.InsertAsync(new PaymentThreshold() + { + UserId = user.Id, + Threshold = null, + Description = null + }); + + l2UsersData.Add(new PaymentThresholdDto() + { + Id = paymentThresholdNew.Id, + UserId = user.Id, + UserName = user.Name, + Threshold = null, + Description = null + }); + } + } + } + } + return l2UsersData; + } +} \ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs index 65ce973d5..60f5c09c0 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Applications/ApplicationForm.cs @@ -24,5 +24,6 @@ public class ApplicationForm : FullAuditedAggregateRoot, IMultiTenant public Guid? AccountCodingId { get; set; } public Guid? ScoresheetId { get; set; } public Guid? TenantId { get; set; } + public decimal? PaymentApprovalThreshold { get; set; } public bool RenderFormIoToHtml { get; set; } = false; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs index 61c89b11d..d27461271 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs @@ -39,6 +39,33 @@ protected override void Up(MigrationBuilder migrationBuilder) table.UniqueConstraint("UK_AccountCodings", x => new { x.MinistryClient, x.Responsibility, x.ServiceLine, x.Stob, x.ProjectNumber }); }); + migrationBuilder.CreateTable( + name: "PaymentThresholds", + schema: "Payments", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + Threshold = table.Column(type: "decimal", nullable: true), + Description = table.Column(type: "text", nullable: true), + ExtraProperties = table.Column(type: "text", nullable: false), + ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true), + LastModificationTime = table.Column(type: "timestamp without time zone", nullable: true), + LastModifierId = table.Column(type: "uuid", nullable: true), + IsDeleted = table.Column(type: "boolean", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uuid", nullable: true), + DeletionTime = table.Column(type: "timestamp without time zone", nullable: true), + TenantId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PaymentThresholds", x => x.Id); + } + ); + + migrationBuilder.AddColumn( name: "DefaultAccountCodingId", table: "PaymentConfigurations", @@ -62,6 +89,13 @@ protected override void Up(MigrationBuilder migrationBuilder) principalTable: "AccountCodings", principalColumn: "Id"); + migrationBuilder.AddColumn( + name: "PaymentApprovalThreshold", + table: "ApplicationForms", + type: "decimal", + nullable: true, + defaultValue: false); + migrationBuilder.AddColumn( name: "PreventPayment", table: "ApplicationForms", @@ -134,10 +168,19 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.DropColumn( name: "AccountCodingId", - table: "ApplicationForms"); + table: "ApplicationForms"); + + migrationBuilder.DropColumn( + name: "PaymentApprovalThreshold", + table: "ApplicationForms"); migrationBuilder.DropTable( + schema: "Payments", name: "AccountCodings"); + + migrationBuilder.DropTable( + schema: "Payments", + name: "PaymentThresholds"); } } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs index a831d9180..c2b65a814 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs @@ -2954,6 +2954,72 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("PaymentConfigurations", "Payments"); }); + modelBuilder.Entity("Unity.Payments.Domain.PaymentThresholds.PaymentThreshold", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("UserId"); + + b.Property("Threshold") + .HasColumnType("numeric"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + }); + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => { b.Property("Id") diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml index 24aaf2db7..11cb1ae04 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml @@ -201,7 +201,7 @@
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml index 510f2ef4b..126e27226 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -1,10 +1,11 @@ -@using System.Text.Json -@using Unity.GrantManager.Comments; -@using Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration; -@using Volo.Abp.AspNetCore.Mvc.UI.Layout; @using Unity.GrantManager.Web.Pages.GrantApplications; +@using Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration; @model PaymentConfigurationViewModel +@section styles { + +} + @{ Layout = null; } @@ -25,14 +26,41 @@ +
+
Approval Payment Threshold
+
+ $ + + +
+
+
+ + + +

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

+

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

-

- Note: The Account Code selected for this form will apply exclusively - to payments within this intake form, and will not affect the global settings. -


Settings
diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css index 83ea941a5..ae6c84c24 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.css @@ -1 +1,14 @@ - \ No newline at end of file +.currencyinput { + float: left; + width: 300px; +} + +.currency { + text-align: right; + width: 100%; + margin-top: -31px; +} + +.currency-label { + margin-bottom: 9px; +} \ No newline at end of file diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js index ddf48b5b1..9ed5c6a2e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.js @@ -2,60 +2,85 @@ const UIElements = { btnSave: $('#btn-save-payment-configuration'), btnBack: $('#btn-back-payment-configuration'), - appFormId: $('#applicationFormId').val(), + appFormId: $('#applicationFormId'), accountCode: $('#AccountCode'), preventPayment: $('#PreventAutomaticPaymentToCAS'), payable: $('#Payable'), - hasEditPermission: $('#HasEditFormPaymentConfiguration').val() + hasEditPermission: $('#HasEditFormPaymentConfiguration'), + paymentApprovalThreshold: $('#PaymentApprovalThreshold'), + paymentThresholdForm: $('#PaymentThresholdform') }; function bindUIEvents() { UIElements.accountCode.on('change', enableSaveButton); UIElements.preventPayment.on('change', enableSaveButton); UIElements.payable.on('change', enableSaveButton); - + UIElements.paymentApprovalThreshold.on('change', enableSaveButton); + UIElements.btnSave.on('click', saveButtonAction); UIElements.btnBack.on('click', backButtonAction); + + UIElements.paymentApprovalThreshold.on('keypress', preventNegativeKeyPress); + UIElements.paymentApprovalThreshold.on('input', preventDecimalKeyPress); } init(); function init() { bindUIEvents(); - console.log('wtf'); toastr.options.positionClass = 'toast-top-center'; UIElements.btnSave.prop('disabled', true); } + + function preventDecimalKeyPress(e) { + const input = e.target; + const cursorPosition = input.selectionStart; + const decimalMatch = input.value.match(/\.(\d+)/); + + // Limit to two decimal places + if (decimalMatch && decimalMatch[1].length > 2) { + input.value = input.value.replace(/\.(\d{2}).*/, '.$1'); + input.setSelectionRange(cursorPosition, cursorPosition); // Restore cursor position + } + } + + function preventNegativeKeyPress(e) { + if (e.key === '-' || e.keyCode === 45) { + e.preventDefault(); + } + const input = e.target; + + if (input.value.length > 17) { + e.preventDefault(); + } + } function saveButtonAction() { - let applicationFormId = UIElements.appFormId; - let accountCodingId = UIElements.accountCode.val(); - let preventPayment = UIElements.preventPayment.is(':checked'); - let payable = UIElements.payable.is(':checked'); unity.grantManager.applicationForms.applicationForm.savePaymentConfiguration( - { - accountCodingId: accountCodingId, - applicationFormId: applicationFormId, - preventPayment: preventPayment, - payable: payable - }) - .then(() => { - UIElements.btnSave.prop('disabled', true); - abp.notify.success( - 'Payment Configuration is successfully saved.', - 'Form Payment Configuration' - ); + { + accountCodingId: UIElements.accountCode.val(), + applicationFormId: UIElements.appFormId.val(), + preventPayment: UIElements.preventPayment.is(':checked'), + payable: UIElements.payable.is(':checked'), + paymentApprovalThreshold: UIElements.paymentApprovalThreshold.val() === '' ? null : UIElements.paymentApprovalThreshold.val() + }) + .then(() => { + UIElements.btnSave.prop('disabled', true); + abp.notify.success( + 'Payment Configuration is successfully saved.', + 'Form Payment Configuration' + ); - Swal.fire({ - title: "Note", - text: "Please note that any changes made to the payment configuration will not impact payment requests that have already been created.", - confirmButtonText: 'Ok', - customClass: { - confirmButton: 'btn btn-primary' - } - }); - }); + Swal.fire({ + title: "Note", + text: "Please note that any changes made to the payment configuration will not impact payment requests that have already been created.", + confirmButtonText: 'Ok', + customClass: { + confirmButton: 'btn btn-primary' + } + }); + }); } function backButtonAction() { @@ -67,7 +92,7 @@ title: "Are you sure?", text: "You have unsaved changes.", showCancelButton: true, - confirmButtonText:'Yes', + confirmButtonText: 'Yes', customClass: { confirmButton: 'btn btn-primary', cancelButton: 'btn btn-secondary' @@ -86,7 +111,7 @@ } function enableSaveButton() { - if (UIElements.hasEditPermission === 'True') { + if (UIElements.hasEditPermission.val() === 'True') { UIElements.btnSave.prop('disabled', false); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs index f1cbfeca7..f7de611c5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewModel.cs @@ -19,6 +19,8 @@ public PaymentConfigurationViewModel() [SelectItems(nameof(AccountCodeList))] public Guid? AccountCode { get; set; } + public decimal? PaymentApprovalThreshold { get; set; } + public bool Payable { get; set; } public bool PreventAutomaticPaymentToCAS { get; set; } From 6ad7ec4a8d3367157ce03f2332ed71f043d9bbad Mon Sep 17 00:00:00 2001 From: jpasta Date: Tue, 13 May 2025 17:11:16 -0700 Subject: [PATCH 05/30] feature/AB#28691-AccountCodingMulti --- ...nity.Payments.Application.Contracts.csproj | 1 + .../PaymentsApplicationAutoMapperProfile.cs | 18 +++++ .../Pages/PaymentConfigurations/Index.cshtml | 2 +- .../PaymentConfigurations/Index.cshtml.cs | 78 +------------------ .../Pages/PaymentConfigurations/Index.css | 8 ++ .../Pages/PaymentConfigurations/Index.js | 50 ++++++++++-- .../PaymentThresholds/UpdateModal.cshtml | 22 ++++++ .../PaymentThresholds/UpdateModal.cshtml.cs | 40 ++++++++++ .../Payments/IPaymentThresholdAppService.cs | 15 ++++ .../Payments/UpdatePaymentThresholdDto.cs | 32 ++++++++ .../Payments/PaymentSettingsAppService.cs | 4 +- .../Payments/PaymentThresholdAppService.cs | 23 ++++++ .../GrantTenantDbContextModelSnapshot.cs | 2 + 13 files changed, 213 insertions(+), 82 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml create mode 100644 applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IPaymentThresholdAppService.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/UpdatePaymentThresholdDto.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentThresholdAppService.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj index b74888255..8ae66445b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/Unity.Payments.Application.Contracts.csproj @@ -13,6 +13,7 @@ + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs index db1d8dcfd..deb8d5c5d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs @@ -8,6 +8,8 @@ using Unity.Payments.Suppliers; using Volo.Abp.Users; using Unity.GrantManager.Payments; +using Unity.Payments.Domain.PaymentThresholds; +using Unity.Payments.PaymentThresholds; namespace Unity.Payments; @@ -31,6 +33,22 @@ public PaymentsApplicationAutoMapperProfile() CreateMap(); CreateMap(); CreateMap() + .ForMember(dest => dest.TenantId, opt => opt.Ignore()) + .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) + .ForMember(dest => dest.DeleterId, opt => opt.Ignore()) + .ForMember(dest => dest.DeletionTime, opt => opt.Ignore()) + .ForMember(dest => dest.LastModificationTime, opt => opt.Ignore()) + .ForMember(dest => dest.LastModifierId, opt => opt.Ignore()) + .ForMember(dest => dest.CreationTime, opt => opt.Ignore()) + .ForMember(dest => dest.CreatorId, opt => opt.Ignore()) + .ForMember(dest => dest.ExtraProperties, opt => opt.Ignore()) + .ForMember(dest => dest.ConcurrencyStamp, opt => opt.Ignore()) + .ForMember(dest => dest.Id, opt => opt.Ignore()); + CreateMap() + .ForMember(dest => dest.UserName, opt => opt.Ignore()); + CreateMap() + .ForMember(dest => dest.UserName, opt => opt.Ignore()); + CreateMap() .ForMember(dest => dest.TenantId, opt => opt.Ignore()) .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) .ForMember(dest => dest.DeleterId, opt => opt.Ignore()) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml index ceee04045..4d8840b9a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml @@ -69,7 +69,7 @@

Approval Threshold

-
+
diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs index 3e5e49603..35dc33c11 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs @@ -1,33 +1,17 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Unity.GrantManager.Identity; using Unity.Payments.Domain.PaymentConfigurations; -using Unity.Payments.Domain.PaymentThresholds; -using Unity.Payments.Web.Pages.PaymentApprovals; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.Identity; -using Volo.Abp.Identity.Integration; -using Volo.Abp.Users; namespace Unity.Payments.Web.Pages.PaymentConfifurations { - public class PaymentConfigurationModel( - IPaymentThresholdRepository paymentThresholdRepository, - IPaymentConfigurationRepository paymentConfigurationRepository, - IIdentityUserIntegrationService identityUserLookupAppService) : AbpPageModel + public class PaymentConfigurationModel(IPaymentConfigurationRepository paymentConfigurationRepository) : AbpPageModel { [HiddenInput] [BindProperty(SupportsGet = true)] public Guid? AccountCodingId { get; set; } - - [HiddenInput] - [BindProperty(SupportsGet = true)] - public List PaymentThresholdList { get; set; } = new List(); - + [BindProperty(SupportsGet = true)] public string? PaymentIdPrefix { get; set; } @@ -40,61 +24,7 @@ public async Task OnGetAsync() { AccountCodingId = paymentConfiguration.DefaultAccountCodingId; PaymentIdPrefix = paymentConfiguration.PaymentIdPrefix; - } - - PaymentThresholdList = await GetL2ApproversThresholds(); - } - - public async Task> GetL2ApproversThresholds() - { - // lookup users with the l2_approval role - List l2UsersData = new List(); - - var userListResult = await identityUserLookupAppService.SearchAsync(new UserLookupSearchInputDto()); - var users = userListResult.Items; - if (users != null) - { - foreach (UserData user in users) - { - var roles = await identityUserLookupAppService.GetRoleNamesAsync(user.Id); - if(roles != null && roles.Contains(UnityRoles.L2Approver) ) - { - PaymentThreshold? paymentThreshold = await paymentThresholdRepository.FirstOrDefaultAsync(x => x.UserId == user.Id); - - if (paymentThreshold != null) - { - l2UsersData.Add(new PaymentThresholdModel() - { - Id = paymentThreshold.Id, - UserId = user.Id, - UserName = user.Name, - PaymentThreshold = paymentThreshold.Threshold, - Description = paymentThreshold.Description - }); - } - else - { - // If the user does not have a payment threshold, create a new one with null values - PaymentThreshold paymentThresholdNew = await paymentThresholdRepository.InsertAsync(new PaymentThreshold() - { - UserId = user.Id, - Threshold = null, - Description = null - }); - - l2UsersData.Add(new PaymentThresholdModel() - { - Id = paymentThresholdNew.Id, - UserId = user.Id, - UserName = user.Name, - PaymentThreshold = null, - Description = null - }); - } - } - } - } - return l2UsersData; - } + } + } } } \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css index 619872f01..39f53b4a4 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css @@ -110,6 +110,14 @@ input.form-control:focus, input.form-control:active, textarea.form-control:focus justify-content: left; } +#payment-settings-div { + width: 750px; +} + +#PaymentThreshold_Threshold { + text-align: right; +} + @media only screen and (max-width: 850px) { .field-validation-error { float: none; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js index 0575732af..c847e0d2e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js @@ -1,6 +1,7 @@ $(function () { let createModal = new abp.ModalManager(abp.appPath + 'AccountCoding/CreateModal'); let updateModal = new abp.ModalManager(abp.appPath + 'AccountCoding/UpdateModal'); + let updateThresholdModal = new abp.ModalManager(abp.appPath + 'PaymentThresholds/UpdateModal'); const l = abp.localization.getResource('GrantManager'); toastr.options.positionClass = 'toast-top-center'; @@ -23,8 +24,6 @@ $(function () { dataTable = initializeAccountCodesDataTable(); paymentSettingsDataTable = initializePaymentSettingsDataTable(); bindUIElements(); - - console.log('in here'); } function bindUIElements() { @@ -42,6 +41,8 @@ $(function () { e.target.classList.add('active'); UIElements.accountCodesDiv.toggleClass('hide'); UIElements.paymentSettingsDiv.toggleClass('hide'); + paymentSettingsDataTable.columns.adjust().draw(); + dataTable.columns.adjust().draw(); } function bindModalElements() { @@ -51,6 +52,7 @@ $(function () { inputServiceLine: $('input[name="AccountCoding.ServiceLine"]'), inputStob: $('input[name="AccountCoding.Stob"]'), inputProjectNumber: $('input[name="AccountCoding.ProjectNumber"]'), + inputPaymentThreshold: $('#PaymentThreshold_Threshold'), readOnlyAccountCoding: $('#account-coding') }; @@ -59,6 +61,29 @@ $(function () { UIElements.inputServiceLine.on('keyup', setAccountCodingDisplay); UIElements.inputStob.on('keyup', setAccountCodingDisplay); UIElements.inputProjectNumber.on('keyup', setAccountCodingDisplay); + + UIElements.inputPaymentThreshold.on('keyup', preventDecimalKeyUp); + UIElements.inputPaymentThreshold.on('keypress', preventNonCurrencyKeyPress); + + function preventNonCurrencyKeyPress(e) { + // Prevent alphabetic characters and - + if (/[a-zA-Z]/.test(e.key) || e.key === ' ' || e.key === '-' || e.keyCode === 45) { + e.preventDefault(); + } + } + + function preventDecimalKeyUp(e) { + const input = e.target; + const cursorPosition = input.selectionStart; + const decimalMatch = input.value.match(/\.(\d+)/); + + // Limit to two decimal places + if (decimalMatch && decimalMatch[1].length > 2) { + input.value = input.value.replace(/\.(\d{2}).*/, '.$1'); + input.setSelectionRange(cursorPosition, cursorPosition); // Restore cursor position + } + } + function setAccountCodingDisplay() { let currentAccount = $(UIElements.inputMinistryClient).val() + "." + @@ -137,8 +162,9 @@ $(function () { }, { title: 'Approval Threshold', - name: "paymentThreshold", - data: "paymentThreshold", + name: "paymentThreshold", + className: 'dt-body-right', + data: "threshold", visible: true, index: index++ }, @@ -163,7 +189,7 @@ $(function () { [ { text: 'Edit', - action: (data) => editPaymentSettingsBtn(data.record.id) + action: (data) => editThresholdBtn(data.record.id, data.record.userName) } ] } @@ -307,6 +333,10 @@ $(function () { updateModal.onResult(function () { accountCodingDataTable.ajax.reload(); }); + + updateThresholdModal.onResult(function () { + paymentSettingsDataTable.ajax.reload(); + }); function editAccountCodingBtn(id) { updateModal.open({ id: id }); @@ -314,6 +344,13 @@ $(function () { bindModalElements(); }); }; + + function editThresholdBtn(id, userName) { + updateThresholdModal.open({ id: id, userName: userName }); + updateThresholdModal.onOpen(function () { + bindModalElements(); + }); + }; function createAccountCodingBtn(e) { e.preventDefault(); @@ -322,6 +359,9 @@ $(function () { bindModalElements(); }); }; + + + }); function handleDefaultAccountCodeRadioClick(id) { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml new file mode 100644 index 000000000..a6ffc38d4 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml @@ -0,0 +1,22 @@ +@page +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal + +@model Unity.GrantManager.Web.Pages.PaymentThresholds.UpdateModalModel + +@{ + Layout = null; +} + + + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs new file mode 100644 index 000000000..9112fd090 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Unity.GrantManager.Payments; +using Unity.Payments.PaymentThresholds; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Integration; + +namespace Unity.GrantManager.Web.Pages.PaymentThresholds; + +public class UpdateModalModel(IPaymentThresholdAppService paymentThresholdAppService) : AbpPageModel +{ + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid Id { get; set; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string? UserName { get; set; } + + [BindProperty] + public UpdatePaymentThresholdDto? PaymentThreshold { get; set; } + + + public async Task OnGetAsync() + { + var paymentThresholdDto = await paymentThresholdAppService.GetAsync(Id); + PaymentThreshold = ObjectMapper.Map(paymentThresholdDto); + PaymentThreshold.UserName = UserName; + } + + public async Task OnPostAsync() + { + + + await paymentThresholdAppService.UpdateAsync(Id, PaymentThreshold!); + return NoContent(); + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IPaymentThresholdAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IPaymentThresholdAppService.cs new file mode 100644 index 000000000..3ee3f0ef9 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/IPaymentThresholdAppService.cs @@ -0,0 +1,15 @@ +using System; +using Unity.Payments.PaymentThresholds; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Unity.GrantManager.Payments +{ + public interface IPaymentThresholdAppService : ICrudAppService< + PaymentThresholdDto, + Guid, + PagedAndSortedResultRequestDto, + UpdatePaymentThresholdDto> + { + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/UpdatePaymentThresholdDto.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/UpdatePaymentThresholdDto.cs new file mode 100644 index 000000000..f8aff3bcc --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/Payments/UpdatePaymentThresholdDto.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; + + +namespace Unity.GrantManager.Payments +{ + public class UpdatePaymentThresholdDto + { + [Required] + [HiddenInput(DisplayValue = false)] + public Guid? UserId { get; set; } + + [DisplayName("User Name")] + [ReadOnlyInput] // This attribute is now resolved with the added namespace + [DisabledInput] + [ReadOnly(true)] + public string? UserName { get; set; } + + [Required] + [DisplayName("Approval Threshold")] + [Range(0, 9999999999.99)] + [DataType(DataType.Currency)] + [RegularExpression(@"^\d+(\.\d{1,2})?$", ErrorMessage = "Invalid amount format.")] + public decimal? Threshold { get; set; } + + [DisplayName("Payment Threshold Description")] + public string? Description { get; set; } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs index 9e53add6a..5fd33c30f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs @@ -43,7 +43,7 @@ public async Task> GetL2ApproversThresholds() { Id = paymentThreshold.Id, UserId = user.Id, - UserName = user.Name, + UserName = user.Name + " " + user.Surname, Threshold = paymentThreshold.Threshold, Description = paymentThreshold.Description }); @@ -62,7 +62,7 @@ public async Task> GetL2ApproversThresholds() { Id = paymentThresholdNew.Id, UserId = user.Id, - UserName = user.Name, + UserName = user.Name + " " + user.Surname, Threshold = null, Description = null }); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentThresholdAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentThresholdAppService.cs new file mode 100644 index 000000000..1ba3e518f --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentThresholdAppService.cs @@ -0,0 +1,23 @@ +using System; +using Unity.Payments.Domain.PaymentThresholds; +using Unity.Payments.PaymentThresholds; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; +using Volo.Abp.Domain.Repositories; + +namespace Unity.GrantManager.Payments +{ + public class PaymentThresholdAppService : + CrudAppService< + PaymentThreshold, + PaymentThresholdDto, + Guid, + PagedAndSortedResultRequestDto, + UpdatePaymentThresholdDto>, IPaymentThresholdAppService + { + public PaymentThresholdAppService(IRepository repository) + : base(repository) + { + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs index c2b65a814..632937109 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs @@ -3017,6 +3017,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnName("TenantId"); b.HasKey("Id"); + + b.ToTable("PaymentThresholds", "Payments"); }); From 26159a50a7f3287e454eed1571f376729094c41f Mon Sep 17 00:00:00 2001 From: Sam Saravillo <7529759+samsaravillo@users.noreply.github.com> Date: Fri, 11 Jul 2025 14:46:40 -0700 Subject: [PATCH 06/30] feature/AB#29315 Summary fields for batch approval - Add a 'Note' property to payment request DTOs, domain model, and database schema. - Update the payment approval workflow and UI to support capturing and displaying notes for payment requests. - Include a new EF Core migration to add the Note column to the database --- .../CreatePaymentRequestDto.cs | 3 +- .../PaymentRequests/PaymentRequestDto.cs | 1 + .../Domain/PaymentRequests/PaymentRequest.cs | 8 + .../PaymentRequestAppService.cs | 5 +- .../Localization/Payments/en.json | 1 + .../UpdatePaymentRequestStatus.cshtml | 18 + .../UpdatePaymentRequestStatus.cshtml.cs | 11 +- .../UpdatePaymentRequestStatusModal.js | 15 + ...711200712_AddPaymentNoteColumn.Designer.cs | 3967 +++++++++++++++++ .../20250711200712_AddPaymentNoteColumn.cs | 30 + .../GrantTenantDbContextModelSnapshot.cs | 3 + 11 files changed, 4058 insertions(+), 4 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs index 0c76936c6..cdc6bf166 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs @@ -25,13 +25,14 @@ public class CreatePaymentRequestDto public string? PaymentNumber { get; set; } public string? PaymentDate { get; set; } public decimal? PaymentThreshold { get; set; } = 500000m; + public string? Note { get; set; } } public class UpdatePaymentStatusRequestDto { public Guid PaymentRequestId { get; set; } - public bool IsApprove { get; set; } + public string Note { get; set; } } #pragma warning restore CS8618 } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs index 3b3c09073..c78ab9a22 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs @@ -32,6 +32,7 @@ public class PaymentRequestDto : AuditedEntityDto public decimal BatchNumber { get; set; } public string ReferenceNumber { get; set; } = string.Empty; public string SubmissionConfirmationCode { get; set; } = string.Empty; + public string? Note { get; set; } public string? ErrorSummary { get; set; } public PaymentUserDto? CreatorUser { get; set; } public Collection PaymentTags { get; set; } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs index 01a862678..c0050a7d9 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs @@ -60,6 +60,7 @@ public virtual Site Site public virtual int? CasHttpStatusCode { get; private set; } = null; public virtual string? CasResponse { get; private set; } = string.Empty; + public virtual string? Note { get; private set; } = null; protected PaymentRequest() { ExpenseApprovals = []; @@ -100,10 +101,17 @@ public PaymentRequest(Guid id, CreatePaymentRequestDto createPaymentRequestDto) BatchName = createPaymentRequestDto.BatchName; BatchNumber = createPaymentRequestDto.BatchNumber; PaymentTags = null; + Note = createPaymentRequestDto.Note; ExpenseApprovals = GenerateExpenseApprovals(createPaymentRequestDto.Amount, createPaymentRequestDto.PaymentThreshold); ValidatePaymentRequest(); } + public PaymentRequest SetNote(string note) + { + Note = note; + return this; + } + public PaymentRequest SetAmount(decimal amount) { Amount = amount; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs index 64537771c..524504f2c 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs @@ -221,6 +221,8 @@ public virtual async Task> UpdateStatusAsync(List CreatePaymentRequestDtoAsync(Guid paymentR CreationTime = payment.CreationTime, Status = payment.Status, ReferenceNumber = payment.ReferenceNumber, - SubmissionConfirmationCode = payment.SubmissionConfirmationCode + SubmissionConfirmationCode = payment.SubmissionConfirmationCode, + Note = payment.Note }; } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json index d70f63207..cd184d146 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json @@ -24,6 +24,7 @@ "ApplicationPaymentRequest:BatchNumberName": "Batch #", "ApplicationPaymentRequest:NumberPayment": "Number of Payments", "ApplicationPaymentRequest:TotalAmount": "Total Amount", + "ApplicationPaymentRequest:BatchNote": "Note", "ApplicationPaymentRequest:Validations:RemainingAmountExceeded": "Cannot add a payment that exceeds the remaining amount of ", "ApplicationPaymentRequest:Validations:L2ApproverRestriction": "You cannot approve this payment as you have already approved it as an L1 Approver.", diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml index 5540b4766..f04bbdbee 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml @@ -36,6 +36,24 @@ } + + + + + + + + + + + + + + + + + + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs index 507b225ba..0b37b0efa 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs @@ -43,6 +43,11 @@ public class UpdatePaymentRequestStatus : AbpPageModel [BindProperty] public bool IsErrors { get; set; } + [BindProperty] + public decimal TotalAmount { get; set; } + + [BindProperty] + public string Note { get; set; } = string.Empty; public List SelectedPaymentIds { get; set; } public string FromStatusText { get; set; } = string.Empty; @@ -136,6 +141,7 @@ public async Task OnGetAsync(string paymentIds, bool isApprove) } DisableSubmit = (paymentApprovals.Count == 0 || !ModelState.IsValid); + TotalAmount = paymentApprovals?.Sum(x => x.Amount) ?? 0m; } private async Task CheckUserPermissionsAsync(PaymentRequestStatus status, bool IsApproval, bool isExceedThreshold, PaymentsApprovalModel request) @@ -179,7 +185,7 @@ public async Task OnPostAsync() if (ModelState.IsValid) { - var payments = MapPaymentRequests(IsApproval); + var payments = MapPaymentRequests(IsApproval, Note); await _paymentRequestService.UpdateStatusAsync(payments); } @@ -202,7 +208,7 @@ public async Task GetFromStateForUserAsync() } } - private List MapPaymentRequests(bool isApprove) + private List MapPaymentRequests(bool isApprove, string note) { var payments = new List(); @@ -216,6 +222,7 @@ private List MapPaymentRequests(bool isApprove) { PaymentRequestId = payment.Id, IsApprove = isApprove, + Note = note }); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js index 947dab940..51e632b2d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatusModal.js @@ -1,5 +1,8 @@ function removeApplicationPaymentApproval(applicationId, groupId) { + let $container = $('#' + applicationId); + $container.remove(); + $('#' + applicationId).remove(); let applicationCount = $('#ApplicationCount').val(); let groupCount = $(`#${groupId}_count`).val(); @@ -35,6 +38,8 @@ function removeApplicationPaymentApproval(applicationId, groupId) { if (groupCount - 1 == 0) { $(`#${groupId}_container .payment-status-transition`).css("display", "none"); } + + calculateTotalAmount(); } function closePaymentModal() { @@ -101,6 +106,16 @@ function getStatusText(data) { } } +function calculateTotalAmount() { + let total = 0; + $('.amount').each(function () { + let value = parseFloat($(this).val().replace(/,/g, '')) || 0; + total += value; + }); + $('.totalAmount').val(total.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })); +} + + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.Designer.cs new file mode 100644 index 000000000..2ed79cdef --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.Designer.cs @@ -0,0 +1,3967 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Unity.GrantManager.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + [DbContext(typeof(GrantTenantDbContext))] + [Migration("20250711200712_AddPaymentNoteColumn")] + partial class AddPaymentNoteColumn + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("ScoresheetInstanceId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.HasIndex("ScoresheetInstanceId"); + + b.ToTable("Answers", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("Questions", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Scoresheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CustomFieldId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetInstanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetInstanceId"); + + b.ToTable("CustomFieldValues", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetCorrelationId") + .HasColumnType("uuid"); + + b.Property("WorksheetCorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("WorksheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetLinks", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("CustomFields", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Worksheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantName") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("character varying(600)"); + + b.Property("ApproxNumberOfEmployees") + .HasColumnType("text"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MatchPercentage") + .HasColumnType("numeric"); + + b.Property("NonRegOrgName") + .HasColumnType("text"); + + b.Property("NonRegisteredBusinessName") + .HasColumnType("text"); + + b.Property("OrgName") + .HasColumnType("text"); + + b.Property("OrgNumber") + .HasColumnType("text"); + + b.Property("OrgStatus") + .HasColumnType("text"); + + b.Property("OrganizationSize") + .HasColumnType("text"); + + b.Property("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("StartedOperatingDate") + .HasColumnType("date"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SubSector") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UnityApplicantId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantName"); + + b.ToTable("Applicants", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AddressType") + .HasColumnType("integer"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Postal") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("Street2") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Unit") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("ApplicantAddresses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("BceidBusinessGuid") + .HasColumnType("uuid"); + + b.Property("BceidBusinessName") + .HasColumnType("text"); + + b.Property("BceidUserGuid") + .HasColumnType("uuid"); + + b.Property("BceidUserName") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactOrder") + .HasColumnType("integer"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IdentityEmail") + .HasColumnType("text"); + + b.Property("IdentityName") + .HasColumnType("text"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSubUser") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("Phone2") + .HasColumnType("text"); + + b.Property("Phone2Extension") + .HasColumnType("text"); + + b.Property("PhoneExtension") + .HasColumnType("text"); + + b.Property("RoleForApplicant") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId") + .IsUnique(); + + b.HasIndex("OidcSubUser"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Acquisition") + .HasColumnType("text"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationStatusId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + b.Property("AssessmentResultDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AssessmentResultStatus") + .HasColumnType("text"); + + b.Property("AssessmentStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Community") + .HasColumnType("text"); + + b.Property("CommunityPopulation") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractExecutionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ContractNumber") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeclineRational") + .HasColumnType("text"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DueDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DueDiligenceStatus") + .HasColumnType("text"); + + b.Property("EconomicRegion") + .HasColumnType("text"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinalDecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Forestry") + .HasColumnType("text"); + + b.Property("ForestryFocus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LikelihoodOfFunding") + .HasColumnType("text"); + + b.Property("Notes") + .HasColumnType("text"); + + b.Property("NotificationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("Payload") + .HasColumnType("jsonb"); + + b.Property("PercentageTotalProjectBudget") + .HasColumnType("double precision"); + + b.Property("Place") + .HasColumnType("text"); + + b.Property("ProjectEndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectFundingTotal") + .HasColumnType("numeric"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ProjectStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectSummary") + .HasColumnType("text"); + + b.Property("ProposalDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RecommendedAmount") + .HasColumnType("numeric"); + + b.Property("ReferenceNo") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrict") + .HasColumnType("text"); + + b.Property("RequestedAmount") + .HasColumnType("numeric"); + + b.Property("RiskRanking") + .HasColumnType("text"); + + b.Property("SigningAuthorityBusinessPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityCellPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityEmail") + .HasColumnType("text"); + + b.Property("SigningAuthorityFullName") + .HasColumnType("text"); + + b.Property("SigningAuthorityTitle") + .HasColumnType("text"); + + b.Property("SubStatus") + .HasColumnType("text"); + + b.Property("SubmissionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalProjectBudget") + .HasColumnType("numeric"); + + b.Property("TotalScore") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.HasIndex("ApplicationStatusId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Applications", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Duty") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssigneeId"); + + b.ToTable("ApplicationAssignments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsFileId") + .HasColumnType("text"); + + b.Property("ChefsSumbissionId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationChefsFileAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactEmail") + .HasColumnType("text"); + + b.Property("ContactFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactMobilePhone") + .HasColumnType("text"); + + b.Property("ContactTitle") + .HasColumnType("text"); + + b.Property("ContactType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactWorkPhone") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationContact", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasColumnType("text"); + + b.Property("ApplicationFormDescription") + .HasColumnType("text"); + + b.Property("ApplicationFormName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AttemptedConnectionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("Category") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsCriteriaFormGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConnectionHttpStatus") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ElectoralDistrictAddressType") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsDirectApproval") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("RenderFormIoToHtml") + .HasColumnType("boolean"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IntakeId"); + + b.ToTable("ApplicationForms", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormVersionId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsSubmissionGuid") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormVersionId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("RenderedHTML") + .HasColumnType("text"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Submission") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormSubmissions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsFormVersionGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormSchema") + .HasColumnType("jsonb"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubmissionHeaderMapping") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormVersion", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LinkedApplicationId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationLinks", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StatusCode") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("StatusCode") + .IsUnique(); + + b.ToTable("ApplicationStatuses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("TagId"); + + b.ToTable("ApplicationTags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.ToTable("AssessmentAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ApprovalRecommended") + .HasColumnType("boolean"); + + b.Property("AssessorId") + .HasColumnType("uuid"); + + b.Property("CleanGrowth") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicImpact") + .HasColumnType("integer"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinancialAnalysis") + .HasColumnType("integer"); + + b.Property("InclusiveGrowth") + .HasColumnType("integer"); + + b.Property("IsComplete") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssessorId"); + + b.ToTable("Assessments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicationComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.HasIndex("CommenterId"); + + b.ToTable("AssessmentComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.GlobalTag.Tag", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Tags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Identity.Person", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Badge") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcDisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("OidcSub"); + + b.ToTable("Persons", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Intakes.Intake", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Budget") + .HasColumnType("double precision"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Intakes", (string)null); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("BCC") + .IsRequired() + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyType") + .IsRequired() + .HasColumnType("text"); + + b.Property("CC") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesMsgId") + .HasColumnType("uuid"); + + b.Property("ChesResponse") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FromAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Priority") + .IsRequired() + .HasColumnType("text"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("SendOnDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SentDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("text"); + + b.Property("TemplateName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ToAddress") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailLogs", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.EmailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BodyHTML") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyText") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SendFrom") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("EmailTemplates", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Subscriber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Subscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("SubscriptionGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriberId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("SubscriberId"); + + b.ToTable("SubscriptionGroupSubscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TemplateVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MapTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Token") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("TemplateVariables", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Trigger", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Triggers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriptionGroupId") + .HasColumnType("uuid"); + + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SubscriptionGroupId"); + + b.HasIndex("TemplateId"); + + b.HasIndex("TriggerId"); + + b.ToTable("TriggerSubscriptions", "Notifications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentConfigurations.PaymentConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MinistryClient") + .HasColumnType("text"); + + b.Property("PaymentIdPrefix") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentThreshold") + .HasColumnType("numeric"); + + b.Property("ProjectNumber") + .HasColumnType("text"); + + b.Property("Responsibility") + .HasColumnType("text"); + + b.Property("ServiceLine") + .HasColumnType("text"); + + b.Property("Stob") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfigurations", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DecisionUserId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.ToTable("ExpenseApprovals", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("BatchName") + .IsRequired() + .HasColumnType("text"); + + b.Property("BatchNumber") + .HasColumnType("numeric"); + + b.Property("CasHttpStatusCode") + .HasColumnType("integer"); + + b.Property("CasResponse") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InvoiceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("InvoiceStatus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsRecon") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PayeeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentDate") + .HasColumnType("text"); + + b.Property("PaymentNumber") + .HasColumnType("text"); + + b.Property("PaymentStatus") + .HasColumnType("text"); + + b.Property("ReferenceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequesterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("SubmissionConfirmationCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SupplierName") + .HasColumnType("text"); + + b.Property("SupplierNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ReferenceNumber") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("PaymentRequests", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.HasIndex("TagId"); + + b.ToTable("PaymentTags", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressLine1") + .HasColumnType("text"); + + b.Property("AddressLine2") + .HasColumnType("text"); + + b.Property("AddressLine3") + .HasColumnType("text"); + + b.Property("BankAccount") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EFTAdvicePref") + .HasColumnType("text"); + + b.Property("EmailAddress") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCas") + .HasColumnType("timestamp without time zone"); + + b.Property("MarkDeletedInUse") + .HasColumnType("boolean"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentGroup") + .HasColumnType("integer"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SiteProtected") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Sites", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCAS") + .HasColumnType("timestamp without time zone"); + + b.Property("MailingAddress") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SIN") + .HasColumnType("text"); + + b.Property("StandardIndustryClassification") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("Subcategory") + .HasColumnType("text"); + + b.Property("SupplierProtected") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Suppliers", "Payments"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Instances") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Question", "Question") + .WithMany("Answers") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", null) + .WithMany("Answers") + .HasForeignKey("ScoresheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.ScoresheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Sections") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.HasOne("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", null) + .WithMany("Values") + .HasForeignKey("WorksheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Links") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.WorksheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Sections") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany("ApplicantAddresses") + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Applicant"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithOne("ApplicantAgent") + .HasForeignKey("Unity.GrantManager.Applications.ApplicantAgent", "ApplicationId"); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("OidcSubUser") + .HasPrincipalKey("OidcSub"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", "ApplicationForm") + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationStatus", "ApplicationStatus") + .WithMany("Applications") + .HasForeignKey("ApplicationStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Applicant"); + + b.Navigation("ApplicationForm"); + + b.Navigation("ApplicationStatus"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationAssignments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Assignee") + .WithMany() + .HasForeignKey("AssigneeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Assignee"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.HasOne("Unity.GrantManager.Intakes.Intake", null) + .WithMany() + .HasForeignKey("IntakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationTags") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("Assessments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("AssessorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("GroupId"); + + b.HasOne("Unity.Notifications.Templates.Subscriber", "Subscriber") + .WithMany() + .HasForeignKey("SubscriberId"); + + b.Navigation("Subscriber"); + + b.Navigation("SubscriptionGroup"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("SubscriptionGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.EmailTemplate", "EmailTemplate") + .WithMany() + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.Trigger", "Trigger") + .WithMany() + .HasForeignKey("TriggerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmailTemplate"); + + b.Navigation("SubscriptionGroup"); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", "PaymentRequest") + .WithMany("ExpenseApprovals") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PaymentRequest"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", null) + .WithMany("PaymentTags") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Supplier", "Supplier") + .WithMany("Sites") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Navigation("Instances"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Navigation("Links"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Navigation("ApplicantAddresses"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Navigation("ApplicantAgent"); + + b.Navigation("ApplicationAssignments"); + + b.Navigation("ApplicationTags"); + + b.Navigation("Assessments"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Navigation("Applications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Navigation("ExpenseApprovals"); + + b.Navigation("PaymentTags"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Navigation("Sites"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.cs new file mode 100644 index 000000000..85abb961a --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250711200712_AddPaymentNoteColumn.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class AddPaymentNoteColumn : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Note", + schema: "Payments", + table: "PaymentRequests", + type: "text", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Note", + schema: "Payments", + table: "PaymentRequests"); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs index dd62f949a..5d3e9a1eb 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs @@ -3129,6 +3129,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Description") .HasColumnType("text"); + b.Property("Note") + .HasColumnType("text"); + b.Property("ExtraProperties") .IsRequired() .HasColumnType("text") From b4c73bd8b25d85f48bdcd8c5f1c46b515249b7c9 Mon Sep 17 00:00:00 2001 From: Sam Saravillo <7529759+samsaravillo@users.noreply.github.com> Date: Mon, 14 Jul 2025 14:14:25 -0700 Subject: [PATCH 07/30] feature/AB#29315 Batch approval summary fields - Add a new 'Note' column in the payment requests table - Add summary fields number of payments, total amount and note in batch payments - Refines event handling and improve UIUX for consistency --- .../Localization/Payments/en.json | 1 + .../UpdatePaymentRequestStatus.cshtml | 4 ++-- .../Pages/PaymentRequests/Index.js | 20 ++++++++++++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json index cd184d146..cb0629455 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Shared/Localization/Payments/en.json @@ -60,6 +60,7 @@ "ApplicationPaymentListTable:CASResponse": "CAS Response", "ApplicationPaymentListTable:InvoiceStatus": "Invoice Status", "ApplicationPaymentListTable:PaymentStatus": "CAS Payment Status", + "ApplicationPaymentListTable:Note": "Note", "ApplicantInfoView:SupplierInfoTitle": "Supplier Info", "ApplicantInfoView:ApplicantInfo:SupplierNumber": "Supplier #", diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml index f04bbdbee..d57cdc48a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml @@ -19,7 +19,7 @@ { public static string GetContainerValidationState(bool isValid) { - return isValid ? "single-payment" : "single-payment bg-danger-subtle border-danger-subtle"; + return isValid ? "single-payment payment-item" : "single-payment bg-danger-subtle border-danger-subtle"; } } @@ -41,7 +41,7 @@ - + diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js index 234264942..7c9d1338c 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js @@ -279,7 +279,8 @@ $(function () { getInvoiceStatusColumn(columnIndex++), getPaymentStatusColumn(columnIndex++), getCASResponseColumn(columnIndex++), - getTagsColumn(columnIndex++) + getTagsColumn(columnIndex++), + getNoteColumn(columnIndex++) ] return columns.map((column) => ({ ...column, targets: [column.index], orderData: [column.index, 0] })); @@ -612,6 +613,17 @@ $(function () { } } + function getNoteColumn(columnIndex) { + return { + title: l('ApplicationPaymentListTable:Note'), + name: 'note', + data: 'note', + className: 'data-table-header', + index: columnIndex + + }; + } + function getExpenseApprovalsDetails(expenseApprovals, type) { return expenseApprovals.find(x => x.type == type); } @@ -678,7 +690,7 @@ $(function () { } } - $('.select-all-payments').click(function () { + $('.select-all-payments').on('click', function () { if ($(this).is(':checked')) { dataTable.rows({ 'page': 'current' }).select(); } @@ -707,6 +719,4 @@ function openCasResponseModal(casResponse) { casPaymentResponseModal.open({ casResponse: casResponse }); -} - - +} \ No newline at end of file From 1611059ef19cc73ae688ffded90b5c15a7bad727 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:53:54 -0700 Subject: [PATCH 08/30] AB#29554 - Hotfix - Payment Info Permissions Loading --- .../Permissions/PaymentsPermissionDefinitionProvider.cs | 5 ++--- .../Permissions/PermissionGrantsDataSeeder.cs | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs index 42fbade83..b1805a955 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs @@ -36,8 +36,7 @@ public static void Add_PaymentInfo_Permissions(this PermissionGroupDefinition gr { #region PAYMENT INFO GRANULAR PERMISSIONS var upx_Payment = grantApplicationPermissionsGroup - .AddPermission(UnitySelector.Payment.Default, LocalizableString.Create(UnitySelector.Payment.Default)) - .RequireFeatures("Unity.Payments"); + .AddPermission(UnitySelector.Payment.Default, LocalizableString.Create(UnitySelector.Payment.Default)); var upx_Payment_Summary = upx_Payment.AddPaymentChild(UnitySelector.Payment.Summary.Default); @@ -52,6 +51,6 @@ public static void Add_PaymentInfo_Permissions(this PermissionGroupDefinition gr public static PermissionDefinition AddPaymentChild(this PermissionDefinition parent, string name) { - return parent.AddChild(name, LocalizableString.Create(name)).RequireFeatures("Unity.Payments"); + return parent.AddChild(name, LocalizableString.Create(name)); } } 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 59abfa7e5..b28ca1764 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Domain/Permissions/PermissionGrantsDataSeeder.cs @@ -62,7 +62,6 @@ public PermissionGrantsDataSeeder(IPermissionDataSeeder permissionDataSeeder) UnitySelector.Payment.Default, UnitySelector.Payment.Summary.Default, UnitySelector.Payment.Supplier.Default, - UnitySelector.Payment.Supplier.Update, UnitySelector.Payment.PaymentList.Default ]; @@ -122,6 +121,7 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, .. ApplicantInfo_CommonPermissions, .. ProjectInfo_CommonPermissions, .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, .. Notifications_CommonPermissions, .. Dashboard_CommonPermissions ], context.TenantId); @@ -180,6 +180,7 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, .. ApplicantInfo_CommonPermissions, .. ProjectInfo_CommonPermissions, .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, .. Notifications_CommonPermissions, .. Dashboard_CommonPermissions, @@ -221,6 +222,7 @@ await _permissionDataSeeder.SeedAsync(RolePermissionValueProvider.ProviderName, .. ApplicantInfo_CommonPermissions, .. ProjectInfo_CommonPermissions, .. PaymentInfo_CommonPermissions, + UnitySelector.Payment.Supplier.Update, .. Notifications_CommonPermissions, NotificationsPermissions.Settings, .. Dashboard_CommonPermissions, From c8852b1f22dab9ca4f5e02d9e3513b06246a8436 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Wed, 16 Jul 2025 13:51:17 -0700 Subject: [PATCH 09/30] AB#29575 move formschema and version info outside of Flex feature check --- .../Pages/GrantApplications/Details.cshtml.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs index 71915a418..6c5419e89 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs @@ -112,15 +112,15 @@ public async Task OnGetAsync() { ApplicationFormSubmission applicationFormSubmission = await _grantApplicationAppService.GetFormSubmissionByApplicationId(ApplicationId); ZoneStateSet = await _zoneManagementAppService.GetZoneStateSetAsync(applicationFormSubmission.ApplicationFormId); + + var formVersion = applicationFormSubmission.ApplicationFormVersionId.HasValue + ? await _applicationFormVersionAppService.GetAsync(applicationFormSubmission.ApplicationFormVersionId.Value) + : null; + ApplicationFormSchema = formVersion?.FormSchema ?? string.Empty; + ApplicationFormVersionId = formVersion?.Id ?? Guid.Empty; if (await _featureChecker.IsEnabledAsync("Unity.Flex")) { - // Need to look at finding another way to extract / store this info on intake - var formVersion = applicationFormSubmission.ApplicationFormVersionId.HasValue - ? await _applicationFormVersionAppService.GetAsync(applicationFormSubmission.ApplicationFormVersionId.Value) - : null; - ApplicationFormSchema = formVersion?.FormSchema ?? string.Empty; - ApplicationFormVersionId = formVersion?.Id ?? Guid.Empty; var worksheetLinks = await _worksheetLinkAppService.GetListByCorrelationAsync(ApplicationFormVersionId, CorrelationConsts.FormVersion); var tabs = worksheetLinks.Where(s => !FlexConsts.UiAnchors.Contains(s.UiAnchor)).Select(s => new { worksheet = s.Worksheet, uiAnchor = s.UiAnchor, order = s.Order }).ToList(); From 5cef0d1f85b93c4007bb63a6f0a59ee80897a69d Mon Sep 17 00:00:00 2001 From: jpasta Date: Wed, 16 Jul 2025 16:07:20 -0700 Subject: [PATCH 10/30] hotfix/AB#29166-UploadToS3 --- .../Attachments/S3BlobProvider.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs index ca02d5919..6812fd3ac 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs @@ -250,16 +250,28 @@ await _applicationAttachmentRepository.InsertAsync( } public async Task UploadToS3(BlobProviderSaveArgs args, string bucket, string key, string mimeType) - { - PutObjectRequest putRequest = new() + { + byte[] fileBytes; + if (args.BlobStream.CanSeek) + { + args.BlobStream.Position = 0; + } + using (var memoryStream = new MemoryStream()) + { + await args.BlobStream.CopyToAsync(memoryStream); + fileBytes = memoryStream.ToArray(); + } + using var uploadStream = new MemoryStream(fileBytes); + var putRequest = new PutObjectRequest { BucketName = bucket, Key = key, ContentType = mimeType, - InputStream = args.BlobStream, + InputStream = uploadStream, + UseChunkEncoding = false, + DisablePayloadSigning = false }; - - await _amazonS3Client.PutObjectAsync(putRequest); + await _amazonS3Client.PutObjectAsync(putRequest); } From a5c10c28a4c5138f485383f7258f1c33edae2864 Mon Sep 17 00:00:00 2001 From: jpasta Date: Fri, 18 Jul 2025 09:15:29 -0700 Subject: [PATCH 11/30] feature/AB#28691-AccountCodingMulti --- .../IPaymentConfigurationAppService.cs | 7 +- .../PaymentConfigurationDto.cs | 4 +- .../UpsertPaymentConfigurationDtoBase.cs | 2 +- .../CreatePaymentRequestDto.cs | 10 +- .../PaymentRequests/PaymentRequestDto.cs | 1 + .../Domain/AccountCodings/AccountCoding.cs | 18 +- .../PaymentConfiguration.cs | 11 - .../Domain/PaymentRequests/PaymentRequest.cs | 13 +- .../Domain/Services/PaymentsManager.cs | 2 - .../Integrations/Cas/InvoiceService.cs | 87 +- .../Integrations/Cas/SupplierService.cs | 2 +- .../Integrations/RabbitMQ/InvoiceConsumer.cs | 21 +- .../PaymentConfigurationAppService.cs | 55 +- .../PaymentsApplicationAutoMapperProfile.cs | 28 +- .../Pages/AccountCoding/CreateModal.cshtml | 2 +- .../Pages/AccountCoding/CreateModal.cshtml.cs | 17 +- .../Pages/AccountCoding/UpdateModal.cshtml | 2 +- .../Pages/AccountCoding/UpdateModal.cshtml.cs | 2 +- .../Pages/PaymentConfigurations/Index.cshtml | 23 +- .../PaymentConfigurations/Index.cshtml.cs | 11 +- .../Pages/PaymentConfigurations/Index.css | 9 + .../Pages/PaymentConfigurations/Index.js | 95 +- .../CreatePaymentRequests.cshtml | 2 + .../CreatePaymentRequests.cshtml.cs | 26 +- .../Pages/PaymentRequests/PaymentsModel.cs | 1 + .../Http/ResilientHttpRequest.cs | 3 +- .../Integrations/TokenService.cs | 2 - .../IGrantApplicationAppService.cs | 1 + .../Applicants/ApplicantAppService.cs | 2 +- .../ApplicationFormAppService.cs | 20 +- .../Attachments/S3BlobProvider.cs | 1 - .../GrantApplicationAppService.cs | 2098 +++++++++-------- .../GrantManagerApplicationModule.cs | 2 +- .../Payments/IPaymentSettingsAppService.cs | 6 +- .../Payments/PaymentSettingsAppService.cs | 23 +- .../PaymentConfigurationViewComponent.cs | 1 + 36 files changed, 1379 insertions(+), 1231 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/IPaymentConfigurationAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/IPaymentConfigurationAppService.cs index 6cd6ffcfc..fbb3645ba 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/IPaymentConfigurationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/IPaymentConfigurationAppService.cs @@ -1,11 +1,14 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace Unity.Payments.PaymentConfigurations { public interface IPaymentConfigurationAppService { - Task GetAsync(); + Task GetAsync(); Task UpdateAsync(UpdatePaymentConfigurationDto updatePaymentConfigurationDto); Task CreateAsync(CreatePaymentConfigurationDto createUpdatePaymentConfigurationDto); + Task UpdatePaymentPrefixAsync(string paymentPrefix); + Task SetDefaultAccountCodeAsync(Guid accountCodingId); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/PaymentConfigurationDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/PaymentConfigurationDto.cs index fc91d2973..9c1606c91 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/PaymentConfigurationDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/PaymentConfigurationDto.cs @@ -5,8 +5,8 @@ namespace Unity.Payments.PaymentConfigurations { [Serializable] public class PaymentConfigurationDto : ExtensibleFullAuditedEntityDto - { - public decimal PaymentThreshold { get; set; } + { public string PaymentIdPrefix { get; set; } = string.Empty; + public Guid DefaultAccountCodingId { get; set; } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs index 03e428b42..9cf56f896 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs @@ -5,7 +5,7 @@ namespace Unity.Payments.PaymentConfigurations [Serializable] public class UpsertPaymentConfigurationDtoBase { - public decimal PaymentThreshold { get; set; } public string PaymentIdPrefix { get; set; } = string.Empty; + public Guid DefaultAcountCodingId { get; set; } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs index 0c76936c6..cfa746947 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/CreatePaymentRequestDto.cs @@ -18,13 +18,13 @@ public class CreatePaymentRequestDto public string CorrelationProvider { get; set; } = string.Empty; public string BatchName { get; set; } public decimal BatchNumber { get; set; } = 0; - public string ReferenceNumber { get; set; } = string.Empty; + public string ReferenceNumber { get; set; } = string.Empty; public string SubmissionConfirmationCode { get; set; } = string.Empty; - public string? InvoiceStatus { get; set; } - public string? PaymentStatus { get; set; } - public string? PaymentNumber { get; set; } + public string? InvoiceStatus { get; set; } + public string? PaymentStatus { get; set; } + public string? PaymentNumber { get; set; } public string? PaymentDate { get; set; } - public decimal? PaymentThreshold { get; set; } = 500000m; + public Guid? AccountCodingId { get; set; } } public class UpdatePaymentStatusRequestDto diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs index 3b3c09073..af5398189 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/PaymentRequestDto.cs @@ -33,6 +33,7 @@ public class PaymentRequestDto : AuditedEntityDto public string ReferenceNumber { get; set; } = string.Empty; public string SubmissionConfirmationCode { get; set; } = string.Empty; public string? ErrorSummary { get; set; } + public Guid? AccountCodingId { get; set; } public PaymentUserDto? CreatorUser { get; set; } public Collection PaymentTags { get; set; } public Collection ExpenseApprovals { get; set; } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs index c474c51e2..a3b264254 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs @@ -1,16 +1,18 @@ using Unity.Payments.Domain.Exceptions; using Volo.Abp; +using System; +using Volo.Abp.Domain.Entities.Auditing; namespace Unity.Payments.Domain.AccountCodings { - public record AccountCoding + public class AccountCoding : AuditedAggregateRoot { - public string MinistryClient { get; private set; } = string.Empty; - public string Responsibility { get; private set; } = string.Empty; - public string ServiceLine { get; private set; } = string.Empty; - public string Stob { get; private set; } = string.Empty; - public string ProjectNumber { get; private set; } = string.Empty; - + public string MinistryClient { get; private set; } + public string Responsibility { get; private set; } + public string ServiceLine { get; private set; } + public string Stob { get; private set; } + public string ProjectNumber { get; private set; } + private AccountCoding(string ministryClient, string responsibility, string serviceLine, @@ -52,4 +54,4 @@ private static void ValidateField(string field, uint length, string fieldName, b } } -} +} \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs index 07f8b5bc5..20304e414 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentConfigurations/PaymentConfiguration.cs @@ -1,5 +1,4 @@ using System; -using Unity.Payments.Domain.AccountCodings; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; @@ -10,19 +9,9 @@ public class PaymentConfiguration : FullAuditedAggregateRoot, IMultiTenant public Guid? TenantId { get; set; } public Guid? DefaultAccountCodingId { get; set; } public string PaymentIdPrefix { get; set; } = string.Empty; - public decimal? PaymentThreshold { get; set; } - public PaymentConfiguration() { /* This constructor is for ORMs to be used while getting the entity from the database. */ } - - public PaymentConfiguration( - decimal? paymentThreshold, - string paymentIdPrefix) - { - PaymentThreshold = paymentThreshold; - PaymentIdPrefix = paymentIdPrefix; - } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs index 01a862678..c7c9afd25 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/PaymentRequest.cs @@ -59,6 +59,7 @@ public virtual Site Site // Corperate Accounting System public virtual int? CasHttpStatusCode { get; private set; } = null; public virtual string? CasResponse { get; private set; } = string.Empty; + public virtual Guid? AccountCodingId { get; private set; } protected PaymentRequest() { @@ -67,7 +68,7 @@ protected PaymentRequest() /* This constructor is for ORMs to be used while getting the entity from the database. */ } - private static Collection GenerateExpenseApprovals(decimal amount, decimal? paymentThreshold = 500000m) + private static Collection GenerateExpenseApprovals() { var expenseApprovals = new Collection() { @@ -75,11 +76,6 @@ private static Collection GenerateExpenseApprovals(decimal amou new(Guid.NewGuid(), ExpenseApprovalType.Level2) }; - if (amount >= paymentThreshold) - { - expenseApprovals.Add(new ExpenseApproval(Guid.NewGuid(), ExpenseApprovalType.Level3)); - } - return expenseApprovals; } @@ -99,8 +95,9 @@ public PaymentRequest(Guid id, CreatePaymentRequestDto createPaymentRequestDto) SubmissionConfirmationCode = createPaymentRequestDto.SubmissionConfirmationCode; BatchName = createPaymentRequestDto.BatchName; BatchNumber = createPaymentRequestDto.BatchNumber; - PaymentTags = null; - ExpenseApprovals = GenerateExpenseApprovals(createPaymentRequestDto.Amount, createPaymentRequestDto.PaymentThreshold); + AccountCodingId = createPaymentRequestDto.AccountCodingId; + PaymentTags = null; + ExpenseApprovals = GenerateExpenseApprovals(); ValidatePaymentRequest(); } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs index 76adb4252..46dde4749 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/Services/PaymentsManager.cs @@ -7,7 +7,6 @@ using Unity.Payments.Domain.Shared; using Unity.Payments.Domain.Workflow; using Unity.Payments.Enums; -using Unity.Payments.Integrations.Cas; using Unity.Payments.PaymentRequests; using Unity.Payments.Permissions; using Volo.Abp.Authorization.Permissions; @@ -28,7 +27,6 @@ public class PaymentsManager : DomainService, IPaymentsManager public PaymentsManager( CasPaymentRequestCoordinator casPaymentRequestCoordinator, - IInvoiceService invoiceService, IPaymentRequestRepository paymentRequestRepository, IUnitOfWorkManager unitOfWorkManager, IPermissionChecker permissionChecker, diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs index 48673e584..f6c85731f 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/InvoiceService.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using Unity.Payments.Enums; using Unity.Payments.Domain.Suppliers; -using Unity.Payments.PaymentConfigurations; using Unity.Payments.Domain.PaymentRequests; using Volo.Abp.DependencyInjection; using Unity.Payments.Codes; @@ -22,16 +21,15 @@ namespace Unity.Payments.Integrations.Cas { [IntegrationService] [ExposeServices(typeof(InvoiceService), typeof(IInvoiceService))] - public class InvoiceService : ApplicationService, IInvoiceService + public class InvoiceService(ICasTokenService iTokenService, + IPaymentRequestRepository paymentRequestRepository, + IResilientHttpRequest resilientHttpRequest, + IOptions casClientOptions, + ISupplierRepository iSupplierRepository, + ISiteRepository iSiteRepository, + IUnitOfWorkManager unitOfWorkManager) : ApplicationService, IInvoiceService { - private readonly ICasTokenService _iTokenService; - private readonly IPaymentRequestRepository _iPaymentRequestRepository; - private readonly IResilientHttpRequest _resilientRestClient; - private readonly ISiteRepository _iSiteRepository; - private readonly ISupplierRepository _iSupplierRepository; - private readonly IOptions _casClientOptions; - private readonly IPaymentConfigurationAppService _paymentConfigurationAppService; - private readonly IUnitOfWorkManager _unitOfWorkManager; + private const string CFS_APINVOICE = "cfs/apinvoice"; @@ -41,25 +39,6 @@ public class InvoiceService : ApplicationService, IInvoiceService [(int)PaymentGroup.Cheque] = "GEN CHQ" }; - public InvoiceService( - ICasTokenService iTokenService, - IPaymentRequestRepository paymentRequestRepository, - IPaymentConfigurationAppService paymentConfigurationAppService, - IResilientHttpRequest resilientHttpRequest, - IOptions casClientOptions, - ISupplierRepository iSupplierRepository, - ISiteRepository iSiteRepository, - IUnitOfWorkManager unitOfWorkManager) - { - _iTokenService = iTokenService; - _iPaymentRequestRepository = paymentRequestRepository; - _paymentConfigurationAppService = paymentConfigurationAppService; - _resilientRestClient = resilientHttpRequest; - _casClientOptions = casClientOptions; - _iSupplierRepository = iSupplierRepository; - _iSiteRepository = iSiteRepository; - _unitOfWorkManager = unitOfWorkManager; - } protected virtual async Task InitializeCASInvoice(PaymentRequest paymentRequest, string? accountDistributionCode) @@ -102,10 +81,10 @@ public InvoiceService( public async Task GetSiteByPaymentRequestAsync(PaymentRequest paymentRequest) { - Site? site = await _iSiteRepository.GetAsync(paymentRequest.SiteId, true); + Site? site = await iSiteRepository.GetAsync(paymentRequest.SiteId, true); if (site?.SupplierId != null) { - Supplier supplier = await _iSupplierRepository.GetAsync(site.SupplierId); + Supplier supplier = await iSupplierRepository.GetAsync(site.SupplierId); site.Supplier = supplier; } return site; @@ -116,13 +95,18 @@ public InvoiceService( InvoiceResponse invoiceResponse = new(); try { - PaymentRequest? paymentRequest = await _iPaymentRequestRepository.GetPaymentRequestByInvoiceNumber(invoiceNumber); + PaymentRequest? paymentRequest = await paymentRequestRepository.GetPaymentRequestByInvoiceNumber(invoiceNumber); if (paymentRequest is null) { throw new UserFriendlyException("CreateInvoiceByPaymentRequestAsync: Payment Request not found"); } - string? accountDistributionCode = ""; // Placeholder for actual logic + // Based on the payment request application id in the correlation id + // lookup the form id + // on the form is there an acount distribution code? + // If no account distribution code then we can use the default account distribution code from payment configuration default account distribution code id + + string? accountDistributionCode = "";// this will be on the payment request if (!string.IsNullOrEmpty(accountDistributionCode)) { @@ -151,8 +135,8 @@ private async Task UpdatePaymentRequestWithInvoice(Guid paymentRequestId, Invoic { try { - using var uow = _unitOfWorkManager.Begin(); - PaymentRequest? paymentRequest = await _iPaymentRequestRepository.GetAsync(paymentRequestId); + using var uow = unitOfWorkManager.Begin(); + PaymentRequest? paymentRequest = await paymentRequestRepository.GetAsync(paymentRequestId); paymentRequest.SetCasHttpStatusCode((int)invoiceResponse.CASHttpStatusCode); paymentRequest.SetCasResponse(invoiceResponse.CASReturnedMessages); // Set the status - for the payment request @@ -164,8 +148,8 @@ private async Task UpdatePaymentRequestWithInvoice(Guid paymentRequestId, Invoic { paymentRequest.SetInvoiceStatus(CasPaymentRequestStatus.ErrorFromCas); } - - await _iPaymentRequestRepository.UpdateAsync(paymentRequest, autoSave: false); + + await paymentRequestRepository.UpdateAsync(paymentRequest, autoSave: false); await uow.SaveChangesAsync(); } catch (Exception ex) @@ -178,13 +162,13 @@ private async Task UpdatePaymentRequestWithInvoice(Guid paymentRequestId, Invoic public async Task CreateInvoiceAsync(Invoice casAPInvoice) { string jsonString = JsonSerializer.Serialize(casAPInvoice); - var authToken = await _iTokenService.GetAuthTokenAsync(); - var resource = $"{_casClientOptions.Value.CasBaseUrl}/{CFS_APINVOICE}/"; - var response = await _resilientRestClient.HttpAsyncWithBody(HttpMethod.Post, resource, jsonString, authToken); + var authToken = await iTokenService.GetAuthTokenAsync(); + var resource = $"{casClientOptions.Value.CasBaseUrl}/{CFS_APINVOICE}/"; + var response = await resilientHttpRequest.HttpAsyncWithBody(HttpMethod.Post, resource, jsonString, authToken); if (response != null) { - if(response.Content != null && response.StatusCode != HttpStatusCode.NotFound) + if (response.Content != null && response.StatusCode != HttpStatusCode.NotFound) { var contentString = ResilientHttpRequest.ContentToString(response.Content); var result = JsonSerializer.Deserialize(contentString) @@ -195,7 +179,8 @@ public async Task CreateInvoiceAsync(Invoice casAPInvoice) else if (response.RequestMessage != null) { throw new UserFriendlyException("CAS InvoiceService CreateInvoiceAsync Exception: " + response.RequestMessage); - } else + } + else { throw new UserFriendlyException("CAS InvoiceService CreateInvoiceAsync Exception: " + response); } @@ -208,29 +193,29 @@ public async Task CreateInvoiceAsync(Invoice casAPInvoice) public async Task GetCasInvoiceAsync(string invoiceNumber, string supplierNumber, string supplierSiteCode) { - var authToken = await _iTokenService.GetAuthTokenAsync(); - var resource = $"{_casClientOptions.Value.CasBaseUrl}/{CFS_APINVOICE}/{invoiceNumber}/{supplierNumber}/{supplierSiteCode}"; - var response = await _resilientRestClient.HttpAsync(HttpMethod.Get, resource, authToken); + var authToken = await iTokenService.GetAuthTokenAsync(); + var resource = $"{casClientOptions.Value.CasBaseUrl}/{CFS_APINVOICE}/{invoiceNumber}/{supplierNumber}/{supplierSiteCode}"; + var response = await resilientHttpRequest.HttpAsync(HttpMethod.Get, resource, authToken); if (response != null && response.Content != null && response.IsSuccessStatusCode) { - string contentString = Unity.Modules.Shared.Http.ResilientHttpRequest.ContentToString(response.Content); + string contentString = ResilientHttpRequest.ContentToString(response.Content); var result = JsonSerializer.Deserialize(contentString); return result ?? new CasPaymentSearchResult(); } else { - return new CasPaymentSearchResult() {}; + return new CasPaymentSearchResult() { }; } } public async Task GetCasPaymentAsync(string invoiceNumber, string supplierNumber, string siteNumber) { - var authToken = await _iTokenService.GetAuthTokenAsync(); - var resource = $"{_casClientOptions.Value.CasBaseUrl}/{CFS_APINVOICE}/{invoiceNumber}/{supplierNumber}/{siteNumber}"; - var response = await _resilientRestClient.HttpAsync(HttpMethod.Get, resource, authToken); + var authToken = await iTokenService.GetAuthTokenAsync(); + var resource = $"{casClientOptions.Value.CasBaseUrl}/{CFS_APINVOICE}/{invoiceNumber}/{supplierNumber}/{siteNumber}"; + var response = await resilientHttpRequest.HttpAsync(HttpMethod.Get, resource, authToken); CasPaymentSearchResult casPaymentSearchResult = new(); if (response != null @@ -241,7 +226,7 @@ public async Task GetCasPaymentAsync(string invoiceNumbe var result = JsonSerializer.Deserialize(content.Result); return result ?? casPaymentSearchResult; } - else if(response != null) + else if (response != null) { casPaymentSearchResult.InvoiceStatus = response.StatusCode.ToString(); } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/SupplierService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/SupplierService.cs index 4cc6a4911..cbaff113e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/SupplierService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/Cas/SupplierService.cs @@ -82,7 +82,7 @@ private async Task UpdateSupplierInfo(dynamic casSupplierResponse, Guid applican supplierEto.CorrelationId = applicantId; supplierEto.CorrelationProvider = CorrelationConsts.Applicant; await localEventBus.PublishAsync(supplierEto); - }catch(Exception ex) + } catch (Exception ex) { Logger.LogError(ex, "An exception occurred updating the supplier: {ExceptionMessage}", ex.Message); throw new UserFriendlyException("An exception occurred updating the supplier."); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/RabbitMQ/InvoiceConsumer.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/RabbitMQ/InvoiceConsumer.cs index 8f3c238e8..1165ebd44 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/RabbitMQ/InvoiceConsumer.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Integrations/RabbitMQ/InvoiceConsumer.cs @@ -3,33 +3,20 @@ using Unity.Payments.RabbitMQ.QueueMessages; using System; using Volo.Abp.MultiTenancy; -using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Integrations.Cas; namespace Unity.Payments.Integrations.RabbitMQ; -public class InvoiceConsumer : IQueueConsumer +public class InvoiceConsumer(InvoiceService invoiceService, + ICurrentTenant currentTenant) : IQueueConsumer { - private readonly ICurrentTenant _currentTenant; - private readonly InvoiceService _invoiceService; - - public InvoiceConsumer( - InvoiceService invoiceService, - IPaymentRequestRepository paymentRequestRepository, - ICurrentTenant currentTenant - ) - { - _invoiceService = invoiceService; - _currentTenant = currentTenant; - } - public async Task ConsumeAsync(InvoiceMessages invoiceMessage) { if (invoiceMessage != null && !invoiceMessage.InvoiceNumber.IsNullOrEmpty() && invoiceMessage.TenantId != Guid.Empty) { - using (_currentTenant.Change(invoiceMessage.TenantId)) + using (currentTenant.Change(invoiceMessage.TenantId)) { - await _invoiceService.CreateInvoiceByPaymentRequestAsync(invoiceMessage.InvoiceNumber); + await invoiceService.CreateInvoiceByPaymentRequestAsync(invoiceMessage.InvoiceNumber); } } return Task.CompletedTask; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs index 9e53be0fe..318caa237 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs @@ -1,8 +1,9 @@ +using System; using System.Threading.Tasks; using Unity.Payments.Domain.AccountCodings; -using Unity.Payments.Domain.AccountCodings; using Unity.Payments.Domain.Exceptions; using Unity.Payments.Domain.PaymentConfigurations; +using Volo.Abp.Domain.Repositories; using Volo.Abp.Features; namespace Unity.Payments.PaymentConfigurations @@ -10,8 +11,6 @@ namespace Unity.Payments.PaymentConfigurations [RequiresFeature("Unity.Payments")] public class PaymentConfigurationAppService(IPaymentConfigurationRepository paymentConfigurationRepository) : PaymentsAppService, IPaymentConfigurationAppService { - - public virtual async Task GetAsync() { PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); @@ -41,19 +40,13 @@ public virtual Task GetAccountDistributionCode(AccountCoding accountCodi public virtual async Task CreateAsync(CreatePaymentConfigurationDto createUpdatePaymentConfigurationDto) { - PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync(); - - if (paymentConfiguration != null) + PaymentConfiguration? paymentConfiguration = new PaymentConfiguration { - throw new ConfigurationExistsException(L[ErrorConsts.ConfigurationExists]); - } - - var newPaymentConfiguration = await paymentConfigurationRepository.InsertAsync(new PaymentConfiguration - ( - createUpdatePaymentConfigurationDto.PaymentThreshold, - createUpdatePaymentConfigurationDto.PaymentIdPrefix - )); + DefaultAccountCodingId = createUpdatePaymentConfigurationDto.DefaultAcountCodingId, + PaymentIdPrefix = createUpdatePaymentConfigurationDto.PaymentIdPrefix + }; + var newPaymentConfiguration = await paymentConfigurationRepository.InsertAsync(paymentConfiguration); return ObjectMapper.Map(newPaymentConfiguration); } @@ -62,14 +55,44 @@ public virtual async Task UpdateAsync(UpdatePaymentConf PaymentConfiguration? paymentConfiguration = await FindPaymentConfigurationAsync() ?? throw new ConfigurationExistsException(L[ErrorConsts.ConfigurationDoesNotExist]); - paymentConfiguration.PaymentThreshold = updatePaymentConfigurationDto.PaymentThreshold; paymentConfiguration.PaymentIdPrefix = updatePaymentConfigurationDto.PaymentIdPrefix; - var updatedConfiguration = await paymentConfigurationRepository.UpdateAsync(paymentConfiguration); return ObjectMapper.Map(updatedConfiguration); } + + public async Task UpdatePaymentPrefixAsync(string paymentPrefix) + { + PaymentConfiguration? paymentConfiguration = await paymentConfigurationRepository.FirstOrDefaultAsync(); + if (paymentConfiguration == null) + { + CreatePaymentConfigurationDto paymentConfigurationDto = new CreatePaymentConfigurationDto(); + paymentConfigurationDto.PaymentIdPrefix = paymentPrefix; + await CreateAsync(paymentConfigurationDto); + } + else + { + paymentConfiguration.PaymentIdPrefix = paymentPrefix; + await paymentConfigurationRepository.UpdateAsync(paymentConfiguration); + } + } + public async Task SetDefaultAccountCodeAsync(Guid accountCodingId) + { + PaymentConfiguration? paymentConfiguration = await paymentConfigurationRepository.FirstOrDefaultAsync(); + + if (paymentConfiguration == null) + { + CreatePaymentConfigurationDto paymentConfigurationDto = new CreatePaymentConfigurationDto(); + paymentConfigurationDto.DefaultAcountCodingId = accountCodingId; + await CreateAsync(paymentConfigurationDto); + } + else + { + paymentConfiguration.DefaultAccountCodingId = accountCodingId; + await paymentConfigurationRepository.UpdateAsync(paymentConfiguration); + } + } protected virtual async Task FindPaymentConfigurationAsync() { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs index af174d9bd..19c00f440 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentsApplicationAutoMapperProfile.cs @@ -1,9 +1,20 @@ using AutoMapper; -using Unity.Payments.Domain.PaymentRequests; +using Unity.GrantManager.Applications; +using Unity.GrantManager.GlobalTag; +using Unity.GrantManager.Payments; +using Unity.Payments.Domain.AccountCodings; using Unity.Payments.Domain.PaymentConfigurations; +using Unity.Payments.Domain.PaymentRequests; +using Unity.Payments.Domain.PaymentTags; +using Unity.Payments.Domain.PaymentThresholds; using Unity.Payments.Domain.Suppliers; +using Unity.Payments.PaymentConfigurations; +using Unity.Payments.PaymentRequests; +using Unity.Payments.PaymentTags; +using Unity.Payments.PaymentThresholds; +using Unity.Payments.Suppliers; using Volo.Abp.Users; -using Unity.Payments.Domain.PaymentThresholds; + namespace Unity.Payments; @@ -24,14 +35,19 @@ public PaymentsApplicationAutoMapperProfile() CreateMap() .ForMember(dest => dest.PaymentGroup, opt => opt.MapFrom(s => s.PaymentGroup.ToString())); CreateMap(); + + CreateMap() + .ForMember(dest => dest.LastModificationTime, opt => opt.Ignore()) + .ForMember(dest => dest.LastModifierId, opt => opt.Ignore()) + .ForMember(dest => dest.CreationTime, opt => opt.Ignore()) + .ForMember(dest => dest.CreatorId, opt => opt.Ignore()) + .ForMember(dest => dest.ExtraProperties, opt => opt.Ignore()) + .ForMember(dest => dest.ConcurrencyStamp, opt => opt.Ignore()) + .ForMember(dest => dest.Id, opt => opt.Ignore()); CreateMap(); CreateMap(); CreateMap(); CreateMap() - .ForMember(dest => dest.TenantId, opt => opt.Ignore()) - .ForMember(dest => dest.IsDeleted, opt => opt.Ignore()) - .ForMember(dest => dest.DeleterId, opt => opt.Ignore()) - .ForMember(dest => dest.DeletionTime, opt => opt.Ignore()) .ForMember(dest => dest.LastModificationTime, opt => opt.Ignore()) .ForMember(dest => dest.LastModifierId, opt => opt.Ignore()) .ForMember(dest => dest.CreationTime, opt => opt.Ignore()) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml index b89b742df..fcda3d04e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml @@ -1,6 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal -@model Unity.GrantManager.Web.Pages.AccountCoding.CreateModalModel +@model Unity.Payments.Web.Pages.AccountCoding.CreateModalModel @{ Layout = null; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs index 84a3102fd..41ce4e2e3 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/CreateModal.cshtml.cs @@ -1,9 +1,11 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using System.Threading.Tasks; using Unity.GrantManager.Payments; +using Volo.Abp; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; -namespace Unity.GrantManager.Web.Pages.AccountCoding; +namespace Unity.Payments.Web.Pages.AccountCoding; public class CreateModalModel(IAccountCodingAppService accountCodingAppService) : AbpPageModel { @@ -12,9 +14,14 @@ public class CreateModalModel(IAccountCodingAppService accountCodingAppService) public async Task OnPostAsync() { - await accountCodingAppService.CreateAsync(AccountCoding!); - return NoContent(); + try + { + await accountCodingAppService.CreateAsync(AccountCoding!); + return NoContent(); + } + catch (DbUpdateException ex) when (ex.InnerException?.Message?.Contains("duplicate key") == true) + { + throw new UserFriendlyException("This Account Coding already exists"); + } } } - - diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml index f7a8afe2e..900ec8ec4 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml @@ -1,7 +1,7 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal -@model Unity.GrantManager.Web.Pages.AccountCoding.UpdateModalModel +@model Unity.Payments.Web.Pages.AccountCoding.UpdateModalModel @{ Layout = null; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs index 752c5a6fd..8376e5f1d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/AccountCoding/UpdateModal.cshtml.cs @@ -4,7 +4,7 @@ using Unity.GrantManager.Payments; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; -namespace Unity.GrantManager.Web.Pages.AccountCoding; +namespace Unity.Payments.Web.Pages.AccountCoding; public class UpdateModalModel(IAccountCodingAppService accountCodingAppService) : AbpPageModel { diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml index 4d8840b9a..3a35ebedd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml @@ -59,15 +59,30 @@ - Payment id Prefix - + Payment ID Prefix + + +
+ + + +

-

Approval Threshold

-
+

Level 2 Approval Threshold

+ +
diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs index 35dc33c11..2af20880b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.cshtml.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Unity.Payments.Domain.PaymentConfigurations; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Domain.Repositories; namespace Unity.Payments.Web.Pages.PaymentConfifurations { @@ -11,20 +12,20 @@ public class PaymentConfigurationModel(IPaymentConfigurationRepository paymentCo [HiddenInput] [BindProperty(SupportsGet = true)] public Guid? AccountCodingId { get; set; } - + [BindProperty(SupportsGet = true)] public string? PaymentIdPrefix { get; set; } public async Task OnGetAsync() { - var paymentConfigurations = await paymentConfigurationRepository.GetListAsync(); - var paymentConfiguration = paymentConfigurations.Count > 0 ? paymentConfigurations[0] : null; + // There should be only one payment configuration, so we can use FirstOrDefaultAsync + PaymentConfiguration? paymentConfiguration = await paymentConfigurationRepository.FirstOrDefaultAsync(); if (paymentConfiguration != null) { AccountCodingId = paymentConfiguration.DefaultAccountCodingId; PaymentIdPrefix = paymentConfiguration.PaymentIdPrefix; - } - } + } + } } } \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css index 39f53b4a4..cd764facf 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.css @@ -118,6 +118,15 @@ input.form-control:focus, input.form-control:active, textarea.form-control:focus text-align: right; } +label.display-input-label { + font-size: var(--bc-font-size-sm); + color: var(--bc-colors-grey-text-300); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 0; +} + @media only screen and (max-width: 850px) { .field-validation-error { float: none; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js index c847e0d2e..d66bc1106 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentConfigurations/Index.js @@ -1,35 +1,44 @@ +let accountCodingDataTable; +let paymentSettingsDataTable; + $(function () { let createModal = new abp.ModalManager(abp.appPath + 'AccountCoding/CreateModal'); let updateModal = new abp.ModalManager(abp.appPath + 'AccountCoding/UpdateModal'); let updateThresholdModal = new abp.ModalManager(abp.appPath + 'PaymentThresholds/UpdateModal'); + const formatter = createNumberFormatter(); const l = abp.localization.getResource('GrantManager'); toastr.options.positionClass = 'toast-top-center'; - let dataTable; - let paymentSettingsDataTable; + const UIElements = { - accountCodingDataTable: $('#AccountCodesDataTable'), - paymentSettingsDataTable: $('#PaymentSettingsDataTable'), + accountCodingDT: $('#AccountCodesDataTable'), + paymentSettingsDT: $('#PaymentSettingsDataTable'), accountCodingId: $('#AccountCodingId'), accountCodingMenu: $('#account-coding-menu-item'), paymentSettingMenu: $('#payment-setting-menu-item'), accountCodesDiv: $('#account-codes-div'), paymentSettingsDiv: $('#payment-settings-div'), + paymentPrefixSaveButton: $('#PaymentPrefixSaveButton'), + paymentPrefixDiscardButton: $('#PaymentPrefixDiscardButton'), + paymentPrefixInput: $('#payment-id-prefix'), + originalPaymentPrefix: $('#payment-id-prefix-original') }; init(); function init() { - dataTable = initializeAccountCodesDataTable(); + accountCodingDataTable = initializeAccountCodesDataTable(); paymentSettingsDataTable = initializePaymentSettingsDataTable(); bindUIElements(); } function bindUIElements() { UIElements.accountCodingMenu.on('click', menuItemClick); - UIElements.paymentSettingMenu.on('click', menuItemClick); - } + UIElements.paymentSettingMenu.on('click', menuItemClick); + UIElements.paymentPrefixSaveButton.on('click', updatePaymentPrefix); + UIElements.paymentPrefixDiscardButton.on('click', discardPaymentPrefix); + UIElements.paymentPrefixInput.on('keyup', checkEnableDiscard); } function removeActiveClassFromMenuItems() { UIElements.accountCodingMenu.removeClass('active'); @@ -42,7 +51,8 @@ $(function () { UIElements.accountCodesDiv.toggleClass('hide'); UIElements.paymentSettingsDiv.toggleClass('hide'); paymentSettingsDataTable.columns.adjust().draw(); - dataTable.columns.adjust().draw(); + accountCodingDataTable.columns.adjust().draw(); + clearFilter(); } function bindModalElements() { @@ -84,7 +94,6 @@ $(function () { } } - function setAccountCodingDisplay() { let currentAccount = $(UIElements.inputMinistryClient).val() + "." + $(UIElements.inputResponsibility).val() + "." + @@ -116,7 +125,7 @@ $(function () { }; }; - let dt = UIElements.paymentSettingsDataTable; + let dt = UIElements.paymentSettingsDT; return initializeDataTable({ dt, defaultVisibleColumns, @@ -133,6 +142,7 @@ $(function () { dataTableName: 'PaymentSettingsDataTable', dynamicButtonContainerId: 'dynamicButtonContainerId', useNullPlaceholder: true, + disableColumnSelect: true, externalSearchId: 'search-data-table' }); @@ -166,7 +176,11 @@ $(function () { className: 'dt-body-right', data: "threshold", visible: true, - index: index++ + index: index++, + render: function (data, type, row) { + if (data == null || data === '') return ''; + return formatter.format(data); + } }, { title: 'Description', @@ -207,8 +221,7 @@ $(function () { id: 'CreateButton', className: 'btn-light rounded-1', action: (e, dt, node, config) => createAccountCodingBtn(e) - }, - ...commonTableActionButtons(l('Intake')) + } ]; const listColumns = getAccountCodingColumns(); @@ -231,7 +244,7 @@ $(function () { }; }; - let dt = UIElements.accountCodingDataTable; + let dt = UIElements.accountCodingDT; return initializeDataTable({ dt, defaultVisibleColumns, @@ -248,6 +261,7 @@ $(function () { dataTableName: 'AccountCodesDataTable', dynamicButtonContainerId: 'dynamicButtonContainerId', useNullPlaceholder: true, + disableColumnSelect: true, externalSearchId: 'search-data-table' }); } @@ -300,7 +314,7 @@ $(function () { data: 'id', render: function (data, type, full, meta) { let checked = UIElements.accountCodingId.val() == data ? 'checked' : ''; - return ``; + return ``; } }, { @@ -360,14 +374,61 @@ $(function () { }); }; + function updatePaymentPrefix() { + unity.payments.paymentConfigurations.paymentConfiguration.updatePaymentPrefix(UIElements.paymentPrefixInput.val()) + .done(function () { + toastr.success('Payment prefix updated successfully.'); + $('#payment-id-prefix-original').val(UIElements.paymentPrefixInput.val()); + checkEnableDiscard(); + }) + .fail(function () { + toastr.error('Failed to update payment prefix.'); + }); + }; + + function checkEnableDiscard() { + const originalPrefix = UIElements.originalPaymentPrefix.val(); + const currentPrefix = UIElements.paymentPrefixInput.val(); + if (currentPrefix !== originalPrefix) { + UIElements.paymentPrefixDiscardButton.prop('disabled', false); + } else { + UIElements.paymentPrefixDiscardButton.prop('disabled', true); + } + } + function discardPaymentPrefix() { + UIElements.paymentPrefixInput.val(UIElements.originalPaymentPrefix.val()); + toastr.info('Payment prefix changes discarded.'); + checkEnableDiscard(); + }; }); +function clearFilter() { + // Clear the search input (assuming external search input has id 'search-data-table') + $('#search-data-table').val(''); + $('#search-data-table').trigger("keyup"); // Trigger keyup to clear DataTable's internal search +} + function handleDefaultAccountCodeRadioClick(id) { - unity.grantManager.payments.paymentConfiguration.setDefaultAccountCode(id).done(function () { - toastr.success('Successfully set default account code.'); + $('#AccountCodingId').val(id); // Update the hidden input with the selected account code ID + unity.payments.paymentConfigurations.paymentConfiguration.setDefaultAccountCode(id).done(function () { + toastr.success('Successfully set default account code. Reloading account codes.'); + clearAccountCodesSearchAndReload(); }).fail(function () { toastr.error('Failed to set default account code.'); }); }; + +function clearAccountCodesSearchAndReload() { + clearFilter(); + // Clear DataTable's internal search and redraw + accountCodingDataTable.search('').draw(); + + // Clear the localStorage key for PaymentSettingsDataTable + localStorage.removeItem('DataTables_AccountCodesDataTable_/PaymentConfigurations'); + localStorage.removeItem('DataTables_PaymentSettingsDataTable_/PaymentConfigurations'); + + // Reload the page + accountCodingDataTable.ajax.reload(); +} diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml index dd08fea90..acfe9cca8 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml @@ -49,6 +49,7 @@ + @@ -90,6 +91,7 @@ Note: + A default Account Coding is required for payments. diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs index 06f44074f..84e9dba91 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs @@ -11,6 +11,7 @@ using System.Text.Json; using Unity.Payments.Domain.Suppliers; using System.Linq; +using Unity.GrantManager.Payments; namespace Unity.Payments.Web.Pages.Payments { @@ -22,8 +23,10 @@ public class CreatePaymentRequestsModel : AbpPageModel private readonly IPaymentConfigurationAppService _paymentConfigurationAppService; private readonly ISupplierAppService _iSupplierAppService; private readonly ISiteRepository _siteRepository; + private readonly IPaymentSettingsAppService _paymentSettingsAppService; public CreatePaymentRequestsModel( + IPaymentSettingsAppService paymentSettingsAppService, ISiteRepository siteRepository, IGrantApplicationAppService applicationService, ISupplierAppService iSupplierAppService, @@ -36,6 +39,7 @@ public CreatePaymentRequestsModel( _paymentRequestService = paymentRequestService; _paymentConfigurationAppService = paymentConfigurationAppService; _iSupplierAppService = iSupplierAppService; + _paymentSettingsAppService = paymentSettingsAppService; } [BindProperty] @@ -64,10 +68,11 @@ public decimal ApplicationPaymentRequestFormTotalAmount public async Task OnGetAsync(string applicationIds) { + // TODO: FIX PAY THRESHOLD var paymentConfiguration = await _paymentConfigurationAppService.GetAsync(); if (paymentConfiguration != null) { - PaymentThreshold = paymentConfiguration?.PaymentThreshold ?? PaymentSharedConsts.DefaultThresholdAmount; + PaymentThreshold = PaymentSharedConsts.DefaultThresholdAmount; HasPaymentConfiguration = true; } else @@ -83,6 +88,10 @@ public async Task OnGetAsync(string applicationIds) { decimal remainingAmount = await GetRemainingAmountAllowedByApplicationAsync(application); + // Grabs the Account Coding ID from the Application Form and if there is none then the Payment Configuration + // If neither exist then an error on the payment request will be shown + Guid? accountCodingId = await _paymentSettingsAppService.GetAccountCodingIdByApplicationIdAsync(application.Id); + PaymentsModel request = new() { CorrelationId = application.Id, @@ -92,7 +101,8 @@ public async Task OnGetAsync(string applicationIds) Description = "", InvoiceNumber = application.ReferenceNo, ContractNumber = application.ContractNumber, - RemainingAmount = remainingAmount + RemainingAmount = remainingAmount, + AccountCodingId = accountCodingId }; var supplier = await GetSupplierByApplicationAync(application); @@ -110,7 +120,7 @@ public async Task OnGetAsync(string applicationIds) request.SupplierName = supplier?.Name; request.SupplierNumber = supplierNumber; - request.ErrorList = GetErrorlist(supplier, site, application, remainingAmount); + request.ErrorList = GetErrorlist(supplier, site, application, remainingAmount, accountCodingId); if (request.ErrorList != null && request.ErrorList.Count > 0) { @@ -125,7 +135,7 @@ public async Task OnGetAsync(string applicationIds) TotalAmount = ApplicationPaymentRequestForm?.Sum(x => x.Amount) ?? 0m; } - private static List GetErrorlist(SupplierDto? supplier, Site? site, GrantApplicationDto application, decimal remainingAmount) + private static List GetErrorlist(SupplierDto? supplier, Site? site, GrantApplicationDto application, decimal remainingAmount, Guid? accountCodingId) { bool missingFields = false; @@ -155,6 +165,11 @@ private static List GetErrorlist(SupplierDto? supplier, Site? site, Gran errorList.Add("The selected application is not Payable. To continue please remove the item from the list."); } + if(accountCodingId == null || accountCodingId == Guid.Empty) + { + errorList.Add("The selected application form does not have an Account Coding or no default Account Coding is set."); + } + return errorList; } @@ -228,7 +243,8 @@ private List MapPaymentRequests() SupplierNumber = payment.SupplierNumber ?? string.Empty, PayeeName = payment.ApplicantName ?? string.Empty, SubmissionConfirmationCode = payment.SubmissionConfirmationCode ?? string.Empty, - CorrelationProvider = GrantManager.Payments.PaymentConsts.ApplicationCorrelationProvider, + CorrelationProvider = PaymentConsts.ApplicationCorrelationProvider, + AccountCodingId = payment.AccountCodingId, }); } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs index 12524c1ed..c0f728061 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/PaymentsModel.cs @@ -34,5 +34,6 @@ public class PaymentsModel public string? SupplierNumber { get; set; } public string? SupplierName { get; set; } public decimal RemainingAmount { get; set; } + public Guid? AccountCodingId { get; set; } } } diff --git a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Http/ResilientHttpRequest.cs b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Http/ResilientHttpRequest.cs index c8d30015d..7af446d75 100644 --- a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Http/ResilientHttpRequest.cs +++ b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Http/ResilientHttpRequest.cs @@ -89,8 +89,7 @@ private async Task ExecuteRequestAsync( string? body, string? authToken) { - //specify to use TLS 1.2 as default connection if 1.3 is not available - ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; + // HttpClient uses the system default TLS settings; no need to set ServicePointManager.SecurityProtocol. HttpRequestMessage requestMessage = new HttpRequestMessage(httpVerb, resource) { Version = new Version(3, 0) }; using HttpClient httpClient = _httpClientFactory.CreateClient(); httpClient.DefaultRequestHeaders.Accept.Clear(); diff --git a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Integrations/TokenService.cs b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Integrations/TokenService.cs index ef5df965c..13c2016ac 100644 --- a/applications/Unity.GrantManager/modules/Unity.SharedKernel/Integrations/TokenService.cs +++ b/applications/Unity.GrantManager/modules/Unity.SharedKernel/Integrations/TokenService.cs @@ -65,8 +65,6 @@ public async Task GetAuthTokenAsync(ClientOptions clientOptions) requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString); requestMessage.Content = content; - //specify to use TLS 1.2 as default connection if TLS 1.3 does not exist - ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; HttpClient client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(clientOptions.Url); client.DefaultRequestHeaders.Accept.Clear(); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs index bc22b37da..e34ed3469 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/GrantApplications/IGrantApplicationAppService.cs @@ -22,5 +22,6 @@ public interface IGrantApplicationAppService : ICommentsService Task GetAsync(Guid id); Task> GetListAsync(PagedAndSortedResultRequestDto input); Task TriggerAction(Guid applicationId, GrantApplicationAction triggerAction); + Task GetAccountCodingIdFromFormIdAsync(Guid formId); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs index e038b3a66..9068e6b03 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs @@ -67,7 +67,7 @@ public async Task CreateOrRetrieveApplicantAsync(IntakeMapping intake [RemoteService(false)] public async Task RelateSupplierToApplicant(ApplicantSupplierEto applicantSupplierEto) { - ArgumentNullException.ThrowIfNull(applicantSupplierEto.ApplicantId); + // Removed unnecessary null check for non-nullable ApplicantId Applicant? applicant = await applicantRepository.GetAsync(applicantSupplierEto.ApplicantId); ArgumentNullException.ThrowIfNull(applicant); applicant.SupplierId = applicantSupplierEto.SupplierId; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index 902316b13..fee728075 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -154,15 +154,15 @@ public async Task PatchOtherConfig(Guid id, OtherConfigDto config) form.ElectoralDistrictAddressType = config.ElectoralDistrictAddressType; await _applicationFormRepository.UpdateAsync(form); - - public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) - { - ApplicationForm appForm = await _applicationFormRepository.GetAsync(dto.ApplicationFormId); - appForm.AccountCodingId = dto.AccountCodingId; - appForm.Payable = dto.Payable; - appForm.PreventPayment = dto.PreventPayment; - appForm.PaymentApprovalThreshold = dto.PaymentApprovalThreshold; - await _applicationFormRepository.UpdateAsync(appForm); - } } + + public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) + { + ApplicationForm appForm = await _applicationFormRepository.GetAsync(dto.ApplicationFormId); + appForm.AccountCodingId = dto.AccountCodingId; + appForm.Payable = dto.Payable; + appForm.PreventPayment = dto.PreventPayment; + appForm.PaymentApprovalThreshold = dto.PaymentApprovalThreshold; + await _applicationFormRepository.UpdateAsync(appForm); + } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs index ca02d5919..b0ed15517 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Attachments/S3BlobProvider.cs @@ -261,6 +261,5 @@ public async Task UploadToS3(BlobProviderSaveArgs args, string bucket, string ke await _amazonS3Client.PutObjectAsync(putRequest); } - } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs index 785acb68d..b9b49829d 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantApplications/GrantApplicationAppService.cs @@ -1,563 +1,570 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Authorization.Infrastructure; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Unity.Flex.WorksheetInstances; -using Unity.Flex.Worksheets; -using Unity.GrantManager.Applicants; -using Unity.GrantManager.ApplicationForms; -using Unity.GrantManager.Applications; -using Unity.GrantManager.Comments; -using Unity.GrantManager.Events; -using Unity.GrantManager.Exceptions; -using Unity.GrantManager.Flex; -using Unity.GrantManager.Identity; -using Unity.GrantManager.Payments; -using Unity.GrantManager.Permissions; -using Unity.GrantManager.Zones; -using Unity.Modules.Shared; -using Unity.Modules.Shared.Correlation; -using Unity.Payments.Domain.PaymentRequests; -using Unity.Payments.Enums; -using Unity.Payments.PaymentRequests; -using Unity.Payments.Permissions; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Authorization; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.EventBus.Local; - -namespace Unity.GrantManager.GrantApplications; - -[Authorize] -[Dependency(ReplaceServices = true)] -[ExposeServices(typeof(GrantApplicationAppService), typeof(IGrantApplicationAppService))] -public class GrantApplicationAppService : GrantManagerAppService, IGrantApplicationAppService -{ - - private readonly IApplicationRepository _applicationRepository; - private readonly IApplicationManager _applicationManager; - private readonly IApplicationStatusRepository _applicationStatusRepository; - private readonly IApplicationFormSubmissionRepository _applicationFormSubmissionRepository; - private readonly IApplicationAssignmentRepository _applicationAssignmentRepository; - private readonly IApplicantRepository _applicantRepository; - private readonly ICommentsManager _commentsManager; - private readonly IApplicationFormRepository _applicationFormRepository; - private readonly IPersonRepository _personRepository; - private readonly IApplicantAgentRepository _applicantAgentRepository; - private readonly IApplicantAddressRepository _applicantAddressRepository; - private readonly ILocalEventBus _localEventBus; - private readonly IApplicantSupplierAppService _applicantSupplierService; - private readonly IPaymentRequestAppService _paymentRequestService; - private readonly IPaymentRequestRepository _paymentRequestsRepository; - private readonly IZoneChecker _zoneChecker; - - public GrantApplicationAppService( - IApplicationManager applicationManager, - IApplicationRepository applicationRepository, - IApplicationStatusRepository applicationStatusRepository, - IApplicationAssignmentRepository applicationAssignmentRepository, - IApplicationFormSubmissionRepository applicationFormSubmissionRepository, - IApplicantRepository applicantRepository, - ICommentsManager commentsManager, - IApplicationFormRepository applicationFormRepository, - IPersonRepository personRepository, - IApplicantAgentRepository applicantAgentRepository, - IApplicantAddressRepository applicantAddressRepository, - ILocalEventBus localEventBus, - IApplicantSupplierAppService applicantSupplierService, - IPaymentRequestAppService paymentRequestService, - IPaymentRequestRepository paymentRequestsRepository, - IZoneChecker zoneChecker) - { - _applicationRepository = applicationRepository; - _applicationManager = applicationManager; - _applicationStatusRepository = applicationStatusRepository; - _applicationAssignmentRepository = applicationAssignmentRepository; - _applicationFormSubmissionRepository = applicationFormSubmissionRepository; - _applicantRepository = applicantRepository; - _commentsManager = commentsManager; - _applicationFormRepository = applicationFormRepository; - _personRepository = personRepository; - _applicantAgentRepository = applicantAgentRepository; - _applicantAddressRepository = applicantAddressRepository; - _applicantSupplierService = applicantSupplierService; - _localEventBus = localEventBus; - _paymentRequestService = paymentRequestService; - _paymentRequestsRepository = paymentRequestsRepository; - _zoneChecker = zoneChecker; - } - - public async Task> GetListAsync(PagedAndSortedResultRequestDto input) - { - var groupedResult = await _applicationRepository.WithFullDetailsGroupedAsync(input.SkipCount, input.MaxResultCount, input.Sorting); - - // Pre-fetch payment requests for all applications in a single query to reduce database calls - var applicationIds = groupedResult.SelectMany(g => g).Select(a => a.Id).ToList(); - - bool paymentsFeatureEnabled = await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature); - - List paymentRequests = new List(); - if (paymentsFeatureEnabled) - { - paymentRequests = await _paymentRequestService.GetListByApplicationIdsAsync(applicationIds); - } - - - // Map applications to DTOs - var appDtos = groupedResult.Select(grouping => - { - var firstApplication = grouping.First(); - var appDto = ObjectMapper.Map(firstApplication); - - // Map additional properties - appDto.Status = firstApplication.ApplicationStatus.InternalStatus; - appDto.Applicant = ObjectMapper.Map(firstApplication.Applicant); - appDto.Category = firstApplication.ApplicationForm.Category ?? string.Empty; - appDto.ApplicationTag = ObjectMapper.Map, List>(firstApplication.ApplicationTags?.ToList() ?? new List()); - appDto.Owner = BuildApplicationOwner(firstApplication.Owner); - appDto.OrganizationName = firstApplication.Applicant?.OrgName ?? string.Empty; - appDto.OrganizationType = firstApplication.Applicant?.OrganizationType ?? string.Empty; - appDto.Assignees = BuildApplicationAssignees(firstApplication.ApplicationAssignments); - appDto.SubStatusDisplayValue = MapSubstatusDisplayValue(appDto.SubStatus); - appDto.DeclineRational = MapDeclineRationalDisplayValue(appDto.DeclineRational); - appDto.ContactFullName = firstApplication.ApplicantAgent?.Name; - appDto.ContactEmail = firstApplication.ApplicantAgent?.Email; - appDto.ContactTitle = firstApplication.ApplicantAgent?.Title; - appDto.ContactBusinessPhone = firstApplication.ApplicantAgent?.Phone; - appDto.ContactCellPhone = firstApplication.ApplicantAgent?.Phone2; - - //Payment request info if the feature is enabled - - if (paymentsFeatureEnabled && paymentRequests != null && paymentRequests is { Count: > 0 }) - { - var paymentInfo = new PaymentInfoDto - { - ApprovedAmount = firstApplication.ApprovedAmount, - TotalPaid = paymentRequests - .Where(pr => pr.CorrelationId == firstApplication.Id && pr.Status.Equals(PaymentRequestStatus.Submitted)) - .Sum(pr => pr.Amount) - }; - appDto.PaymentInfo = paymentInfo; - } - - return appDto; - }).ToList(); - - var totalCount = await _applicationRepository.GetCountAsync(); - - return new PagedResultDto(totalCount, appDtos); - } - - - private static string MapSubstatusDisplayValue(string subStatus) - { - if (subStatus == null) { return string.Empty; } - var hasKey = AssessmentResultsOptionsList.SubStatusActionList.TryGetValue(subStatus, out string? subStatusValue); - if (hasKey) - return subStatusValue ?? string.Empty; - else - return string.Empty; - } - private static string MapDeclineRationalDisplayValue(string value) - { - if (value == null) { return string.Empty; } - var hasKey = AssessmentResultsOptionsList.DeclineRationalActionList.TryGetValue(value, out string? subStatusValue); - if (hasKey) - return subStatusValue ?? string.Empty; - else - return string.Empty; - } - - private static List BuildApplicationAssignees(IEnumerable? applicationAssignments) - { - var appAssignmentDtos = new List(); - if (applicationAssignments != null) - { - foreach (var assignment in applicationAssignments) - { - appAssignmentDtos.Add(new GrantApplicationAssigneeDto() - { - ApplicationId = assignment.ApplicationId, - AssigneeId = assignment.AssigneeId, - FullName = assignment.Assignee?.FullName ?? string.Empty, - Id = assignment.Id, - Duty = assignment.Duty - }); - } - } - return appAssignmentDtos; - } - - private static GrantApplicationAssigneeDto BuildApplicationOwner(Person? applicationOwner) - { - if (applicationOwner != null) - { - return new GrantApplicationAssigneeDto() - { - Id = applicationOwner.Id, - FullName = applicationOwner.FullName - }; - } - return new GrantApplicationAssigneeDto(); - } - - public async Task GetAsync(Guid id) - { - var application = await _applicationRepository.GetWithFullDetailsByIdAsync(id); - - if (application == null) return new GrantApplicationDto(); - - var appDto = ObjectMapper.Map(application); - - appDto.StatusCode = application.ApplicationStatus.StatusCode; - appDto.Status = application.ApplicationStatus.InternalStatus; - - if (application.ApplicantAgent != null) - { - appDto.ContactFullName = application.ApplicantAgent.Name; - appDto.ContactEmail = application.ApplicantAgent.Email; - appDto.ContactTitle = application.ApplicantAgent.Title; - appDto.ContactBusinessPhone = application.ApplicantAgent.Phone; - appDto.ContactCellPhone = application.ApplicantAgent.Phone2; - } - - if (application.Applicant != null) - { - appDto.OrganizationName = application.Applicant.OrgName; - appDto.OrgNumber = application.Applicant.OrgNumber; - appDto.OrganizationSize = application.Applicant.OrganizationSize; - appDto.OrgStatus = application.Applicant.OrgStatus; - appDto.OrganizationName = application.Applicant.OrgName; - appDto.Sector = application.Applicant.Sector; - appDto.OrganizationType = application.Applicant.OrganizationType; - appDto.SubSector = application.Applicant.SubSector; - appDto.SectorSubSectorIndustryDesc = application.Applicant.SectorSubSectorIndustryDesc; - } - - return appDto; - } - - public async Task GetApplicationFormAsync(Guid applicationFormId) - { - return await (await _applicationFormRepository.GetQueryableAsync()).FirstOrDefaultAsync(s => s.Id == applicationFormId); - } - - public async Task GetSummaryAsync(Guid applicationId) - { - var query = from application in await _applicationRepository.GetQueryableAsync() - join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id - join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id - where application.Id == applicationId - select new GetSummaryDto - { - Category = applicationForm == null ? string.Empty : applicationForm.Category, - SubmissionDate = application.SubmissionDate, - OrganizationName = applicant.OrgName, - OrganizationNumber = applicant.OrgNumber, - EconomicRegion = application.EconomicRegion, - City = application.City, - RequestedAmount = application.RequestedAmount, - ProjectBudget = application.TotalProjectBudget, - Sector = applicant.Sector, - Community = application.Community, - Status = application.ApplicationStatus.InternalStatus, - LikelihoodOfFunding = application.LikelihoodOfFunding != null && application.LikelihoodOfFunding != "" ? AssessmentResultsOptionsList.FundingList[application.LikelihoodOfFunding] : "", - AssessmentStartDate = string.Format("{0:yyyy/MM/dd}", application.AssessmentStartDate), - FinalDecisionDate = string.Format("{0:yyyy/MM/dd}", application.FinalDecisionDate), - TotalScore = application.TotalScore.ToString(), - AssessmentResult = application.AssessmentResultStatus != null && application.AssessmentResultStatus != "" ? AssessmentResultsOptionsList.AssessmentResultStatusList[application.AssessmentResultStatus] : "", - RecommendedAmount = application.RecommendedAmount, - ApprovedAmount = application.ApprovedAmount, - Batch = "", // to-do: ask BA for the implementation of Batch field, - RegionalDistrict = application.RegionalDistrict, - OwnerId = application.OwnerId, - - }; - - var queryResult = await AsyncExecuter.FirstOrDefaultAsync(query); - if (queryResult != null) - { - var ownerId = queryResult.OwnerId ?? Guid.Empty; - queryResult.Owner = await GetOwnerAsync(ownerId); - queryResult.Assignees = await GetAssigneesAsync(applicationId); - - return queryResult; - } - else - { - return await Task.FromResult(new GetSummaryDto()); - } - - } - - [Authorize(UnitySelector.Review.AssessmentResults.Update.Default)] - public async Task UpdateAssessmentResultsAsync(Guid id, CreateUpdateAssessmentResultsDto input) - { - var application = await _applicationRepository.GetAsync(id); - - await SanitizeApprovalZoneInputs(input, application); - await SanitizeAssessmentResultsZoneInputs(input, application); - - application.ValidateAndSetDueDate(input.DueDate); - application.UpdateAlwaysChangeableFields(input.Notes, input.SubStatus, input.LikelihoodOfFunding, input.TotalProjectBudget, input.NotificationDate, input.RiskRanking); - - if (application.IsInFinalDecisionState()) - { - if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.Approval.Update.UpdateFinalStateFields)) - { - application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); - } - - if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.UpdateFinalStateFields)) // User allowed to edit specific fields past approval - { - application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); - } - } - else - { - if (await CurrentUserCanUpdateAssessmentFieldsAsync()) - { - application.ValidateAndSetFinalDecisionDate(input.FinalDecisionDate); - application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); - application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); - application.UpdateFieldsOnlyForPreFinalDecision(input.DueDiligenceStatus, - input.RecommendedAmount, - input.DeclineRational); - - application.UpdateAssessmentResultStatus(input.AssessmentResultStatus); - } - } - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.AssessmentInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - return ObjectMapper.Map(application); - } - - private async Task SanitizeApprovalZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) - { - // Approval Zone Fields - Disabled Inputs - input.ApprovedAmount ??= application.ApprovedAmount; - - // Sanitize if zone is disabled - if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.Approval.Default, application.ApplicationFormId)) - { - input.SubStatus ??= application.SubStatus; - input.FinalDecisionDate ??= application.FinalDecisionDate; - input.Notes ??= application.Notes; - } - else - { - // Sanitize if zone is enabled but fields are disabled - if (application.IsInFinalDecisionState()) - { - input.FinalDecisionDate ??= application.FinalDecisionDate; - } - } - } - - private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) - { - // Approval Zone Fields - Disabled Inputs - input.RequestedAmount ??= application.RequestedAmount; - input.TotalProjectBudget ??= application.TotalProjectBudget; - input.RecommendedAmount ??= application.RecommendedAmount; - input.TotalScore ??= application.TotalScore; - - // Sanitize if zone is disabled - if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.AssessmentResults.Default, application.ApplicationFormId)) - { - input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; - input.RiskRanking ??= application.RiskRanking; - input.DueDiligenceStatus ??= application.DueDiligenceStatus; - input.AssessmentResultStatus ??= application.AssessmentResultStatus; - input.DeclineRational ??= application.DeclineRational; - - input.NotificationDate ??= application.NotificationDate; - input.DueDate ??= application.DueDate; - } - else - { - // Sanitize if zone is enabled but fields are disabled - if (application.IsInFinalDecisionState()) - { - input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; - input.RiskRanking ??= application.RiskRanking; - input.DueDiligenceStatus ??= application.DueDiligenceStatus; - input.AssessmentResultStatus ??= application.AssessmentResultStatus; - input.DeclineRational ??= application.DeclineRational; - } - } - } - - private async Task CurrentUserCanUpdateAssessmentFieldsAsync() - { - return await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.Default); - } - - [Authorize(UnitySelector.Project.UpdatePolicy)] - public async Task UpdateProjectInfoAsync(Guid id, CreateUpdateProjectInfoDto input) - { - // Check if the user has the required permissions to update Project Info for either fieldset zone - var hasSummaryPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Summary.Update.Default); - var hasLocationPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Location.Update.Default); - - if (!hasSummaryPermission || !hasLocationPermission) - { - throw new AbpAuthorizationException("The user doesn't have the required permissions to update Project Info."); - } - - var application = await _applicationRepository.GetAsync(id); - - var hasSummaryZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Summary.Default, application.ApplicationFormId); - var hasLocationZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Location.Default, application.ApplicationFormId); - - if (!hasSummaryZone || !hasLocationZone) - { - throw new BusinessException("The Project Info zones are not enabled for this application form."); - } - - SanitizeProjectInfoDisabledInputs(input, application); - - var percentageTotalProjectBudget = (input.TotalProjectBudget == 0 || input.TotalProjectBudget == null) ? 0 : decimal.Multiply(decimal.Divide(input.RequestedAmount ?? 0, input.TotalProjectBudget ?? 0), 100).To(); - - if (application != null) - { - application.ProjectSummary = input.ProjectSummary; - application.ProjectName = input.ProjectName ?? string.Empty; - application.RequestedAmount = input.RequestedAmount ?? 0; - application.TotalProjectBudget = input.TotalProjectBudget ?? 0; - application.ProjectStartDate = input.ProjectStartDate; - application.ProjectEndDate = input.ProjectEndDate; - application.PercentageTotalProjectBudget = Math.Round(percentageTotalProjectBudget, 2); - application.ProjectFundingTotal = input.ProjectFundingTotal; - application.Community = input.Community; - application.CommunityPopulation = input.CommunityPopulation; - application.Acquisition = input.Acquisition; - application.Forestry = input.Forestry; - application.ForestryFocus = input.ForestryFocus; - application.EconomicRegion = input.EconomicRegion; - application.ElectoralDistrict = input.ElectoralDistrict; - application.RegionalDistrict = input.RegionalDistrict; - application.Place = input.Place; - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - return ObjectMapper.Map(application); - } - else - { - throw new EntityNotFoundException(); - } - } - private static void SanitizeProjectInfoDisabledInputs(CreateUpdateProjectInfoDto input, Application application) - { - // Cater for disabled fields that are not serialized with post - fall back to the previous value, these should be 0 from the API call - input.TotalProjectBudget ??= application.TotalProjectBudget; - input.RequestedAmount ??= application.RequestedAmount; - input.ProjectFundingTotal ??= application.ProjectFundingTotal; - } - - [Authorize(UnitySelector.Project.UpdatePolicy)] - public async Task UpdatePartialProjectInfoAsync(Guid id, PartialUpdateDto input) - { - // Only update the fields we need to update based on the modified fields - // This is required to handle controls like the date picker that do not send null values for unchanged fields - var application = await _applicationRepository.GetAsync(id) ?? throw new EntityNotFoundException($"Application with ID {id} not found."); - ObjectMapper.Map(input.Data, application); - - // Explicitly handle properties that are null but listed in ModifiedFields - var dtoProperties = typeof(UpdateProjectInfoDto).GetProperties(); - var appProperties = typeof(Application).GetProperties().ToDictionary(p => p.Name, p => p); - - foreach (var fieldName in input.ModifiedFields) - { - if (dtoProperties.FirstOrDefault(p => - string.Equals(p.Name, fieldName, StringComparison.OrdinalIgnoreCase)) is { } dtoProperty) - { - var value = dtoProperty.GetValue(input.Data); - if (value == null && appProperties.TryGetValue(dtoProperty.Name, out var appProperty) && appProperty.CanWrite) - { - appProperty.SetValue(application, appProperty.PropertyType.IsValueType - && Nullable.GetUnderlyingType(appProperty.PropertyType) == null - ? Activator.CreateInstance(appProperty.PropertyType) - : null); - } - } - } - - // Calculate the percentage of the total project budget based on - // the requested amount and total project budget. Percentage total has to be - // updated whenever RequestedAmount or TotalProjectBudget changes - application.UpdatePercentageTotalProjectBudget(); - - // Add custom worksheet data - if (input.Data.CustomFields is not null && input.Data.WorksheetId != Guid.Empty && input.Data.CorrelationId != Guid.Empty) - { - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input.Data); - } - - await _applicationRepository.UpdateAsync(application); - return ObjectMapper.Map(application); - } - - public async Task UpdateFundingAgreementInfoAsync(Guid id, CreateUpdateFundingAgreementInfoDto input) - { - var application = await _applicationRepository.GetAsync(id); - - if (application != null) - { - application.ContractNumber = input.ContractNumber; - application.ContractExecutionDate = input.ContractExecutionDate; - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.FundingAgreementInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - return ObjectMapper.Map(application); - } - else - { - throw new EntityNotFoundException(); - } - } - +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization.Infrastructure; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Unity.Flex.WorksheetInstances; +using Unity.Flex.Worksheets; +using Unity.GrantManager.Applicants; +using Unity.GrantManager.ApplicationForms; +using Unity.GrantManager.Applications; +using Unity.GrantManager.Comments; +using Unity.GrantManager.Events; +using Unity.GrantManager.Exceptions; +using Unity.GrantManager.Flex; +using Unity.GrantManager.Identity; +using Unity.GrantManager.Payments; +using Unity.GrantManager.Permissions; +using Unity.GrantManager.Zones; +using Unity.Modules.Shared; +using Unity.Modules.Shared.Correlation; +using Unity.Payments.Domain.PaymentRequests; +using Unity.Payments.Enums; +using Unity.Payments.PaymentRequests; +using Unity.Payments.Permissions; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Authorization; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.EventBus.Local; + +namespace Unity.GrantManager.GrantApplications; + +[Authorize] +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(GrantApplicationAppService), typeof(IGrantApplicationAppService))] +public class GrantApplicationAppService : GrantManagerAppService, IGrantApplicationAppService +{ + + private readonly IApplicationRepository _applicationRepository; + private readonly IApplicationManager _applicationManager; + private readonly IApplicationStatusRepository _applicationStatusRepository; + private readonly IApplicationFormSubmissionRepository _applicationFormSubmissionRepository; + private readonly IApplicationAssignmentRepository _applicationAssignmentRepository; + private readonly IApplicantRepository _applicantRepository; + private readonly ICommentsManager _commentsManager; + private readonly IApplicationFormRepository _applicationFormRepository; + private readonly IPersonRepository _personRepository; + private readonly IApplicantAgentRepository _applicantAgentRepository; + private readonly IApplicantAddressRepository _applicantAddressRepository; + private readonly ILocalEventBus _localEventBus; + private readonly IApplicantSupplierAppService _applicantSupplierService; + private readonly IPaymentRequestAppService _paymentRequestService; + private readonly IPaymentRequestRepository _paymentRequestsRepository; + private readonly IZoneChecker _zoneChecker; + + public GrantApplicationAppService( + IApplicationManager applicationManager, + IApplicationRepository applicationRepository, + IApplicationStatusRepository applicationStatusRepository, + IApplicationAssignmentRepository applicationAssignmentRepository, + IApplicationFormSubmissionRepository applicationFormSubmissionRepository, + IApplicantRepository applicantRepository, + ICommentsManager commentsManager, + IApplicationFormRepository applicationFormRepository, + IPersonRepository personRepository, + IApplicantAgentRepository applicantAgentRepository, + IApplicantAddressRepository applicantAddressRepository, + ILocalEventBus localEventBus, + IApplicantSupplierAppService applicantSupplierService, + IPaymentRequestAppService paymentRequestService, + IPaymentRequestRepository paymentRequestsRepository, + IZoneChecker zoneChecker) + { + _applicationRepository = applicationRepository; + _applicationManager = applicationManager; + _applicationStatusRepository = applicationStatusRepository; + _applicationAssignmentRepository = applicationAssignmentRepository; + _applicationFormSubmissionRepository = applicationFormSubmissionRepository; + _applicantRepository = applicantRepository; + _commentsManager = commentsManager; + _applicationFormRepository = applicationFormRepository; + _personRepository = personRepository; + _applicantAgentRepository = applicantAgentRepository; + _applicantAddressRepository = applicantAddressRepository; + _applicantSupplierService = applicantSupplierService; + _localEventBus = localEventBus; + _paymentRequestService = paymentRequestService; + _paymentRequestsRepository = paymentRequestsRepository; + _zoneChecker = zoneChecker; + } + + public async Task> GetListAsync(PagedAndSortedResultRequestDto input) + { + var groupedResult = await _applicationRepository.WithFullDetailsGroupedAsync(input.SkipCount, input.MaxResultCount, input.Sorting); + + // Pre-fetch payment requests for all applications in a single query to reduce database calls + var applicationIds = groupedResult.SelectMany(g => g).Select(a => a.Id).ToList(); + + bool paymentsFeatureEnabled = await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature); + + List paymentRequests = new List(); + if (paymentsFeatureEnabled) + { + paymentRequests = await _paymentRequestService.GetListByApplicationIdsAsync(applicationIds); + } + + + // Map applications to DTOs + var appDtos = groupedResult.Select(grouping => + { + var firstApplication = grouping.First(); + var appDto = ObjectMapper.Map(firstApplication); + + // Map additional properties + appDto.Status = firstApplication.ApplicationStatus.InternalStatus; + appDto.Applicant = ObjectMapper.Map(firstApplication.Applicant); + appDto.Category = firstApplication.ApplicationForm.Category ?? string.Empty; + appDto.ApplicationTag = ObjectMapper.Map, List>(firstApplication.ApplicationTags?.ToList() ?? new List()); + appDto.Owner = BuildApplicationOwner(firstApplication.Owner); + appDto.OrganizationName = firstApplication.Applicant?.OrgName ?? string.Empty; + appDto.OrganizationType = firstApplication.Applicant?.OrganizationType ?? string.Empty; + appDto.Assignees = BuildApplicationAssignees(firstApplication.ApplicationAssignments); + appDto.SubStatusDisplayValue = MapSubstatusDisplayValue(appDto.SubStatus); + appDto.DeclineRational = MapDeclineRationalDisplayValue(appDto.DeclineRational); + appDto.ContactFullName = firstApplication.ApplicantAgent?.Name; + appDto.ContactEmail = firstApplication.ApplicantAgent?.Email; + appDto.ContactTitle = firstApplication.ApplicantAgent?.Title; + appDto.ContactBusinessPhone = firstApplication.ApplicantAgent?.Phone; + appDto.ContactCellPhone = firstApplication.ApplicantAgent?.Phone2; + + //Payment request info if the feature is enabled + + if (paymentsFeatureEnabled && paymentRequests != null && paymentRequests is { Count: > 0 }) + { + var paymentInfo = new PaymentInfoDto + { + ApprovedAmount = firstApplication.ApprovedAmount, + TotalPaid = paymentRequests + .Where(pr => pr.CorrelationId == firstApplication.Id && pr.Status.Equals(PaymentRequestStatus.Submitted)) + .Sum(pr => pr.Amount) + }; + appDto.PaymentInfo = paymentInfo; + } + + return appDto; + }).ToList(); + + long totalCount = 0; + try + { + totalCount = await _applicationRepository.GetCountAsync(); + } catch(Exception ex) + { + Logger.LogError(ex, "An exception occurred GetCountAsync: {ExceptionMessage}", ex.Message); + } + + return new PagedResultDto(totalCount, appDtos); + } + + + private static string MapSubstatusDisplayValue(string subStatus) + { + if (subStatus == null) { return string.Empty; } + var hasKey = AssessmentResultsOptionsList.SubStatusActionList.TryGetValue(subStatus, out string? subStatusValue); + if (hasKey) + return subStatusValue ?? string.Empty; + else + return string.Empty; + } + private static string MapDeclineRationalDisplayValue(string value) + { + if (value == null) { return string.Empty; } + var hasKey = AssessmentResultsOptionsList.DeclineRationalActionList.TryGetValue(value, out string? subStatusValue); + if (hasKey) + return subStatusValue ?? string.Empty; + else + return string.Empty; + } + + private static List BuildApplicationAssignees(IEnumerable? applicationAssignments) + { + var appAssignmentDtos = new List(); + if (applicationAssignments != null) + { + foreach (var assignment in applicationAssignments) + { + appAssignmentDtos.Add(new GrantApplicationAssigneeDto() + { + ApplicationId = assignment.ApplicationId, + AssigneeId = assignment.AssigneeId, + FullName = assignment.Assignee?.FullName ?? string.Empty, + Id = assignment.Id, + Duty = assignment.Duty + }); + } + } + return appAssignmentDtos; + } + + private static GrantApplicationAssigneeDto BuildApplicationOwner(Person? applicationOwner) + { + if (applicationOwner != null) + { + return new GrantApplicationAssigneeDto() + { + Id = applicationOwner.Id, + FullName = applicationOwner.FullName + }; + } + return new GrantApplicationAssigneeDto(); + } + + public async Task GetAsync(Guid id) + { + var application = await _applicationRepository.GetWithFullDetailsByIdAsync(id); + + if (application == null) return new GrantApplicationDto(); + + var appDto = ObjectMapper.Map(application); + + appDto.StatusCode = application.ApplicationStatus.StatusCode; + appDto.Status = application.ApplicationStatus.InternalStatus; + + if (application.ApplicantAgent != null) + { + appDto.ContactFullName = application.ApplicantAgent.Name; + appDto.ContactEmail = application.ApplicantAgent.Email; + appDto.ContactTitle = application.ApplicantAgent.Title; + appDto.ContactBusinessPhone = application.ApplicantAgent.Phone; + appDto.ContactCellPhone = application.ApplicantAgent.Phone2; + } + + if (application.Applicant != null) + { + appDto.OrganizationName = application.Applicant.OrgName; + appDto.OrgNumber = application.Applicant.OrgNumber; + appDto.OrganizationSize = application.Applicant.OrganizationSize; + appDto.OrgStatus = application.Applicant.OrgStatus; + appDto.OrganizationName = application.Applicant.OrgName; + appDto.Sector = application.Applicant.Sector; + appDto.OrganizationType = application.Applicant.OrganizationType; + appDto.SubSector = application.Applicant.SubSector; + appDto.SectorSubSectorIndustryDesc = application.Applicant.SectorSubSectorIndustryDesc; + } + + return appDto; + } + + public async Task GetApplicationFormAsync(Guid applicationFormId) + { + return await (await _applicationFormRepository.GetQueryableAsync()).FirstOrDefaultAsync(s => s.Id == applicationFormId); + } + + public async Task GetSummaryAsync(Guid applicationId) + { + var query = from application in await _applicationRepository.GetQueryableAsync() + join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id + join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id + where application.Id == applicationId + select new GetSummaryDto + { + Category = applicationForm == null ? string.Empty : applicationForm.Category, + SubmissionDate = application.SubmissionDate, + OrganizationName = applicant.OrgName, + OrganizationNumber = applicant.OrgNumber, + EconomicRegion = application.EconomicRegion, + City = application.City, + RequestedAmount = application.RequestedAmount, + ProjectBudget = application.TotalProjectBudget, + Sector = applicant.Sector, + Community = application.Community, + Status = application.ApplicationStatus.InternalStatus, + LikelihoodOfFunding = application.LikelihoodOfFunding != null && application.LikelihoodOfFunding != "" ? AssessmentResultsOptionsList.FundingList[application.LikelihoodOfFunding] : "", + AssessmentStartDate = string.Format("{0:yyyy/MM/dd}", application.AssessmentStartDate), + FinalDecisionDate = string.Format("{0:yyyy/MM/dd}", application.FinalDecisionDate), + TotalScore = application.TotalScore.ToString(), + AssessmentResult = application.AssessmentResultStatus != null && application.AssessmentResultStatus != "" ? AssessmentResultsOptionsList.AssessmentResultStatusList[application.AssessmentResultStatus] : "", + RecommendedAmount = application.RecommendedAmount, + ApprovedAmount = application.ApprovedAmount, + Batch = "", // to-do: ask BA for the implementation of Batch field, + RegionalDistrict = application.RegionalDistrict, + OwnerId = application.OwnerId, + + }; + + var queryResult = await AsyncExecuter.FirstOrDefaultAsync(query); + if (queryResult != null) + { + var ownerId = queryResult.OwnerId ?? Guid.Empty; + queryResult.Owner = await GetOwnerAsync(ownerId); + queryResult.Assignees = await GetAssigneesAsync(applicationId); + + return queryResult; + } + else + { + return await Task.FromResult(new GetSummaryDto()); + } + + } + + [Authorize(UnitySelector.Review.AssessmentResults.Update.Default)] + public async Task UpdateAssessmentResultsAsync(Guid id, CreateUpdateAssessmentResultsDto input) + { + var application = await _applicationRepository.GetAsync(id); + + await SanitizeApprovalZoneInputs(input, application); + await SanitizeAssessmentResultsZoneInputs(input, application); + + application.ValidateAndSetDueDate(input.DueDate); + application.UpdateAlwaysChangeableFields(input.Notes, input.SubStatus, input.LikelihoodOfFunding, input.TotalProjectBudget, input.NotificationDate, input.RiskRanking); + + if (application.IsInFinalDecisionState()) + { + if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.Approval.Update.UpdateFinalStateFields)) + { + application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); + } + + if (await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.UpdateFinalStateFields)) // User allowed to edit specific fields past approval + { + application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); + } + } + else + { + if (await CurrentUserCanUpdateAssessmentFieldsAsync()) + { + application.ValidateAndSetFinalDecisionDate(input.FinalDecisionDate); + application.UpdateApprovalFieldsRequiringPostEditPermission(input.ApprovedAmount); + application.UpdateAssessmentResultFieldsRequiringPostEditPermission(input.RequestedAmount, input.TotalScore); + application.UpdateFieldsOnlyForPreFinalDecision(input.DueDiligenceStatus, + input.RecommendedAmount, + input.DeclineRational); + + application.UpdateAssessmentResultStatus(input.AssessmentResultStatus); + } + } + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.AssessmentInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + return ObjectMapper.Map(application); + } + + private async Task SanitizeApprovalZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) + { + // Approval Zone Fields - Disabled Inputs + input.ApprovedAmount ??= application.ApprovedAmount; + + // Sanitize if zone is disabled + if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.Approval.Default, application.ApplicationFormId)) + { + input.SubStatus ??= application.SubStatus; + input.FinalDecisionDate ??= application.FinalDecisionDate; + input.Notes ??= application.Notes; + } + else + { + // Sanitize if zone is enabled but fields are disabled + if (application.IsInFinalDecisionState()) + { + input.FinalDecisionDate ??= application.FinalDecisionDate; + } + } + } + + private async Task SanitizeAssessmentResultsZoneInputs(CreateUpdateAssessmentResultsDto input, Application application) + { + // Approval Zone Fields - Disabled Inputs + input.RequestedAmount ??= application.RequestedAmount; + input.TotalProjectBudget ??= application.TotalProjectBudget; + input.RecommendedAmount ??= application.RecommendedAmount; + input.TotalScore ??= application.TotalScore; + + // Sanitize if zone is disabled + if (!await _zoneChecker.IsEnabledAsync(UnitySelector.Review.AssessmentResults.Default, application.ApplicationFormId)) + { + input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; + input.RiskRanking ??= application.RiskRanking; + input.DueDiligenceStatus ??= application.DueDiligenceStatus; + input.AssessmentResultStatus ??= application.AssessmentResultStatus; + input.DeclineRational ??= application.DeclineRational; + + input.NotificationDate ??= application.NotificationDate; + input.DueDate ??= application.DueDate; + } + else + { + // Sanitize if zone is enabled but fields are disabled + if (application.IsInFinalDecisionState()) + { + input.LikelihoodOfFunding ??= application.LikelihoodOfFunding; + input.RiskRanking ??= application.RiskRanking; + input.DueDiligenceStatus ??= application.DueDiligenceStatus; + input.AssessmentResultStatus ??= application.AssessmentResultStatus; + input.DeclineRational ??= application.DeclineRational; + } + } + } + + private async Task CurrentUserCanUpdateAssessmentFieldsAsync() + { + return await AuthorizationService.IsGrantedAsync(UnitySelector.Review.AssessmentResults.Update.Default); + } + + [Authorize(UnitySelector.Project.UpdatePolicy)] + public async Task UpdateProjectInfoAsync(Guid id, CreateUpdateProjectInfoDto input) + { + // Check if the user has the required permissions to update Project Info for either fieldset zone + var hasSummaryPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Summary.Update.Default); + var hasLocationPermission = await AuthorizationService.IsGrantedAsync(UnitySelector.Project.Location.Update.Default); + + if (!hasSummaryPermission || !hasLocationPermission) + { + throw new AbpAuthorizationException("The user doesn't have the required permissions to update Project Info."); + } + + var application = await _applicationRepository.GetAsync(id); + + var hasSummaryZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Summary.Default, application.ApplicationFormId); + var hasLocationZone = await _zoneChecker.IsEnabledAsync(UnitySelector.Project.Location.Default, application.ApplicationFormId); + + if (!hasSummaryZone || !hasLocationZone) + { + throw new BusinessException("The Project Info zones are not enabled for this application form."); + } + + SanitizeProjectInfoDisabledInputs(input, application); + + var percentageTotalProjectBudget = (input.TotalProjectBudget == 0 || input.TotalProjectBudget == null) ? 0 : decimal.Multiply(decimal.Divide(input.RequestedAmount ?? 0, input.TotalProjectBudget ?? 0), 100).To(); + + if (application != null) + { + application.ProjectSummary = input.ProjectSummary; + application.ProjectName = input.ProjectName ?? string.Empty; + application.RequestedAmount = input.RequestedAmount ?? 0; + application.TotalProjectBudget = input.TotalProjectBudget ?? 0; + application.ProjectStartDate = input.ProjectStartDate; + application.ProjectEndDate = input.ProjectEndDate; + application.PercentageTotalProjectBudget = Math.Round(percentageTotalProjectBudget, 2); + application.ProjectFundingTotal = input.ProjectFundingTotal; + application.Community = input.Community; + application.CommunityPopulation = input.CommunityPopulation; + application.Acquisition = input.Acquisition; + application.Forestry = input.Forestry; + application.ForestryFocus = input.ForestryFocus; + application.EconomicRegion = input.EconomicRegion; + application.ElectoralDistrict = input.ElectoralDistrict; + application.RegionalDistrict = input.RegionalDistrict; + application.Place = input.Place; + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + return ObjectMapper.Map(application); + } + else + { + throw new EntityNotFoundException(); + } + } + private static void SanitizeProjectInfoDisabledInputs(CreateUpdateProjectInfoDto input, Application application) + { + // Cater for disabled fields that are not serialized with post - fall back to the previous value, these should be 0 from the API call + input.TotalProjectBudget ??= application.TotalProjectBudget; + input.RequestedAmount ??= application.RequestedAmount; + input.ProjectFundingTotal ??= application.ProjectFundingTotal; + } + + [Authorize(UnitySelector.Project.UpdatePolicy)] + public async Task UpdatePartialProjectInfoAsync(Guid id, PartialUpdateDto input) + { + // Only update the fields we need to update based on the modified fields + // This is required to handle controls like the date picker that do not send null values for unchanged fields + var application = await _applicationRepository.GetAsync(id) ?? throw new EntityNotFoundException($"Application with ID {id} not found."); + ObjectMapper.Map(input.Data, application); + + // Explicitly handle properties that are null but listed in ModifiedFields + var dtoProperties = typeof(UpdateProjectInfoDto).GetProperties(); + var appProperties = typeof(Application).GetProperties().ToDictionary(p => p.Name, p => p); + + foreach (var fieldName in input.ModifiedFields) + { + if (dtoProperties.FirstOrDefault(p => + string.Equals(p.Name, fieldName, StringComparison.OrdinalIgnoreCase)) is { } dtoProperty) + { + var value = dtoProperty.GetValue(input.Data); + if (value == null && appProperties.TryGetValue(dtoProperty.Name, out var appProperty) && appProperty.CanWrite) + { + appProperty.SetValue(application, appProperty.PropertyType.IsValueType + && Nullable.GetUnderlyingType(appProperty.PropertyType) == null + ? Activator.CreateInstance(appProperty.PropertyType) + : null); + } + } + } + + // Calculate the percentage of the total project budget based on + // the requested amount and total project budget. Percentage total has to be + // updated whenever RequestedAmount or TotalProjectBudget changes + application.UpdatePercentageTotalProjectBudget(); + + // Add custom worksheet data + if (input.Data.CustomFields is not null && input.Data.WorksheetId != Guid.Empty && input.Data.CorrelationId != Guid.Empty) + { + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ProjectInfoUiAnchor, input.Data); + } + + await _applicationRepository.UpdateAsync(application); + return ObjectMapper.Map(application); + } + + public async Task UpdateFundingAgreementInfoAsync(Guid id, CreateUpdateFundingAgreementInfoDto input) + { + var application = await _applicationRepository.GetAsync(id); + + if (application != null) + { + application.ContractNumber = input.ContractNumber; + application.ContractExecutionDate = input.ContractExecutionDate; + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.FundingAgreementInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + return ObjectMapper.Map(application); + } + else + { + throw new EntityNotFoundException(); + } + } + /// /// Update the supplier number for the applicant associated with the application. - /// - [Authorize(UnitySelector.Payment.Supplier.Update)] + /// + [Authorize(UnitySelector.Payment.Supplier.Update)] public async Task UpdateSupplierNumberAsync(Guid applicationId, string supplierNumber) { // Could be moved to payments module but dependency on ApplicationId - // Integrate with payments module to update / insert supplier + // Integrate with payments module to update / insert supplier var application = await _applicationRepository.GetAsync(applicationId); - if (await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature) && application != null && !string.IsNullOrEmpty(supplierNumber)) - { - var pendingPayments = await _paymentRequestsRepository.GetPaymentPendingListByCorrelationIdAsync(applicationId); - if (pendingPayments != null && pendingPayments.Count > 0) - { - throw new UserFriendlyException("There are outstanding payment requests with the current Supplier. Please decline or approve the outstanding payments before changing the Supplier Number"); - } - - await _applicantSupplierService.UpdateApplicantSupplierNumberAsync(application.ApplicantId, supplierNumber); + if (await FeatureChecker.IsEnabledAsync(PaymentConsts.UnityPaymentsFeature) && application != null && !string.IsNullOrEmpty(supplierNumber)) + { + var pendingPayments = await _paymentRequestsRepository.GetPaymentPendingListByCorrelationIdAsync(applicationId); + if (pendingPayments != null && pendingPayments.Count > 0) + { + throw new UserFriendlyException("There are outstanding payment requests with the current Supplier. Please decline or approve the outstanding payments before changing the Supplier Number"); + } + + await _applicantSupplierService.UpdateApplicantSupplierNumberAsync(application.ApplicantId, supplierNumber); } - } - + } + protected internal async Task CreateOrUpdateApplicantAgentAsync(Application application, ContactInfoDto? input) { if (input == null @@ -586,491 +593,502 @@ public async Task UpdateSupplierNumberAsync(Guid applicationId, string supplierN } return await _applicantAgentRepository.UpdateAsync(applicantAgent); - } - - [Obsolete("Use ApplicationApplicantAppService.UpdatePartialApplicantInfoAsync instead.")] - [Authorize(UnitySelector.Applicant.UpdatePolicy)] - public async Task UpdateProjectApplicantInfoAsync(Guid id, CreateUpdateApplicantInfoDto input) - { - var application = await _applicationRepository.GetAsync(id); - - var applicant = await _applicantRepository - .FirstOrDefaultAsync(a => a.Id == application.ApplicantId) ?? throw new EntityNotFoundException(); - - applicant.OrganizationType = input.OrganizationType ?? ""; - applicant.OrgName = input.OrgName ?? ""; - applicant.OrgNumber = input.OrgNumber ?? ""; - applicant.OrgStatus = input.OrgStatus ?? ""; - applicant.OrganizationSize = input.OrganizationSize ?? ""; - applicant.Sector = input.Sector ?? ""; - applicant.SubSector = input.SubSector ?? ""; - applicant.SectorSubSectorIndustryDesc = input.SectorSubSectorIndustryDesc ?? ""; - applicant.IndigenousOrgInd = input.IndigenousOrgInd ?? ""; - applicant.UnityApplicantId = input.UnityApplicantId ?? ""; - applicant.FiscalDay = input.FiscalDay; - applicant.FiscalMonth = input.FiscalMonth ?? ""; - applicant.NonRegOrgName = input.NonRegOrgName ?? ""; - applicant.ElectoralDistrict = input.ElectoralDistrict ?? ""; - applicant.ApplicantName = input.ApplicantName ?? ""; - - _ = await _applicantRepository.UpdateAsync(applicant); - - var applicantAgent = await _applicantAgentRepository.FirstOrDefaultAsync(agent => agent.ApplicantId == application.ApplicantId); - if (applicantAgent == null) - { - applicantAgent = await _applicantAgentRepository.InsertAsync(new ApplicantAgent - { - ApplicantId = application.ApplicantId, - ApplicationId = application.Id, - Name = input.ContactFullName ?? "", - Phone = input.ContactBusinessPhone ?? "", - Phone2 = input.ContactCellPhone ?? "", - Email = input.ContactEmail ?? "", - Title = input.ContactTitle ?? "" - }); - } - else - { - applicantAgent.Name = input.ContactFullName ?? ""; - applicantAgent.Phone = input.ContactBusinessPhone ?? ""; - applicantAgent.Phone2 = input.ContactCellPhone ?? ""; - applicantAgent.Email = input.ContactEmail ?? ""; - applicantAgent.Title = input.ContactTitle ?? ""; - applicantAgent = await _applicantAgentRepository.UpdateAsync(applicantAgent); - } - - await UpdateApplicantAddresses(input); - - application.SigningAuthorityFullName = input.SigningAuthorityFullName ?? ""; - application.SigningAuthorityTitle = input.SigningAuthorityTitle ?? ""; - application.SigningAuthorityEmail = input.SigningAuthorityEmail ?? ""; - application.SigningAuthorityBusinessPhone = input.SigningAuthorityBusinessPhone ?? ""; - application.SigningAuthorityCellPhone = input.SigningAuthorityCellPhone ?? ""; - - await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ApplicantInfoUiAnchor, input); - - await _applicationRepository.UpdateAsync(application); - - var appDto = ObjectMapper.Map(application); - - appDto.ContactFullName = applicantAgent.Name; - appDto.ContactEmail = applicantAgent.Email; - appDto.ContactTitle = applicantAgent.Title; - appDto.ContactBusinessPhone = applicantAgent.Phone; - appDto.ContactCellPhone = applicantAgent.Phone2; - - return appDto; - } - - protected virtual async Task PublishCustomFieldUpdatesAsync(Guid applicationId, - string uiAnchor, - CustomDataFieldDto input) - { - if (await FeatureChecker.IsEnabledAsync("Unity.Flex")) - { - if (input.CorrelationId != Guid.Empty) - { - await _localEventBus.PublishAsync(new PersistWorksheetIntanceValuesEto() - { - InstanceCorrelationId = applicationId, - InstanceCorrelationProvider = CorrelationConsts.Application, - SheetCorrelationId = input.CorrelationId, - SheetCorrelationProvider = CorrelationConsts.FormVersion, - UiAnchor = uiAnchor, - CustomFields = input.CustomFields, - WorksheetId = input.WorksheetId - }); - } - else - { - Logger.LogError("Unable to resolve for version"); - } - } - } - - protected virtual async Task UpdateApplicantAddresses(CreateUpdateApplicantInfoDto input) - { - List applicantAddresses = await _applicantAddressRepository.FindByApplicantIdAsync(input.ApplicantId); - if (applicantAddresses != null) - { - await UpsertAddress(input, applicantAddresses, AddressType.MailingAddress, input.ApplicantId); - await UpsertAddress(input, applicantAddresses, AddressType.PhysicalAddress, input.ApplicantId); - } - } - - protected virtual async Task UpsertAddress(CreateUpdateApplicantInfoDto input, List applicantAddresses, AddressType applicantAddressType, Guid applicantId) - { - ApplicantAddress? dbAddress = applicantAddresses.Find(address => address.AddressType == applicantAddressType); - - if (dbAddress != null) - { - MapApplicantAddress(input, applicantAddressType, dbAddress); - await _applicantAddressRepository.UpdateAsync(dbAddress); - } - else - { - var newAddress = new ApplicantAddress() { AddressType = applicantAddressType, ApplicantId = applicantId }; - MapApplicantAddress(input, applicantAddressType, newAddress); - await _applicantAddressRepository.InsertAsync(newAddress); - } - } - - private static void MapApplicantAddress(CreateUpdateApplicantInfoDto input, AddressType applicantAddressType, ApplicantAddress address) - { - switch (applicantAddressType) - { - case AddressType.MailingAddress: - address.AddressType = AddressType.MailingAddress; - address.Street = input.MailingAddressStreet ?? ""; - address.Street2 = input.MailingAddressStreet2 ?? ""; - address.Unit = input.MailingAddressUnit ?? ""; - address.City = input.MailingAddressCity ?? ""; - address.Province = input.MailingAddressProvince ?? ""; - address.Postal = input.MailingAddressPostalCode ?? ""; - break; - case AddressType.PhysicalAddress: - address.AddressType = AddressType.PhysicalAddress; - address.Street = input.PhysicalAddressStreet ?? ""; - address.Street2 = input.PhysicalAddressStreet2 ?? ""; - address.Unit = input.PhysicalAddressUnit ?? ""; - address.City = input.PhysicalAddressCity ?? ""; - address.Province = input.PhysicalAddressProvince ?? ""; - address.Postal = input.PhysicalAddressPostalCode ?? ""; - break; - } - } - - public async Task> GetAssigneesAsync(Guid applicationId) - { - var query = from userAssignment in await _applicationAssignmentRepository.GetQueryableAsync() - join user in await _personRepository.GetQueryableAsync() on userAssignment.AssigneeId equals user.Id - where userAssignment.ApplicationId == applicationId - select new GrantApplicationAssigneeDto - { - Id = userAssignment.Id, - AssigneeId = userAssignment.AssigneeId, - FullName = user.FullName, - Duty = userAssignment.Duty, - ApplicationId = applicationId - }; - - return await query.ToListAsync(); - } - - public async Task GetOwnerAsync(Guid ownerId) - { - var owner = await _personRepository.FindAsync(ownerId); - - if (owner != null) - { - return new GrantApplicationAssigneeDto - { - Id = owner.Id, - FullName = owner.FullName - }; - } - else - return new GrantApplicationAssigneeDto(); - } - - public async Task GetFormSubmissionByApplicationId(Guid applicationId) - { - ApplicationFormSubmission applicationFormSubmission = new(); - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - IQueryable queryableFormSubmissions = await _applicationFormSubmissionRepository.GetQueryableAsync(); - if (queryableFormSubmissions != null) - { - var dbResult = await queryableFormSubmissions - .FirstOrDefaultAsync(a => a.ApplicationId.Equals(applicationId)); - - if (dbResult != null) - { - applicationFormSubmission = dbResult; - } - } - } - return applicationFormSubmission; - } - - public async Task UpdateApplicationStatus(Guid[] applicationIds, Guid statusId) - { - foreach (Guid applicationId in applicationIds) - { - try - { - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - application.ApplicationStatusId = statusId; - await _applicationRepository.UpdateAsync(application); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - } - - public async Task InsertAssigneeAsync(Guid applicationId, Guid assigneeId, string? duty) - { - try - { - var assignees = await GetAssigneesAsync(applicationId); - if (assignees == null || assignees.FindIndex(a => a.AssigneeId == assigneeId) == -1) - { - await _applicationManager.AssignUserAsync(applicationId, assigneeId, duty); - } - else - { - await _applicationManager.UpdateAssigneeAsync(applicationId, assigneeId, duty); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - public async Task DeleteAssigneeAsync(Guid applicationId, Guid assigneeId) - { - try - { - await _applicationManager.RemoveAssigneeAsync(applicationId, assigneeId); - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - public async Task> GetApplicationListAsync(List applicationIds) - { - var applications = await - (await _applicationRepository.WithDetailsAsync()) - .OrderBy(s => s.Id) - .Where(s => applicationIds.Contains(s.Id)) - .ToListAsync(); - - return ObjectMapper.Map, List>(applications); - } - - public async Task> GetApplicationDetailsListAsync(List applicationIds) - { - var query = from application in await _applicationRepository.GetQueryableAsync() - join appStatus in await _applicationStatusRepository.GetQueryableAsync() on application.ApplicationStatusId equals appStatus.Id - join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id - join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id - where applicationIds.Contains(application.Id) - select new - { - application, - appStatus, - applicant, - applicationForm - }; - - var result = query - - .OrderBy(s => s.application.Id) - .GroupBy(s => s.application.Id) - .AsEnumerable() - .ToList(); - - var appDtos = new List(); - - foreach (var grouping in result) - { - var appDto = ObjectMapper.Map(grouping.First().application); - appDto.Status = grouping.First().appStatus.InternalStatus; - appDto.StatusCode = grouping.First().appStatus.StatusCode; - appDto.Applicant = ObjectMapper.Map(grouping.First().applicant); - appDto.ApplicationForm = ObjectMapper.Map(grouping.First().applicationForm); - appDtos.Add(appDto); - } - - return new List(appDtos); - } - - public async Task InsertOwnerAsync(Guid applicationId, Guid? assigneeId) - { - try - { - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - application.OwnerId = assigneeId; - await _applicationRepository.UpdateAsync(application); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - public async Task DeleteOwnerAsync(Guid applicationId) - { - try - { - var application = await _applicationRepository.GetAsync(applicationId, false); - if (application != null) - { - application.OwnerId = null; - await _applicationRepository.UpdateAsync(application); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } - } - - [HttpPut] - public async Task UpdateAssigneesAsync(dynamic modifiedAssignees) - { - var dynamicObject = JsonConvert.DeserializeObject(modifiedAssignees); - if (dynamicObject is IEnumerable) - { - Guid previousApplicationId = Guid.Empty; - foreach (JProperty item in dynamicObject) - { - Guid currentApplicationId = Guid.Parse(item.Name); - if (currentApplicationId != previousApplicationId) - { - var assignees = new List<(Guid? assigneeId, string? fullName)>(); - - foreach (JToken assigneeToken in item.Value.Children()) - { - string? assigneeId = assigneeToken.Value("assigneeId") ?? null; - string? fullName = assigneeToken.Value("fullName") ?? null; - assignees.Add(new(assigneeId != null ? Guid.Parse(assigneeId) : null, fullName)); - } - - await _applicationManager.SetAssigneesAsync(currentApplicationId, assignees); - } - - previousApplicationId = currentApplicationId; - } - } - } - - public async Task CreateCommentAsync(Guid id, CreateCommentDto dto) - { - return ObjectMapper.Map((ApplicationComment) - await _commentsManager.CreateCommentAsync(id, dto.Comment, CommentType.ApplicationComment)); - } - - public async Task> GetCommentsAsync(Guid id) - { - return ObjectMapper.Map, IReadOnlyList>((IReadOnlyList) - await _commentsManager.GetCommentsAsync(id, CommentType.ApplicationComment)); - } - - public async Task UpdateCommentAsync(Guid id, UpdateCommentDto dto) - { - try - { - return ObjectMapper.Map((ApplicationComment) - await _commentsManager.UpdateCommentAsync(id, dto.CommentId, dto.Comment, CommentType.ApplicationComment)); - - } - catch (EntityNotFoundException) - { - throw new InvalidCommentParametersException(); - } - } - - public async Task GetCommentAsync(Guid id, Guid commentId) - { - var comment = await _commentsManager.GetCommentAsync(id, commentId, CommentType.ApplicationComment); - - return comment == null - ? throw new InvalidCommentParametersException() - : ObjectMapper.Map((ApplicationComment)comment); - } - - public async Task GetApplicationStatusAsync(Guid id) - { - var application = await _applicationRepository.GetAsync(id, true); - return ObjectMapper.Map(await _applicationStatusRepository.GetAsync(application.ApplicationStatusId)); - } - - #region APPLICATION WORKFLOW - /// - /// Fetches the list of actions and their status context for a given application. - /// - /// The application - /// A list of application actions with their state machine permitted and authorization status. - public async Task> GetActions(Guid applicationId, bool includeInternal = false) - { - var actionList = await _applicationManager.GetActions(applicationId); - var application = await _applicationRepository.GetAsync(applicationId, true); - - // Note: Remove internal state change actions that are side-effects of domain events - var externalActionsList = actionList.Where(a => includeInternal || !a.IsInternal).ToList(); - var actionDtos = ObjectMapper.Map< - List, - List>(externalActionsList); - - // NOTE: Authorization is applied on the AppService layer and is false by default - // TODO: Replace placeholder loop with authorization handler mapped to permissions - // AUTHORIZATION HANDLING - actionDtos.ForEach(async item => - { - item.IsPermitted = item.IsPermitted && (await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(item.ApplicationAction))); - item.IsAuthorized = true; - }); - - return new ListResultDto(actionDtos); - } - - private static OperationAuthorizationRequirement GetActionAuthorizationRequirement(GrantApplicationAction triggerAction) - { - return new OperationAuthorizationRequirement { Name = triggerAction.ToString() }; - } - - /// - /// Transitions the Application workflow state machine given an action. - /// - /// The application - /// The action to be invoked on an Application - public async Task TriggerAction(Guid applicationId, GrantApplicationAction triggerAction) - { - // AUTHORIZATION HANDLING - var application = await _applicationRepository.GetAsync(applicationId, true); - if (!await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(triggerAction))) - { - throw new UnauthorizedAccessException(); - } - - application = await _applicationManager.TriggerAction(applicationId, triggerAction); - - await _localEventBus.PublishAsync( - new ApplicationChangedEvent - { - Action = triggerAction, - ApplicationId = applicationId - } - ); - - return ObjectMapper.Map(application); - } - #endregion APPLICATION WORKFLOW - - public async Task> GetAllApplicationsAsync() - { - - var query = from applications in await _applicationRepository.GetQueryableAsync() - select new GrantApplicationLiteDto - { - Id = applications.Id, - ProjectName = applications.ProjectName, - ReferenceNo = applications.ReferenceNo - }; - - return await query.ToListAsync(); } -} + + [Obsolete("Use ApplicationApplicantAppService.UpdatePartialApplicantInfoAsync instead.")] + [Authorize(UnitySelector.Applicant.UpdatePolicy)] + public async Task UpdateProjectApplicantInfoAsync(Guid id, CreateUpdateApplicantInfoDto input) + { + var application = await _applicationRepository.GetAsync(id); + + var applicant = await _applicantRepository + .FirstOrDefaultAsync(a => a.Id == application.ApplicantId) ?? throw new EntityNotFoundException(); + + applicant.OrganizationType = input.OrganizationType ?? ""; + applicant.OrgName = input.OrgName ?? ""; + applicant.OrgNumber = input.OrgNumber ?? ""; + applicant.OrgStatus = input.OrgStatus ?? ""; + applicant.OrganizationSize = input.OrganizationSize ?? ""; + applicant.Sector = input.Sector ?? ""; + applicant.SubSector = input.SubSector ?? ""; + applicant.SectorSubSectorIndustryDesc = input.SectorSubSectorIndustryDesc ?? ""; + applicant.IndigenousOrgInd = input.IndigenousOrgInd ?? ""; + applicant.UnityApplicantId = input.UnityApplicantId ?? ""; + applicant.FiscalDay = input.FiscalDay; + applicant.FiscalMonth = input.FiscalMonth ?? ""; + applicant.NonRegOrgName = input.NonRegOrgName ?? ""; + applicant.ElectoralDistrict = input.ElectoralDistrict ?? ""; + applicant.ApplicantName = input.ApplicantName ?? ""; + + _ = await _applicantRepository.UpdateAsync(applicant); + + var applicantAgent = await _applicantAgentRepository.FirstOrDefaultAsync(agent => agent.ApplicantId == application.ApplicantId); + if (applicantAgent == null) + { + applicantAgent = await _applicantAgentRepository.InsertAsync(new ApplicantAgent + { + ApplicantId = application.ApplicantId, + ApplicationId = application.Id, + Name = input.ContactFullName ?? "", + Phone = input.ContactBusinessPhone ?? "", + Phone2 = input.ContactCellPhone ?? "", + Email = input.ContactEmail ?? "", + Title = input.ContactTitle ?? "" + }); + } + else + { + applicantAgent.Name = input.ContactFullName ?? ""; + applicantAgent.Phone = input.ContactBusinessPhone ?? ""; + applicantAgent.Phone2 = input.ContactCellPhone ?? ""; + applicantAgent.Email = input.ContactEmail ?? ""; + applicantAgent.Title = input.ContactTitle ?? ""; + applicantAgent = await _applicantAgentRepository.UpdateAsync(applicantAgent); + } + + await UpdateApplicantAddresses(input); + + application.SigningAuthorityFullName = input.SigningAuthorityFullName ?? ""; + application.SigningAuthorityTitle = input.SigningAuthorityTitle ?? ""; + application.SigningAuthorityEmail = input.SigningAuthorityEmail ?? ""; + application.SigningAuthorityBusinessPhone = input.SigningAuthorityBusinessPhone ?? ""; + application.SigningAuthorityCellPhone = input.SigningAuthorityCellPhone ?? ""; + + await PublishCustomFieldUpdatesAsync(application.Id, FlexConsts.ApplicantInfoUiAnchor, input); + + await _applicationRepository.UpdateAsync(application); + + var appDto = ObjectMapper.Map(application); + + appDto.ContactFullName = applicantAgent.Name; + appDto.ContactEmail = applicantAgent.Email; + appDto.ContactTitle = applicantAgent.Title; + appDto.ContactBusinessPhone = applicantAgent.Phone; + appDto.ContactCellPhone = applicantAgent.Phone2; + + return appDto; + } + + protected virtual async Task PublishCustomFieldUpdatesAsync(Guid applicationId, + string uiAnchor, + CustomDataFieldDto input) + { + if (await FeatureChecker.IsEnabledAsync("Unity.Flex")) + { + if (input.CorrelationId != Guid.Empty) + { + await _localEventBus.PublishAsync(new PersistWorksheetIntanceValuesEto() + { + InstanceCorrelationId = applicationId, + InstanceCorrelationProvider = CorrelationConsts.Application, + SheetCorrelationId = input.CorrelationId, + SheetCorrelationProvider = CorrelationConsts.FormVersion, + UiAnchor = uiAnchor, + CustomFields = input.CustomFields, + WorksheetId = input.WorksheetId + }); + } + else + { + Logger.LogError("Unable to resolve for version"); + } + } + } + + protected virtual async Task UpdateApplicantAddresses(CreateUpdateApplicantInfoDto input) + { + List applicantAddresses = await _applicantAddressRepository.FindByApplicantIdAsync(input.ApplicantId); + if (applicantAddresses != null) + { + await UpsertAddress(input, applicantAddresses, AddressType.MailingAddress, input.ApplicantId); + await UpsertAddress(input, applicantAddresses, AddressType.PhysicalAddress, input.ApplicantId); + } + } + + protected virtual async Task UpsertAddress(CreateUpdateApplicantInfoDto input, List applicantAddresses, AddressType applicantAddressType, Guid applicantId) + { + ApplicantAddress? dbAddress = applicantAddresses.Find(address => address.AddressType == applicantAddressType); + + if (dbAddress != null) + { + MapApplicantAddress(input, applicantAddressType, dbAddress); + await _applicantAddressRepository.UpdateAsync(dbAddress); + } + else + { + var newAddress = new ApplicantAddress() { AddressType = applicantAddressType, ApplicantId = applicantId }; + MapApplicantAddress(input, applicantAddressType, newAddress); + await _applicantAddressRepository.InsertAsync(newAddress); + } + } + + private static void MapApplicantAddress(CreateUpdateApplicantInfoDto input, AddressType applicantAddressType, ApplicantAddress address) + { + switch (applicantAddressType) + { + case AddressType.MailingAddress: + address.AddressType = AddressType.MailingAddress; + address.Street = input.MailingAddressStreet ?? ""; + address.Street2 = input.MailingAddressStreet2 ?? ""; + address.Unit = input.MailingAddressUnit ?? ""; + address.City = input.MailingAddressCity ?? ""; + address.Province = input.MailingAddressProvince ?? ""; + address.Postal = input.MailingAddressPostalCode ?? ""; + break; + case AddressType.PhysicalAddress: + address.AddressType = AddressType.PhysicalAddress; + address.Street = input.PhysicalAddressStreet ?? ""; + address.Street2 = input.PhysicalAddressStreet2 ?? ""; + address.Unit = input.PhysicalAddressUnit ?? ""; + address.City = input.PhysicalAddressCity ?? ""; + address.Province = input.PhysicalAddressProvince ?? ""; + address.Postal = input.PhysicalAddressPostalCode ?? ""; + break; + } + } + + public async Task> GetAssigneesAsync(Guid applicationId) + { + var query = from userAssignment in await _applicationAssignmentRepository.GetQueryableAsync() + join user in await _personRepository.GetQueryableAsync() on userAssignment.AssigneeId equals user.Id + where userAssignment.ApplicationId == applicationId + select new GrantApplicationAssigneeDto + { + Id = userAssignment.Id, + AssigneeId = userAssignment.AssigneeId, + FullName = user.FullName, + Duty = userAssignment.Duty, + ApplicationId = applicationId + }; + + return await query.ToListAsync(); + } + + public async Task GetOwnerAsync(Guid ownerId) + { + var owner = await _personRepository.FindAsync(ownerId); + + if (owner != null) + { + return new GrantApplicationAssigneeDto + { + Id = owner.Id, + FullName = owner.FullName + }; + } + else + return new GrantApplicationAssigneeDto(); + } + + public async Task GetFormSubmissionByApplicationId(Guid applicationId) + { + ApplicationFormSubmission applicationFormSubmission = new(); + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + IQueryable queryableFormSubmissions = await _applicationFormSubmissionRepository.GetQueryableAsync(); + if (queryableFormSubmissions != null) + { + var dbResult = await queryableFormSubmissions + .FirstOrDefaultAsync(a => a.ApplicationId.Equals(applicationId)); + + if (dbResult != null) + { + applicationFormSubmission = dbResult; + } + } + } + return applicationFormSubmission; + } + + public async Task UpdateApplicationStatus(Guid[] applicationIds, Guid statusId) + { + foreach (Guid applicationId in applicationIds) + { + try + { + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + application.ApplicationStatusId = statusId; + await _applicationRepository.UpdateAsync(application); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + } + + public async Task InsertAssigneeAsync(Guid applicationId, Guid assigneeId, string? duty) + { + try + { + var assignees = await GetAssigneesAsync(applicationId); + if (assignees == null || assignees.FindIndex(a => a.AssigneeId == assigneeId) == -1) + { + await _applicationManager.AssignUserAsync(applicationId, assigneeId, duty); + } + else + { + await _applicationManager.UpdateAssigneeAsync(applicationId, assigneeId, duty); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public async Task DeleteAssigneeAsync(Guid applicationId, Guid assigneeId) + { + try + { + await _applicationManager.RemoveAssigneeAsync(applicationId, assigneeId); + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public async Task> GetApplicationListAsync(List applicationIds) + { + var applications = await + (await _applicationRepository.WithDetailsAsync()) + .OrderBy(s => s.Id) + .Where(s => applicationIds.Contains(s.Id)) + .ToListAsync(); + + return ObjectMapper.Map, List>(applications); + } + + public async Task> GetApplicationDetailsListAsync(List applicationIds) + { + var query = from application in await _applicationRepository.GetQueryableAsync() + join appStatus in await _applicationStatusRepository.GetQueryableAsync() on application.ApplicationStatusId equals appStatus.Id + join applicant in await _applicantRepository.GetQueryableAsync() on application.ApplicantId equals applicant.Id + join applicationForm in await _applicationFormRepository.GetQueryableAsync() on application.ApplicationFormId equals applicationForm.Id + where applicationIds.Contains(application.Id) + select new + { + application, + appStatus, + applicant, + applicationForm + }; + + var result = query + + .OrderBy(s => s.application.Id) + .GroupBy(s => s.application.Id) + .AsEnumerable() + .ToList(); + + var appDtos = new List(); + + foreach (var grouping in result) + { + var appDto = ObjectMapper.Map(grouping.First().application); + appDto.Status = grouping.First().appStatus.InternalStatus; + appDto.StatusCode = grouping.First().appStatus.StatusCode; + appDto.Applicant = ObjectMapper.Map(grouping.First().applicant); + appDto.ApplicationForm = ObjectMapper.Map(grouping.First().applicationForm); + appDtos.Add(appDto); + } + + return new List(appDtos); + } + + public async Task InsertOwnerAsync(Guid applicationId, Guid? assigneeId) + { + try + { + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + application.OwnerId = assigneeId; + await _applicationRepository.UpdateAsync(application); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public async Task DeleteOwnerAsync(Guid applicationId) + { + try + { + var application = await _applicationRepository.GetAsync(applicationId, false); + if (application != null) + { + application.OwnerId = null; + await _applicationRepository.UpdateAsync(application); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + [HttpPut] + public async Task UpdateAssigneesAsync(dynamic modifiedAssignees) + { + var dynamicObject = JsonConvert.DeserializeObject(modifiedAssignees); + if (dynamicObject is IEnumerable) + { + Guid previousApplicationId = Guid.Empty; + foreach (JProperty item in dynamicObject) + { + Guid currentApplicationId = Guid.Parse(item.Name); + if (currentApplicationId != previousApplicationId) + { + var assignees = new List<(Guid? assigneeId, string? fullName)>(); + + foreach (JToken assigneeToken in item.Value.Children()) + { + string? assigneeId = assigneeToken.Value("assigneeId") ?? null; + string? fullName = assigneeToken.Value("fullName") ?? null; + assignees.Add(new(assigneeId != null ? Guid.Parse(assigneeId) : null, fullName)); + } + + await _applicationManager.SetAssigneesAsync(currentApplicationId, assignees); + } + + previousApplicationId = currentApplicationId; + } + } + } + + public async Task CreateCommentAsync(Guid id, CreateCommentDto dto) + { + return ObjectMapper.Map((ApplicationComment) + await _commentsManager.CreateCommentAsync(id, dto.Comment, CommentType.ApplicationComment)); + } + + public async Task> GetCommentsAsync(Guid id) + { + return ObjectMapper.Map, IReadOnlyList>((IReadOnlyList) + await _commentsManager.GetCommentsAsync(id, CommentType.ApplicationComment)); + } + + public async Task UpdateCommentAsync(Guid id, UpdateCommentDto dto) + { + try + { + return ObjectMapper.Map((ApplicationComment) + await _commentsManager.UpdateCommentAsync(id, dto.CommentId, dto.Comment, CommentType.ApplicationComment)); + + } + catch (EntityNotFoundException) + { + throw new InvalidCommentParametersException(); + } + } + + public async Task GetCommentAsync(Guid id, Guid commentId) + { + var comment = await _commentsManager.GetCommentAsync(id, commentId, CommentType.ApplicationComment); + + return comment == null + ? throw new InvalidCommentParametersException() + : ObjectMapper.Map((ApplicationComment)comment); + } + + public async Task GetApplicationStatusAsync(Guid id) + { + var application = await _applicationRepository.GetAsync(id, true); + return ObjectMapper.Map(await _applicationStatusRepository.GetAsync(application.ApplicationStatusId)); + } + + public async Task GetAccountCodingIdFromFormIdAsync(Guid formId) + { + ApplicationForm? form = await _applicationFormRepository.GetAsync(formId, true); + if (form == null) + { + return null; + } + + return form.AccountCodingId; + } + + #region APPLICATION WORKFLOW + /// + /// Fetches the list of actions and their status context for a given application. + /// + /// The application + /// A list of application actions with their state machine permitted and authorization status. + public async Task> GetActions(Guid applicationId, bool includeInternal = false) + { + var actionList = await _applicationManager.GetActions(applicationId); + var application = await _applicationRepository.GetAsync(applicationId, true); + + // Note: Remove internal state change actions that are side-effects of domain events + var externalActionsList = actionList.Where(a => includeInternal || !a.IsInternal).ToList(); + var actionDtos = ObjectMapper.Map< + List, + List>(externalActionsList); + + // NOTE: Authorization is applied on the AppService layer and is false by default + // TODO: Replace placeholder loop with authorization handler mapped to permissions + // AUTHORIZATION HANDLING + actionDtos.ForEach(async item => + { + item.IsPermitted = item.IsPermitted && (await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(item.ApplicationAction))); + item.IsAuthorized = true; + }); + + return new ListResultDto(actionDtos); + } + + private static OperationAuthorizationRequirement GetActionAuthorizationRequirement(GrantApplicationAction triggerAction) + { + return new OperationAuthorizationRequirement { Name = triggerAction.ToString() }; + } + + /// + /// Transitions the Application workflow state machine given an action. + /// + /// The application + /// The action to be invoked on an Application + public async Task TriggerAction(Guid applicationId, GrantApplicationAction triggerAction) + { + // AUTHORIZATION HANDLING + var application = await _applicationRepository.GetAsync(applicationId, true); + if (!await AuthorizationService.IsGrantedAsync(application, GetActionAuthorizationRequirement(triggerAction))) + { + throw new UnauthorizedAccessException(); + } + + application = await _applicationManager.TriggerAction(applicationId, triggerAction); + + await _localEventBus.PublishAsync( + new ApplicationChangedEvent + { + Action = triggerAction, + ApplicationId = applicationId + } + ); + + return ObjectMapper.Map(application); + } + #endregion APPLICATION WORKFLOW + + public async Task> GetAllApplicationsAsync() + { + + var query = from applications in await _applicationRepository.GetQueryableAsync() + select new GrantApplicationLiteDto + { + Id = applications.Id, + ProjectName = applications.ProjectName, + ReferenceNo = applications.ReferenceNo + }; + + return await query.ToListAsync(); + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs index 20808103a..06ddfc9be 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/GrantManagerApplicationModule.cs @@ -85,7 +85,7 @@ public override void PreConfigureServices(ServiceConfigurationContext context) t.CheckinMisfireThreshold = TimeSpan.FromSeconds(20); t.CheckinInterval = TimeSpan.FromSeconds(10); }); - storeOptions.UseJsonSerializer(); + storeOptions.UseNewtonsoftJsonSerializer(); storeOptions.SetProperty("quartz.jobStore.tablePrefix", "qrtz_"); storeOptions.SetProperty("quartz.scheduler.instanceName", "UnityQuartz"); storeOptions.SetProperty("quartz.scheduler.instanceId", "AUTO"); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs index e45632021..9c93174d0 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/IPaymentSettingsAppService.cs @@ -1,10 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading.Tasks; using Unity.Payments.PaymentThresholds; namespace Unity.GrantManager.Payments; -public interface IPaymentSettingsAppService +public interface IPaymentSettingsAppService { Task> GetL2ApproversThresholds(); + Task GetAccountCodingIdByApplicationIdAsync(Guid applicationId); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs index 5fd33c30f..e087f1b1a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Payments/PaymentSettingsAppService.cs @@ -10,18 +10,35 @@ using Volo.Abp.Identity.Integration; using Unity.Payments.PaymentThresholds; using Volo.Abp.Users; +using Unity.GrantManager.GrantApplications; +using Unity.Payments.PaymentRequests; namespace Unity.GrantManager.Payments; - [Dependency(ReplaceServices = true)] [ExposeServices(typeof(PaymentSettingsAppService), typeof(IPaymentSettingsAppService))] public class PaymentSettingsAppService( IPaymentThresholdRepository paymentThresholdRepository, + IGrantApplicationAppService applicationService, + IPaymentRequestAppService paymentRequestAppService, IIdentityUserIntegrationService identityUserLookupAppService) : GrantManagerAppService, IPaymentSettingsAppService { -public async Task> GetL2ApproversThresholds() + public async Task GetAccountCodingIdByApplicationIdAsync(Guid applicationId) + { + GrantApplicationDto application = await applicationService.GetAsync(applicationId); + Guid formId = application.ApplicationForm.Id; + Guid? accountCodingId = await applicationService.GetAccountCodingIdFromFormIdAsync(formId); + if (accountCodingId == null || accountCodingId == Guid.Empty) + { + // If no account coding is found look up the payment configuration + accountCodingId = await paymentRequestAppService.GetDefaultAccountCodingId(); + + } + return accountCodingId; + } + + public async Task> GetL2ApproversThresholds() { // lookup users with the l2_approval role List l2UsersData = new List(); @@ -33,7 +50,7 @@ public async Task> GetL2ApproversThresholds() foreach (UserData user in users) { var roles = await identityUserLookupAppService.GetRoleNamesAsync(user.Id); - if(roles != null && roles.Contains(UnityRoles.L2Approver) ) + if (roles != null && roles.Contains(UnityRoles.L2Approver)) { PaymentThreshold? paymentThreshold = await paymentThresholdRepository.FirstOrDefaultAsync(x => x.UserId == user.Id); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs index f797f860c..4c30c6cec 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/PaymentConfigurationViewComponent.cs @@ -35,6 +35,7 @@ public async Task InvokeAsync(Guid formId) PaymentConfigurationViewModel model = new(); model.HasEditFormPaymentConfiguration = await HasEditPaymentConfiguration(); model.Payable = applicationForm?.Payable ?? false; + model.PaymentApprovalThreshold = applicationForm?.PaymentApprovalThreshold; model.PreventAutomaticPaymentToCAS = applicationForm?.PreventPayment ?? false; model.AccountCode = applicationForm?.AccountCodingId; model.AccountCodeList = new(); From 7474e11057b92f39de43d0885114cac6eaee0596 Mon Sep 17 00:00:00 2001 From: don-aot Date: Fri, 18 Jul 2025 09:37:39 -0700 Subject: [PATCH 12/30] 29471:Create a DB table for Internal notification groups to be used for the FSB Account Payable --- .../EmailGroupUsers/EmailGroupUsersDto.cs | 13 + .../IEmailGroupUsersAppService.cs | 16 + .../EmailGroups/EmailGroupDto.cs | 14 + .../EmailGroups/IEmailGroupsAppService.cs | 16 + .../EmailGroupUsersAppService.cs | 88 + .../EmailGroups/EmailGroupsAppService.cs | 84 + ...tificationsApplicationAutoMapperProfile.cs | 3 + .../EmailGroupUsers/EmailGroupUser.cs | 14 + .../IEmailGroupUsersRepository.cs | 9 + .../EmailGroups/EmailGroup.cs | 14 + .../EmailGroups/IEmailGroupsRepository.cs | 9 + .../NotificationsDataSeedContributor.cs | 81 +- .../NotificationsDbContext.cs | 3 + ...cationsDbContextModelCreatingExtensions.cs | 18 + .../Repositories/EmailGroupUsersRepository.cs | 16 + .../Repositories/EmailGroupsRepository.cs | 16 + .../20250718155619_EmailGroups.Designer.cs | 4082 +++++++++++++++++ .../20250718155619_EmailGroups.cs | 83 + .../GrantTenantDbContextModelSnapshot.cs | 115 + 19 files changed, 4676 insertions(+), 18 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/EmailGroupUsersDto.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/IEmailGroupUsersAppService.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/EmailGroupDto.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/IEmailGroupsAppService.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/EmailGroupUser.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/IEmailGroupUsersRepository.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/EmailGroup.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/IEmailGroupsRepository.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupUsersRepository.cs create mode 100644 applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupsRepository.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/EmailGroupUsersDto.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/EmailGroupUsersDto.cs new file mode 100644 index 000000000..a4ef1d5b4 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/EmailGroupUsersDto.cs @@ -0,0 +1,13 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Unity.Notifications.EmailGroups +{ + public class EmailGroupUsersDto :EntityDto + { + + public Guid GroupId { get; set; } + public Guid UserId { get; set; } + + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/IEmailGroupUsersAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/IEmailGroupUsersAppService.cs new file mode 100644 index 000000000..d4279dcf5 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroupUsers/IEmailGroupUsersAppService.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + + +namespace Unity.Notifications.EmailGroups +{ + public interface IEmailGroupUsersAppService + { + Task InsertAsync (EmailGroupUsersDto dto); + Task DeleteUserAsync (Guid id); + Task DeleteUsersByGroupIdAsync (Guid id); + Task DeleteUsersByUserIdAsync(Guid id); + Task> GetEmailGroupUsersByGroupIdAsync(Guid id); + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/EmailGroupDto.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/EmailGroupDto.cs new file mode 100644 index 000000000..7af15420e --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/EmailGroupDto.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Unity.Notifications.EmailGroups +{ + public class EmailGroupDto :EntityDto + { + + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/IEmailGroupsAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/IEmailGroupsAppService.cs new file mode 100644 index 000000000..c9616322c --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/EmailGroups/IEmailGroupsAppService.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + + +namespace Unity.Notifications.EmailGroups +{ + public interface IEmailGroupsAppService + { + Task CreateAsync (EmailGroupDto dto); + Task UpdateAsync (EmailGroupDto dto); + Task DeleteAsync (Guid id); + Task> GetListAsync(); + Task GetEmailGroupByIdAsync(Guid id); + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs new file mode 100644 index 000000000..fee843cf0 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs @@ -0,0 +1,88 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.ObjectMapping; + + +namespace Unity.Notifications.EmailGroups +{ + + [Authorize] + [Dependency(ReplaceServices = true)] + [ExposeServices(typeof(EmailGroupUsersAppService), typeof(IEmailGroupUsersAppService))] + public class EmailGroupUsersAppService : ApplicationService, IEmailGroupUsersAppService + { + private readonly IEmailGroupUsersRepository _emailGroupUsersRepository; + + public EmailGroupUsersAppService(IEmailGroupUsersRepository emailGroupUsersRepository) + { + _emailGroupUsersRepository = emailGroupUsersRepository; + } + public async Task InsertAsync(EmailGroupUsersDto dto) + { + var newUser = await _emailGroupUsersRepository.InsertAsync(new EmailGroupUser + { + GroupId = dto.GroupId, + UserId = dto.UserId, + + }); + return new EmailGroupUsersDto + { + Id = newUser.Id, + GroupId = newUser.GroupId, + UserId = newUser.UserId, + }; + } + + + + public async Task DeleteUserAsync(Guid id) + { + try + { + await _emailGroupUsersRepository.DeleteAsync(id); + return true; + } + catch(Exception ex) + { + throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + } + } + public async Task DeleteUsersByUserIdAsync(Guid id) + { + try + { + await _emailGroupUsersRepository.DeleteAsync(id); + return true; + } + catch (Exception ex) + { + throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + } + } + public async Task DeleteUsersByGroupIdAsync(Guid id) + { + try + { + await _emailGroupUsersRepository.DeleteAsync(id); + return true; + } + catch (Exception ex) + { + throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + } + } + + public async Task> GetEmailGroupUsersByGroupIdsync(Guid id) + { + var users = await _emailGroupUsersRepository.GetListAsync(u => u.GroupId == id); + + return ObjectMapper.Map, List>(users); + } + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs new file mode 100644 index 000000000..a4b8fec64 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs @@ -0,0 +1,84 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Unity.GrantManager.Comments; +using Volo.Abp.Application.Services; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; + + +namespace Unity.Notifications.EmailGroups +{ + + [Authorize] + [Dependency(ReplaceServices = true)] + [ExposeServices(typeof(EmailGroupsAppService), typeof(IEmailGroupsAppService))] + public class EmailGroupsAppService : ApplicationService, IEmailGroupsAppService + { + private readonly IEmailGroupsRepository _emailGroupsRepository; + + public EmailGroupsAppService(IEmailGroupsRepository emailGroupsRepository) + { + _emailGroupsRepository = emailGroupsRepository; + } + public async Task CreateAsync(EmailGroupDto dto) + { + var newGroup = await _emailGroupsRepository.InsertAsync(new EmailGroup + { + Name = dto.Name, + Description = dto.Description, + Type = dto.Type + }); + return new EmailGroupDto + { + Id = newGroup.Id, + Name = newGroup.Name, + Description = newGroup.Description, + Type = newGroup.Type + }; + } + + public async Task UpdateAsync(EmailGroupDto dto) + { + var emailGroup = await _emailGroupsRepository.GetAsync(dto.Id, true); + emailGroup.Name = dto.Name; + emailGroup.Description = dto.Description; + emailGroup.Type = dto.Type; + await _emailGroupsRepository.UpdateAsync(emailGroup,autoSave:true); + return new EmailGroupDto + { + Id = emailGroup.Id, + Name = emailGroup.Name, + Description = emailGroup.Description, + Type = emailGroup.Type + }; + } + + public async Task DeleteAsync(Guid id) + { + try + { + await _emailGroupsRepository.DeleteAsync(id); + return true; + } + catch(Exception ex) + { + throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + } + } + + public async Task> GetListAsync() + { + var groups = await _emailGroupsRepository.GetListAsync(); + return ObjectMapper.Map, List>(groups); + } + + public async Task GetEmailGroupByIdAsync(Guid id) + { + var group = await _emailGroupsRepository.GetAsync(id); + return ObjectMapper.Map(group); + } + + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationAutoMapperProfile.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationAutoMapperProfile.cs index 9d6f93788..e9ad095c5 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationAutoMapperProfile.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/NotificationsApplicationAutoMapperProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using Unity.Notifications.EmailGroups; using Unity.Notifications.Emails; using Volo.Abp.Users; @@ -11,5 +12,7 @@ public NotificationsApplicationAutoMapperProfile() CreateMap() .ForMember(x => x.SentBy, map => map.Ignore()); CreateMap(); + CreateMap(); + CreateMap(); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/EmailGroupUser.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/EmailGroupUser.cs new file mode 100644 index 000000000..f66c204f1 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/EmailGroupUser.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Unity.Notifications.EmailGroups; + +public class EmailGroupUser : AuditedAggregateRoot, IMultiTenant +{ + + public virtual Guid? TenantId { get; protected set; } + public Guid GroupId { get; set; } + public Guid UserId { get; set; } + +} \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/IEmailGroupUsersRepository.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/IEmailGroupUsersRepository.cs new file mode 100644 index 000000000..0f98b4936 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroupUsers/IEmailGroupUsersRepository.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Domain.Repositories; + +namespace Unity.Notifications.EmailGroups; + +public interface IEmailGroupUsersRepository : IRepository +{ + +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/EmailGroup.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/EmailGroup.cs new file mode 100644 index 000000000..56fd2e896 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/EmailGroup.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Unity.Notifications.EmailGroups; + +public class EmailGroup : AuditedAggregateRoot, IMultiTenant +{ + public virtual Guid? TenantId { get; protected set; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + +} \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/IEmailGroupsRepository.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/IEmailGroupsRepository.cs new file mode 100644 index 000000000..782f20623 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/EmailGroups/IEmailGroupsRepository.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Domain.Repositories; + +namespace Unity.Notifications.EmailGroups; + +public interface IEmailGroupsRepository : IRepository +{ + +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs index 165ae2e8d..977fecde8 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs @@ -1,18 +1,24 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; +using Unity.Notifications.EmailGroups; using Unity.Notifications.Templates; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; + namespace Unity.Notifications; public class NotificationsDataSeedContributor : IDataSeedContributor, ITransientDependency { private readonly ITemplateVariablesRepository _templateVariablesRepository; + private readonly IEmailGroupsRepository _emailGroupsRepository; - public NotificationsDataSeedContributor(ITemplateVariablesRepository templateVariablesRepository) + public NotificationsDataSeedContributor(ITemplateVariablesRepository templateVariablesRepository, IEmailGroupsRepository emailGroupsRepository) { _templateVariablesRepository = templateVariablesRepository; + _emailGroupsRepository = emailGroupsRepository; } public async Task SeedAsync(DataSeedContext context) @@ -45,28 +51,67 @@ public async Task SeedAsync(DataSeedContext context) new EmailTempateVariableDto { Name = "Applicant ID", Token = "applicant_id", MapTo = "applicant.unityApplicantId" } }; - foreach (var template in emailTemplateVariableDtos) + try { - var existingVariable = await _templateVariablesRepository.FindAsync(tv => tv.Token == template.Token); - if (existingVariable == null) + foreach (var template in emailTemplateVariableDtos) { - await _templateVariablesRepository.InsertAsync( - new TemplateVariable { Name = template.Name, Token = template.Token, MapTo = template.MapTo }, - autoSave: true - ); + var existingVariable = await _templateVariablesRepository.FindAsync(tv => tv.Token == template.Token); + if (existingVariable == null) + { + await _templateVariablesRepository.InsertAsync( + new TemplateVariable { Name = template.Name, Token = template.Token, MapTo = template.MapTo }, + autoSave: true + ); + } + else if (existingVariable.Token == "category" && existingVariable.MapTo == "category") + { + existingVariable.MapTo = "applicationForm.category"; + await _templateVariablesRepository.UpdateAsync(existingVariable, autoSave: true); + } } - else if (existingVariable.Token == "category" && existingVariable.MapTo == "category") + } + catch (Exception ex) + { + + } + + var emailGroups = new List + { + new EmailGroupDto {Name = "FSB-AP", Description = "This group manages the recipients for PO-related payments, which will be sent to FSB-AP to update contracts and initiate payment creation.",Type = "static"}, + new EmailGroupDto {Name = "Payments", Description = "This group manages the recipients for payment notifications, such as failures or errors",Type = "dynamic"} + }; + try + { + var allGroups = await _emailGroupsRepository.GetListAsync(); + foreach (var emailGroup in emailGroups) { - existingVariable.MapTo = "applicationForm.category"; - await _templateVariablesRepository.UpdateAsync(existingVariable, autoSave: true); + var existingGroup = allGroups.FirstOrDefault(g => g.Name == emailGroup.Name); + if (existingGroup == null) + { + await _emailGroupsRepository.InsertAsync( + new EmailGroup { Name = emailGroup.Name, Description = emailGroup.Description, Type = emailGroup.Type }, + autoSave: true + ); + } } + + } + catch (Exception ex) + { + } } -} -internal class EmailTempateVariableDto -{ - public string Name { get; set; } = string.Empty; - public string Token { get; set; } = string.Empty; - public string MapTo { get; set; } = string.Empty; + internal class EmailGroupDto + { + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + } + internal class EmailTempateVariableDto + { + public string Name { get; set; } = string.Empty; + public string Token { get; set; } = string.Empty; + public string MapTo { get; set; } = string.Empty; + } } \ No newline at end of file diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContext.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContext.cs index 2ccc1dea7..1bd185960 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContext.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContext.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Unity.Notifications.Emails; using Unity.Notifications.Templates; +using Unity.Notifications.EmailGroups; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -12,6 +13,8 @@ public class NotificationsDbContext : AbpDbContext, INot public DbSet EmailLogs { get; set; } public DbSet EmailTemplates { get; set; } public DbSet TemplateVariables { get; set; } + public DbSet EmailGroups { get; set; } + public DbSet EmailGroupUsers { get; set; } // Add DbSet for each Aggregate Root here. public NotificationsDbContext(DbContextOptions options) diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContextModelCreatingExtensions.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContextModelCreatingExtensions.cs index fb096ce08..2a294a8d2 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContextModelCreatingExtensions.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/EntityFrameworkCore/NotificationsDbContextModelCreatingExtensions.cs @@ -1,6 +1,8 @@ using Microsoft.EntityFrameworkCore; + using Unity.Notifications.Emails; using Unity.Notifications.Templates; +using Unity.Notifications.EmailGroups; using Volo.Abp; using Volo.Abp.EntityFrameworkCore.Modeling; @@ -96,5 +98,21 @@ public static void ConfigureNotifications( b.ConfigureByConvention(); }); + modelBuilder.Entity(b => + { + b.ToTable(NotificationsDbProperties.DbTablePrefix + "EmailGroups", NotificationsDbProperties.DbSchema); + + b.ConfigureByConvention(); + }); + + modelBuilder.Entity(b => + { + b.ToTable(NotificationsDbProperties.DbTablePrefix + "EmailGroupUsers", NotificationsDbProperties.DbSchema); + + b.ConfigureByConvention(); + b.HasOne() + .WithMany() + .HasForeignKey(x => x.GroupId); + }); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupUsersRepository.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupUsersRepository.cs new file mode 100644 index 000000000..d5b7ef572 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupUsersRepository.cs @@ -0,0 +1,16 @@ +using System; +using Unity.Notifications.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Unity.Notifications.EmailGroups; + +namespace Unity.Notifications.Repositories +{ + public class EmailGroupUsersRepository : EfCoreRepository, IEmailGroupUsersRepository + { + public EmailGroupUsersRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + + } +} diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupsRepository.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupsRepository.cs new file mode 100644 index 000000000..7a5332c4a --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.EntityFrameworkCore/Repositories/EmailGroupsRepository.cs @@ -0,0 +1,16 @@ +using System; +using Unity.Notifications.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Unity.Notifications.EmailGroups; + + +namespace Unity.Notifications.Repositories +{ + public class EmailGroupsRepository : EfCoreRepository, IEmailGroupsRepository + { + public EmailGroupsRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.Designer.cs new file mode 100644 index 000000000..70dd6c022 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.Designer.cs @@ -0,0 +1,4082 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Unity.GrantManager.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + [DbContext(typeof(GrantTenantDbContext))] + [Migration("20250718155619_EmailGroups")] + partial class EmailGroups + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("ScoresheetInstanceId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.HasIndex("ScoresheetInstanceId"); + + b.ToTable("Answers", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("Questions", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Scoresheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CustomFieldId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetInstanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetInstanceId"); + + b.ToTable("CustomFieldValues", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetCorrelationId") + .HasColumnType("uuid"); + + b.Property("WorksheetCorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("WorksheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetLinks", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("CustomFields", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Worksheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantName") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("character varying(600)"); + + b.Property("ApproxNumberOfEmployees") + .HasColumnType("text"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MatchPercentage") + .HasColumnType("numeric"); + + b.Property("NonRegOrgName") + .HasColumnType("text"); + + b.Property("NonRegisteredBusinessName") + .HasColumnType("text"); + + b.Property("OrgName") + .HasColumnType("text"); + + b.Property("OrgNumber") + .HasColumnType("text"); + + b.Property("OrgStatus") + .HasColumnType("text"); + + b.Property("OrganizationSize") + .HasColumnType("text"); + + b.Property("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("StartedOperatingDate") + .HasColumnType("date"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SubSector") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UnityApplicantId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantName"); + + b.ToTable("Applicants", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AddressType") + .HasColumnType("integer"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Postal") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("Street2") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Unit") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("ApplicantAddresses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("BceidBusinessGuid") + .HasColumnType("uuid"); + + b.Property("BceidBusinessName") + .HasColumnType("text"); + + b.Property("BceidUserGuid") + .HasColumnType("uuid"); + + b.Property("BceidUserName") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactOrder") + .HasColumnType("integer"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IdentityEmail") + .HasColumnType("text"); + + b.Property("IdentityName") + .HasColumnType("text"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSubUser") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("Phone2") + .HasColumnType("text"); + + b.Property("Phone2Extension") + .HasColumnType("text"); + + b.Property("PhoneExtension") + .HasColumnType("text"); + + b.Property("RoleForApplicant") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId") + .IsUnique(); + + b.HasIndex("OidcSubUser"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Acquisition") + .HasColumnType("text"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationStatusId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + b.Property("AssessmentResultDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AssessmentResultStatus") + .HasColumnType("text"); + + b.Property("AssessmentStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Community") + .HasColumnType("text"); + + b.Property("CommunityPopulation") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractExecutionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ContractNumber") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeclineRational") + .HasColumnType("text"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DueDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DueDiligenceStatus") + .HasColumnType("text"); + + b.Property("EconomicRegion") + .HasColumnType("text"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinalDecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Forestry") + .HasColumnType("text"); + + b.Property("ForestryFocus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LikelihoodOfFunding") + .HasColumnType("text"); + + b.Property("Notes") + .HasColumnType("text"); + + b.Property("NotificationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("Payload") + .HasColumnType("jsonb"); + + b.Property("PercentageTotalProjectBudget") + .HasColumnType("double precision"); + + b.Property("Place") + .HasColumnType("text"); + + b.Property("ProjectEndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectFundingTotal") + .HasColumnType("numeric"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ProjectStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectSummary") + .HasColumnType("text"); + + b.Property("ProposalDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RecommendedAmount") + .HasColumnType("numeric"); + + b.Property("ReferenceNo") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrict") + .HasColumnType("text"); + + b.Property("RequestedAmount") + .HasColumnType("numeric"); + + b.Property("RiskRanking") + .HasColumnType("text"); + + b.Property("SigningAuthorityBusinessPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityCellPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityEmail") + .HasColumnType("text"); + + b.Property("SigningAuthorityFullName") + .HasColumnType("text"); + + b.Property("SigningAuthorityTitle") + .HasColumnType("text"); + + b.Property("SubStatus") + .HasColumnType("text"); + + b.Property("SubmissionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalProjectBudget") + .HasColumnType("numeric"); + + b.Property("TotalScore") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.HasIndex("ApplicationStatusId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Applications", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Duty") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssigneeId"); + + b.ToTable("ApplicationAssignments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsFileId") + .HasColumnType("text"); + + b.Property("ChefsSumbissionId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationChefsFileAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactEmail") + .HasColumnType("text"); + + b.Property("ContactFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactMobilePhone") + .HasColumnType("text"); + + b.Property("ContactTitle") + .HasColumnType("text"); + + b.Property("ContactType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactWorkPhone") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationContact", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasColumnType("text"); + + b.Property("ApplicationFormDescription") + .HasColumnType("text"); + + b.Property("ApplicationFormName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AttemptedConnectionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("Category") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsCriteriaFormGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConnectionHttpStatus") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ElectoralDistrictAddressType") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsDirectApproval") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("RenderFormIoToHtml") + .HasColumnType("boolean"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IntakeId"); + + b.ToTable("ApplicationForms", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormVersionId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsSubmissionGuid") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormVersionId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("RenderedHTML") + .HasColumnType("text"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Submission") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormSubmissions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsFormVersionGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormSchema") + .HasColumnType("jsonb"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubmissionHeaderMapping") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormVersion", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LinkedApplicationId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationLinks", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StatusCode") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("StatusCode") + .IsUnique(); + + b.ToTable("ApplicationStatuses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("TagId"); + + b.ToTable("ApplicationTags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.ToTable("AssessmentAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ApprovalRecommended") + .HasColumnType("boolean"); + + b.Property("AssessorId") + .HasColumnType("uuid"); + + b.Property("CleanGrowth") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicImpact") + .HasColumnType("integer"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinancialAnalysis") + .HasColumnType("integer"); + + b.Property("InclusiveGrowth") + .HasColumnType("integer"); + + b.Property("IsComplete") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssessorId"); + + b.ToTable("Assessments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicationComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.HasIndex("CommenterId"); + + b.ToTable("AssessmentComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.GlobalTag.Tag", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Tags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Identity.Person", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Badge") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcDisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("OidcSub"); + + b.ToTable("Persons", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Intakes.Intake", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Budget") + .HasColumnType("double precision"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Intakes", (string)null); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.ToTable("EmailGroupUsers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("BCC") + .IsRequired() + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyType") + .IsRequired() + .HasColumnType("text"); + + b.Property("CC") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesMsgId") + .HasColumnType("uuid"); + + b.Property("ChesResponse") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FromAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Priority") + .IsRequired() + .HasColumnType("text"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("SendOnDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SentDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("text"); + + b.Property("TemplateName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ToAddress") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailLogs", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.EmailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BodyHTML") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyText") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SendFrom") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("EmailTemplates", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Subscriber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Subscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("SubscriptionGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriberId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("SubscriberId"); + + b.ToTable("SubscriptionGroupSubscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TemplateVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MapTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Token") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("TemplateVariables", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Trigger", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Triggers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriptionGroupId") + .HasColumnType("uuid"); + + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SubscriptionGroupId"); + + b.HasIndex("TemplateId"); + + b.HasIndex("TriggerId"); + + b.ToTable("TriggerSubscriptions", "Notifications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentConfigurations.PaymentConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MinistryClient") + .HasColumnType("text"); + + b.Property("PaymentIdPrefix") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentThreshold") + .HasColumnType("numeric"); + + b.Property("ProjectNumber") + .HasColumnType("text"); + + b.Property("Responsibility") + .HasColumnType("text"); + + b.Property("ServiceLine") + .HasColumnType("text"); + + b.Property("Stob") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfigurations", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DecisionUserId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.ToTable("ExpenseApprovals", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("BatchName") + .IsRequired() + .HasColumnType("text"); + + b.Property("BatchNumber") + .HasColumnType("numeric"); + + b.Property("CasHttpStatusCode") + .HasColumnType("integer"); + + b.Property("CasResponse") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InvoiceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("InvoiceStatus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsRecon") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PayeeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentDate") + .HasColumnType("text"); + + b.Property("PaymentNumber") + .HasColumnType("text"); + + b.Property("PaymentStatus") + .HasColumnType("text"); + + b.Property("ReferenceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequesterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("SubmissionConfirmationCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SupplierName") + .HasColumnType("text"); + + b.Property("SupplierNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ReferenceNumber") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("PaymentRequests", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.HasIndex("TagId"); + + b.ToTable("PaymentTags", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressLine1") + .HasColumnType("text"); + + b.Property("AddressLine2") + .HasColumnType("text"); + + b.Property("AddressLine3") + .HasColumnType("text"); + + b.Property("BankAccount") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EFTAdvicePref") + .HasColumnType("text"); + + b.Property("EmailAddress") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCas") + .HasColumnType("timestamp without time zone"); + + b.Property("MarkDeletedInUse") + .HasColumnType("boolean"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentGroup") + .HasColumnType("integer"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SiteProtected") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Sites", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCAS") + .HasColumnType("timestamp without time zone"); + + b.Property("MailingAddress") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SIN") + .HasColumnType("text"); + + b.Property("StandardIndustryClassification") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("Subcategory") + .HasColumnType("text"); + + b.Property("SupplierProtected") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Suppliers", "Payments"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Instances") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Question", "Question") + .WithMany("Answers") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", null) + .WithMany("Answers") + .HasForeignKey("ScoresheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.ScoresheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Sections") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.HasOne("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", null) + .WithMany("Values") + .HasForeignKey("WorksheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Links") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.WorksheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Sections") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany("ApplicantAddresses") + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Applicant"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithOne("ApplicantAgent") + .HasForeignKey("Unity.GrantManager.Applications.ApplicantAgent", "ApplicationId"); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("OidcSubUser") + .HasPrincipalKey("OidcSub"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", "ApplicationForm") + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationStatus", "ApplicationStatus") + .WithMany("Applications") + .HasForeignKey("ApplicationStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Applicant"); + + b.Navigation("ApplicationForm"); + + b.Navigation("ApplicationStatus"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationAssignments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Assignee") + .WithMany() + .HasForeignKey("AssigneeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Assignee"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.HasOne("Unity.GrantManager.Intakes.Intake", null) + .WithMany() + .HasForeignKey("IntakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationTags") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("Assessments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("AssessorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("GroupId"); + + b.HasOne("Unity.Notifications.Templates.Subscriber", "Subscriber") + .WithMany() + .HasForeignKey("SubscriberId"); + + b.Navigation("Subscriber"); + + b.Navigation("SubscriptionGroup"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("SubscriptionGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.EmailTemplate", "EmailTemplate") + .WithMany() + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.Trigger", "Trigger") + .WithMany() + .HasForeignKey("TriggerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmailTemplate"); + + b.Navigation("SubscriptionGroup"); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", "PaymentRequest") + .WithMany("ExpenseApprovals") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PaymentRequest"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", null) + .WithMany("PaymentTags") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Supplier", "Supplier") + .WithMany("Sites") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Navigation("Instances"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Navigation("Links"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Navigation("ApplicantAddresses"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Navigation("ApplicantAgent"); + + b.Navigation("ApplicationAssignments"); + + b.Navigation("ApplicationTags"); + + b.Navigation("Assessments"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Navigation("Applications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Navigation("ExpenseApprovals"); + + b.Navigation("PaymentTags"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Navigation("Sites"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.cs new file mode 100644 index 000000000..62d944b5b --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250718155619_EmailGroups.cs @@ -0,0 +1,83 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class EmailGroups : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "EmailGroups", + schema: "Notifications", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + Name = table.Column(type: "text", nullable: false), + Description = table.Column(type: "text", nullable: false), + Type = table.Column(type: "text", nullable: false), + ExtraProperties = table.Column(type: "text", nullable: false), + ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true), + LastModificationTime = table.Column(type: "timestamp without time zone", nullable: true), + LastModifierId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_EmailGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "EmailGroupUsers", + schema: "Notifications", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + GroupId = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + ExtraProperties = table.Column(type: "text", nullable: false), + ConcurrencyStamp = table.Column(type: "character varying(40)", maxLength: 40, nullable: false), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true), + LastModificationTime = table.Column(type: "timestamp without time zone", nullable: true), + LastModifierId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_EmailGroupUsers", x => x.Id); + table.ForeignKey( + name: "FK_EmailGroupUsers_EmailGroups_GroupId", + column: x => x.GroupId, + principalSchema: "Notifications", + principalTable: "EmailGroups", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_EmailGroupUsers_GroupId", + schema: "Notifications", + table: "EmailGroupUsers", + column: "GroupId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "EmailGroupUsers", + schema: "Notifications"); + + migrationBuilder.DropTable( + name: "EmailGroups", + schema: "Notifications"); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs index dd62f949a..592d6a6d9 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs @@ -2410,6 +2410,112 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Intakes", (string)null); }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.ToTable("EmailGroupUsers", "Notifications"); + }); + modelBuilder.Entity("Unity.Notifications.Emails.EmailLog", b => { b.Property("Id") @@ -3795,6 +3901,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("Unity.Notifications.EmailGroups.EmailGroupUser", b => + { + b.HasOne("Unity.Notifications.EmailGroups.EmailGroup", null) + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => { b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") From 1a4d41520e3ac6c0c30d4d84e07e66ba16965b97 Mon Sep 17 00:00:00 2001 From: jpasta Date: Fri, 18 Jul 2025 12:04:59 -0700 Subject: [PATCH 13/30] feature/AB#28691-AccountCodingMulti --- .../IPaymentRequestAppService.cs | 1 + .../PaymentRequestAppService.cs | 47 +- .../UpdatePaymentRequestStatus.cshtml.cs | 280 +- .../IApplicationFormAppService.cs | 1 + .../ApplicationFormAppService.cs | 15 +- .../20250409224221_AccountCoding.cs | 56 +- ...58_PaymentRequestAccountCoding.Designer.cs | 4086 +++++++++++++++++ ...50716225458_PaymentRequestAccountCoding.cs | 81 + .../GrantTenantDbContextModelSnapshot.cs | 172 +- .../Pages/ApplicationForms/Index.js | 2 +- 10 files changed, 4432 insertions(+), 309 deletions(-) create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.Designer.cs create mode 100644 applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.cs diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs index 18468a6be..18d2e538e 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs @@ -17,5 +17,6 @@ public interface IPaymentRequestAppService : IApplicationService Task GetPaymentRequestCountBySiteIdAsync(Guid siteId); Task> GetListByApplicationIdsAsync(List applicationIds); Task GetNextBatchInfoAsync(); + Task GetDefaultAccountCodingId(); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs index efdc79f5b..27ae58a8a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs @@ -32,34 +32,29 @@ public class PaymentRequestAppService( IPaymentsManager paymentsManager, IPaymentRequestRepository paymentRequestsRepository, IPermissionChecker permissionChecker) : PaymentsAppService, IPaymentRequestAppService - { - protected virtual async Task<(PaymentConfiguration? Config, decimal Threshold)> GetPaymentConfigurationWithThresholdAsync() + { + public async Task GetDefaultAccountCodingId() { - var paymentConfigs = await paymentConfigurationRepository.GetListAsync(); - var paymentConfig = paymentConfigs.FirstOrDefault(); - - if (paymentConfig == null) + Guid? accountCodingId = null; + // If no account coding is found look up the payment configuration + PaymentConfiguration? paymentConfiguration = await GetPaymentConfigurationAsync(); + if (paymentConfiguration != null && paymentConfiguration.DefaultAccountCodingId.HasValue) { - return (null, PaymentSharedConsts.DefaultThresholdAmount); + accountCodingId = paymentConfiguration.DefaultAccountCodingId; } - - return (paymentConfig, paymentConfig.PaymentThreshold ?? PaymentSharedConsts.DefaultThresholdAmount); + return accountCodingId; } [Authorize(PaymentsPermissions.Payments.RequestPayment)] public virtual async Task> CreateAsync(List paymentRequests) { List createdPayments = []; - var (paymentConfig, paymentThreshold) = await GetPaymentConfigurationWithThresholdAsync(); + var paymentConfig = await GetPaymentConfigurationAsync(); var paymentIdPrefix = string.Empty; if (paymentConfig != null) { - if (paymentConfig.PaymentThreshold != null) - { - paymentThreshold = (decimal)paymentConfig.PaymentThreshold; - } if (!paymentConfig.PaymentIdPrefix.IsNullOrEmpty()) { paymentIdPrefix = paymentConfig.PaymentIdPrefix; @@ -80,14 +75,13 @@ public virtual async Task> CreateAsync(List> CreateAsync(List GetNextBatchInfoAsync() { - var (paymentConfig, _) = await GetPaymentConfigurationWithThresholdAsync(); + var paymentConfig = await GetPaymentConfigurationAsync(); var paymentIdPrefix = string.Empty; if (paymentConfig != null && !paymentConfig.PaymentIdPrefix.IsNullOrEmpty()) @@ -186,7 +180,7 @@ public virtual async Task> UpdateStatusAsync(List r.IsApprove).Select(x => x.PaymentRequestId).ToList(); - var approvalList = await _paymentRequestsRepository.GetListAsync(x => approvalRequests.Contains(x.Id), includeDetails: true); + var approvalList = await paymentRequestsRepository.GetListAsync(x => approvalRequests.Contains(x.Id), includeDetails: true); // Rule AB#26693: Reject Payment Request update batch if violates L1 and L2 separation of duties if (approvalList.Any( @@ -258,7 +252,7 @@ private async Task CanPerformLevel1ActionAsync(PaymentRequestStatus status private async Task CanPerformLevel2ActionAsync(PaymentRequest payment, bool IsApprove) { List level2Approvals = new() { PaymentRequestStatus.L2Pending, PaymentRequestStatus.L2Declined }; - + // Rule AB#26693: Reject Payment Request update if violates L1 and L2 separation of duties var IsSameApprover = CurrentUser.Id == payment.ExpenseApprovals.FirstOrDefault(x => x.Type == ExpenseApprovalType.Level1)?.DecisionUserId; if (IsSameApprover && IsApprove) @@ -300,7 +294,7 @@ private async Task CreatePaymentRequestDtoAsync(Guid paymentR public async Task> GetListByApplicationIdsAsync(List applicationIds) { - var paymentsQueryable = await _paymentRequestsRepository.GetQueryableAsync(); + var paymentsQueryable = await paymentRequestsRepository.GetQueryableAsync(); var payments = await paymentsQueryable.Include(pr => pr.Site).ToListAsync(); var filteredPayments = payments.Where(pr => applicationIds.Contains(pr.CorrelationId)).ToList(); @@ -312,15 +306,18 @@ public async Task> GetListAsync(PagedAndSorted var totalCount = await paymentRequestsRepository.GetCountAsync(); using (dataFilter.Disable()) { - await _paymentRequestsRepository + await paymentRequestsRepository .GetPagedListAsync(input.SkipCount, input.MaxResultCount, input.Sorting ?? string.Empty, includeDetails: true); // Include PaymentTags in the query - var paymentsQueryable = await _paymentRequestsRepository.GetQueryableAsync(); + var paymentsQueryable = await paymentRequestsRepository.GetQueryableAsync(); + // Changing this breaks the code so suppressing the warning +#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. var paymentsWithTags = await paymentsQueryable .Include(pr => pr.PaymentTags) .ThenInclude(pt => pt.Tag) .ToListAsync(); +#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. var mappedPayments = await MapToDtoAndLoadDetailsAsync(paymentsWithTags); @@ -449,7 +446,9 @@ protected virtual async Task GetPaymentThresholdAsync() if (paymentConfigs.Count > 0) { var paymentConfig = paymentConfigs[0]; - return paymentConfig.PaymentThreshold ?? PaymentSharedConsts.DefaultThresholdAmount; + + // TODO: FIX To current user threshold throw exception if the user does not have a threshold? + return PaymentSharedConsts.DefaultThresholdAmount; } return PaymentSharedConsts.DefaultThresholdAmount; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs index 507b225ba..313b07ed5 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs @@ -5,7 +5,9 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; +using Unity.GrantManager.ApplicationForms; using Unity.Payment.Shared; +using Unity.Payments.Domain.PaymentThresholds; using Unity.Payments.Domain.Shared; using Unity.Payments.Enums; using Unity.Payments.PaymentConfigurations; @@ -20,208 +22,173 @@ public class PaymentGrouping { public int GroupId { get; set; } public PaymentRequestStatus ToStatus { get; set; } - public List Items { get; set; } = []; + public List Items { get; set; } = new(); } - public class UpdatePaymentRequestStatus : AbpPageModel + public class UpdatePaymentRequestStatus( + IPaymentRequestAppService paymentRequestService, + IPaymentConfigurationAppService paymentConfigurationAppService, + IApplicationFormAppService applicationFormAppService, + IPaymentThresholdRepository paymentThresholdRepository, + ICurrentUser currentUser, + IPermissionCheckerService permissionCheckerService) : AbpPageModel { - [BindProperty] - public List PaymentGroupings { get; set; } = []; - - [BindProperty] - public decimal PaymentThreshold { get; set; } - - [BindProperty] - public bool DisableSubmit { get; set; } - - [BindProperty] - public bool HasPaymentConfiguration { get; set; } - - [BindProperty] - public bool IsApproval { get; set; } - - [BindProperty] - public bool IsErrors { get; set; } - - public List SelectedPaymentIds { get; set; } - + [BindProperty] public List PaymentGroupings { get; set; } = new(); + [BindProperty] public decimal PaymentThreshold { get; set; } + [BindProperty] public bool DisableSubmit { get; set; } + [BindProperty] public bool HasPaymentConfiguration { get; set; } + [BindProperty] public bool IsApproval { get; set; } + [BindProperty] public bool IsErrors { get; set; } + public List SelectedPaymentIds { get; set; } = new(); public string FromStatusText { get; set; } = string.Empty; - private readonly IPaymentRequestAppService _paymentRequestService; - private readonly IPaymentConfigurationAppService _paymentConfigurationAppService; - private readonly IPermissionCheckerService _permissionCheckerService; - - public UpdatePaymentRequestStatus(IPaymentRequestAppService paymentRequestService, - IPaymentConfigurationAppService paymentConfigurationAppService, - ICurrentUser currentUser, - IPermissionCheckerService permissionCheckerService) + public async Task OnGetAsync(string paymentIds, bool isApprove) { - SelectedPaymentIds = []; - _paymentRequestService = paymentRequestService; - _paymentConfigurationAppService = paymentConfigurationAppService; - _permissionCheckerService = permissionCheckerService; + await InitializeStateAsync(paymentIds, isApprove); + var payments = await paymentRequestService.GetListByPaymentIdsAsync(SelectedPaymentIds); + var paymentApprovals = await BuildPaymentApprovalsAsync(payments); + + PaymentGroupings = paymentApprovals + .GroupBy(item => item.ToStatus) + .Select((group, index) => new PaymentGrouping + { + GroupId = index, + ToStatus = group.Key, + Items = group.ToList() + }) + .ToList(); + + DisableSubmit = !paymentApprovals.Any() || !ModelState.IsValid; } - public async Task OnGetAsync(string paymentIds, bool isApprove) + private async Task InitializeStateAsync(string paymentIds, bool isApprove) { await GetFromStateForUserAsync(); - IsApproval = isApprove; - SelectedPaymentIds = JsonSerializer.Deserialize>(paymentIds) ?? []; - var payments = await _paymentRequestService.GetListByPaymentIdsAsync(SelectedPaymentIds); - var permissionsToCheck = new[] { PaymentsPermissions.Payments.L1ApproveOrDecline, PaymentsPermissions.Payments.L2ApproveOrDecline, PaymentsPermissions.Payments.L3ApproveOrDecline }; - _ = await _permissionCheckerService.CheckPermissionsAsync(permissionsToCheck); - var paymentConfiguration = await _paymentConfigurationAppService.GetAsync(); + SelectedPaymentIds = JsonSerializer.Deserialize>(paymentIds) ?? new(); + PaymentThreshold = await GetUserPaymentThresholdAsync(); + HasPaymentConfiguration = await paymentConfigurationAppService.GetAsync() != null; + } - PaymentThreshold = paymentConfiguration?.PaymentThreshold ?? PaymentSharedConsts.DefaultThresholdAmount; - HasPaymentConfiguration = true; + private async Task GetUserPaymentThresholdAsync() + { + var userThreshold = await paymentThresholdRepository.GetAsync(x => x.UserId == currentUser.Id); + return userThreshold?.Threshold ?? PaymentSharedConsts.DefaultThresholdAmount; + } + private async Task> BuildPaymentApprovalsAsync(List payments) + { var paymentApprovals = new List(); - foreach (var payment in payments) { - PaymentsApprovalModel request = new() - { - Id = payment.Id, - ReferenceNumber = payment.ReferenceNumber, - CorrelationId = payment.Id, - ApplicantName = payment.PayeeName, - Amount = payment.Amount, - Description = payment.Description, - InvoiceNumber = payment.InvoiceNumber, - Status = payment.Status, - IsL3ApprovalRequired = payment.Amount > PaymentThreshold, - ToStatus = payment.Status, - IsApproval = isApprove, - PreviousL1Approver = payment.ExpenseApprovals.FirstOrDefault(x => x.Type == ExpenseApprovalType.Level1)?.DecisionUserId, - }; - - var validationContext = new ValidationContext(request, LazyServiceProvider, null); - var validationResults = new List(); - request.IsValid = Validator.TryValidateObject(request, validationContext, validationResults, true); - - // Add validation errors to ModelState - foreach (var validationResult in validationResults) - { - foreach (var memberName in validationResult.MemberNames) - { - ModelState.AddModelError(memberName, validationResult.ErrorMessage ?? "Validation message error."); - } - } + var formThreshold = await applicationFormAppService.GetFormPaymentApprovalThresholdByApplicationIdAsync(payment.CorrelationId); + PaymentThreshold = formThreshold.HasValue && formThreshold.Value < PaymentThreshold ? formThreshold.Value : PaymentThreshold; - var verifiedRequest = await CheckUserPermissionsAsync(payment.Status, IsApproval, payment.Amount > PaymentThreshold, request); + var request = CreateApprovalModel(payment); + ValidateApprovalModel(request); - if (verifiedRequest.isPermitted) + if (await VerifyPermissionsAsync(payment.Status, request)) { - paymentApprovals!.Add(request); + paymentApprovals.Add(request); } } - var grouping = paymentApprovals.GroupBy(item => item.ToStatus) - .Select((g, index) => (GroupId: index, ToStatus: g.Key, Items: g.ToList())) - .ToList(); + return paymentApprovals; + } - var indx = 0; - foreach (var (GroupId, ToStatus, Items) in grouping) + private PaymentsApprovalModel CreateApprovalModel(PaymentDetailsDto payment) + { + return new PaymentsApprovalModel { - PaymentGroupings.Add(new PaymentGrouping() - { - GroupId = GroupId, - Items = Items, - ToStatus = ToStatus - }); - - indx++; - } - - DisableSubmit = (paymentApprovals.Count == 0 || !ModelState.IsValid); + Id = payment.Id, + ReferenceNumber = payment.ReferenceNumber, + CorrelationId = payment.Id, + ApplicantName = payment.PayeeName, + Amount = payment.Amount, + Description = payment.Description, + InvoiceNumber = payment.InvoiceNumber, + Status = payment.Status, + IsL3ApprovalRequired = payment.Amount > PaymentThreshold, + ToStatus = payment.Status, + IsApproval = IsApproval, + PreviousL1Approver = payment.ExpenseApprovals.FirstOrDefault(x => x.Type == ExpenseApprovalType.Level1)?.DecisionUserId + }; } - private async Task CheckUserPermissionsAsync(PaymentRequestStatus status, bool IsApproval, bool isExceedThreshold, PaymentsApprovalModel request) + private void ValidateApprovalModel(PaymentsApprovalModel request) { - if (status.Equals(PaymentRequestStatus.L1Pending)) - { - request.ToStatus = IsApproval ? PaymentRequestStatus.L2Pending : PaymentRequestStatus.L1Declined; - request.isPermitted = await _permissionCheckerService.IsGrantedAsync(PaymentsPermissions.Payments.L1ApproveOrDecline); + var validationContext = new ValidationContext(request, LazyServiceProvider, null); + var validationResults = new List(); + request.IsValid = Validator.TryValidateObject(request, validationContext, validationResults, true); - } - else if (status.Equals(PaymentRequestStatus.L2Pending)) + foreach (var validationResult in validationResults) { - if (isExceedThreshold) - { - request.ToStatus = IsApproval ? PaymentRequestStatus.L3Pending : PaymentRequestStatus.L2Declined; - } - else + foreach (var memberName in validationResult.MemberNames) { - request.ToStatus = IsApproval ? PaymentRequestStatus.Submitted : PaymentRequestStatus.L2Declined; + ModelState.AddModelError(memberName, validationResult.ErrorMessage ?? "Validation error."); } - - request.isPermitted = await _permissionCheckerService.IsGrantedAsync(PaymentsPermissions.Payments.L2ApproveOrDecline); } - else if (status.Equals(PaymentRequestStatus.L3Pending)) - { - request.ToStatus = IsApproval ? PaymentRequestStatus.Submitted : PaymentRequestStatus.L3Declined; - request.isPermitted = await _permissionCheckerService.IsGrantedAsync(PaymentsPermissions.Payments.L3ApproveOrDecline); - } - else + } + + private async Task VerifyPermissionsAsync(PaymentRequestStatus status, PaymentsApprovalModel request) + { + request.ToStatus = status switch { - request.isPermitted = false; - } + PaymentRequestStatus.L1Pending => IsApproval ? PaymentRequestStatus.L2Pending : PaymentRequestStatus.L1Declined, + PaymentRequestStatus.L2Pending => IsApproval + ? (request.IsL3ApprovalRequired ? PaymentRequestStatus.L3Pending : PaymentRequestStatus.Submitted) + : PaymentRequestStatus.L2Declined, + PaymentRequestStatus.L3Pending => IsApproval ? PaymentRequestStatus.Submitted : PaymentRequestStatus.L3Declined, + _ => request.ToStatus + }; - return request; + var permission = status switch + { + PaymentRequestStatus.L1Pending => PaymentsPermissions.Payments.L1ApproveOrDecline, + PaymentRequestStatus.L2Pending => PaymentsPermissions.Payments.L2ApproveOrDecline, + PaymentRequestStatus.L3Pending => PaymentsPermissions.Payments.L3ApproveOrDecline, + _ => null + }; + return permission != null && await permissionCheckerService.IsGrantedAsync(permission); } public async Task OnPostAsync() { - if (PaymentGroupings == null || PaymentGroupings.Count == 0) return NoContent(); + if (PaymentGroupings == null || !PaymentGroupings.Any() || !ModelState.IsValid) return NoContent(); - if (ModelState.IsValid) - { - var payments = MapPaymentRequests(IsApproval); - await _paymentRequestService.UpdateStatusAsync(payments); - } + var payments = PaymentGroupings.SelectMany(group => group.Items) + .Select(payment => new UpdatePaymentStatusRequestDto + { + PaymentRequestId = payment.Id, + IsApprove = IsApproval + }) + .ToList(); + await paymentRequestService.UpdateStatusAsync(payments); return NoContent(); } - public async Task GetFromStateForUserAsync() + private async Task GetFromStateForUserAsync() { - if (await _permissionCheckerService.IsGrantedAsync(PaymentsPermissions.Payments.L1ApproveOrDecline)) + var permissions = new[] { - FromStatusText = GetStatusText(PaymentRequestStatus.L1Pending); - } - else if (await _permissionCheckerService.IsGrantedAsync(PaymentsPermissions.Payments.L2ApproveOrDecline)) - { - FromStatusText = GetStatusText(PaymentRequestStatus.L2Pending); - } - else if (await _permissionCheckerService.IsGrantedAsync(PaymentsPermissions.Payments.L3ApproveOrDecline)) - { - FromStatusText = GetStatusText(PaymentRequestStatus.L3Pending); - } - } - - private List MapPaymentRequests(bool isApprove) - { - var payments = new List(); - - if (PaymentGroupings == null || PaymentGroupings.Count == 0) return payments; + PaymentsPermissions.Payments.L1ApproveOrDecline, + PaymentsPermissions.Payments.L2ApproveOrDecline, + PaymentsPermissions.Payments.L3ApproveOrDecline + }; - foreach (var grouping in PaymentGroupings) + foreach (var permission in permissions) { - foreach (var payment in grouping.Items) + if (await permissionCheckerService.IsGrantedAsync(permission)) { - payments.Add(new UpdatePaymentStatusRequestDto() - { - PaymentRequestId = payment.Id, - IsApprove = isApprove, - }); + FromStatusText = GetStatusText((PaymentRequestStatus)Array.IndexOf(permissions, permission)); + break; } } - - return payments; } + public static string GetStatusText(PaymentRequestStatus status) { return status.ToString() switch @@ -242,15 +209,12 @@ public static string GetStatusText(PaymentRequestStatus status) }; } - public static string GetStatusTextColor(PaymentRequestStatus status) + public static string GetStatusTextColor(PaymentRequestStatus status) => status switch { - return status.ToString() switch - { - "L1Declined" or "L2Declined" or "L3Declined" or "PaymentFailed" => "#CE3E39", - "Submitted" => "#5595D9", - "Paid" => "#42814A", - _ => "#053662", - }; - } + PaymentRequestStatus.L1Declined or PaymentRequestStatus.L2Declined or PaymentRequestStatus.L3Declined => "#CE3E39", + PaymentRequestStatus.Submitted => "#5595D9", + PaymentRequestStatus.Paid => "#42814A", + _ => "#053662" + }; } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs index e7db0c975..0550e005e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application.Contracts/ApplicationForms/IApplicationFormAppService.cs @@ -18,5 +18,6 @@ public interface IApplicationFormAppService : ICrudAppService< Task> GetVersionsAsync(Guid id); Task> GetPublishedVersionsAsync(Guid id); Task PatchOtherConfig(Guid id, OtherConfigDto config); + Task GetFormPaymentApprovalThresholdByApplicationIdAsync(Guid applicationId); } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs index fee728075..75d863e0f 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/ApplicationForms/ApplicationFormAppService.cs @@ -31,11 +31,14 @@ public class ApplicationFormAppService : private readonly IFormsApiService _formsApiService; private readonly IApplicationFormVersionAppService _applicationFormVersionAppService; private readonly IApplicationFormVersionRepository _applicationFormVersionRepository; + private readonly IGrantApplicationAppService _applicationService; private readonly IRepository _applicationFormRepository; + public ApplicationFormAppService(IRepository repository, IStringEncryptionService stringEncryptionService, IApplicationFormVersionAppService applicationFormVersionAppService, IApplicationFormVersionRepository applicationFormVersionRepository, + IGrantApplicationAppService applicationService, IFormsApiService formsApiService) : base(repository) { @@ -44,6 +47,7 @@ public ApplicationFormAppService(IRepository repository, _formsApiService = formsApiService; _applicationFormVersionRepository = applicationFormVersionRepository; _applicationFormRepository = repository; + _applicationService = applicationService; } [Authorize(GrantManagerPermissions.ApplicationForms.Default)] @@ -164,5 +168,14 @@ public async Task SavePaymentConfiguration(FormPaymentConfigurationDto dto) appForm.PreventPayment = dto.PreventPayment; appForm.PaymentApprovalThreshold = dto.PaymentApprovalThreshold; await _applicationFormRepository.UpdateAsync(appForm); - } + } + + public async Task GetFormPaymentApprovalThresholdByApplicationIdAsync(Guid applicationId) + { + // Get the payment threshold for the application + GrantApplicationDto application = await _applicationService.GetAsync(applicationId); + Guid formId = application.ApplicationForm.Id; + ApplicationForm appForm = await _applicationFormRepository.GetAsync(formId); + return appForm.PaymentApprovalThreshold; + } } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs index d27461271..6e3385d0e 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250409224221_AccountCoding.cs @@ -65,7 +65,6 @@ protected override void Up(MigrationBuilder migrationBuilder) } ); - migrationBuilder.AddColumn( name: "DefaultAccountCodingId", table: "PaymentConfigurations", @@ -80,14 +79,6 @@ protected override void Up(MigrationBuilder migrationBuilder) table: "PaymentConfigurations", column: "DefaultAccountCodingId"); - migrationBuilder.AddForeignKey( - name: "FK_PaymentConfiguration_AccountCodings_Id", - schema: "Payments", - table: "PaymentConfigurations", - column: "DefaultAccountCodingId", - principalSchema: "Payments", - principalTable: "AccountCodings", - principalColumn: "Id"); migrationBuilder.AddColumn( name: "PaymentApprovalThreshold", @@ -109,44 +100,12 @@ protected override void Up(MigrationBuilder migrationBuilder) type: "uuid", nullable: true, defaultValue: null); + migrationBuilder.CreateIndex( name: "IX_ApplicationForms_AccountCodingId", table: "ApplicationForms", - column: "AccountCodingId"); - - migrationBuilder.AddForeignKey( - name: "FK_ApplicationForms_AccountCodings_Id", - table: "ApplicationForms", - column: "AccountCodingId", - principalSchema: "Payments", - principalTable: "AccountCodings", - principalColumn: "Id"); - - migrationBuilder.DropColumn( - name: "MinistryClient", - table: "PaymentConfigurations", - schema: "Payments"); - - migrationBuilder.DropColumn( - name: "Responsibility", - table: "PaymentConfigurations", - schema: "Payments"); - - migrationBuilder.DropColumn( - name: "ServiceLine", - table: "PaymentConfigurations", - schema: "Payments"); - - migrationBuilder.DropColumn( - name: "Stob", - table: "PaymentConfigurations", - schema: "Payments"); - - migrationBuilder.DropColumn( - name: "ProjectNumber", - table: "PaymentConfigurations", - schema: "Payments"); + column: "AccountCodingId"); } @@ -157,6 +116,17 @@ protected override void Down(MigrationBuilder migrationBuilder) name: "FK_ApplicationForms_AccountCodings_Id", table: "ApplicationForms"); + migrationBuilder.AddColumn( + name: "PaymentThreshold", + schema: "Payments", + table: "PaymentConfigurations", + type: "numeric"); + + migrationBuilder.DropColumn( + name: "PaymentThreshold", + table: "PaymentConfigurations", + schema: "Payments"); + migrationBuilder.DropColumn( name: "PreventPayment", table: "ApplicationForms"); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.Designer.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.Designer.cs new file mode 100644 index 000000000..ef4f0c7ad --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.Designer.cs @@ -0,0 +1,4086 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Unity.GrantManager.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + [DbContext(typeof(GrantTenantDbContext))] + [Migration("20250716225458_PaymentRequestAccountCoding")] + partial class PaymentRequestAccountCoding + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("ScoresheetInstanceId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.HasIndex("ScoresheetInstanceId"); + + b.ToTable("Answers", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("Questions", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Scoresheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ScoresheetId"); + + b.ToTable("ScoresheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CustomFieldId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetInstanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetInstanceId"); + + b.ToTable("CustomFieldValues", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CurrentValue") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetCorrelationId") + .HasColumnType("uuid"); + + b.Property("WorksheetCorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("WorksheetInstances", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UiAnchor") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetLinks", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Definition") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("SectionId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("CustomFields", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("Worksheets", "Flex"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("WorksheetId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WorksheetId"); + + b.ToTable("WorksheetSections", "Flex"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantName") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("character varying(600)"); + + b.Property("ApproxNumberOfEmployees") + .HasColumnType("text"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FiscalDay") + .HasColumnType("integer"); + + b.Property("FiscalMonth") + .HasColumnType("text"); + + b.Property("IndigenousOrgInd") + .HasColumnType("text"); + + b.Property("IsDuplicated") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MatchPercentage") + .HasColumnType("numeric"); + + b.Property("NonRegOrgName") + .HasColumnType("text"); + + b.Property("NonRegisteredBusinessName") + .HasColumnType("text"); + + b.Property("OrgName") + .HasColumnType("text"); + + b.Property("OrgNumber") + .HasColumnType("text"); + + b.Property("OrgStatus") + .HasColumnType("text"); + + b.Property("OrganizationSize") + .HasColumnType("text"); + + b.Property("OrganizationType") + .HasColumnType("text"); + + b.Property("RedStop") + .HasColumnType("boolean"); + + b.Property("Sector") + .HasColumnType("text"); + + b.Property("SectorSubSectorIndustryDesc") + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("StartedOperatingDate") + .HasColumnType("date"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SubSector") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UnityApplicantId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantName"); + + b.ToTable("Applicants", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AddressType") + .HasColumnType("integer"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Postal") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("Street") + .HasColumnType("text"); + + b.Property("Street2") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Unit") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.ToTable("ApplicantAddresses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("BceidBusinessGuid") + .HasColumnType("uuid"); + + b.Property("BceidBusinessName") + .HasColumnType("text"); + + b.Property("BceidUserGuid") + .HasColumnType("uuid"); + + b.Property("BceidUserName") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactOrder") + .HasColumnType("integer"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IdentityEmail") + .HasColumnType("text"); + + b.Property("IdentityName") + .HasColumnType("text"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsConfirmed") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSubUser") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("Phone2") + .HasColumnType("text"); + + b.Property("Phone2Extension") + .HasColumnType("text"); + + b.Property("PhoneExtension") + .HasColumnType("text"); + + b.Property("RoleForApplicant") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Title") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationId") + .IsUnique(); + + b.HasIndex("OidcSubUser"); + + b.ToTable("ApplicantAgents", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Acquisition") + .HasColumnType("text"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationStatusId") + .HasColumnType("uuid"); + + b.Property("ApprovedAmount") + .HasColumnType("numeric"); + + b.Property("AssessmentResultDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AssessmentResultStatus") + .HasColumnType("text"); + + b.Property("AssessmentStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Community") + .HasColumnType("text"); + + b.Property("CommunityPopulation") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractExecutionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ContractNumber") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeclineRational") + .HasColumnType("text"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DueDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DueDiligenceStatus") + .HasColumnType("text"); + + b.Property("EconomicRegion") + .HasColumnType("text"); + + b.Property("ElectoralDistrict") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinalDecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Forestry") + .HasColumnType("text"); + + b.Property("ForestryFocus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LikelihoodOfFunding") + .HasColumnType("text"); + + b.Property("Notes") + .HasColumnType("text"); + + b.Property("NotificationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("Payload") + .HasColumnType("jsonb"); + + b.Property("PercentageTotalProjectBudget") + .HasColumnType("double precision"); + + b.Property("Place") + .HasColumnType("text"); + + b.Property("ProjectEndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectFundingTotal") + .HasColumnType("numeric"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ProjectStartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ProjectSummary") + .HasColumnType("text"); + + b.Property("ProposalDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RecommendedAmount") + .HasColumnType("numeric"); + + b.Property("ReferenceNo") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegionalDistrict") + .HasColumnType("text"); + + b.Property("RequestedAmount") + .HasColumnType("numeric"); + + b.Property("RiskRanking") + .HasColumnType("text"); + + b.Property("SigningAuthorityBusinessPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityCellPhone") + .HasColumnType("text"); + + b.Property("SigningAuthorityEmail") + .HasColumnType("text"); + + b.Property("SigningAuthorityFullName") + .HasColumnType("text"); + + b.Property("SigningAuthorityTitle") + .HasColumnType("text"); + + b.Property("SubStatus") + .HasColumnType("text"); + + b.Property("SubmissionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalProjectBudget") + .HasColumnType("numeric"); + + b.Property("TotalScore") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.HasIndex("ApplicationStatusId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Applications", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssigneeId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Duty") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssigneeId"); + + b.ToTable("ApplicationAssignments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsFileId") + .HasColumnType("text"); + + b.Property("ChefsSumbissionId") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationChefsFileAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContactEmail") + .HasColumnType("text"); + + b.Property("ContactFullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactMobilePhone") + .HasColumnType("text"); + + b.Property("ContactTitle") + .HasColumnType("text"); + + b.Property("ContactType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ContactWorkPhone") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationContact", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountCodingId") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasColumnType("text"); + + b.Property("ApplicationFormDescription") + .HasColumnType("text"); + + b.Property("ApplicationFormName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AttemptedConnectionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("Category") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsCriteriaFormGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConnectionHttpStatus") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ElectoralDistrictAddressType") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsDirectApproval") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Payable") + .HasColumnType("boolean"); + + b.Property("PaymentApprovalThreshold") + .HasColumnType("numeric"); + + b.Property("PreventPayment") + .HasColumnType("boolean"); + + b.Property("RenderFormIoToHtml") + .HasColumnType("boolean"); + + b.Property("ScoresheetId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IntakeId"); + + b.ToTable("ApplicationForms", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("ApplicationFormVersionId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChefsSubmissionGuid") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormVersionId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("RenderedHTML") + .HasColumnType("text"); + + b.Property("ReportData") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Submission") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormSubmissions", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationFormId") + .HasColumnType("uuid"); + + b.Property("AvailableChefsFields") + .HasColumnType("text"); + + b.Property("ChefsApplicationFormGuid") + .HasColumnType("text"); + + b.Property("ChefsFormVersionGuid") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FormSchema") + .HasColumnType("jsonb"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Published") + .HasColumnType("boolean"); + + b.Property("ReportColumns") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportKeys") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReportViewName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubmissionHeaderMapping") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationFormId"); + + b.ToTable("ApplicationFormVersion", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LinkedApplicationId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.ToTable("ApplicationLinks", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StatusCode") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("StatusCode") + .IsUnique(); + + b.ToTable("ApplicationStatuses", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("TagId"); + + b.ToTable("ApplicationTags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("S3ObjectKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Time") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.ToTable("AssessmentAttachments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ApprovalRecommended") + .HasColumnType("boolean"); + + b.Property("AssessorId") + .HasColumnType("uuid"); + + b.Property("CleanGrowth") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EconomicImpact") + .HasColumnType("integer"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FinancialAnalysis") + .HasColumnType("integer"); + + b.Property("InclusiveGrowth") + .HasColumnType("integer"); + + b.Property("IsComplete") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("AssessorId"); + + b.ToTable("Assessments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("CommenterId"); + + b.ToTable("ApplicationComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("text"); + + b.Property("CommenterId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AssessmentId"); + + b.HasIndex("CommenterId"); + + b.ToTable("AssessmentComments", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.GlobalTag.Tag", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Tags", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Identity.Person", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Badge") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("OidcDisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("OidcSub") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("OidcSub"); + + b.ToTable("Persons", (string)null); + }); + + modelBuilder.Entity("Unity.GrantManager.Intakes.Intake", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Budget") + .HasColumnType("double precision"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EndDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IntakeName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("StartDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Intakes", (string)null); + }); + + modelBuilder.Entity("Unity.Notifications.Emails.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicantId") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AssessmentId") + .HasColumnType("uuid"); + + b.Property("BCC") + .IsRequired() + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyType") + .IsRequired() + .HasColumnType("text"); + + b.Property("CC") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesMsgId") + .HasColumnType("uuid"); + + b.Property("ChesResponse") + .IsRequired() + .HasColumnType("text"); + + b.Property("ChesStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FromAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Priority") + .IsRequired() + .HasColumnType("text"); + + b.Property("RetryAttempts") + .HasColumnType("integer"); + + b.Property("SendOnDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SentDateTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("text"); + + b.Property("TemplateName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ToAddress") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EmailLogs", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.EmailTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BodyHTML") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyText") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SendFrom") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("EmailTemplates", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Subscriber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Subscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("SubscriptionGroups", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriberId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("SubscriberId"); + + b.ToTable("SubscriptionGroupSubscribers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TemplateVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MapTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Token") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("TemplateVariables", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.Trigger", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InternalName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Triggers", "Notifications"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("SubscriptionGroupId") + .HasColumnType("uuid"); + + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SubscriptionGroupId"); + + b.HasIndex("TemplateId"); + + b.HasIndex("TriggerId"); + + b.ToTable("TriggerSubscriptions", "Notifications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.AccountCodings.AccountCoding", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MinistryClient") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProjectNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("Responsibility") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServiceLine") + .IsRequired() + .HasColumnType("text"); + + b.Property("Stob") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AccountCodings", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentConfigurations.PaymentConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DefaultAccountCodingId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentIdPrefix") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfigurations", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DecisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("DecisionUserId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.ToTable("ExpenseApprovals", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("BatchName") + .IsRequired() + .HasColumnType("text"); + + b.Property("BatchNumber") + .HasColumnType("numeric"); + + b.Property("CasHttpStatusCode") + .HasColumnType("integer"); + + b.Property("CasResponse") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContractNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("InvoiceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("InvoiceStatus") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsRecon") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PayeeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentDate") + .HasColumnType("text"); + + b.Property("PaymentNumber") + .HasColumnType("text"); + + b.Property("PaymentStatus") + .HasColumnType("text"); + + b.Property("ReferenceNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequesterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SiteId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("SubmissionConfirmationCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("SupplierName") + .HasColumnType("text"); + + b.Property("SupplierNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ReferenceNumber") + .IsUnique(); + + b.HasIndex("SiteId"); + + b.ToTable("PaymentRequests", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("PaymentRequestId") + .HasColumnType("uuid"); + + b.Property("TagId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PaymentRequestId"); + + b.HasIndex("TagId"); + + b.ToTable("PaymentTags", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentThresholds.PaymentThreshold", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Threshold") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("PaymentThresholds", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddressLine1") + .HasColumnType("text"); + + b.Property("AddressLine2") + .HasColumnType("text"); + + b.Property("AddressLine3") + .HasColumnType("text"); + + b.Property("BankAccount") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EFTAdvicePref") + .HasColumnType("text"); + + b.Property("EmailAddress") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCas") + .HasColumnType("timestamp without time zone"); + + b.Property("MarkDeletedInUse") + .HasColumnType("boolean"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("PaymentGroup") + .HasColumnType("integer"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SiteProtected") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("SupplierId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Sites", "Payments"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessNumber") + .HasColumnType("text"); + + b.Property("City") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasColumnType("uuid"); + + b.Property("CorrelationProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastUpdatedInCAS") + .HasColumnType("timestamp without time zone"); + + b.Property("MailingAddress") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("text"); + + b.Property("PostalCode") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("Province") + .HasColumnType("text"); + + b.Property("SIN") + .HasColumnType("text"); + + b.Property("StandardIndustryClassification") + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("text"); + + b.Property("Subcategory") + .HasColumnType("text"); + + b.Property("SupplierProtected") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("Suppliers", "Payments"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Instances") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Answer", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Question", "Question") + .WithMany("Answers") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", null) + .WithMany("Answers") + .HasForeignKey("ScoresheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.ScoresheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Scoresheets.Scoresheet", "Scoresheet") + .WithMany("Sections") + .HasForeignKey("ScoresheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scoresheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.CustomFieldValue", b => + { + b.HasOne("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", null) + .WithMany("Values") + .HasForeignKey("WorksheetInstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetLinks.WorksheetLink", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Links") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.CustomField", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.WorksheetSection", "Section") + .WithMany("Fields") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.HasOne("Unity.Flex.Domain.Worksheets.Worksheet", "Worksheet") + .WithMany("Sections") + .HasForeignKey("WorksheetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Worksheet"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAddress", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany("ApplicantAddresses") + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Applicant"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicantAgent", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithOne("ApplicantAgent") + .HasForeignKey("Unity.GrantManager.Applications.ApplicantAgent", "ApplicationId"); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("OidcSubUser") + .HasPrincipalKey("OidcSub"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", "Applicant") + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", "ApplicationForm") + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationStatus", "ApplicationStatus") + .WithMany("Applications") + .HasForeignKey("ApplicationStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Applicant"); + + b.Navigation("ApplicationForm"); + + b.Navigation("ApplicationStatus"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAssignment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationAssignments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", "Assignee") + .WithMany() + .HasForeignKey("AssigneeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Assignee"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationChefsFileAttachment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationContact", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationForm", b => + { + b.HasOne("Unity.GrantManager.Intakes.Intake", null) + .WithMany() + .HasForeignKey("IntakeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormSubmission", b => + { + b.HasOne("Unity.GrantManager.Applications.Applicant", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationFormVersion", b => + { + b.HasOne("Unity.GrantManager.Applications.ApplicationForm", null) + .WithMany() + .HasForeignKey("ApplicationFormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationLink", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationTags", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("ApplicationTags") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.AssessmentAttachment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Assessments.Assessment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", "Application") + .WithMany("Assessments") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("AssessorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.ApplicationComment", b => + { + b.HasOne("Unity.GrantManager.Applications.Application", null) + .WithMany() + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.GrantManager.Comments.AssessmentComment", b => + { + b.HasOne("Unity.GrantManager.Assessments.Assessment", null) + .WithMany() + .HasForeignKey("AssessmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.Identity.Person", null) + .WithMany() + .HasForeignKey("CommenterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.SubscriptionGroupSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("GroupId"); + + b.HasOne("Unity.Notifications.Templates.Subscriber", "Subscriber") + .WithMany() + .HasForeignKey("SubscriberId"); + + b.Navigation("Subscriber"); + + b.Navigation("SubscriptionGroup"); + }); + + modelBuilder.Entity("Unity.Notifications.Templates.TriggerSubscription", b => + { + b.HasOne("Unity.Notifications.Templates.SubscriptionGroup", "SubscriptionGroup") + .WithMany() + .HasForeignKey("SubscriptionGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.EmailTemplate", "EmailTemplate") + .WithMany() + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.Notifications.Templates.Trigger", "Trigger") + .WithMany() + .HasForeignKey("TriggerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EmailTemplate"); + + b.Navigation("SubscriptionGroup"); + + b.Navigation("Trigger"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", "PaymentRequest") + .WithMany("ExpenseApprovals") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PaymentRequest"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Site", "Site") + .WithMany() + .HasForeignKey("SiteId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Site"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentTags.PaymentTag", b => + { + b.HasOne("Unity.Payments.Domain.PaymentRequests.PaymentRequest", null) + .WithMany("PaymentTags") + .HasForeignKey("PaymentRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Unity.GrantManager.GlobalTag.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => + { + b.HasOne("Unity.Payments.Domain.Suppliers.Supplier", "Supplier") + .WithMany("Sites") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.ScoresheetInstances.ScoresheetInstance", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Question", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.Scoresheet", b => + { + b.Navigation("Instances"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Scoresheets.ScoresheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.WorksheetInstances.WorksheetInstance", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.Worksheet", b => + { + b.Navigation("Links"); + + b.Navigation("Sections"); + }); + + modelBuilder.Entity("Unity.Flex.Domain.Worksheets.WorksheetSection", b => + { + b.Navigation("Fields"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Applicant", b => + { + b.Navigation("ApplicantAddresses"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.Application", b => + { + b.Navigation("ApplicantAgent"); + + b.Navigation("ApplicationAssignments"); + + b.Navigation("ApplicationTags"); + + b.Navigation("Assessments"); + }); + + modelBuilder.Entity("Unity.GrantManager.Applications.ApplicationStatus", b => + { + b.Navigation("Applications"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.PaymentRequest", b => + { + b.Navigation("ExpenseApprovals"); + + b.Navigation("PaymentTags"); + }); + + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Supplier", b => + { + b.Navigation("Sites"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.cs new file mode 100644 index 000000000..82ca5adc3 --- /dev/null +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/20250716225458_PaymentRequestAccountCoding.cs @@ -0,0 +1,81 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Unity.GrantManager.Migrations.TenantMigrations +{ + /// + public partial class PaymentRequestAccountCoding : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AccountCodingId", + table: "PaymentRequests", + type: "uuid", + nullable: false, + schema: "Payments", + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + + // Need to run some scripts to move existing Payment configurations to AccountCodings then relate the fk to the above column + + // migrationBuilder.AddForeignKey( + // name: "FK_PaymentRequest_AccountCodings_Id", + // schema: "Payments", + // table: "PaymentRequests", + // column: "AccountCodingId", + // principalSchema: "Payments", + // principalTable: "AccountCodings", + // principalColumn: "Id"); + + // migrationBuilder.DropColumn( + // name: "PaymentThreshold", + // table: "PaymentConfigurations", + // schema: "Payments"); + + // migrationBuilder.DropColumn( + // name: "MinistryClient", + // table: "PaymentConfigurations", + // schema: "Payments"); + + // migrationBuilder.DropColumn( + // name: "Responsibility", + // table: "PaymentConfigurations", + // schema: "Payments"); + + // migrationBuilder.DropColumn( + // name: "ServiceLine", + // table: "PaymentConfigurations", + // schema: "Payments"); + + // migrationBuilder.DropColumn( + // name: "Stob", + // table: "PaymentConfigurations", + // schema: "Payments"); + + // migrationBuilder.DropColumn( + // name: "ProjectNumber", + // table: "PaymentConfigurations", + // schema: "Payments"); + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + // migrationBuilder.DropForeignKey( + // schema: "Payments", + // name: "FK_ApplicationForms_AccountCodings_Id", + // table: "PaymentRequests"); + + migrationBuilder.DropColumn( + name: "AccountCodingId", + table: "PaymentRequests", + schema: "Payments"); + } + } +} diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs index 62e65ada2..fe3f971b2 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.EntityFrameworkCore/Migrations/TenantMigrations/GrantTenantDbContextModelSnapshot.cs @@ -1,4 +1,4 @@ -// +// using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -1553,6 +1553,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Id") .HasColumnType("uuid"); + b.Property("AccountCodingId") + .HasColumnType("uuid"); + b.Property("ApiKey") .HasColumnType("text"); @@ -1636,6 +1639,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Payable") .HasColumnType("boolean"); + b.Property("PaymentApprovalThreshold") + .HasColumnType("numeric"); + + b.Property("PreventPayment") + .HasColumnType("boolean"); + b.Property("RenderFormIoToHtml") .HasColumnType("boolean"); @@ -2929,7 +2938,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("TriggerSubscriptions", "Notifications"); }); - modelBuilder.Entity("Unity.Payments.Domain.PaymentConfigurations.PaymentConfiguration", b => + modelBuilder.Entity("Unity.Payments.Domain.AccountCodings.AccountCoding", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -2950,25 +2959,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("CreatorId"); - b.Property("DeleterId") - .HasColumnType("uuid") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("DeletionTime"); - b.Property("ExtraProperties") .IsRequired() .HasColumnType("text") .HasColumnName("ExtraProperties"); - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - b.Property("LastModificationTime") .HasColumnType("timestamp without time zone") .HasColumnName("LastModificationTime"); @@ -2978,52 +2973,36 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnName("LastModifierId"); b.Property("MinistryClient") - .HasColumnType("text"); - - b.Property("PaymentIdPrefix") .IsRequired() .HasColumnType("text"); - b.Property("PaymentThreshold") - .HasColumnType("numeric"); - b.Property("ProjectNumber") + .IsRequired() .HasColumnType("text"); b.Property("Responsibility") + .IsRequired() .HasColumnType("text"); b.Property("ServiceLine") + .IsRequired() .HasColumnType("text"); b.Property("Stob") + .IsRequired() .HasColumnType("text"); - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - b.HasKey("Id"); - b.ToTable("PaymentConfigurations", "Payments"); + b.ToTable("AccountCodings", "Payments"); }); - modelBuilder.Entity("Unity.Payments.Domain.PaymentThresholds.PaymentThreshold", b => + modelBuilder.Entity("Unity.Payments.Domain.PaymentConfigurations.PaymentConfiguration", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property("UserId") - .HasColumnType("uuid") - .HasColumnName("UserId"); - - b.Property("Threshold") - .HasColumnType("numeric"); - - b.Property("Description") - .HasColumnType("text"); - b.Property("ConcurrencyStamp") .IsConcurrencyToken() .IsRequired() @@ -3039,47 +3018,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("CreatorId"); - b.Property("DeleterId") - .HasColumnType("uuid") - .HasColumnName("DeleterId"); - - b.Property("DeletionTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("DeletionTime"); - - b.Property("ExtraProperties") - .IsRequired() - .HasColumnType("text") - .HasColumnName("ExtraProperties"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("boolean") - .HasDefaultValue(false) - .HasColumnName("IsDeleted"); - - b.Property("LastModificationTime") - .HasColumnType("timestamp without time zone") - .HasColumnName("LastModificationTime"); - - b.Property("LastModifierId") - .HasColumnType("uuid") - .HasColumnName("LastModifierId"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.ToTable("PaymentThresholds", "Payments"); - - }); - - modelBuilder.Entity("Unity.Payments.Domain.PaymentThresholds.PaymentThreshold", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() + b.Property("DefaultAccountCodingId") .HasColumnType("uuid"); b.Property("UserId") @@ -3134,15 +3073,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("LastModifierId"); + b.Property("PaymentIdPrefix") + .IsRequired() + .HasColumnType("text"); + b.Property("TenantId") .HasColumnType("uuid") .HasColumnName("TenantId"); b.HasKey("Id"); - b.ToTable("PaymentThresholds", "Payments"); - - }); + b.ToTable("PaymentConfigurations", "Payments"); + }); modelBuilder.Entity("Unity.Payments.Domain.PaymentRequests.ExpenseApproval", b => { @@ -3403,6 +3345,72 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("PaymentTags", "Payments"); }); + modelBuilder.Entity("Unity.Payments.Domain.PaymentThresholds.PaymentThreshold", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Threshold") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("PaymentThresholds", "Payments"); + }); + modelBuilder.Entity("Unity.Payments.Domain.Suppliers.Site", b => { b.Property("Id") diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Index.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Index.js index b41af76cb..df0268574 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Index.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Index.js @@ -29,7 +29,7 @@ } }, { - text: l('ApplicationForms:Mapping'), + text: "Configuration", action: function (data) { location.href = '/ApplicationForms/Mapping?ApplicationId=' + data.record.id } From 08de2bfee8d67d8f9499c490284d9ab52052c73b Mon Sep 17 00:00:00 2001 From: jpasta Date: Fri, 18 Jul 2025 13:40:29 -0700 Subject: [PATCH 14/30] feature/AB#28691-AccountCodingMulti --- .../Domain/AccountCodings/AccountCoding.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs index a3b264254..a741de531 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs @@ -2,6 +2,7 @@ using Volo.Abp; using System; using Volo.Abp.Domain.Entities.Auditing; +using System.Linq; namespace Unity.Payments.Domain.AccountCodings { @@ -35,16 +36,23 @@ public static AccountCoding Create( { ValidateField(ministryClient, 3, nameof(MinistryClient), false); ValidateField(responsibility, 5, nameof(Responsibility), false); - ValidateField(serviceLine, 5, nameof(serviceLine)); - ValidateField(stob, 4, nameof(stob)); - ValidateField(projectNumber, 7, nameof(projectNumber)); + ValidateField(serviceLine, 5, nameof(serviceLine), true); + ValidateField(stob, 4, nameof(stob), true); + ValidateField(projectNumber, 7, nameof(projectNumber), true); return new AccountCoding(ministryClient, responsibility, serviceLine, stob, projectNumber); } - private static void ValidateField(string field, uint length, string fieldName, bool validAlphanumeric = true) + private static void ValidateField(string field, uint length, string fieldName, bool validateAlphanumeric) { + bool validAlphanumeric = true; + + if (validateAlphanumeric) + { + validAlphanumeric = field.All(char.IsLetterOrDigit); + } + if (field.Length != length || !validAlphanumeric) { throw new BusinessException(ErrorConsts.InvalidAccountCodingField) From 6a2372533ed36ea348dd0119fe592d27bc352382 Mon Sep 17 00:00:00 2001 From: jpasta Date: Fri, 18 Jul 2025 13:42:06 -0700 Subject: [PATCH 15/30] feature/AB#28691-AccountCodingMulti-FixUnit --- .../PaymentConfigurations/AccountCoding_Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs index dbc8961ce..4ea2482cb 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/test/Unity.Payments.Application.Tests/PaymentConfigurations/AccountCoding_Tests.cs @@ -14,8 +14,8 @@ public void Create_ValidParameters_ShouldNotThrow() // Arrange // Act var accountCoding = AccountCoding.Create( - ministryClient: "0TW", - responsibility: "51OCG", + ministryClient: "126", + responsibility: "51545", serviceLine: "00000", stob: "5717", projectNumber: "5100000" From fc8037934f5c81faf609774d1d0f59f2e3642843 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Fri, 18 Jul 2025 13:54:26 -0700 Subject: [PATCH 16/30] Fix error when merging applicants --- .../Views/Shared/Components/ApplicantInfo/Default.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js index cdecde9a0..03d087fd5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js @@ -278,7 +278,7 @@ $(function () { let selectedPrincipal = $('input[name="merge_ApplicantId"]:checked').val(); let principalApplicantId = selectedPrincipal === 'existing' ? existing.ApplicantId : newData.ApplicantId; let nonPrincipalApplicantId = selectedPrincipal === 'existing' ? newData.ApplicantId : existing.ApplicantId; - let applicationId = $('#ApplicantInfoViewApplicationId').val(); + let applicationId = $('#ApplicantInfo_ApplicationId').val(); // Merge and update applicant info let mergedApplicantInfo = {}; From f4603edb3293605c0a26b82a972cef4cc9b3100e Mon Sep 17 00:00:00 2001 From: jpasta Date: Fri, 18 Jul 2025 15:29:00 -0700 Subject: [PATCH 17/30] feature/AB#28691-AccountCodingMulti-FixSonarFinishEAApproval --- .../Domain/PaymentRequests/ExpenseApproval.cs | 2 +- .../PaymentRequestAppService.cs | 4 +- .../UpdatePaymentRequestStatus.cshtml.cs | 89 +++++++++++++------ .../PaymentThresholds/UpdateModal.cshtml.cs | 2 - .../Pages/ApplicationForms/Mapping.cshtml | 1 - .../PaymentConfiguration/Default.cshtml | 1 - 6 files changed, 64 insertions(+), 35 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/ExpenseApproval.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/ExpenseApproval.cs index b8c2b423c..43b6f42f6 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/ExpenseApproval.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/PaymentRequests/ExpenseApproval.cs @@ -49,7 +49,7 @@ public virtual PaymentRequest PaymentRequest } private PaymentRequest? _paymentRequest; - protected ExpenseApproval() + public ExpenseApproval() { /* This constructor is for ORMs to be used while getting the entity from the database. */ } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs index 27ae58a8a..e16134530 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs @@ -15,9 +15,9 @@ using Unity.Payments.Permissions; using Volo.Abp; using Volo.Abp.Application.Dtos; -using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.Features; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Users; namespace Unity.Payments.PaymentRequests @@ -400,7 +400,7 @@ public async Task> GetListByApplicationIdAsync(Guid appl var payments = await paymentsQueryable.Include(pr => pr.Site).ToListAsync(); var filteredPayments = payments.Where(e => e.CorrelationId == applicationId).ToList(); - return new List(ObjectMapper.Map, List>(filteredPayments)); + return ObjectMapper.Map, List>(filteredPayments); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs index 313b07ed5..ea42b303a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Unity.GrantManager.ApplicationForms; using Unity.Payment.Shared; +using Unity.Payments.Domain.PaymentRequests; using Unity.Payments.Domain.PaymentThresholds; using Unity.Payments.Domain.Shared; using Unity.Payments.Enums; @@ -26,7 +27,8 @@ public class PaymentGrouping } public class UpdatePaymentRequestStatus( - IPaymentRequestAppService paymentRequestService, + IPaymentRequestRepository paymentRepository, + IPaymentRequestAppService paymentRequestAppService, IPaymentConfigurationAppService paymentConfigurationAppService, IApplicationFormAppService applicationFormAppService, IPaymentThresholdRepository paymentThresholdRepository, @@ -45,7 +47,7 @@ public class UpdatePaymentRequestStatus( public async Task OnGetAsync(string paymentIds, bool isApprove) { await InitializeStateAsync(paymentIds, isApprove); - var payments = await paymentRequestService.GetListByPaymentIdsAsync(SelectedPaymentIds); + var payments = await paymentRequestAppService.GetListByPaymentIdsAsync(SelectedPaymentIds); var paymentApprovals = await BuildPaymentApprovalsAsync(payments); PaymentGroupings = paymentApprovals @@ -58,7 +60,7 @@ public async Task OnGetAsync(string paymentIds, bool isApprove) }) .ToList(); - DisableSubmit = !paymentApprovals.Any() || !ModelState.IsValid; + DisableSubmit = paymentApprovals.Count == 0 || !ModelState.IsValid; } private async Task InitializeStateAsync(string paymentIds, bool isApprove) @@ -85,20 +87,23 @@ private async Task> BuildPaymentApprovalsAsync(List< var formThreshold = await applicationFormAppService.GetFormPaymentApprovalThresholdByApplicationIdAsync(payment.CorrelationId); PaymentThreshold = formThreshold.HasValue && formThreshold.Value < PaymentThreshold ? formThreshold.Value : PaymentThreshold; - var request = CreateApprovalModel(payment); - ValidateApprovalModel(request); + var approvalModel = await CreateApprovalModel(payment); + ValidateApprovalModel(approvalModel); - if (await VerifyPermissionsAsync(payment.Status, request)) + if (await VerifyPermissionsAsync(payment.Status, approvalModel)) { - paymentApprovals.Add(request); + paymentApprovals.Add(approvalModel); } } return paymentApprovals; } - private PaymentsApprovalModel CreateApprovalModel(PaymentDetailsDto payment) + private async Task CreateApprovalModel(PaymentDetailsDto payment) { + bool isL3ApprovalRequired = payment.Amount > PaymentThreshold; + await UpdateExpenseApprovalsAsync(payment, isL3ApprovalRequired); + return new PaymentsApprovalModel { Id = payment.Id, @@ -109,18 +114,42 @@ private PaymentsApprovalModel CreateApprovalModel(PaymentDetailsDto payment) Description = payment.Description, InvoiceNumber = payment.InvoiceNumber, Status = payment.Status, - IsL3ApprovalRequired = payment.Amount > PaymentThreshold, + IsL3ApprovalRequired = isL3ApprovalRequired, ToStatus = payment.Status, IsApproval = IsApproval, PreviousL1Approver = payment.ExpenseApprovals.FirstOrDefault(x => x.Type == ExpenseApprovalType.Level1)?.DecisionUserId }; } + private async Task UpdateExpenseApprovalsAsync(PaymentDetailsDto payment, bool isL3ApprovalRequired) + { + if (payment.Status == PaymentRequestStatus.L2Pending) + { + + var l3Approval = payment.ExpenseApprovals.FirstOrDefault(x => x.Type == ExpenseApprovalType.Level3); + PaymentRequest paymentEntity = await paymentRepository.GetAsync(payment.Id); + if (isL3ApprovalRequired && l3Approval == null) + { + paymentEntity.ExpenseApprovals.Add(new ExpenseApproval(Guid.NewGuid(), ExpenseApprovalType.Level3)); + + } + else if (!isL3ApprovalRequired && l3Approval != null) + { + var l3ApprovalEntity = paymentEntity.ExpenseApprovals.FirstOrDefault(x => x.Type == ExpenseApprovalType.Level3); + if (l3ApprovalEntity != null) + { + paymentEntity.ExpenseApprovals.Remove(l3ApprovalEntity); + } + } + + await paymentRepository.UpdateAsync(paymentEntity); + } + } + private void ValidateApprovalModel(PaymentsApprovalModel request) { - var validationContext = new ValidationContext(request, LazyServiceProvider, null); var validationResults = new List(); - request.IsValid = Validator.TryValidateObject(request, validationContext, validationResults, true); + request.IsValid = Validator.TryValidateObject(request, new ValidationContext(request, LazyServiceProvider, null), validationResults, true); foreach (var validationResult in validationResults) { @@ -133,15 +162,20 @@ private void ValidateApprovalModel(PaymentsApprovalModel request) private async Task VerifyPermissionsAsync(PaymentRequestStatus status, PaymentsApprovalModel request) { - request.ToStatus = status switch + if (status == PaymentRequestStatus.L2Pending && IsApproval) { - PaymentRequestStatus.L1Pending => IsApproval ? PaymentRequestStatus.L2Pending : PaymentRequestStatus.L1Declined, - PaymentRequestStatus.L2Pending => IsApproval - ? (request.IsL3ApprovalRequired ? PaymentRequestStatus.L3Pending : PaymentRequestStatus.Submitted) - : PaymentRequestStatus.L2Declined, - PaymentRequestStatus.L3Pending => IsApproval ? PaymentRequestStatus.Submitted : PaymentRequestStatus.L3Declined, - _ => request.ToStatus - }; + request.ToStatus = request.IsL3ApprovalRequired ? PaymentRequestStatus.L3Pending : PaymentRequestStatus.Submitted; + } + else + { + request.ToStatus = status switch + { + PaymentRequestStatus.L1Pending => IsApproval ? PaymentRequestStatus.L2Pending : PaymentRequestStatus.L1Declined, + PaymentRequestStatus.L2Pending => PaymentRequestStatus.L2Declined, + PaymentRequestStatus.L3Pending => IsApproval ? PaymentRequestStatus.Submitted : PaymentRequestStatus.L3Declined, + _ => request.ToStatus + }; + } var permission = status switch { @@ -156,17 +190,17 @@ private async Task VerifyPermissionsAsync(PaymentRequestStatus status, Pay public async Task OnPostAsync() { - if (PaymentGroupings == null || !PaymentGroupings.Any() || !ModelState.IsValid) return NoContent(); + if (PaymentGroupings == null || PaymentGroupings.Count == 0 || !ModelState.IsValid) return NoContent(); var payments = PaymentGroupings.SelectMany(group => group.Items) - .Select(payment => new UpdatePaymentStatusRequestDto - { - PaymentRequestId = payment.Id, - IsApprove = IsApproval - }) - .ToList(); + .Select(payment => new UpdatePaymentStatusRequestDto + { + PaymentRequestId = payment.Id, + IsApprove = IsApproval + }) + .ToList(); - await paymentRequestService.UpdateStatusAsync(payments); + await paymentRequestAppService.UpdateStatusAsync(payments); return NoContent(); } @@ -208,7 +242,6 @@ public static string GetStatusText(PaymentRequestStatus status) _ => "L1 Pending", }; } - public static string GetStatusTextColor(PaymentRequestStatus status) => status switch { PaymentRequestStatus.L1Declined or PaymentRequestStatus.L2Declined or PaymentRequestStatus.L3Declined => "#CE3E39", diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs index 9112fd090..57e23d9d0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentThresholds/UpdateModal.cshtml.cs @@ -4,8 +4,6 @@ using Unity.GrantManager.Payments; using Unity.Payments.PaymentThresholds; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; -using Volo.Abp.Identity; -using Volo.Abp.Identity.Integration; namespace Unity.GrantManager.Web.Pages.PaymentThresholds; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml index 28505b5cc..767c67454 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/ApplicationForms/Mapping.cshtml @@ -5,7 +5,6 @@ @using Unity.GrantManager.Permissions; @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal; @using Volo.Abp.Authorization.Permissions; -@using Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration; @using Unity.GrantManager.Web.Views.Shared.Components.ApplicationFormConfigWidget; @model MappingModel diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml index 126e27226..9137426f5 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -1,4 +1,3 @@ -@using Unity.GrantManager.Web.Pages.GrantApplications; @using Unity.GrantManager.Web.Views.Shared.Components.PaymentConfiguration; @model PaymentConfigurationViewModel From d8c08a88c44eb1837977f3ddae8b51ad839d569e Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 21 Jul 2025 08:01:57 -0700 Subject: [PATCH 18/30] AB#29554 - Payment Info Permissions - SonarQube Cleanup --- .../Permissions/PaymentsPermissionDefinitionProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs index b1805a955..4794cd169 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Permissions/PaymentsPermissionDefinitionProvider.cs @@ -1,7 +1,6 @@ using Unity.Modules.Shared; using Unity.Payments.Localization; using Volo.Abp.Authorization.Permissions; -using Volo.Abp.Features; using Volo.Abp.Localization; namespace Unity.Payments.Permissions; @@ -47,7 +46,7 @@ public static void Add_PaymentInfo_Permissions(this PermissionGroupDefinition gr #endregion } - + public static PermissionDefinition AddPaymentChild(this PermissionDefinition parent, string name) { From 409de7c9660ba97178fb8eb8d046a2e5c056ace7 Mon Sep 17 00:00:00 2001 From: jpasta Date: Mon, 21 Jul 2025 09:27:51 -0700 Subject: [PATCH 19/30] feature/AB#28691-AccountCodingMulti-FixSonarFinishEAApproval --- .../PaymentRequestAppService.cs | 28 +++---------------- .../CreatePaymentRequests.cshtml | 1 - .../CreatePaymentRequests.cshtml.cs | 5 +--- 3 files changed, 5 insertions(+), 29 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs index e16134530..97f9139a0 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs @@ -174,9 +174,7 @@ public Task GetPaymentRequestCountBySiteIdAsync(Guid siteId) public virtual async Task> UpdateStatusAsync(List paymentRequests) { - List updatedPayments = []; - - var paymentThreshold = await GetPaymentThresholdAsync(); + List updatedPayments = []; // Check approval batches var approvalRequests = paymentRequests.Where(r => r.IsApprove).Select(x => x.PaymentRequestId).ToList(); @@ -197,7 +195,7 @@ public virtual async Task> UpdateStatusAsync(List> UpdateStatusAsync(List DetermineTriggerActionAsync( UpdatePaymentStatusRequestDto dto, - PaymentRequest payment, - decimal paymentThreshold) + PaymentRequest payment) { if (await CanPerformLevel1ActionAsync(payment.Status)) { @@ -228,9 +225,7 @@ private async Task DetermineTriggerActionAsync( { if (dto.IsApprove) { - return payment.Amount > paymentThreshold - ? PaymentApprovalAction.L2Approve - : PaymentApprovalAction.Submit; + return PaymentApprovalAction.Submit; } return PaymentApprovalAction.L2Decline; } @@ -439,21 +434,6 @@ protected virtual string GetCurrentRequesterName() return null; } - protected virtual async Task GetPaymentThresholdAsync() - { - var paymentConfigs = await paymentConfigurationRepository.GetListAsync(); - - if (paymentConfigs.Count > 0) - { - var paymentConfig = paymentConfigs[0]; - - // TODO: FIX To current user threshold throw exception if the user does not have a threshold? - return PaymentSharedConsts.DefaultThresholdAmount; - } - - return PaymentSharedConsts.DefaultThresholdAmount; - } - private async Task GetNextSequenceNumberAsync(int currentYear) { // Retrieve all payment requests diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml index acfe9cca8..fc0b0fa83 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml @@ -31,7 +31,6 @@ - @for (var i = 0; i < Model.ApplicationPaymentRequestForm?.Count; i++) {
diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs index 84e9dba91..b0a42832a 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs @@ -44,8 +44,7 @@ public CreatePaymentRequestsModel( [BindProperty] public List ApplicationPaymentRequestForm { get; set; } = []; - [BindProperty] - public decimal PaymentThreshold { get; set; } + [BindProperty] public bool DisableSubmit { get; set; } [BindProperty] @@ -68,11 +67,9 @@ public decimal ApplicationPaymentRequestFormTotalAmount public async Task OnGetAsync(string applicationIds) { - // TODO: FIX PAY THRESHOLD var paymentConfiguration = await _paymentConfigurationAppService.GetAsync(); if (paymentConfiguration != null) { - PaymentThreshold = PaymentSharedConsts.DefaultThresholdAmount; HasPaymentConfiguration = true; } else From 51cdb5330758ecee8498fd5c504d242d65ddbc35 Mon Sep 17 00:00:00 2001 From: Cyrus Parsons Date: Mon, 21 Jul 2025 09:52:50 -0700 Subject: [PATCH 20/30] bugfix/AB#29376 Added scrolling to submissions summary page --- .../TenantManagement/Reconciliation/Index.css | 28 +++++++++++++++++++ .../Reconciliation/index.cshtml | 25 ++--------------- 2 files changed, 30 insertions(+), 23 deletions(-) create mode 100644 applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/Index.css diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/Index.css b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/Index.css new file mode 100644 index 000000000..63ac396c9 --- /dev/null +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/Index.css @@ -0,0 +1,28 @@ +.dataTables_wrapper .dataTables_scrollHead { + background-color: transparent; +} + +.submissionSummaryFilterContainer { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-rows: auto; +} + +label { + font-size: 0.8rem; + margin: 0px !important; +} + +.form-control { + font-size: 0.8rem; + border: 2px solid rgb(46, 93, 215); +} + +.abp-application-layout { + overflow-y: scroll; +} + +.unity-app-container { + height: auto; + min-height: calc(100vh - 6.75rem); +} diff --git a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/index.cshtml b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/index.cshtml index ef2281cc2..ad75fd76d 100644 --- a/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.TenantManagement/src/Unity.TenantManagement.Web/Pages/TenantManagement/Reconciliation/index.cshtml @@ -19,28 +19,7 @@ - + } @section scripts { @@ -89,7 +68,7 @@
Missing Submissions Browser @await Component.InvokeAsync("ActionBar") -
+
\ No newline at end of file From cabdc95a5cfd6c0d4d5ef51a2071c4b5249e649a Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:33:33 -0700 Subject: [PATCH 21/30] AB#29471 - Update EmailGroupUsersAppService.cs --- .../EmailGroupUsers/EmailGroupUsersAppService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs index fee843cf0..9336bf539 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs @@ -78,7 +78,7 @@ public async Task DeleteUsersByGroupIdAsync(Guid id) } } - public async Task> GetEmailGroupUsersByGroupIdsync(Guid id) + public async Task> GetEmailGroupUsersByGroupIdAsync(Guid id) { var users = await _emailGroupUsersRepository.GetListAsync(u => u.GroupId == id); From 429d95c48ecea173b0733f32193036321632e030 Mon Sep 17 00:00:00 2001 From: Patrick <135162612+plavoie-BC@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:16:04 -0700 Subject: [PATCH 22/30] AB#29471 - Email Group SonarQube Fixes --- .../EmailGroupUsersAppService.cs | 31 +++++++++---------- .../EmailGroups/EmailGroupsAppService.cs | 20 ++++++------ .../NotificationsDataSeedContributor.cs | 6 ++-- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs index 9336bf539..55ed0fab8 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroupUsers/EmailGroupUsersAppService.cs @@ -1,12 +1,9 @@ using Microsoft.AspNetCore.Authorization; using System; using System.Collections.Generic; -using System.Text.RegularExpressions; using System.Threading.Tasks; using Volo.Abp.Application.Services; using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Repositories; -using Volo.Abp.ObjectMapping; namespace Unity.Notifications.EmailGroups @@ -24,12 +21,12 @@ public EmailGroupUsersAppService(IEmailGroupUsersRepository emailGroupUsersRepos _emailGroupUsersRepository = emailGroupUsersRepository; } public async Task InsertAsync(EmailGroupUsersDto dto) - { - var newUser = await _emailGroupUsersRepository.InsertAsync(new EmailGroupUser - { + { + var newUser = await _emailGroupUsersRepository.InsertAsync(new EmailGroupUser + { GroupId = dto.GroupId, - UserId = dto.UserId, - + UserId = dto.UserId, + }); return new EmailGroupUsersDto { @@ -37,10 +34,10 @@ public async Task InsertAsync(EmailGroupUsersDto dto) GroupId = newUser.GroupId, UserId = newUser.UserId, }; - } - - - + } + + + public async Task DeleteUserAsync(Guid id) { try @@ -48,9 +45,9 @@ public async Task DeleteUserAsync(Guid id) await _emailGroupUsersRepository.DeleteAsync(id); return true; } - catch(Exception ex) + catch (Exception ex) { - throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + throw new InvalidOperationException($"Error deleting email group with ID {id}: {ex.Message}"); } } public async Task DeleteUsersByUserIdAsync(Guid id) @@ -62,7 +59,7 @@ public async Task DeleteUsersByUserIdAsync(Guid id) } catch (Exception ex) { - throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + throw new InvalidOperationException($"Error deleting email group with ID {id}: {ex.Message}"); } } public async Task DeleteUsersByGroupIdAsync(Guid id) @@ -74,7 +71,7 @@ public async Task DeleteUsersByGroupIdAsync(Guid id) } catch (Exception ex) { - throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + throw new InvalidOperationException($"Error deleting email group with ID {id}: {ex.Message}"); } } @@ -82,7 +79,7 @@ public async Task> GetEmailGroupUsersByGroupIdAsync(Gui { var users = await _emailGroupUsersRepository.GetListAsync(u => u.GroupId == id); - return ObjectMapper.Map, List>(users); + return ObjectMapper.Map, List>(users); } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs index a4b8fec64..bec6f3748 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/EmailGroups/EmailGroupsAppService.cs @@ -2,10 +2,8 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Unity.GrantManager.Comments; using Volo.Abp.Application.Services; using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Repositories; namespace Unity.Notifications.EmailGroups @@ -23,8 +21,8 @@ public EmailGroupsAppService(IEmailGroupsRepository emailGroupsRepository) _emailGroupsRepository = emailGroupsRepository; } public async Task CreateAsync(EmailGroupDto dto) - { - var newGroup = await _emailGroupsRepository.InsertAsync(new EmailGroup + { + var newGroup = await _emailGroupsRepository.InsertAsync(new EmailGroup { Name = dto.Name, Description = dto.Description, @@ -44,8 +42,8 @@ public async Task UpdateAsync(EmailGroupDto dto) var emailGroup = await _emailGroupsRepository.GetAsync(dto.Id, true); emailGroup.Name = dto.Name; emailGroup.Description = dto.Description; - emailGroup.Type = dto.Type; - await _emailGroupsRepository.UpdateAsync(emailGroup,autoSave:true); + emailGroup.Type = dto.Type; + await _emailGroupsRepository.UpdateAsync(emailGroup, autoSave: true); return new EmailGroupDto { Id = emailGroup.Id, @@ -62,22 +60,22 @@ public async Task DeleteAsync(Guid id) await _emailGroupsRepository.DeleteAsync(id); return true; } - catch(Exception ex) + catch (Exception ex) { - throw new Exception($"Error deleting email group with ID {id}: {ex.Message}"); + throw new InvalidOperationException($"Error deleting email group with ID {id}: {ex.Message}"); } } public async Task> GetListAsync() { - var groups = await _emailGroupsRepository.GetListAsync(); - return ObjectMapper.Map, List>(groups); + var groups = await _emailGroupsRepository.GetListAsync(); + return ObjectMapper.Map, List>(groups); } public async Task GetEmailGroupByIdAsync(Guid id) { var group = await _emailGroupsRepository.GetAsync(id); - return ObjectMapper.Map(group); + return ObjectMapper.Map(group); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs index 977fecde8..902524266 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Domain/NotificationsDataSeedContributor.cs @@ -71,8 +71,8 @@ await _templateVariablesRepository.InsertAsync( } } catch (Exception ex) - { - + { + throw new InvalidOperationException($"Error seeding Notifications Data for Templates: {ex.Message}"); } var emailGroups = new List @@ -98,7 +98,7 @@ await _emailGroupsRepository.InsertAsync( } catch (Exception ex) { - + throw new InvalidOperationException($"Error seeding Notifications Data for Email Groups: {ex.Message}"); } } From 80751c84c6eb73fe7943c74c3a2617a70b4a7b8f Mon Sep 17 00:00:00 2001 From: jpasta Date: Mon, 21 Jul 2025 11:38:16 -0700 Subject: [PATCH 23/30] feature/AB#28691-AccountCodingMulti-Finish Edge cases --- .../IPaymentRequestAppService.cs | 1 + .../PaymentRequestAppService.cs | 10 +++- .../UpdatePaymentRequestStatus.cshtml | 1 + .../UpdatePaymentRequestStatus.cshtml.cs | 29 ++++++---- .../CreatePaymentRequests.cshtml.cs | 55 +++++++------------ .../Pages/PaymentRequests/Index.cshtml | 1 + .../Pages/PaymentRequests/Index.cshtml.cs | 11 +++- .../Pages/PaymentRequests/Index.js | 9 +++ 8 files changed, 69 insertions(+), 48 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs index 18d2e538e..9af5ab42d 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentRequests/IPaymentRequestAppService.cs @@ -18,5 +18,6 @@ public interface IPaymentRequestAppService : IApplicationService Task> GetListByApplicationIdsAsync(List applicationIds); Task GetNextBatchInfoAsync(); Task GetDefaultAccountCodingId(); + Task GetUserPaymentThresholdAsync(); } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs index 97f9139a0..ff920d483 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentRequests/PaymentRequestAppService.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Unity.Payment.Shared; using Unity.Payments.Domain.Exceptions; using Unity.Payments.Domain.PaymentConfigurations; using Unity.Payments.Domain.PaymentRequests; @@ -19,6 +18,8 @@ using Volo.Abp.Features; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Users; +using Unity.Payments.Domain.PaymentThresholds; +using Volo.Abp.Domain.Repositories; namespace Unity.Payments.PaymentRequests { @@ -31,6 +32,7 @@ public class PaymentRequestAppService( IPaymentConfigurationRepository paymentConfigurationRepository, IPaymentsManager paymentsManager, IPaymentRequestRepository paymentRequestsRepository, + IPaymentThresholdRepository paymentThresholdRepository, IPermissionChecker permissionChecker) : PaymentsAppService, IPaymentRequestAppService { @@ -416,6 +418,12 @@ public virtual async Task GetTotalPaymentRequestAmountByCorrelationIdAs return await paymentRequestsRepository.GetTotalPaymentRequestAmountByCorrelationIdAsync(correlationId); } + public async Task GetUserPaymentThresholdAsync() + { + var userThreshold = await paymentThresholdRepository.FirstOrDefaultAsync(x => x.UserId == currentUser.Id); + return userThreshold?.Threshold; + } + protected virtual string GetCurrentRequesterName() { return $"{currentUser.Name} {currentUser.SurName}"; diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml index 5540b4766..1509f63c7 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml @@ -39,6 +39,7 @@ + @if (Model.PaymentGroupings.Count > 0) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs index ea42b303a..b967dbdff 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs @@ -15,7 +15,6 @@ using Unity.Payments.PaymentRequests; using Unity.Payments.Permissions; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; -using Volo.Abp.Users; namespace Unity.Payments.Web.Pages.PaymentApprovals { @@ -31,11 +30,10 @@ public class UpdatePaymentRequestStatus( IPaymentRequestAppService paymentRequestAppService, IPaymentConfigurationAppService paymentConfigurationAppService, IApplicationFormAppService applicationFormAppService, - IPaymentThresholdRepository paymentThresholdRepository, - ICurrentUser currentUser, IPermissionCheckerService permissionCheckerService) : AbpPageModel { [BindProperty] public List PaymentGroupings { get; set; } = new(); + [BindProperty] public decimal? UserPaymentThreshold { get; set; } [BindProperty] public decimal PaymentThreshold { get; set; } [BindProperty] public bool DisableSubmit { get; set; } [BindProperty] public bool HasPaymentConfiguration { get; set; } @@ -68,15 +66,11 @@ private async Task InitializeStateAsync(string paymentIds, bool isApprove) await GetFromStateForUserAsync(); IsApproval = isApprove; SelectedPaymentIds = JsonSerializer.Deserialize>(paymentIds) ?? new(); - PaymentThreshold = await GetUserPaymentThresholdAsync(); + UserPaymentThreshold = await paymentRequestAppService.GetUserPaymentThresholdAsync(); HasPaymentConfiguration = await paymentConfigurationAppService.GetAsync() != null; } - private async Task GetUserPaymentThresholdAsync() - { - var userThreshold = await paymentThresholdRepository.GetAsync(x => x.UserId == currentUser.Id); - return userThreshold?.Threshold ?? PaymentSharedConsts.DefaultThresholdAmount; - } + private async Task> BuildPaymentApprovalsAsync(List payments) { @@ -85,7 +79,22 @@ private async Task> BuildPaymentApprovalsAsync(List< foreach (var payment in payments) { var formThreshold = await applicationFormAppService.GetFormPaymentApprovalThresholdByApplicationIdAsync(payment.CorrelationId); - PaymentThreshold = formThreshold.HasValue && formThreshold.Value < PaymentThreshold ? formThreshold.Value : PaymentThreshold; + if (formThreshold.HasValue && UserPaymentThreshold.HasValue) + { + PaymentThreshold = formThreshold.Value < UserPaymentThreshold.Value ? formThreshold.Value : UserPaymentThreshold.Value; + } + else if (formThreshold.HasValue) + { + PaymentThreshold = formThreshold.Value; + } + else if (UserPaymentThreshold.HasValue) + { + PaymentThreshold = UserPaymentThreshold.Value; + } + else + { + PaymentThreshold = 0m; + } var approvalModel = await CreateApprovalModel(payment); ValidateApprovalModel(approvalModel); diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs index b0a42832a..4555af749 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/CreatePaymentRequests.cshtml.cs @@ -7,7 +7,6 @@ using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; using Unity.Payments.PaymentConfigurations; using Unity.GrantManager.GrantApplications; -using Unity.Payment.Shared; using System.Text.Json; using Unity.Payments.Domain.Suppliers; using System.Linq; @@ -15,32 +14,17 @@ namespace Unity.Payments.Web.Pages.Payments { - public class CreatePaymentRequestsModel : AbpPageModel + public class CreatePaymentRequestsModel( + IGrantApplicationAppService applicationService, + IPaymentRequestAppService paymentRequestAppService, + IPaymentConfigurationAppService paymentConfigurationAppService, + ISupplierAppService iSupplierAppService, + ISiteRepository siteRepository, + IPaymentSettingsAppService paymentSettingsAppService + ) : AbpPageModel { - public List SelectedApplicationIds { get; set; } - private readonly IGrantApplicationAppService _applicationService; - private readonly IPaymentRequestAppService _paymentRequestService; - private readonly IPaymentConfigurationAppService _paymentConfigurationAppService; - private readonly ISupplierAppService _iSupplierAppService; - private readonly ISiteRepository _siteRepository; - private readonly IPaymentSettingsAppService _paymentSettingsAppService; - - public CreatePaymentRequestsModel( - IPaymentSettingsAppService paymentSettingsAppService, - ISiteRepository siteRepository, - IGrantApplicationAppService applicationService, - ISupplierAppService iSupplierAppService, - IPaymentRequestAppService paymentRequestService, - IPaymentConfigurationAppService paymentConfigurationAppService) - { - SelectedApplicationIds = []; - _siteRepository = siteRepository; - _applicationService = applicationService; - _paymentRequestService = paymentRequestService; - _paymentConfigurationAppService = paymentConfigurationAppService; - _iSupplierAppService = iSupplierAppService; - _paymentSettingsAppService = paymentSettingsAppService; - } + + public List SelectedApplicationIds { get; set; } = []; [BindProperty] public List ApplicationPaymentRequestForm { get; set; } = []; @@ -53,7 +37,6 @@ public CreatePaymentRequestsModel( [BindProperty] public string BatchNumberDisplay { get; set; } = string.Empty; - [BindProperty] public decimal TotalAmount { get; set; } @@ -67,7 +50,7 @@ public decimal ApplicationPaymentRequestFormTotalAmount public async Task OnGetAsync(string applicationIds) { - var paymentConfiguration = await _paymentConfigurationAppService.GetAsync(); + var paymentConfiguration = await paymentConfigurationAppService.GetAsync(); if (paymentConfiguration != null) { HasPaymentConfiguration = true; @@ -79,7 +62,7 @@ public async Task OnGetAsync(string applicationIds) } SelectedApplicationIds = JsonSerializer.Deserialize>(applicationIds) ?? []; - var applications = await _applicationService.GetApplicationDetailsListAsync(SelectedApplicationIds); + var applications = await applicationService.GetApplicationDetailsListAsync(SelectedApplicationIds); foreach (var application in applications) { @@ -87,7 +70,7 @@ public async Task OnGetAsync(string applicationIds) // Grabs the Account Coding ID from the Application Form and if there is none then the Payment Configuration // If neither exist then an error on the payment request will be shown - Guid? accountCodingId = await _paymentSettingsAppService.GetAccountCodingIdByApplicationIdAsync(application.Id); + Guid? accountCodingId = await paymentSettingsAppService.GetAccountCodingIdByApplicationIdAsync(application.Id); PaymentsModel request = new() { @@ -108,7 +91,7 @@ public async Task OnGetAsync(string applicationIds) Guid siteId = application.Applicant.SiteId; Site? site = null; if(siteId != Guid.Empty) { - site = await _siteRepository.GetAsync(siteId); + site = await siteRepository.GetAsync(siteId); var siteName = $"{site.Number} ({supplierNumber}, {site.City})"; request.SiteName = siteName; request.SiteId = siteId; @@ -127,7 +110,7 @@ public async Task OnGetAsync(string applicationIds) ApplicationPaymentRequestForm!.Add(request); } - var batchName = await _paymentRequestService.GetNextBatchInfoAsync(); + var batchName = await paymentRequestAppService.GetNextBatchInfoAsync(); BatchNumberDisplay = batchName; TotalAmount = ApplicationPaymentRequestForm?.Sum(x => x.Amount) ?? 0m; } @@ -180,7 +163,7 @@ private async Task GetRemainingAmountAllowedByApplicationAsync(GrantApp if (application.ApprovedAmount > 0) { decimal approvedAmmount = application.ApprovedAmount; - decimal totalFutureRequested = await _paymentRequestService.GetTotalPaymentRequestAmountByCorrelationIdAsync(application.Id); + decimal totalFutureRequested = await paymentRequestAppService.GetTotalPaymentRequestAmountByCorrelationIdAsync(application.Id); if (approvedAmmount > totalFutureRequested) { remainingAmount = approvedAmmount - totalFutureRequested; @@ -194,14 +177,14 @@ private async Task GetRemainingAmountAllowedByApplicationAsync(GrantApp { if(application.Applicant.SupplierId != Guid.Empty) { - SupplierDto? supplierDto = await _iSupplierAppService.GetAsync(application.Applicant.SupplierId); + SupplierDto? supplierDto = await iSupplierAppService.GetAsync(application.Applicant.SupplierId); if (supplierDto != null) { return supplierDto; } } - return await _iSupplierAppService.GetByCorrelationAsync(new GetSupplierByCorrelationDto() + return await iSupplierAppService.GetByCorrelationAsync(new GetSupplierByCorrelationDto() { CorrelationId = application.Applicant.Id, CorrelationProvider = GrantManager.Payments.PaymentConsts.ApplicantCorrelationProvider, @@ -215,7 +198,7 @@ public async Task OnPostAsync() var payments = MapPaymentRequests(); - await _paymentRequestService.CreateAsync(payments); + await paymentRequestAppService.CreateAsync(payments); return NoContent(); } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml index f80522871..ba5d3c1f8 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml @@ -24,5 +24,6 @@
+
diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml.cs index cc9b1b3fe..e1c68f3fd 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.cshtml.cs @@ -1,13 +1,22 @@ using Microsoft.AspNetCore.Mvc; using System; +using System.Threading.Tasks; +using Unity.Payments.PaymentRequests; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; namespace Unity.Payments.Web.Pages.Payments { - public class PaymentsPageModel : AbpPageModel + public class PaymentsPageModel(IPaymentRequestAppService paymentRequestAppService) : AbpPageModel { + [BindProperty] public decimal? UserPaymentThreshold { get; set; } + [BindProperty(SupportsGet = true)] public Guid BatchPaymentId { get; set; } + + public async Task OnGetAsync() + { + UserPaymentThreshold = await paymentRequestAppService.GetUserPaymentThresholdAsync(); + } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js index 234264942..f42126501 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentRequests/Index.js @@ -5,6 +5,7 @@ $(function () { let dt = $('#PaymentRequestListTable'); let dataTable; let isApprove = false; + toastr.options.positionClass = 'toast-top-center'; const listColumns = getColumns(); const defaultVisibleColumns = [ 'referenceNumber', @@ -38,6 +39,14 @@ $(function () { text: 'Approve', className: 'custom-table-btn flex-none btn btn-secondary payment-status', action: function (e, dt, node, config) { + // Check if user payment threshold is defined and greater than 0 + if (parseFloat($("#UserPaymentThreshold").val() || 0) <= 0) { + abp.notify.error( + 'Your User has not been configured with an Approved Payment Threshold. Please contact your system administrator.', + 'Payment Requests' + ); + return; + } paymentRequestStatusModal.open({ paymentIds: JSON.stringify(selectedPaymentIds), isApprove: true From 37a08571a17346605d08e8b4de0e2529ce733b1e Mon Sep 17 00:00:00 2001 From: jpasta Date: Mon, 21 Jul 2025 11:52:17 -0700 Subject: [PATCH 24/30] feature/AB#28691-AccountCodingMulti-FinishMergeDev --- .../Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs index 3dbcbe294..697edf9be 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs @@ -27,6 +27,8 @@ public class PaymentGrouping public class UpdatePaymentRequestStatus( IPaymentRequestAppService paymentRequestAppService, + IApplicationFormAppService applicationFormAppService, + IPaymentRequestRepository paymentRepository, IPaymentConfigurationAppService paymentConfigurationAppService, IPermissionCheckerService permissionCheckerService) : AbpPageModel { From 0920e0fa27059899719b6412185875d7d400048e Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:54:11 -0700 Subject: [PATCH 25/30] Update applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Views/Shared/Components/PaymentConfiguration/Default.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml index 9137426f5..c109b1dfd 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -2,7 +2,7 @@ @model PaymentConfigurationViewModel @section styles { - + } @{ From c0bf9f3a3344e345a314ca7abaa42f13fb1d0b94 Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:54:58 -0700 Subject: [PATCH 26/30] Update applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Views/Shared/Components/PaymentConfiguration/Default.cshtml | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml index c109b1dfd..1d4017b1c 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/PaymentConfiguration/Default.cshtml @@ -41,7 +41,6 @@ id="PaymentApprovalThreshold" name="PaymentApprovalThreshold" value="@Model.PaymentApprovalThreshold" class="form-control currency"> -
From 0d60bafe388c2d602d4c64eca48c20e1d4adfb7a Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:56:04 -0700 Subject: [PATCH 27/30] Update applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Domain/AccountCodings/AccountCoding.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs index a741de531..d7a058ebf 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/Domain/AccountCodings/AccountCoding.cs @@ -14,6 +14,14 @@ public class AccountCoding : AuditedAggregateRoot public string Stob { get; private set; } public string ProjectNumber { get; private set; } + public AccountCoding() + { + MinistryClient = string.Empty; + Responsibility = string.Empty; + ServiceLine = string.Empty; + Stob = string.Empty; + ProjectNumber = string.Empty; + } private AccountCoding(string ministryClient, string responsibility, string serviceLine, From 8743745e3983b56c1e65fb50d02073ad43e708fc Mon Sep 17 00:00:00 2001 From: James Pasta <129337673+JamesPasta@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:56:55 -0700 Subject: [PATCH 28/30] Update applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Applicants/ApplicantAppService.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs index 9068e6b03..d8be56f78 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs @@ -67,7 +67,11 @@ public async Task CreateOrRetrieveApplicantAsync(IntakeMapping intake [RemoteService(false)] public async Task RelateSupplierToApplicant(ApplicantSupplierEto applicantSupplierEto) { - // Removed unnecessary null check for non-nullable ApplicantId + // Validate ApplicantId to ensure it is not Guid.Empty + if (applicantSupplierEto.ApplicantId == Guid.Empty) + { + throw new ArgumentException("ApplicantId cannot be Guid.Empty.", nameof(applicantSupplierEto.ApplicantId)); + } Applicant? applicant = await applicantRepository.GetAsync(applicantSupplierEto.ApplicantId); ArgumentNullException.ThrowIfNull(applicant); applicant.SupplierId = applicantSupplierEto.SupplierId; From f8b2e59b812bb134e6b1a9c40f042ad87cdc1f6a Mon Sep 17 00:00:00 2001 From: jpasta Date: Mon, 21 Jul 2025 11:58:47 -0700 Subject: [PATCH 29/30] feature/AB#28691-AccountCodingMulti-FinishMergeDev --- .../UpsertPaymentConfigurationDtoBase.cs | 2 +- .../PaymentConfigurations/PaymentConfigurationAppService.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs index 9cf56f896..0d8003614 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application.Contracts/PaymentConfigurations/UpsertPaymentConfigurationDtoBase.cs @@ -6,6 +6,6 @@ namespace Unity.Payments.PaymentConfigurations public class UpsertPaymentConfigurationDtoBase { public string PaymentIdPrefix { get; set; } = string.Empty; - public Guid DefaultAcountCodingId { get; set; } + public Guid DefaultAccountCodingId { get; set; } } } diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs index 318caa237..d4dc6b0aa 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Application/PaymentConfigurations/PaymentConfigurationAppService.cs @@ -42,7 +42,7 @@ public virtual async Task CreateAsync(CreatePaymentConf { PaymentConfiguration? paymentConfiguration = new PaymentConfiguration { - DefaultAccountCodingId = createUpdatePaymentConfigurationDto.DefaultAcountCodingId, + DefaultAccountCodingId = createUpdatePaymentConfigurationDto.DefaultAccountCodingId, PaymentIdPrefix = createUpdatePaymentConfigurationDto.PaymentIdPrefix }; @@ -84,7 +84,7 @@ public async Task SetDefaultAccountCodeAsync(Guid accountCodingId) if (paymentConfiguration == null) { CreatePaymentConfigurationDto paymentConfigurationDto = new CreatePaymentConfigurationDto(); - paymentConfigurationDto.DefaultAcountCodingId = accountCodingId; + paymentConfigurationDto.DefaultAccountCodingId = accountCodingId; await CreateAsync(paymentConfigurationDto); } else From 82f69cd49a565b505d680b68a569ac5d2b2d6677 Mon Sep 17 00:00:00 2001 From: jpasta Date: Mon, 21 Jul 2025 13:14:26 -0700 Subject: [PATCH 30/30] feature/AB#28691-AccountCodingMulti-Sonarissues --- .../Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs | 2 -- .../Applicants/ApplicantAppService.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs index 697edf9be..bdfaeba7b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Pages/PaymentApprovals/UpdatePaymentRequestStatus.cshtml.cs @@ -6,9 +6,7 @@ using System.Text.Json; using System.Threading.Tasks; using Unity.GrantManager.ApplicationForms; -using Unity.Payment.Shared; using Unity.Payments.Domain.PaymentRequests; -using Unity.Payments.Domain.PaymentThresholds; using Unity.Payments.Domain.Shared; using Unity.Payments.Enums; using Unity.Payments.PaymentConfigurations; diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs index d8be56f78..158120538 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Application/Applicants/ApplicantAppService.cs @@ -70,7 +70,7 @@ public async Task RelateSupplierToApplicant(ApplicantSupplierEto appl // Validate ApplicantId to ensure it is not Guid.Empty if (applicantSupplierEto.ApplicantId == Guid.Empty) { - throw new ArgumentException("ApplicantId cannot be Guid.Empty.", nameof(applicantSupplierEto.ApplicantId)); + throw new ArgumentException("ApplicantId cannot be Guid.Empty.", "applicantSupplierEto.ApplicantId"); } Applicant? applicant = await applicantRepository.GetAsync(applicantSupplierEto.ApplicantId); ArgumentNullException.ThrowIfNull(applicant);