From 2d209374276c4cfd9c7112035274544d489df712 Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Mon, 16 Dec 2024 09:48:35 -0500 Subject: [PATCH 01/13] Reorganize violation types --- .../Cases/EnforcementCase.cs | 4 +-- .../ViolationType.cs | 2 +- .../ViolationTypeData.cs} | 11 ++------ .../Enforcement/EnforcementCaseData.cs | 28 ++++++++++--------- 4 files changed, 21 insertions(+), 24 deletions(-) rename src/Domain/EnforcementEntities/{Cases => ViolationTypes}/ViolationType.cs (71%) rename src/Domain/EnforcementEntities/{Data/ViolationTypes.cs => ViolationTypes/ViolationTypeData.cs} (95%) diff --git a/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs b/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs index f259c5fe..9b6a39e2 100644 --- a/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs +++ b/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs @@ -3,7 +3,7 @@ using AirWeb.Domain.Data; using AirWeb.Domain.DataExchange; using AirWeb.Domain.EnforcementEntities.Actions; -using AirWeb.Domain.EnforcementEntities.Data; +using AirWeb.Domain.EnforcementEntities.ViolationTypes; using AirWeb.Domain.Identity; using System.ComponentModel; using System.Text.Json.Serialization; @@ -55,7 +55,7 @@ public Facility Facility // Required if the data flow is enabled. public ViolationType? ViolationType { - get => EnforcementData.GetViolationType(ViolationTypeId); + get => ViolationTypeData.GetViolationType(ViolationTypeId); set => ViolationTypeId = value?.Code; } diff --git a/src/Domain/EnforcementEntities/Cases/ViolationType.cs b/src/Domain/EnforcementEntities/ViolationTypes/ViolationType.cs similarity index 71% rename from src/Domain/EnforcementEntities/Cases/ViolationType.cs rename to src/Domain/EnforcementEntities/ViolationTypes/ViolationType.cs index f8e2cd9c..1deef219 100644 --- a/src/Domain/EnforcementEntities/Cases/ViolationType.cs +++ b/src/Domain/EnforcementEntities/ViolationTypes/ViolationType.cs @@ -1,4 +1,4 @@ -namespace AirWeb.Domain.EnforcementEntities.Cases; +namespace AirWeb.Domain.EnforcementEntities.ViolationTypes; public record ViolationType( [StringLength(3)] string Code, diff --git a/src/Domain/EnforcementEntities/Data/ViolationTypes.cs b/src/Domain/EnforcementEntities/ViolationTypes/ViolationTypeData.cs similarity index 95% rename from src/Domain/EnforcementEntities/Data/ViolationTypes.cs rename to src/Domain/EnforcementEntities/ViolationTypes/ViolationTypeData.cs index 32bfb6b5..d9774f20 100644 --- a/src/Domain/EnforcementEntities/Data/ViolationTypes.cs +++ b/src/Domain/EnforcementEntities/ViolationTypes/ViolationTypeData.cs @@ -1,6 +1,4 @@ -using AirWeb.Domain.EnforcementEntities.Cases; - -namespace AirWeb.Domain.EnforcementEntities.Data; +namespace AirWeb.Domain.EnforcementEntities.ViolationTypes; // Source of data from IAIP airbranch DB: // @@ -14,14 +12,11 @@ namespace AirWeb.Domain.EnforcementEntities.Data; // order by SEVERITYCODE, DEPRECATED, VIOLATIONTYPEDESC // ``` -public static class EnforcementData +public static class ViolationTypeData { - public static ViolationType GetRandomViolationType() => - ViolationTypes.Where(t => !t.Deprecated).OrderBy(_ => Guid.NewGuid()).First(); - public static ViolationType? GetViolationType(string? code) => ViolationTypes.Find(type => type.Code == code); - private static List ViolationTypes { get; } = + internal static List ViolationTypes { get; } = [ new("FCIO", "Failure to construct, install or operate facility/equipment in accordance with permit or regulation", diff --git a/src/TestData/Enforcement/EnforcementCaseData.cs b/src/TestData/Enforcement/EnforcementCaseData.cs index c4437f08..8e84bd6f 100644 --- a/src/TestData/Enforcement/EnforcementCaseData.cs +++ b/src/TestData/Enforcement/EnforcementCaseData.cs @@ -1,15 +1,17 @@ using AirWeb.Domain.EnforcementEntities.Cases; -using AirWeb.Domain.EnforcementEntities.Data; +using AirWeb.Domain.EnforcementEntities.ViolationTypes; using AirWeb.TestData.Compliance; using AirWeb.TestData.Identity; using AirWeb.TestData.SampleData; -using IaipDataService.Facilities; using IaipDataService.TestData; namespace AirWeb.TestData.Enforcement; internal static class EnforcementCaseData { + public static ViolationType GetRandomViolationType() => + ViolationTypeData.ViolationTypes.Where(type => !type.Deprecated).OrderBy(_ => Guid.NewGuid()).First(); + private static IEnumerable EnforcementCaseSeedItems => [ new(300, DomainData.GetRandomFacility().Id, null) @@ -39,21 +41,21 @@ internal static class EnforcementCaseData new(304, DomainData.GetRandomFacility().Id, null) { Notes = "Unsent LON + NOV - draft", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-9).Date), }, new(305, DomainData.GetRandomFacility().Id, null) { Notes = "NOV - no response", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-9).Date), }, new(306, DomainData.GetRandomFacility().Id, null) { Notes = "NOV + NFA", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.CaseResolved, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-100).Date), }, @@ -61,42 +63,42 @@ internal static class EnforcementCaseData { ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-60).Date), Notes = "Combined NOV/NFA", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.CaseResolved, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-100).Date), }, new(308, DomainData.GetRandomFacility().Id, null) { Notes = "NOV + Proposed Consent Order - draft", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(309, DomainData.GetRandomFacility().Id, null) { Notes = "Straight to Proposed CO - no response received", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(310, DomainData.GetRandomFacility().Id, null) { Notes = "Proposed CO + signed Consent Order received", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(311, DomainData.GetRandomFacility().Id, null) { Notes = "Consent Order - executed", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(312, DomainData.GetRandomFacility().Id, null) { Notes = "Consent Order + Stipulated Penalties - closed", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.CaseClosed, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-210).Date), ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddMonths(-6).Date), @@ -104,7 +106,7 @@ internal static class EnforcementCaseData new(313, DomainData.GetRandomFacility().Id, null) { Notes = "Administrative Order - executed", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-320).Date), ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddMonths(-9).Date), @@ -112,7 +114,7 @@ internal static class EnforcementCaseData new(314, DomainData.GetRandomFacility().Id, null) { Notes = "Administrative Order - closed", - ViolationType = EnforcementData.GetRandomViolationType(), + ViolationType = GetRandomViolationType(), Status = EnforcementCaseStatus.CaseClosed, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-320).Date), ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-200).Date), From 212bf2af2ec040f99467cfb1930d477879aa9c25 Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Mon, 16 Dec 2024 13:49:23 -0500 Subject: [PATCH 02/13] Update enforcement site map --- docs/Site-map.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/Site-map.md b/docs/Site-map.md index 284069c8..a0403082 100644 --- a/docs/Site-map.md +++ b/docs/Site-map.md @@ -61,32 +61,32 @@ These pages are only available to logged-in staff. ### Enforcement -* `/Compliance/Enforcement` Enforcement search form. -* `/Compliance/Enforcement/Details/{enforcementId}` Enforcement details. +* `/Enforcement` Enforcement search form. +* `/Enforcement/Details/{enforcementId}` Enforcement details. #### Enforcement Case Initiation -* `/Compliance/Enforcement/Add/{facilityId}` Start new enforcement case for the specified facility. -* `/Compliance/Enforcement/Add/{facilityId}/{entryId}` Start new enforcement case for the specified work entry. +* `/Enforcement/Add?{facilityId}` Start new enforcement case for the specified facility. +* `/Enforcement/Add?{entryId}` Start new enforcement case for the specified compliance entry. #### Enforcement Case Workflow -* `/Compliance/Enforcement/Edit/{enforcementId}` Edit enforcement details. -* `/Compliance/Enforcement/[Close|Reopen]/{enforcementId}` Close/reopen an enforcement case. -* `/Compliance/Enforcement/Link/{enforcementId}` Link an enforcement case to a compliance event. -* `/Compliance/Enforcement/[Delete|Restore]/{enforcementId}` Delete/restore an enforcement case. +* `/Enforcement/Edit/{enforcementId}` Edit enforcement details. +* `/Enforcement/[Close|Reopen]/{enforcementId}` Close/reopen an enforcement case. +* `/Enforcement/Link/{enforcementId}` Link an enforcement case to a compliance event. +* `/Enforcement/[Delete|Restore]/{enforcementId}` Delete/restore an enforcement case. #### Enforcement Action Workflow -* `/Compliance/Enforcement/Details/{enforcementId}/Action/{actionId}` View enforcement action details. -* `/Compliance/Enforcement/Details/{enforcementId}/Action/Add` Add an enforcement action to an enforcement case. -* `/Compliance/Enforcement/Details/{enforcementId}/Action/Add/{actionId}` Add an enforcement action linked from another +* `/Enforcement/Details/{enforcementId}/Action/{actionId}` View enforcement action details. +* `/Enforcement/Details/{enforcementId}/Action/Add` Add an enforcement action to an enforcement case. +* `/Enforcement/Details/{enforcementId}/Action/Add/{actionId}` Add an enforcement action linked from another enforcement action. -* `/Compliance/Enforcement/Details/{enforcementId}/Action/Edit/{actionId}` Edit an enforcement action details. -* `/Compliance/Enforcement/Details/{enforcementId}/Action/RequestReview/{actionId}` Request review for an enforcement action. -* `/Compliance/Enforcement/Details/{enforcementId}/Action/[Approve/Return]/{actionId}` Approve or return an enforcement +* `/Enforcement/Details/{enforcementId}/Action/Edit/{actionId}` Edit an enforcement action details. +* `/Enforcement/Details/{enforcementId}/Action/RequestReview/{actionId}` Request review for an enforcement action. +* `/Enforcement/Details/{enforcementId}/Action/[Approve/Return]/{actionId}` Approve or return an enforcement action review. -* `/Compliance/Enforcement/Details/{enforcementId}/Action/Issue/{actionId}` Issue (and close) an enforcement action. +* `/Enforcement/Details/{enforcementId}/Action/Issue/{actionId}` Issue (and close) an enforcement action. ## User Account From 292488cacb7fa806a918603a995e132b37f8042f Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Mon, 16 Dec 2024 14:07:20 -0500 Subject: [PATCH 03/13] Update code related to nullability --- .../Compliance/Fces/FceCreateDto.cs | 2 +- .../Compliance/Fces/FceSummaryDto.cs | 2 +- src/AppServices/Compliance/Fces/FceViewDto.cs | 4 +-- .../Compliance/Search/WorkEntryExportDto.cs | 2 +- .../Compliance/Search/WorkEntrySearchDto.cs | 2 +- .../Inspections/InspectionViewDto.cs | 4 +-- .../Command/WorkEntryCommandDto.cs | 2 +- .../Query/SupportingData/FeeYearSummaryDto.cs | 2 +- .../SupportingData/SourceTestSummaryDto.cs | 6 ++-- .../WorkEntryDto/Query/WorkEntryViewDto.cs | 4 +-- .../Enforcement/EnforcementSummaryDto.cs | 2 +- .../NamedEntitiesBase/NamedEntityDtos.cs | 2 +- src/Domain/Comments/Comment.cs | 6 ++-- src/Domain/ComplianceEntities/Fces/Fce.cs | 4 +-- .../ComplianceEntities/IComplianceEntity.cs | 2 +- .../WorkEntries/BaseInspection.cs | 4 +-- .../WorkEntries/WorkEntry.cs | 8 +++--- .../Actions/EnforcementAction.cs | 2 +- .../Cases/EnforcementCase.cs | 4 +-- src/IaipDataService/Facilities/Facility.cs | 4 +-- src/IaipDataService/Facilities/FacilityId.cs | 2 +- .../Models/BaseSourceTestReport.cs | 14 +++++----- .../Models/SourceTestMemorandum.cs | 6 ++-- .../Models/SourceTestReportFlare.cs | 4 +-- .../SourceTestReportGasConcentration.cs | 4 +-- .../Models/SourceTestReportLoadingRack.cs | 2 +- .../Models/SourceTestReportOneStack.cs | 4 +-- .../Models/SourceTestReportOpacity.cs | 14 +++++----- .../Models/SourceTestReportPondTreatment.cs | 4 +-- .../Models/SourceTestReportRata.cs | 16 +++++------ .../Models/SourceTestReportTwoStack.cs | 10 +++---- .../SourceTests/Models/SourceTestSummary.cs | 6 ++-- .../SourceTests/Models/TestRun/BaseTestRun.cs | 4 +-- .../Models/TestRun/FlareTestRun.cs | 4 +-- .../Models/TestRun/GasConcentrationTestRun.cs | 4 +-- .../Models/TestRun/OpacityTestRun.cs | 12 ++++---- .../Models/TestRun/PondTreatmentTestRun.cs | 4 +-- .../SourceTests/Models/TestRun/RataTestRun.cs | 4 +-- .../Models/TestRun/StackTestRun.cs | 12 ++++---- .../Models/TestRun/TwoStackTestRun.cs | 28 +++++++++---------- .../ComplianceSearch/CountTests.cs | 2 +- .../ComplianceSearch/FilterTests.cs | 2 +- tests/EfRepositoryTests/Fces/ExistsTests.cs | 2 +- .../Fces/FindIncludeProperty.cs | 2 +- .../Fces/GetIncludeProperty.cs | 2 +- tests/EfRepositoryTests/Fces/GetNextId.cs | 2 +- .../Offices/GetActiveStaffMembersList.cs | 2 +- tests/EfRepositoryTests/RepositoryHelper.cs | 2 +- .../WorkEntries/FindIncludeProperty.cs | 2 +- .../WorkEntries/FindOfType.cs | 2 +- .../WorkEntries/FindWorkEntry.cs | 2 +- .../WorkEntries/GetIncludeProperty.cs | 2 +- .../WorkEntries/GetNextId.cs | 2 +- .../WorkEntries/GetNotificationType.cs | 2 +- .../WorkEntries/GetWorkEntryType.cs | 2 +- .../ComplianceSearch/CountTests.cs | 6 ++-- .../ComplianceSearch/FilterTests.cs | 6 ++-- .../LocalRepositoryTests/Fces/ExistsTests.cs | 2 +- tests/LocalRepositoryTests/Fces/GetNextId.cs | 2 +- .../Identity/RoleStore.cs | 2 +- .../Identity/UserRoleStore.cs | 2 +- .../Identity/UserStore.cs | 2 +- .../Offices/GetActiveStaffMembersList.cs | 2 +- .../WorkEntries/FindWorkEntry.cs | 2 +- .../WorkEntries/GetNextId.cs | 2 +- .../WorkEntries/GetNotificationType.cs | 2 +- .../WorkEntries/GetWorkEntryType.cs | 2 +- 67 files changed, 144 insertions(+), 144 deletions(-) diff --git a/src/AppServices/Compliance/Fces/FceCreateDto.cs b/src/AppServices/Compliance/Fces/FceCreateDto.cs index 71f89854..9bb07b55 100644 --- a/src/AppServices/Compliance/Fces/FceCreateDto.cs +++ b/src/AppServices/Compliance/Fces/FceCreateDto.cs @@ -31,5 +31,5 @@ public FceCreateDto(FacilityId facilityId, string userId) [DataType(DataType.MultilineText)] [StringLength(7000)] [Display(Name = "Notes")] - public string? Notes { get; init; } = string.Empty; + public string? Notes { get; init; } } diff --git a/src/AppServices/Compliance/Fces/FceSummaryDto.cs b/src/AppServices/Compliance/Fces/FceSummaryDto.cs index c1d3c3b4..30345d49 100644 --- a/src/AppServices/Compliance/Fces/FceSummaryDto.cs +++ b/src/AppServices/Compliance/Fces/FceSummaryDto.cs @@ -7,7 +7,7 @@ public record FceSummaryDto : IDeletable { public int Id { get; init; } - public string FacilityId { get; init; } = default!; + public string FacilityId { get; init; } = null!; public string? FacilityName { get; set; } [Display(Name = "FCE Year")] diff --git a/src/AppServices/Compliance/Fces/FceViewDto.cs b/src/AppServices/Compliance/Fces/FceViewDto.cs index 08b6b724..b0ffc21a 100644 --- a/src/AppServices/Compliance/Fces/FceViewDto.cs +++ b/src/AppServices/Compliance/Fces/FceViewDto.cs @@ -10,7 +10,7 @@ public record FceViewDto : IHasOwnerAndDeletable { public int Id { get; init; } - public string FacilityId { get; init; } = default!; + public string FacilityId { get; init; } = null!; public string? FacilityName { get; set; } [Display(Name = "FCE Year")] @@ -25,7 +25,7 @@ public record FceViewDto : IHasOwnerAndDeletable [Display(Name = "With on-site inspection")] public bool OnsiteInspection { get; init; } - public string Notes { get; init; } = string.Empty; + public string Notes { get; init; } = null!; [UsedImplicitly] public List Comments { get; } = []; diff --git a/src/AppServices/Compliance/Search/WorkEntryExportDto.cs b/src/AppServices/Compliance/Search/WorkEntryExportDto.cs index 8e2fc0f4..a1195c09 100644 --- a/src/AppServices/Compliance/Search/WorkEntryExportDto.cs +++ b/src/AppServices/Compliance/Search/WorkEntryExportDto.cs @@ -37,7 +37,7 @@ public WorkEntryExportDto(WorkEntry workEntry) public DateOnly EventDate { get; init; } [XLColumn(Header = "Event")] - public string EventDateName { get; init; } = string.Empty; + public string EventDateName { get; init; } [XLColumn(Header = "Staff Responsible")] public string? ResponsibleStaff { get; init; } diff --git a/src/AppServices/Compliance/Search/WorkEntrySearchDto.cs b/src/AppServices/Compliance/Search/WorkEntrySearchDto.cs index 239e1938..cfc82bf4 100644 --- a/src/AppServices/Compliance/Search/WorkEntrySearchDto.cs +++ b/src/AppServices/Compliance/Search/WorkEntrySearchDto.cs @@ -26,7 +26,7 @@ public record WorkEntrySearchDto : IComplianceSearchDto // == Staff == - [Display(Name = "Responsible Staff")] + [Display(Name = "Staff Responsible")] // Guid as string public string? ResponsibleStaff { get; init; } diff --git a/src/AppServices/Compliance/WorkEntries/Inspections/InspectionViewDto.cs b/src/AppServices/Compliance/WorkEntries/Inspections/InspectionViewDto.cs index 22abb609..53fb016d 100644 --- a/src/AppServices/Compliance/WorkEntries/Inspections/InspectionViewDto.cs +++ b/src/AppServices/Compliance/WorkEntries/Inspections/InspectionViewDto.cs @@ -19,10 +19,10 @@ public record InspectionViewDto : WorkEntryViewDto public InspectionReason? InspectionReason { get; init; } [Display(Name = "Weather Conditions")] - public required string WeatherConditions { get; init; } + public string? WeatherConditions { get; init; } [Display(Name = "Inspection Guides")] - public required string InspectionGuide { get; init; } + public string? InspectionGuide { get; init; } [Display(Name = "Facility Operating")] public bool FacilityOperating { get; init; } diff --git a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Command/WorkEntryCommandDto.cs b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Command/WorkEntryCommandDto.cs index f8c670de..c72a585e 100644 --- a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Command/WorkEntryCommandDto.cs +++ b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Command/WorkEntryCommandDto.cs @@ -14,5 +14,5 @@ public record WorkEntryCommandDto : IWorkEntryCommandDto [DataType(DataType.MultilineText)] [StringLength(7000)] - public string? Notes { get; init; } = string.Empty; + public string? Notes { get; init; } } diff --git a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/FeeYearSummaryDto.cs b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/FeeYearSummaryDto.cs index 8d1958d9..99b7d761 100644 --- a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/FeeYearSummaryDto.cs +++ b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/FeeYearSummaryDto.cs @@ -13,5 +13,5 @@ public record FeeYearSummaryDto public decimal Balance { get; init; } - public string Status { get; init; } = string.Empty; + public string Status { get; init; } = null!; } diff --git a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs index fa408afc..e7e70aca 100644 --- a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs +++ b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs @@ -16,11 +16,11 @@ public record SourceTestSummaryDto public PersonName ResponsibleStaff { get; init; } [Display(Name = "Compliance status")] - public string ComplianceStatus { get; init; } = ""; + public string ComplianceStatus { get; init; } = null!; [Display(Name = "Pollutant measured")] - public string PollutantMeasured { get; init; } = ""; + public string PollutantMeasured { get; init; } = null!; [Display(Name = "Source tested")] - public string SourceTested { get; init; } = ""; + public string SourceTested { get; init; } = null!; } diff --git a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/WorkEntryViewDto.cs b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/WorkEntryViewDto.cs index 46c846c2..d77949c3 100644 --- a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/WorkEntryViewDto.cs +++ b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/WorkEntryViewDto.cs @@ -11,7 +11,7 @@ protected WorkEntryViewDto() { } public int Id { get; init; } public string ItemName => WorkEntryType.GetDescription(); - public string FacilityId { get; init; } = default!; + public string FacilityId { get; init; } = null!; public string? FacilityName { get; set; } public WorkEntryType WorkEntryType { get; init; } public virtual bool HasPrintout => false; @@ -23,7 +23,7 @@ protected WorkEntryViewDto() { } [Display(Name = "Date Acknowledgment Letter Sent")] public DateOnly? AcknowledgmentLetterDate { get; init; } - public string Notes { get; init; } = string.Empty; + public string Notes { get; init; } = null!; public List Comments { get; } = []; // Properties: Closure diff --git a/src/AppServices/Enforcement/EnforcementSummaryDto.cs b/src/AppServices/Enforcement/EnforcementSummaryDto.cs index 40dc540b..40897da9 100644 --- a/src/AppServices/Enforcement/EnforcementSummaryDto.cs +++ b/src/AppServices/Enforcement/EnforcementSummaryDto.cs @@ -14,5 +14,5 @@ public record EnforcementSummaryDto public DateOnly EnforcementDate { get; init; } [Display(Name = "Type")] - public string EnforcementType { get; init; } = string.Empty; + public string EnforcementType { get; init; } = null!; } diff --git a/src/AppServices/NamedEntities/NamedEntitiesBase/NamedEntityDtos.cs b/src/AppServices/NamedEntities/NamedEntitiesBase/NamedEntityDtos.cs index d3fc1c91..1e5d4df5 100644 --- a/src/AppServices/NamedEntities/NamedEntitiesBase/NamedEntityDtos.cs +++ b/src/AppServices/NamedEntities/NamedEntitiesBase/NamedEntityDtos.cs @@ -23,7 +23,7 @@ public abstract record NamedEntityUpdateDto [Required(AllowEmptyStrings = false)] [StringLength(AppConstants.MaximumNameLength, MinimumLength = AppConstants.MinimumNameLength)] - public string Name { get; init; } = string.Empty; + public string Name { get; init; } = null!; public bool Active { get; init; } } diff --git a/src/Domain/Comments/Comment.cs b/src/Domain/Comments/Comment.cs index 3f114102..d94fac07 100644 --- a/src/Domain/Comments/Comment.cs +++ b/src/Domain/Comments/Comment.cs @@ -16,7 +16,7 @@ public record Comment : ISoftDelete public Guid Id { get; init; } [StringLength(15_000)] - public string Text { get; init; } = string.Empty; + public string Text { get; init; } = null!; public ApplicationUser? CommentBy { get; init; } public DateTimeOffset CommentedAt { get; init; } = DateTimeOffset.Now; @@ -34,7 +34,7 @@ public void SetDeleted(string? userId) public void SetNotDeleted() { - DeletedAt = default; - DeletedById = default; + DeletedAt = null; + DeletedById = null; } } diff --git a/src/Domain/ComplianceEntities/Fces/Fce.cs b/src/Domain/ComplianceEntities/Fces/Fce.cs index 848c82e9..d04d305b 100644 --- a/src/Domain/ComplianceEntities/Fces/Fce.cs +++ b/src/Domain/ComplianceEntities/Fces/Fce.cs @@ -27,7 +27,7 @@ internal Fce(int? id, FacilityId facilityId, int year, ApplicationUser? user = n // FCE properties [StringLength(9)] - public string FacilityId { get; private set; } = string.Empty; + public string FacilityId { get; } = null!; public int Year { get; init; } public ApplicationUser? ReviewedBy { get; set; } @@ -35,7 +35,7 @@ internal Fce(int? id, FacilityId facilityId, int year, ApplicationUser? user = n public bool OnsiteInspection { get; set; } [StringLength(7000)] - public string Notes { get; set; } = string.Empty; + public string? Notes { get; set; } // Comments public List Comments { get; } = []; diff --git a/src/Domain/ComplianceEntities/IComplianceEntity.cs b/src/Domain/ComplianceEntities/IComplianceEntity.cs index 23c3b628..ba79ad78 100644 --- a/src/Domain/ComplianceEntities/IComplianceEntity.cs +++ b/src/Domain/ComplianceEntities/IComplianceEntity.cs @@ -3,6 +3,6 @@ namespace AirWeb.Domain.ComplianceEntities; public interface IComplianceEntity { public string FacilityId { get; } - public string Notes { get; } + public string? Notes { get; } public bool IsDeleted { get; } } diff --git a/src/Domain/ComplianceEntities/WorkEntries/BaseInspection.cs b/src/Domain/ComplianceEntities/WorkEntries/BaseInspection.cs index e48c6adc..4a9a0efe 100644 --- a/src/Domain/ComplianceEntities/WorkEntries/BaseInspection.cs +++ b/src/Domain/ComplianceEntities/WorkEntries/BaseInspection.cs @@ -25,10 +25,10 @@ protected BaseInspection(int? id, FacilityId facilityId, ApplicationUser? user) public DateTime InspectionEnded { get; set; } [StringLength(250)] - public string WeatherConditions { get; set; } = string.Empty; + public string? WeatherConditions { get; set; } [StringLength(250)] - public string InspectionGuide { get; set; } = string.Empty; + public string? InspectionGuide { get; set; } public bool FacilityOperating { get; set; } diff --git a/src/Domain/ComplianceEntities/WorkEntries/WorkEntry.cs b/src/Domain/ComplianceEntities/WorkEntries/WorkEntry.cs index b658f6d5..70250d7d 100644 --- a/src/Domain/ComplianceEntities/WorkEntries/WorkEntry.cs +++ b/src/Domain/ComplianceEntities/WorkEntries/WorkEntry.cs @@ -20,9 +20,9 @@ private protected WorkEntry(int? id, FacilityId facilityId, ApplicationUser? use // Properties: Basic data - [MaxLength(9)] - public string FacilityId { get; [UsedImplicitly] private init; } = string.Empty; - + [StringLength(9)] + public string FacilityId { get; } = null!; + [StringLength(29)] public WorkEntryType WorkEntryType { get; internal init; } @@ -30,7 +30,7 @@ private protected WorkEntry(int? id, FacilityId facilityId, ApplicationUser? use public DateOnly? AcknowledgmentLetterDate { get; set; } [StringLength(7000)] - public string Notes { get; set; } = string.Empty; + public string? Notes { get; set; } // Comments public List Comments { get; } = []; diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs index 8babbe71..f841ab4e 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs @@ -27,7 +27,7 @@ private protected EnforcementAction(Guid id, EnforcementCase enforcementCase, Ap public EnforcementActionType EnforcementActionType { get; protected init; } [StringLength(7000)] - public string Notes { get; set; } = string.Empty; + public string? Notes { get; set; } // Staff public ApplicationUser? ResponsibleStaff { get; set; } diff --git a/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs b/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs index 9b6a39e2..62d211ad 100644 --- a/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs +++ b/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs @@ -27,7 +27,7 @@ internal EnforcementCase(int? id, FacilityId facilityId, ApplicationUser? user) [StringLength(9)] public string FacilityId { get; private init; } = string.Empty; - private readonly Facility _facility = default!; + private readonly Facility _facility = null!; [NotMapped] public Facility Facility @@ -46,7 +46,7 @@ public Facility Facility public ApplicationUser? ResponsibleStaff { get; set; } [StringLength(7000)] - public string Notes { get; set; } = string.Empty; + public string? Notes { get; set; } [StringLength(5)] private string? ViolationTypeId { get; set; } diff --git a/src/IaipDataService/Facilities/Facility.cs b/src/IaipDataService/Facilities/Facility.cs index 0b496491..6dde6bd1 100644 --- a/src/IaipDataService/Facilities/Facility.cs +++ b/src/IaipDataService/Facilities/Facility.cs @@ -21,10 +21,10 @@ private Facility() { } // Used by ORM. // Description [Display(Name = "Facility name")] - public string Name { get; init; } = ""; + public string Name { get; init; } = null!; [Display(Name = "Description")] - public string Description { get; init; } = ""; + public string Description { get; init; } = null!; // Location diff --git a/src/IaipDataService/Facilities/FacilityId.cs b/src/IaipDataService/Facilities/FacilityId.cs index 77997110..cbf64173 100644 --- a/src/IaipDataService/Facilities/FacilityId.cs +++ b/src/IaipDataService/Facilities/FacilityId.cs @@ -5,7 +5,7 @@ namespace IaipDataService.Facilities; public partial record FacilityId : IComparable { - private readonly string? _id = string.Empty; + private readonly string? _id; // Constructor diff --git a/src/IaipDataService/SourceTests/Models/BaseSourceTestReport.cs b/src/IaipDataService/SourceTests/Models/BaseSourceTestReport.cs index bb07c996..6a4f9556 100644 --- a/src/IaipDataService/SourceTests/Models/BaseSourceTestReport.cs +++ b/src/IaipDataService/SourceTests/Models/BaseSourceTestReport.cs @@ -22,10 +22,10 @@ public abstract record BaseSourceTestReport public FacilitySummary? Facility { get; set; } [Display(Name = "Pollutant determined")] - public string Pollutant { get; init; } = ""; + public string Pollutant { get; init; } = null!; [Display(Name = "Source tested")] - public string Source { get; init; } = ""; + public string Source { get; init; } = null!; [JsonIgnore] public ReportType ReportType { get; init; } @@ -44,12 +44,12 @@ public abstract record BaseSourceTestReport }; [Display(Name = "Applicable requirement")] - public string ApplicableRequirement { get; init; } = ""; + public string ApplicableRequirement { get; init; } = null!; [Display(Name = "Other information")] - public string Comments { get; set; } = ""; + public string Comments { get; set; } = null!; - public string ReportStatement { get; init; } = ""; + public string ReportStatement { get; init; } = null!; public bool ReportClosed { get; init; } // Test report routing @@ -75,7 +75,7 @@ public abstract record BaseSourceTestReport public PersonName TestingUnitManager { get; set; } [Display(Name = "Director")] - public string EpdDirector { get; init; } = string.Empty; + public string EpdDirector { get; init; } = null!; #region Confidential info handling @@ -85,7 +85,7 @@ public abstract record BaseSourceTestReport // https://github.com/gaepdit/iaip/blob/main/IAIP/ISMP/ISMPConfidentialData.vb [JsonIgnore] - public string ConfidentialParametersCode { protected get; init; } = ""; + public string ConfidentialParametersCode { protected get; init; } = null!; public ICollection ConfidentialParameters { get; protected set; } = []; diff --git a/src/IaipDataService/SourceTests/Models/SourceTestMemorandum.cs b/src/IaipDataService/SourceTests/Models/SourceTestMemorandum.cs index e2158e41..9c6b39b7 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestMemorandum.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestMemorandum.cs @@ -9,10 +9,10 @@ public record SourceTestMemorandum : BaseSourceTestReport // Only used by MemorandumToFile [Display(Name = "Monitor manufacturer and model")] - public string MonitorManufacturer { get; set; } = ""; + public string MonitorManufacturer { get; set; } = null!; [Display(Name = "Monitor serial number")] - public string MonitorSerialNumber { get; set; } = ""; + public string MonitorSerialNumber { get; set; } = null!; // Only used by PTE [Display(Name = "Maximum expected operating capacity")] @@ -25,7 +25,7 @@ public record SourceTestMemorandum : BaseSourceTestReport public List AllowableEmissionRates { get; init; } = []; [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportFlare.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportFlare.cs index a1bbd35a..33c2f920 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportFlare.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportFlare.cs @@ -18,7 +18,7 @@ public record SourceTestReportFlare : BaseSourceTestReport public List AllowableEmissionRates { get; init; } = []; [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; // Test run data @@ -32,7 +32,7 @@ public record SourceTestReportFlare : BaseSourceTestReport public ValueWithUnits AvgEmissionRateVelocity { get; set; } [Display(Name = "Percent allowable")] - public string PercentAllowable { get; set; } = ""; + public string PercentAllowable { get; set; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportGasConcentration.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportGasConcentration.cs index 766cfd8e..9c1f682f 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportGasConcentration.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportGasConcentration.cs @@ -18,7 +18,7 @@ public record SourceTestReportGasConcentration : BaseSourceTestReport public List AllowableEmissionRates { get; init; } = []; [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; // Test run data @@ -32,7 +32,7 @@ public record SourceTestReportGasConcentration : BaseSourceTestReport public ValueWithUnits AvgEmissionRate { get; set; } [Display(Name = "Percent allowable")] - public string PercentAllowable { get; set; } = ""; + public string PercentAllowable { get; set; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportLoadingRack.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportLoadingRack.cs index 1d42b557..ff9fcf94 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportLoadingRack.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportLoadingRack.cs @@ -17,7 +17,7 @@ public record SourceTestReportLoadingRack : BaseSourceTestReport public List AllowableEmissionRates { get; init; } = []; [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; // Test run data diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportOneStack.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportOneStack.cs index d24f047a..7d534678 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportOneStack.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportOneStack.cs @@ -18,7 +18,7 @@ public record SourceTestReportOneStack : BaseSourceTestReport public List AllowableEmissionRates { get; init; } = []; [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; // Test run data @@ -32,7 +32,7 @@ public record SourceTestReportOneStack : BaseSourceTestReport public ValueWithUnits AvgEmissionRate { get; set; } [Display(Name = "Percent allowable")] - public string PercentAllowable { get; set; } = ""; + public string PercentAllowable { get; set; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportOpacity.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportOpacity.cs index 819d8994..29f6e2cd 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportOpacity.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportOpacity.cs @@ -8,33 +8,33 @@ public record SourceTestReportOpacity : BaseSourceTestReport // Operating data [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; [Display(Name = "Compliance status")] - public string ComplianceStatus { get; set; } = ""; + public string ComplianceStatus { get; set; } = null!; // `OpacityStandard` is used by "Method9Single" and "Method9Multi" // but not by "Method22" [Display(Name = "Opacity standard")] - public string OpacityStandard { get; set; } = ""; + public string OpacityStandard { get; set; } = null!; // `EquipmentItem` is used by "Method9Single" and "Method22" // but not by "Method9Multi" [Display(Name = "Test duration")] - public string TestDuration { get; set; } = ""; + public string TestDuration { get; set; } = null!; // Test run data [Display(Name = "Maximum expected operating capacity")] - public string MaxOperatingCapacityUnits { get; set; } = ""; + public string MaxOperatingCapacityUnits { get; set; } = null!; [Display(Name = "Operating capacity")] - public string OperatingCapacityUnits { get; set; } = ""; + public string OperatingCapacityUnits { get; set; } = null!; // `AllowableEmissionRateUnits` is used by "Method9Single" and "Method9Multi" // but not by "Method22" [Display(Name = "Allowable emission rate(s)")] - public string AllowableEmissionRateUnits { get; set; } = ""; + public string AllowableEmissionRateUnits { get; set; } = null!; [Display(Name = "Test runs")] public List TestRuns { get; set; } = []; diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportPondTreatment.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportPondTreatment.cs index 31246dcb..eb0764d7 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportPondTreatment.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportPondTreatment.cs @@ -15,7 +15,7 @@ public record SourceTestReportPondTreatment : BaseSourceTestReport public ValueWithUnits OperatingCapacity { get; set; } [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; // Test run data @@ -29,7 +29,7 @@ public record SourceTestReportPondTreatment : BaseSourceTestReport public ValueWithUnits AvgTreatmentRate { get; set; } [Display(Name = "Destruction efficiency")] - public string DestructionEfficiency { get; set; } = ""; + public string DestructionEfficiency { get; set; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportRata.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportRata.cs index 7576fde1..24efd276 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportRata.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportRata.cs @@ -7,25 +7,25 @@ namespace IaipDataService.SourceTests.Models; public record SourceTestReportRata : BaseSourceTestReport { [Display(Name = "Applicable standard")] - public string ApplicableStandard { get; set; } = ""; + public string ApplicableStandard { get; set; } = null!; [Display(Name = "Diluent monitored")] - public string Diluent { get; set; } = ""; + public string Diluent { get; set; } = null!; // Test run data [Display(Name = "Units")] - public string Units { get; set; } = ""; + public string Units { get; set; } = null!; [Display(Name = "Test data")] public List TestRuns { get; set; } = []; [Display(Name = "Accuracy choice")] // STRACCURACYCHOICE [JsonIgnore] - public string RelativeAccuracyCode { get; set; } = ""; + public string RelativeAccuracyCode { get; set; } = null!; [Display(Name = "Relative accuracy")] // STRRELATIVEACCURACYPERCENT - public string RelativeAccuracyPercent { get; set; } = ""; + public string RelativeAccuracyPercent { get; set; } = null!; public string RelativeAccuracyLabel => RelativeAccuracyCode switch @@ -37,13 +37,13 @@ public record SourceTestReportRata : BaseSourceTestReport }; [Display(Name = "Relative accuracy required")] // STRACCURACYREQUIREDPERCENT - public string RelativeAccuracyRequiredPercent { get; set; } = ""; + public string RelativeAccuracyRequiredPercent { get; set; } = null!; [Display(Name = "Relative accuracy required statement")] // STRACCURACYREQUIREDSTATEMENT - public string RelativeAccuracyRequiredLabel { get; set; } = ""; + public string RelativeAccuracyRequiredLabel { get; set; } = null!; [Display(Name = "Result")] - public string ComplianceStatus { get; set; } = ""; + public string ComplianceStatus { get; set; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/SourceTestReportTwoStack.cs b/src/IaipDataService/SourceTests/Models/SourceTestReportTwoStack.cs index 05275008..adddaf5f 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestReportTwoStack.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestReportTwoStack.cs @@ -18,12 +18,12 @@ public record SourceTestReportTwoStack : BaseSourceTestReport public List AllowableEmissionRates { get; init; } = []; [Display(Name = "Control equipment and monitoring data")] - public string ControlEquipmentInfo { get; set; } = ""; + public string ControlEquipmentInfo { get; set; } = null!; // Stacks - public string StackOneName { get; set; } = ""; - public string StackTwoName { get; set; } = ""; + public string StackOneName { get; set; } = null!; + public string StackTwoName { get; set; } = null!; [Display(Name = "Test runs")] public List TestRuns { get; set; } = []; @@ -44,11 +44,11 @@ public record SourceTestReportTwoStack : BaseSourceTestReport // `PercentAllowable` is only used by Two Stack (Standard) [Display(Name = "Percent allowable")] - public string PercentAllowable { get; set; } = ""; + public string PercentAllowable { get; set; } = null!; // `DestructionEfficiency` is only used by Two Stack (DRE) [Display(Name = "Destruction efficiency")] - public string DestructionEfficiency { get; set; } = ""; + public string DestructionEfficiency { get; set; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/SourceTestSummary.cs b/src/IaipDataService/SourceTests/Models/SourceTestSummary.cs index 2658e162..8bdd7de8 100644 --- a/src/IaipDataService/SourceTests/Models/SourceTestSummary.cs +++ b/src/IaipDataService/SourceTests/Models/SourceTestSummary.cs @@ -38,13 +38,13 @@ public SourceTestSummary(BaseSourceTestReport report) public FacilitySummary? Facility { get; set; } [Display(Name = "Source tested")] - public string Source { get; init; } = ""; + public string Source { get; init; } = null!; [Display(Name = "Pollutant determined")] - public string Pollutant { get; init; } = ""; + public string Pollutant { get; init; } = null!; [Display(Name = "Applicable requirement")] - public string ApplicableRequirement { get; init; } = ""; + public string ApplicableRequirement { get; init; } = null!; [Display(Name = "Status")] public bool ReportClosed { get; init; } diff --git a/src/IaipDataService/SourceTests/Models/TestRun/BaseTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/BaseTestRun.cs index 8415828d..11e2cc51 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/BaseTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/BaseTestRun.cs @@ -7,12 +7,12 @@ namespace IaipDataService.SourceTests.Models.TestRun; public abstract record BaseTestRun { [Display(Name = "Test run #")] - public string RunNumber { get; init; } = ""; + public string RunNumber { get; init; } = null!; #region Confidential info handling [JsonIgnore] - public string ConfidentialParametersCode { protected get; init; } = ""; + public string ConfidentialParametersCode { protected get; init; } = null!; protected ICollection ConfidentialParameters { get; set; } = new HashSet(); diff --git a/src/IaipDataService/SourceTests/Models/TestRun/FlareTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/FlareTestRun.cs index 398a8feb..fb82a1f1 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/FlareTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/FlareTestRun.cs @@ -5,10 +5,10 @@ namespace IaipDataService.SourceTests.Models.TestRun; public record FlareTestRun : BaseTestRun { [Display(Name = "Heating value")] - public string HeatingValue { get; init; } = ""; + public string HeatingValue { get; init; } = null!; [Display(Name = "Emission rate velocity")] - public string EmissionRateVelocity { get; init; } = ""; + public string EmissionRateVelocity { get; init; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/TestRun/GasConcentrationTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/GasConcentrationTestRun.cs index 693308e0..3da7c366 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/GasConcentrationTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/GasConcentrationTestRun.cs @@ -5,10 +5,10 @@ namespace IaipDataService.SourceTests.Models.TestRun; public record GasConcentrationTestRun : BaseTestRun { [Display(Name = "Pollutant concentration")] - public string PollutantConcentration { get; init; } = ""; + public string PollutantConcentration { get; init; } = null!; [Display(Name = "Emission rate")] - public string EmissionRate { get; init; } = ""; + public string EmissionRate { get; init; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/TestRun/OpacityTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/OpacityTestRun.cs index a150b17a..044c21ea 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/OpacityTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/OpacityTestRun.cs @@ -5,28 +5,28 @@ namespace IaipDataService.SourceTests.Models.TestRun; public record OpacityTestRun : BaseTestRun { [Display(Name = "Maximum expected operating capacity")] - public string MaxOperatingCapacity { get; init; } = ""; + public string MaxOperatingCapacity { get; init; } = null!; [Display(Name = "Operating capacity")] - public string OperatingCapacity { get; init; } = ""; + public string OperatingCapacity { get; init; } = null!; [Display(Name = "Allowable emission rate")] - public string AllowableEmissionRate { get; init; } = ""; + public string AllowableEmissionRate { get; init; } = null!; // `Opacity` is used by "Method 9 (Single)" and "Method 9 (Multi.)" // but not by "Method22" [Display(Name = "Opacity")] - public string Opacity { get; init; } = ""; + public string Opacity { get; init; } = null!; // `EquipmentItem` is used by "Method22" // but not by "Method 9 (Single)" or "Method 9 (Multi.)" [Display(Name = "Accumulated emission time")] - public string AccumulatedEmissionTime { get; init; } = ""; + public string AccumulatedEmissionTime { get; init; } = null!; // `EquipmentItem` is used by "Method 9 (Multi.)" // but not by "Method 9 (Single)" or "Method22" [Display(Name = "Equipment list")] - public string EquipmentItem { get; init; } = ""; + public string EquipmentItem { get; init; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/TestRun/PondTreatmentTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/PondTreatmentTestRun.cs index 7aabdb5f..3e6e6057 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/PondTreatmentTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/PondTreatmentTestRun.cs @@ -5,10 +5,10 @@ namespace IaipDataService.SourceTests.Models.TestRun; public record PondTreatmentTestRun : BaseTestRun { [Display(Name = "Pollutant collection rate")] - public string PollutantCollectionRate { get; init; } = ""; + public string PollutantCollectionRate { get; init; } = null!; [Display(Name = "Treatment rate")] - public string TreatmentRate { get; init; } = ""; + public string TreatmentRate { get; init; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/TestRun/RataTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/RataTestRun.cs index 3885179c..7c3ff8e3 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/RataTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/RataTestRun.cs @@ -5,10 +5,10 @@ namespace IaipDataService.SourceTests.Models.TestRun; public record RataTestRun : BaseTestRun { [Display(Name = "Reference method")] - public string ReferenceMethod { get; init; } = ""; + public string ReferenceMethod { get; init; } = null!; [Display(Name = "CMS")] - public string Cms { get; init; } = ""; + public string Cms { get; init; } = null!; public bool Omitted { get; init; } diff --git a/src/IaipDataService/SourceTests/Models/TestRun/StackTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/StackTestRun.cs index cf0095ba..9b032fdd 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/StackTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/StackTestRun.cs @@ -5,22 +5,22 @@ namespace IaipDataService.SourceTests.Models.TestRun; public record StackTestRun : BaseTestRun { [Display(Name = "Gas temperature")] - public string GasTemperature { get; init; } = ""; + public string GasTemperature { get; init; } = null!; [Display(Name = "Gas moisture")] - public string GasMoisture { get; init; } = ""; + public string GasMoisture { get; init; } = null!; [Display(Name = "Gas flow rate")] - public string GasFlowRateAcfm { get; init; } = ""; + public string GasFlowRateAcfm { get; init; } = null!; [Display(Name = "Gas flow rate")] - public string GasFlowRateDscfm { get; init; } = ""; + public string GasFlowRateDscfm { get; init; } = null!; [Display(Name = "Pollutant concentration")] - public string PollutantConcentration { get; init; } = ""; + public string PollutantConcentration { get; init; } = null!; [Display(Name = "Emission rate")] - public string EmissionRate { get; init; } = ""; + public string EmissionRate { get; init; } = null!; #region Confidential info handling diff --git a/src/IaipDataService/SourceTests/Models/TestRun/TwoStackTestRun.cs b/src/IaipDataService/SourceTests/Models/TestRun/TwoStackTestRun.cs index 39815fb1..4581db4d 100644 --- a/src/IaipDataService/SourceTests/Models/TestRun/TwoStackTestRun.cs +++ b/src/IaipDataService/SourceTests/Models/TestRun/TwoStackTestRun.cs @@ -8,41 +8,41 @@ public record TwoStackTestRun : BaseTestRun // The database and IAIP allow each stack to have different run numbers, // but only the Stack One run numbers are displayed in the report. // Stack Two run numbers are not used: - // `public string StackTwoRunNumber { get; init; } = "";` + // `public string StackTwoRunNumber { get; init; } = null!; [Display(Name = "Gas temperature")] - public string StackOneGasTemperature { get; init; } = ""; + public string StackOneGasTemperature { get; init; } = null!; - public string StackTwoGasTemperature { get; init; } = ""; + public string StackTwoGasTemperature { get; init; } = null!; [Display(Name = "Gas moisture")] - public string StackOneGasMoisture { get; init; } = ""; + public string StackOneGasMoisture { get; init; } = null!; - public string StackTwoGasMoisture { get; init; } = ""; + public string StackTwoGasMoisture { get; init; } = null!; [Display(Name = "Gas flow rate")] - public string StackOneGasFlowRateAcfm { get; init; } = ""; + public string StackOneGasFlowRateAcfm { get; init; } = null!; - public string StackTwoGasFlowRateAcfm { get; init; } = ""; + public string StackTwoGasFlowRateAcfm { get; init; } = null!; [Display(Name = "Gas flow rate")] - public string StackOneGasFlowRateDscfm { get; init; } = ""; + public string StackOneGasFlowRateDscfm { get; init; } = null!; - public string StackTwoGasFlowRateDscfm { get; init; } = ""; + public string StackTwoGasFlowRateDscfm { get; init; } = null!; [Display(Name = "Pollutant concentration")] - public string StackOnePollutantConcentration { get; init; } = ""; + public string StackOnePollutantConcentration { get; init; } = null!; - public string StackTwoPollutantConcentration { get; init; } = ""; + public string StackTwoPollutantConcentration { get; init; } = null!; [Display(Name = "Emission rate")] - public string StackOneEmissionRate { get; init; } = ""; + public string StackOneEmissionRate { get; init; } = null!; - public string StackTwoEmissionRate { get; init; } = ""; + public string StackTwoEmissionRate { get; init; } = null!; // `SumEmissionRate` is used by Two Stack (Standard) but not by Two Stack (DRE) [Display(Name = "Total")] - public string SumEmissionRate { get; init; } = ""; + public string SumEmissionRate { get; init; } = null!; #region Confidential info handling diff --git a/tests/EfRepositoryTests/ComplianceSearch/CountTests.cs b/tests/EfRepositoryTests/ComplianceSearch/CountTests.cs index 1ad474fc..7417c775 100644 --- a/tests/EfRepositoryTests/ComplianceSearch/CountTests.cs +++ b/tests/EfRepositoryTests/ComplianceSearch/CountTests.cs @@ -8,7 +8,7 @@ namespace EfRepositoryTests.ComplianceSearch; public class CountTests { - private ComplianceSearchRepository _repository = default!; + private ComplianceSearchRepository _repository = null!; private readonly Expression> _workEntryTrueExpression = f => true; private readonly Expression> _workEntryNotDeletedExpression = f => !f.IsDeleted; private readonly Expression> _fceTrueExpression = f => true; diff --git a/tests/EfRepositoryTests/ComplianceSearch/FilterTests.cs b/tests/EfRepositoryTests/ComplianceSearch/FilterTests.cs index ea4f2aaf..467999c0 100644 --- a/tests/EfRepositoryTests/ComplianceSearch/FilterTests.cs +++ b/tests/EfRepositoryTests/ComplianceSearch/FilterTests.cs @@ -9,7 +9,7 @@ namespace EfRepositoryTests.ComplianceSearch; public class FilterTests { - private ComplianceSearchRepository _repository = default!; + private ComplianceSearchRepository _repository = null!; private readonly Expression> _workEntryTrueExpression = f => true; private readonly Expression> _workEntryNotDeletedExpression = f => !f.IsDeleted; private readonly Expression> _fceTrueExpression = f => true; diff --git a/tests/EfRepositoryTests/Fces/ExistsTests.cs b/tests/EfRepositoryTests/Fces/ExistsTests.cs index 8bce79b5..11961c1c 100644 --- a/tests/EfRepositoryTests/Fces/ExistsTests.cs +++ b/tests/EfRepositoryTests/Fces/ExistsTests.cs @@ -6,7 +6,7 @@ namespace EfRepositoryTests.Fces; public class ExistsTests { - private FceRepository _repository = default!; + private FceRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetFceRepository(); diff --git a/tests/EfRepositoryTests/Fces/FindIncludeProperty.cs b/tests/EfRepositoryTests/Fces/FindIncludeProperty.cs index e99a1adb..6ca27fbc 100644 --- a/tests/EfRepositoryTests/Fces/FindIncludeProperty.cs +++ b/tests/EfRepositoryTests/Fces/FindIncludeProperty.cs @@ -6,7 +6,7 @@ namespace EfRepositoryTests.Fces; public class FindIncludeProperty { - private FceRepository _repository = default!; + private FceRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetFceRepository(); diff --git a/tests/EfRepositoryTests/Fces/GetIncludeProperty.cs b/tests/EfRepositoryTests/Fces/GetIncludeProperty.cs index cfe35c74..ca59b390 100644 --- a/tests/EfRepositoryTests/Fces/GetIncludeProperty.cs +++ b/tests/EfRepositoryTests/Fces/GetIncludeProperty.cs @@ -6,7 +6,7 @@ namespace EfRepositoryTests.Fces; public class GetIncludeProperty { - private FceRepository _repository = default!; + private FceRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetFceRepository(); diff --git a/tests/EfRepositoryTests/Fces/GetNextId.cs b/tests/EfRepositoryTests/Fces/GetNextId.cs index 2c01734b..dbb7cbe0 100644 --- a/tests/EfRepositoryTests/Fces/GetNextId.cs +++ b/tests/EfRepositoryTests/Fces/GetNextId.cs @@ -5,7 +5,7 @@ namespace EfRepositoryTests.Fces; public class GetNextId { - private FceRepository _repository = default!; + private FceRepository _repository = null!; [TearDown] public void TearDown() => _repository.Dispose(); diff --git a/tests/EfRepositoryTests/Offices/GetActiveStaffMembersList.cs b/tests/EfRepositoryTests/Offices/GetActiveStaffMembersList.cs index 4fde59da..cfec3552 100644 --- a/tests/EfRepositoryTests/Offices/GetActiveStaffMembersList.cs +++ b/tests/EfRepositoryTests/Offices/GetActiveStaffMembersList.cs @@ -5,7 +5,7 @@ namespace EfRepositoryTests.Offices; public class GetActiveStaffMembersList { - private OfficeRepository _repository = default!; + private OfficeRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetOfficeRepository(); diff --git a/tests/EfRepositoryTests/RepositoryHelper.cs b/tests/EfRepositoryTests/RepositoryHelper.cs index cd1da9cf..cb91d8ce 100644 --- a/tests/EfRepositoryTests/RepositoryHelper.cs +++ b/tests/EfRepositoryTests/RepositoryHelper.cs @@ -26,7 +26,7 @@ namespace EfRepositoryTests; /// public sealed class RepositoryHelper : IDisposable, IAsyncDisposable { - public AppDbContext Context { get; private set; } = default!; + public AppDbContext Context { get; private set; } = null!; private readonly DbContextOptions _options; private readonly AppDbContext _context; diff --git a/tests/EfRepositoryTests/WorkEntries/FindIncludeProperty.cs b/tests/EfRepositoryTests/WorkEntries/FindIncludeProperty.cs index b1e8fdd4..f4bc5f8d 100644 --- a/tests/EfRepositoryTests/WorkEntries/FindIncludeProperty.cs +++ b/tests/EfRepositoryTests/WorkEntries/FindIncludeProperty.cs @@ -6,7 +6,7 @@ namespace EfRepositoryTests.WorkEntries; public class FindIncludeProperty { - private WorkEntryRepository _repository = default!; + private WorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetWorkEntryRepository(); diff --git a/tests/EfRepositoryTests/WorkEntries/FindOfType.cs b/tests/EfRepositoryTests/WorkEntries/FindOfType.cs index d5bd3a20..9445e3e5 100644 --- a/tests/EfRepositoryTests/WorkEntries/FindOfType.cs +++ b/tests/EfRepositoryTests/WorkEntries/FindOfType.cs @@ -6,7 +6,7 @@ namespace EfRepositoryTests.WorkEntries; public class FindOfType { - private WorkEntryRepository _repository = default!; + private WorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetWorkEntryRepository(); diff --git a/tests/EfRepositoryTests/WorkEntries/FindWorkEntry.cs b/tests/EfRepositoryTests/WorkEntries/FindWorkEntry.cs index 8a1b881a..cf55b8b0 100644 --- a/tests/EfRepositoryTests/WorkEntries/FindWorkEntry.cs +++ b/tests/EfRepositoryTests/WorkEntries/FindWorkEntry.cs @@ -5,7 +5,7 @@ namespace EfRepositoryTests.WorkEntries; public class FindWorkEntry { - private WorkEntryRepository _repository = default!; + private WorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetWorkEntryRepository(); diff --git a/tests/EfRepositoryTests/WorkEntries/GetIncludeProperty.cs b/tests/EfRepositoryTests/WorkEntries/GetIncludeProperty.cs index 1ce8eaa5..9602473c 100644 --- a/tests/EfRepositoryTests/WorkEntries/GetIncludeProperty.cs +++ b/tests/EfRepositoryTests/WorkEntries/GetIncludeProperty.cs @@ -6,7 +6,7 @@ namespace EfRepositoryTests.WorkEntries; public class GetIncludeProperty { - private WorkEntryRepository _repository = default!; + private WorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetWorkEntryRepository(); diff --git a/tests/EfRepositoryTests/WorkEntries/GetNextId.cs b/tests/EfRepositoryTests/WorkEntries/GetNextId.cs index 7b97be2e..7004720f 100644 --- a/tests/EfRepositoryTests/WorkEntries/GetNextId.cs +++ b/tests/EfRepositoryTests/WorkEntries/GetNextId.cs @@ -5,7 +5,7 @@ namespace EfRepositoryTests.WorkEntries; public class GetNextId { - private WorkEntryRepository _repository = default!; + private WorkEntryRepository _repository = null!; [TearDown] public void TearDown() => _repository.Dispose(); diff --git a/tests/EfRepositoryTests/WorkEntries/GetNotificationType.cs b/tests/EfRepositoryTests/WorkEntries/GetNotificationType.cs index d4abe75a..f2bc1b59 100644 --- a/tests/EfRepositoryTests/WorkEntries/GetNotificationType.cs +++ b/tests/EfRepositoryTests/WorkEntries/GetNotificationType.cs @@ -5,7 +5,7 @@ namespace EfRepositoryTests.WorkEntries; public class GetNotificationType { - private WorkEntryRepository _repository = default!; + private WorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetWorkEntryRepository(); diff --git a/tests/EfRepositoryTests/WorkEntries/GetWorkEntryType.cs b/tests/EfRepositoryTests/WorkEntries/GetWorkEntryType.cs index 2aa3aa44..6536ee3c 100644 --- a/tests/EfRepositoryTests/WorkEntries/GetWorkEntryType.cs +++ b/tests/EfRepositoryTests/WorkEntries/GetWorkEntryType.cs @@ -6,7 +6,7 @@ namespace EfRepositoryTests.WorkEntries; public class GetWorkEntryType { - private WorkEntryRepository _repository = default!; + private WorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.CreateRepositoryHelper().GetWorkEntryRepository(); diff --git a/tests/LocalRepositoryTests/ComplianceSearch/CountTests.cs b/tests/LocalRepositoryTests/ComplianceSearch/CountTests.cs index ab158168..2301006c 100644 --- a/tests/LocalRepositoryTests/ComplianceSearch/CountTests.cs +++ b/tests/LocalRepositoryTests/ComplianceSearch/CountTests.cs @@ -7,9 +7,9 @@ namespace LocalRepositoryTests.ComplianceSearch; public class CountTests { - private LocalFceRepository _fceRepository = default!; - private LocalWorkEntryRepository _entryRepository = default!; - private LocalComplianceSearchRepository _repository = default!; + private LocalFceRepository _fceRepository = null!; + private LocalWorkEntryRepository _entryRepository = null!; + private LocalComplianceSearchRepository _repository = null!; private readonly Expression> _workEntryTrueExpression = f => true; private readonly Expression> _workEntryNotDeletedExpression = f => !f.IsDeleted; diff --git a/tests/LocalRepositoryTests/ComplianceSearch/FilterTests.cs b/tests/LocalRepositoryTests/ComplianceSearch/FilterTests.cs index 0e9ca25c..b93e1315 100644 --- a/tests/LocalRepositoryTests/ComplianceSearch/FilterTests.cs +++ b/tests/LocalRepositoryTests/ComplianceSearch/FilterTests.cs @@ -8,9 +8,9 @@ namespace LocalRepositoryTests.ComplianceSearch; public class FilterTests { - private LocalFceRepository _fceRepository = default!; - private LocalWorkEntryRepository _entryRepository = default!; - private LocalComplianceSearchRepository _repository = default!; + private LocalFceRepository _fceRepository = null!; + private LocalWorkEntryRepository _entryRepository = null!; + private LocalComplianceSearchRepository _repository = null!; private readonly Expression> _workEntryTrueExpression = f => true; private readonly Expression> _workEntryNotDeletedExpression = f => !f.IsDeleted; diff --git a/tests/LocalRepositoryTests/Fces/ExistsTests.cs b/tests/LocalRepositoryTests/Fces/ExistsTests.cs index 6d7a359c..d9db3cb5 100644 --- a/tests/LocalRepositoryTests/Fces/ExistsTests.cs +++ b/tests/LocalRepositoryTests/Fces/ExistsTests.cs @@ -6,7 +6,7 @@ namespace LocalRepositoryTests.Fces; public class ExistsTests { - private LocalFceRepository _repository = default!; + private LocalFceRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.GetFceRepository(); diff --git a/tests/LocalRepositoryTests/Fces/GetNextId.cs b/tests/LocalRepositoryTests/Fces/GetNextId.cs index 150ffb2c..e2afd00c 100644 --- a/tests/LocalRepositoryTests/Fces/GetNextId.cs +++ b/tests/LocalRepositoryTests/Fces/GetNextId.cs @@ -4,7 +4,7 @@ namespace LocalRepositoryTests.Fces; public class GetNextId { - private LocalFceRepository _repository = default!; + private LocalFceRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.GetFceRepository(); diff --git a/tests/LocalRepositoryTests/Identity/RoleStore.cs b/tests/LocalRepositoryTests/Identity/RoleStore.cs index 9d5d9b39..2eb9f0ce 100644 --- a/tests/LocalRepositoryTests/Identity/RoleStore.cs +++ b/tests/LocalRepositoryTests/Identity/RoleStore.cs @@ -5,7 +5,7 @@ namespace LocalRepositoryTests.Identity; public class RoleStore { - private static LocalRoleStore _store = default!; + private static LocalRoleStore _store = null!; [SetUp] public void SetUp() => _store = new LocalRoleStore(); diff --git a/tests/LocalRepositoryTests/Identity/UserRoleStore.cs b/tests/LocalRepositoryTests/Identity/UserRoleStore.cs index 579a45fb..2a7be665 100644 --- a/tests/LocalRepositoryTests/Identity/UserRoleStore.cs +++ b/tests/LocalRepositoryTests/Identity/UserRoleStore.cs @@ -6,7 +6,7 @@ namespace LocalRepositoryTests.Identity; public class UserRoleStore { - private LocalUserStore _store = default!; + private LocalUserStore _store = null!; [SetUp] public void SetUp() => _store = RepositoryHelper.GetUserStore(); diff --git a/tests/LocalRepositoryTests/Identity/UserStore.cs b/tests/LocalRepositoryTests/Identity/UserStore.cs index 37093000..9d984f71 100644 --- a/tests/LocalRepositoryTests/Identity/UserStore.cs +++ b/tests/LocalRepositoryTests/Identity/UserStore.cs @@ -10,7 +10,7 @@ namespace LocalRepositoryTests.Identity; public class UserStore { - private LocalUserStore _store = default!; + private LocalUserStore _store = null!; [SetUp] public void SetUp() => _store = RepositoryHelper.GetUserStore(); diff --git a/tests/LocalRepositoryTests/Offices/GetActiveStaffMembersList.cs b/tests/LocalRepositoryTests/Offices/GetActiveStaffMembersList.cs index 6c6126b3..50acf856 100644 --- a/tests/LocalRepositoryTests/Offices/GetActiveStaffMembersList.cs +++ b/tests/LocalRepositoryTests/Offices/GetActiveStaffMembersList.cs @@ -4,7 +4,7 @@ namespace LocalRepositoryTests.Offices; public class GetActiveStaffMembersList { - private LocalOfficeRepository _repository = default!; + private LocalOfficeRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.GetOfficeRepository(); diff --git a/tests/LocalRepositoryTests/WorkEntries/FindWorkEntry.cs b/tests/LocalRepositoryTests/WorkEntries/FindWorkEntry.cs index 1d4e9680..8017eaf1 100644 --- a/tests/LocalRepositoryTests/WorkEntries/FindWorkEntry.cs +++ b/tests/LocalRepositoryTests/WorkEntries/FindWorkEntry.cs @@ -5,7 +5,7 @@ namespace LocalRepositoryTests.WorkEntries; public class FindWorkEntry { - private LocalWorkEntryRepository _repository = default!; + private LocalWorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.GetWorkEntryRepository(); diff --git a/tests/LocalRepositoryTests/WorkEntries/GetNextId.cs b/tests/LocalRepositoryTests/WorkEntries/GetNextId.cs index 673df933..4a91759f 100644 --- a/tests/LocalRepositoryTests/WorkEntries/GetNextId.cs +++ b/tests/LocalRepositoryTests/WorkEntries/GetNextId.cs @@ -4,7 +4,7 @@ namespace LocalRepositoryTests.WorkEntries; public class GetNextId { - private LocalWorkEntryRepository _repository = default!; + private LocalWorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.GetWorkEntryRepository(); diff --git a/tests/LocalRepositoryTests/WorkEntries/GetNotificationType.cs b/tests/LocalRepositoryTests/WorkEntries/GetNotificationType.cs index 578aef3f..c6afae52 100644 --- a/tests/LocalRepositoryTests/WorkEntries/GetNotificationType.cs +++ b/tests/LocalRepositoryTests/WorkEntries/GetNotificationType.cs @@ -5,7 +5,7 @@ namespace LocalRepositoryTests.WorkEntries; public class GetNotificationType { - private LocalWorkEntryRepository _repository = default!; + private LocalWorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.GetWorkEntryRepository(); diff --git a/tests/LocalRepositoryTests/WorkEntries/GetWorkEntryType.cs b/tests/LocalRepositoryTests/WorkEntries/GetWorkEntryType.cs index b71963fa..dec49f01 100644 --- a/tests/LocalRepositoryTests/WorkEntries/GetWorkEntryType.cs +++ b/tests/LocalRepositoryTests/WorkEntries/GetWorkEntryType.cs @@ -6,7 +6,7 @@ namespace LocalRepositoryTests.WorkEntries; public class GetWorkEntryType { - private LocalWorkEntryRepository _repository = default!; + private LocalWorkEntryRepository _repository = null!; [SetUp] public void SetUp() => _repository = RepositoryHelper.GetWorkEntryRepository(); From a8c733f9069eb5a83966a2ebfc7141561d64353d Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Tue, 17 Dec 2024 09:31:20 -0500 Subject: [PATCH 04/13] Rename CaseFile entity --- .../WorkEntries/ComplianceEvent.cs | 4 +- .../Actions/AdministrativeOrder.cs | 4 +- .../Actions/AoResolvedLetter.cs | 2 +- .../Actions/CoResolvedLetter.cs | 2 +- .../Actions/ConsentOrder.cs | 6 +- .../Actions/EnforcementAction.cs | 6 +- .../Actions/EnforcementLetter.cs | 4 +- .../Actions/LetterOfNoncompliance.cs | 4 +- .../Actions/NoFurtherActionLetter.cs | 2 +- .../Actions/NoticeOfViolation.cs | 4 +- .../Actions/NovNfaLetter.cs | 4 +- .../Actions/ProposedConsentOrder.cs | 6 +- .../Cases/{EnforcementCase.cs => CaseFile.cs} | 65 ++++++++++--------- .../Cases/CaseFileComment.cs | 13 ++++ .../Cases/EnforcementCaseComment.cs | 13 ---- src/EfRepository/DbContext/AppDbContext.cs | 4 +- .../AppDbContextConfiguration.cs | 10 +-- .../DbContext/DevData/DbSeedDataHelpers.cs | 2 +- ...EnforcementCaseData.cs => CaseFileData.cs} | 38 +++++------ .../Enforcement/EnforcementActionData.cs | 32 ++++----- tests/EfRepositoryTests/RepositoryHelper.cs | 2 +- 21 files changed, 117 insertions(+), 110 deletions(-) rename src/Domain/EnforcementEntities/Cases/{EnforcementCase.cs => CaseFile.cs} (69%) create mode 100644 src/Domain/EnforcementEntities/Cases/CaseFileComment.cs delete mode 100644 src/Domain/EnforcementEntities/Cases/EnforcementCaseComment.cs rename src/TestData/Enforcement/{EnforcementCaseData.cs => CaseFileData.cs} (81%) diff --git a/src/Domain/ComplianceEntities/WorkEntries/ComplianceEvent.cs b/src/Domain/ComplianceEntities/WorkEntries/ComplianceEvent.cs index fd61ebf4..166b2d40 100644 --- a/src/Domain/ComplianceEntities/WorkEntries/ComplianceEvent.cs +++ b/src/Domain/ComplianceEntities/WorkEntries/ComplianceEvent.cs @@ -11,10 +11,10 @@ public abstract class ComplianceEvent : WorkEntry [UsedImplicitly] // Used by ORM. private protected ComplianceEvent() { } - private protected ComplianceEvent(int? id, FacilityId facilityId, ApplicationUser? user) + private protected ComplianceEvent(int? id, FacilityId facilityId, ApplicationUser? user) : base(id, facilityId, user) { } - public ICollection EnforcementCases { get; } = []; + public ICollection CaseFiles { get; } = []; // Data exchange properties public bool IsDataFlowEnabled => IsClosed && !IsDeleted && WorkEntryType != WorkEntryType.RmpInspection; diff --git a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs index 85e3cacc..c920ad2e 100644 --- a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs @@ -9,8 +9,8 @@ public class AdministrativeOrder : EnforcementAction [UsedImplicitly] // Used by ORM. private AdministrativeOrder() { } - internal AdministrativeOrder(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) : - base(id, enforcementCase, user) + internal AdministrativeOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : + base(id, caseFile, user) { EnforcementActionType = EnforcementActionType.AdministrativeOrder; } diff --git a/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs b/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs index 354c407c..e14391a2 100644 --- a/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs @@ -9,7 +9,7 @@ public class AoResolvedLetter : EnforcementAction private AoResolvedLetter() { } internal AoResolvedLetter(Guid id, AdministrativeOrder administrativeOrder, ApplicationUser? user) - : base(id, administrativeOrder.EnforcementCase, user) + : base(id, administrativeOrder.CaseFile, user) { EnforcementActionType = EnforcementActionType.AoResolvedLetter; AdministrativeOrder = administrativeOrder; diff --git a/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs b/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs index 7a3b94f7..c7a68d38 100644 --- a/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs @@ -9,7 +9,7 @@ public class CoResolvedLetter : EnforcementAction private CoResolvedLetter() { } internal CoResolvedLetter(Guid id, ConsentOrder consentOrder, ApplicationUser? user) - : base(id, consentOrder.EnforcementCase, user) + : base(id, consentOrder.CaseFile, user) { EnforcementActionType = EnforcementActionType.CoResolvedLetter; ConsentOrder = consentOrder; diff --git a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs index 7ef7184a..eb267649 100644 --- a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs @@ -12,14 +12,14 @@ public class ConsentOrder : EnforcementAction private ConsentOrder() { } internal ConsentOrder(Guid id, ProposedConsentOrder proposedConsentOrder, ApplicationUser? user) : - base(id, proposedConsentOrder.EnforcementCase, user) + base(id, proposedConsentOrder.CaseFile, user) { EnforcementActionType = EnforcementActionType.ConsentOrder; ProposedConsentOrder = proposedConsentOrder; } - internal ConsentOrder(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) : - base(id, enforcementCase, user) + internal ConsentOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : + base(id, caseFile, user) { EnforcementActionType = EnforcementActionType.ConsentOrder; } diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs index f841ab4e..3d6b8e99 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs @@ -15,15 +15,15 @@ public abstract class EnforcementAction : DeletableEntity [UsedImplicitly] // Used by ORM. private protected EnforcementAction() { } - private protected EnforcementAction(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) + private protected EnforcementAction(Guid id, CaseFile caseFile, ApplicationUser? user) { Id = id; - EnforcementCase = enforcementCase; + CaseFile = caseFile; SetCreator(user?.Id); } // Basic data - public EnforcementCase EnforcementCase { get; init; } = null!; + public CaseFile CaseFile { get; init; } = null!; public EnforcementActionType EnforcementActionType { get; protected init; } [StringLength(7000)] diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs b/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs index 7a66bf37..1fff37e0 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs @@ -9,8 +9,8 @@ public class EnforcementLetter : EnforcementAction [UsedImplicitly] // Used by ORM. private EnforcementLetter() { } - internal EnforcementLetter(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) - : base(id, enforcementCase, user) + internal EnforcementLetter(Guid id, CaseFile caseFile, ApplicationUser? user) + : base(id, caseFile, user) { EnforcementActionType = EnforcementActionType.EnforcementLetter; } diff --git a/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs b/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs index ee7bdf4b..b31c570d 100644 --- a/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs +++ b/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs @@ -9,8 +9,8 @@ public class LetterOfNoncompliance : EnforcementAction [UsedImplicitly] // Used by ORM. private LetterOfNoncompliance() { } - internal LetterOfNoncompliance(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) - : base(id, enforcementCase, user) + internal LetterOfNoncompliance(Guid id, CaseFile caseFile, ApplicationUser? user) + : base(id, caseFile, user) { EnforcementActionType = EnforcementActionType.LetterOfNoncompliance; } diff --git a/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs b/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs index c5f264e7..65de8d6b 100644 --- a/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs @@ -9,7 +9,7 @@ public class NoFurtherActionLetter : EnforcementAction private NoFurtherActionLetter() { } internal NoFurtherActionLetter(Guid id, NoticeOfViolation noticeOfViolation, ApplicationUser? user) - : base(id, noticeOfViolation.EnforcementCase, user) + : base(id, noticeOfViolation.CaseFile, user) { EnforcementActionType = EnforcementActionType.NoFurtherAction; NoticeOfViolation = noticeOfViolation; diff --git a/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs b/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs index 8434d545..f57cc19f 100644 --- a/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs +++ b/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs @@ -9,8 +9,8 @@ public class NoticeOfViolation : EnforcementAction [UsedImplicitly] // Used by ORM. private NoticeOfViolation() { } - internal NoticeOfViolation(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) - : base(id, enforcementCase, user) + internal NoticeOfViolation(Guid id, CaseFile caseFile, ApplicationUser? user) + : base(id, caseFile, user) { EnforcementActionType = EnforcementActionType.NoticeOfViolation; } diff --git a/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs b/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs index ea079839..be09cc01 100644 --- a/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs @@ -9,8 +9,8 @@ public class NovNfaLetter : EnforcementAction [UsedImplicitly] // Used by ORM. private NovNfaLetter() { } - internal NovNfaLetter(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) - : base(id, enforcementCase, user) + internal NovNfaLetter(Guid id, CaseFile caseFile, ApplicationUser? user) + : base(id, caseFile, user) { EnforcementActionType = EnforcementActionType.NovNfaLetter; } diff --git a/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs b/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs index 6890d09e..3aac842c 100644 --- a/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs @@ -10,14 +10,14 @@ public class ProposedConsentOrder : EnforcementAction private ProposedConsentOrder() { } internal ProposedConsentOrder(Guid id, NoticeOfViolation noticeOfViolation, ApplicationUser? user) : - base(id, noticeOfViolation.EnforcementCase, user) + base(id, noticeOfViolation.CaseFile, user) { EnforcementActionType = EnforcementActionType.ProposedConsentOrder; NoticeOfViolation = noticeOfViolation; } - internal ProposedConsentOrder(Guid id, EnforcementCase enforcementCase, ApplicationUser? user) : - base(id, enforcementCase, user) + internal ProposedConsentOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : + base(id, caseFile, user) { EnforcementActionType = EnforcementActionType.ProposedConsentOrder; } diff --git a/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs b/src/Domain/EnforcementEntities/Cases/CaseFile.cs similarity index 69% rename from src/Domain/EnforcementEntities/Cases/EnforcementCase.cs rename to src/Domain/EnforcementEntities/Cases/CaseFile.cs index 62d211ad..429677a3 100644 --- a/src/Domain/EnforcementEntities/Cases/EnforcementCase.cs +++ b/src/Domain/EnforcementEntities/Cases/CaseFile.cs @@ -1,4 +1,4 @@ -using AirWeb.Domain.BaseEntities; +using AirWeb.Domain.BaseEntities; using AirWeb.Domain.ComplianceEntities.WorkEntries; using AirWeb.Domain.Data; using AirWeb.Domain.DataExchange; @@ -10,47 +10,33 @@ namespace AirWeb.Domain.EnforcementEntities.Cases; -public class EnforcementCase : ClosableEntity +public class CaseFile : ClosableEntity { // Constructors [UsedImplicitly] // Used by ORM. - private EnforcementCase() { } + private CaseFile() { } - internal EnforcementCase(int? id, FacilityId facilityId, ApplicationUser? user) + internal CaseFile(int? id, FacilityId facilityId, ApplicationUser? user) { if (id is not null) Id = id.Value; FacilityId = facilityId; SetCreator(user?.Id); } - // Facility properties - [StringLength(9)] - public string FacilityId { get; private init; } = string.Empty; - - private readonly Facility _facility = null!; - - [NotMapped] - public Facility Facility - { - get => _facility; - init - { - _facility = value; - FacilityId = value.Id; - } - } - // Basic data - // Required but nullable for historical data. - public ApplicationUser? ResponsibleStaff { get; set; } + [StringLength(9)] + public string FacilityId { get; } = null!; - [StringLength(7000)] - public string? Notes { get; set; } + // Required for new cases but nullable for historical data. + public ApplicationUser? ResponsibleStaff { get; set; } [StringLength(5)] private string? ViolationTypeId { get; set; } + [StringLength(7000)] + public string? Notes { get; set; } + [NotMapped] // Required if the data flow is enabled. public ViolationType? ViolationType @@ -64,7 +50,28 @@ public ViolationType? ViolationType [StringLength(27)] public EnforcementCaseStatus Status { get; set; } - // Required but nullable for historical data. + public EnforcementCaseStatus StatusCalc + { + // TODO: Review the logic for this property. + get + { + if (IsClosed) return EnforcementCaseStatus.CaseClosed; + + if (EnforcementActions.Exists(action => + action.EnforcementActionType is EnforcementActionType.ConsentOrder + or EnforcementActionType.AdministrativeOrder && + action.IsIssued)) + { + return EnforcementActions.Exists(action => !((IResolvable)action).IsResolved) + ? EnforcementCaseStatus.SubjectToComplianceSchedule + : EnforcementCaseStatus.CaseResolved; + } + + return EnforcementCaseStatus.CaseOpen; + } + } + + // Required for new cases but nullable for historical data. public DateOnly? DiscoveryDate { get; set; } private DateOnly? MaxDayZero => DiscoveryDate?.AddDays(90); @@ -92,11 +99,11 @@ public ICollection GetPollutants() => CommonData.AllPollutants public List AirPrograms { get; } = []; // Comments - public List Comments { get; } = []; + public List Comments { get; } = []; // Compliance Event & Enforcement Action relationships public ICollection ComplianceEvents { get; } = []; - public ICollection EnforcementActions { get; } = []; + public List EnforcementActions { get; } = []; // Data flow properties @@ -104,7 +111,7 @@ public ICollection GetPollutants() => CommonData.AllPollutants // or Cases where the only linked compliance event is an RMP inspection. public bool IsDataFlowEnabled => ComplianceEvents.Any(complianceEvent => complianceEvent.IsDataFlowEnabled) && - EnforcementActions.Any(action => action.IsDataFlowEnabled); + EnforcementActions.Exists(action => action.IsDataFlowEnabled); // Required if the data flow is enabled. public short? ActionNumber { get; set; } diff --git a/src/Domain/EnforcementEntities/Cases/CaseFileComment.cs b/src/Domain/EnforcementEntities/Cases/CaseFileComment.cs new file mode 100644 index 00000000..431cff49 --- /dev/null +++ b/src/Domain/EnforcementEntities/Cases/CaseFileComment.cs @@ -0,0 +1,13 @@ +using AirWeb.Domain.Comments; + +namespace AirWeb.Domain.EnforcementEntities.Cases; + +public record CaseFileComment : Comment +{ + [UsedImplicitly] // Used by ORM. + private CaseFileComment() { } + + private CaseFileComment(Comment c) : base(c) { } + public CaseFileComment(Comment c, int caseFileId) : this(c) => CaseFileId = caseFileId; + public int CaseFileId { get; init; } +} diff --git a/src/Domain/EnforcementEntities/Cases/EnforcementCaseComment.cs b/src/Domain/EnforcementEntities/Cases/EnforcementCaseComment.cs deleted file mode 100644 index b7c2b550..00000000 --- a/src/Domain/EnforcementEntities/Cases/EnforcementCaseComment.cs +++ /dev/null @@ -1,13 +0,0 @@ -using AirWeb.Domain.Comments; - -namespace AirWeb.Domain.EnforcementEntities.Cases; - -public record EnforcementCaseComment : Comment -{ - [UsedImplicitly] // Used by ORM. - private EnforcementCaseComment() { } - - private EnforcementCaseComment(Comment c) : base(c) { } - public EnforcementCaseComment(Comment c, int enforcementCaseId) : this(c) => EnforcementCaseId = enforcementCaseId; - public int EnforcementCaseId { get; init; } -} diff --git a/src/EfRepository/DbContext/AppDbContext.cs b/src/EfRepository/DbContext/AppDbContext.cs index 31fde176..e51f7795 100644 --- a/src/EfRepository/DbContext/AppDbContext.cs +++ b/src/EfRepository/DbContext/AppDbContext.cs @@ -40,7 +40,7 @@ public class AppDbContext(DbContextOptions options) : IdentityDbCo public DbSet SourceTestReviews => Set(); // Enforcement - Cases - public DbSet EnforcementCases => Set(); + public DbSet EnforcementCases => Set(); // Enforcement - Actions public DbSet AdministrativeOrders => Set(); @@ -61,7 +61,7 @@ public class AppDbContext(DbContextOptions options) : IdentityDbCo // Comments public DbSet FceComments => Set(); public DbSet WorkEntryComments => Set(); - public DbSet EnforcementCaseComments => Set(); + public DbSet EnforcementCaseComments => Set(); // Ancillary tables public DbSet EmailLogs => Set(); diff --git a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs index d9243b62..6a42ed4e 100644 --- a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs +++ b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs @@ -34,7 +34,7 @@ internal static ModelBuilder ConfigureNavigationAutoIncludes(this ModelBuilder b workEntryEntity.Navigation(entry => entry.ResponsibleStaff).AutoInclude(); // Enforcement entities - var enforcementCaseEntity = builder.Entity(); + var enforcementCaseEntity = builder.Entity(); enforcementCaseEntity.Navigation(enforcementCase => enforcementCase.ResponsibleStaff).AutoInclude(); var enforcementActionEntity = builder.Entity(); @@ -152,9 +152,9 @@ internal static ModelBuilder ConfigureEnforcementActionMapping(this ModelBuilder // Many-to-many relationships. // https://learn.microsoft.com/en-us/ef/core/modeling/relationships/many-to-many#many-to-many-with-named-join-table - builder.Entity() + builder.Entity() .HasMany(enforcementCase => enforcementCase.ComplianceEvents) - .WithMany(complianceEvent => complianceEvent.EnforcementCases) + .WithMany(complianceEvent => complianceEvent.CaseFiles) .UsingEntity("EnforcementCaseComplianceEvents"); // Self-referencing relationships. @@ -231,11 +231,11 @@ internal static ModelBuilder ConfigureEnumValues(this ModelBuilder builder) builder.Entity().Property(e => e.EnforcementActionType).HasConversion(); // Status - builder.Entity().Property(e => e.Status).HasConversion(); + builder.Entity().Property(e => e.Status).HasConversion(); builder.Entity().Property(e => e.Status).HasConversion(); // Data exchange status - builder.Entity().Property(e => e.DataExchangeStatus).HasConversion(); + builder.Entity().Property(e => e.DataExchangeStatus).HasConversion(); builder.Entity().Property(e => e.DataExchangeStatus).HasConversion(); builder.Entity().Property(e => e.DataExchangeStatus).HasConversion(); diff --git a/src/EfRepository/DbContext/DevData/DbSeedDataHelpers.cs b/src/EfRepository/DbContext/DevData/DbSeedDataHelpers.cs index e177fac8..d8859c61 100644 --- a/src/EfRepository/DbContext/DevData/DbSeedDataHelpers.cs +++ b/src/EfRepository/DbContext/DevData/DbSeedDataHelpers.cs @@ -40,7 +40,7 @@ private static void SeedEnforcementCaseData(AppDbContext context) if (context.Database.ProviderName == AppDbContext.SqlServerProvider) context.Database.ExecuteSqlRaw("SET IDENTITY_INSERT EnforcementCases ON"); - context.EnforcementCases.AddRange(EnforcementCaseData.GetData); + context.EnforcementCases.AddRange(CaseFileData.GetData); context.SaveChanges(); if (context.Database.ProviderName == AppDbContext.SqlServerProvider) diff --git a/src/TestData/Enforcement/EnforcementCaseData.cs b/src/TestData/Enforcement/CaseFileData.cs similarity index 81% rename from src/TestData/Enforcement/EnforcementCaseData.cs rename to src/TestData/Enforcement/CaseFileData.cs index 8e84bd6f..2068af72 100644 --- a/src/TestData/Enforcement/EnforcementCaseData.cs +++ b/src/TestData/Enforcement/CaseFileData.cs @@ -7,12 +7,12 @@ namespace AirWeb.TestData.Enforcement; -internal static class EnforcementCaseData +internal static class CaseFileData { - public static ViolationType GetRandomViolationType() => + private static ViolationType GetRandomViolationType() => ViolationTypeData.ViolationTypes.Where(type => !type.Deprecated).OrderBy(_ => Guid.NewGuid()).First(); - private static IEnumerable EnforcementCaseSeedItems => + private static IEnumerable CaseFileSeedItems => [ new(300, DomainData.GetRandomFacility().Id, null) { @@ -127,39 +127,39 @@ public static ViolationType GetRandomViolationType() => }, ]; - private static IEnumerable? _enforcementCases; + private static IEnumerable? _caseFiles; - public static IEnumerable GetData + public static IEnumerable GetData { get { - if (_enforcementCases is not null) return _enforcementCases; - _enforcementCases = EnforcementCaseSeedItems.ToList(); + if (_caseFiles is not null) return _caseFiles; + _caseFiles = CaseFileSeedItems.ToList(); - foreach (var enforcementCase in _enforcementCases) + foreach (var caseFile in _caseFiles) { - enforcementCase.ResponsibleStaff = UserData.GetRandomUser(); - enforcementCase.Comments.AddRange(CommentData.GetRandomCommentsList(1) - .Select(comment => new EnforcementCaseComment(comment, enforcementCase.Id))); + caseFile.ResponsibleStaff = UserData.GetRandomUser(); + caseFile.Comments.AddRange(CommentData.GetRandomCommentsList(1) + .Select(comment => new CaseFileComment(comment, caseFile.Id))); - if (enforcementCase is not { Id: > 302 }) continue; + if (caseFile is not { Id: > 302 }) continue; - enforcementCase.ComplianceEvents.Add(WorkEntryData.GetRandomComplianceEvent()); + caseFile.ComplianceEvents.Add(WorkEntryData.GetRandomComplianceEvent()); - var facility = FacilityData.GetFacility(enforcementCase.FacilityId); + var facility = FacilityData.GetFacility(caseFile.FacilityId); if (facility.RegulatoryData is null) continue; - enforcementCase.PollutantIds.AddRange( + caseFile.PollutantIds.AddRange( facility.RegulatoryData.Pollutants.Select(pollutant => pollutant.Code)); - enforcementCase.AirPrograms.AddRange(facility.RegulatoryData.AirPrograms); + caseFile.AirPrograms.AddRange(facility.RegulatoryData.AirPrograms); } // Set as deleted - _enforcementCases.Single(enforcementCase => enforcementCase.Id == 329).SetDeleted(UserData.AdminUserId); + _caseFiles.Single(enforcementCase => enforcementCase.Id == 329).SetDeleted(UserData.AdminUserId); - return _enforcementCases; + return _caseFiles; } } - public static void ClearData() => _enforcementCases = null; + public static void ClearData() => _caseFiles = null; } diff --git a/src/TestData/Enforcement/EnforcementActionData.cs b/src/TestData/Enforcement/EnforcementActionData.cs index a0b331a7..88c5cd0b 100644 --- a/src/TestData/Enforcement/EnforcementActionData.cs +++ b/src/TestData/Enforcement/EnforcementActionData.cs @@ -10,13 +10,13 @@ public static class EnforcementActionData private static IEnumerable EnforcementActionSeedItems => [ // 301 (0) - new LetterOfNoncompliance(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(1), null) + new LetterOfNoncompliance(Guid.NewGuid(), CaseFileData.GetData.ElementAt(1), null) { Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), }, // 302 (1) - new LetterOfNoncompliance(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(2), null) + new LetterOfNoncompliance(Guid.NewGuid(), CaseFileData.GetData.ElementAt(2), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-10).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), @@ -24,7 +24,7 @@ public static class EnforcementActionData }, // 303 (2) - new LetterOfNoncompliance(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(3), null) + new LetterOfNoncompliance(Guid.NewGuid(), CaseFileData.GetData.ElementAt(3), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-10).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), @@ -33,27 +33,27 @@ public static class EnforcementActionData }, // 304 (3, 4) - new LetterOfNoncompliance(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(4), null) + new LetterOfNoncompliance(Guid.NewGuid(), CaseFileData.GetData.ElementAt(4), null) { Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), ResponseRequested = true, ResponseReceived = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).Date), ClosedAsUnsent = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-5).Date), }, - new NoticeOfViolation(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(4), null) + new NoticeOfViolation(Guid.NewGuid(), CaseFileData.GetData.ElementAt(4), null) { Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), }, // 305 (5) - new NoticeOfViolation(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(5), null) + new NoticeOfViolation(Guid.NewGuid(), CaseFileData.GetData.ElementAt(5), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-15).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), }, // 306 (6) - new NoticeOfViolation(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(6), null) + new NoticeOfViolation(Guid.NewGuid(), CaseFileData.GetData.ElementAt(6), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-15).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), @@ -61,7 +61,7 @@ public static class EnforcementActionData }, // 307 (7) - new NovNfaLetter(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(7), null) + new NovNfaLetter(Guid.NewGuid(), CaseFileData.GetData.ElementAt(7), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-75).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), @@ -69,7 +69,7 @@ public static class EnforcementActionData }, // 308 (8) - new NoticeOfViolation(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(8), null) + new NoticeOfViolation(Guid.NewGuid(), CaseFileData.GetData.ElementAt(8), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-15).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), @@ -77,35 +77,35 @@ public static class EnforcementActionData }, // 309 (9) - new ProposedConsentOrder(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(9), null) + new ProposedConsentOrder(Guid.NewGuid(), CaseFileData.GetData.ElementAt(9), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-5).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), }, // 310 (10) - new ProposedConsentOrder(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(10), null) + new ProposedConsentOrder(Guid.NewGuid(), CaseFileData.GetData.ElementAt(10), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-5).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), }, // 311 (11) - new ProposedConsentOrder(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(11), null) + new ProposedConsentOrder(Guid.NewGuid(), CaseFileData.GetData.ElementAt(11), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-5).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), }, // 312 (12) - new ProposedConsentOrder(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(12), null) + new ProposedConsentOrder(Guid.NewGuid(), CaseFileData.GetData.ElementAt(12), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-5).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), }, // 313 (13) - new AdministrativeOrder(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(13), null) + new AdministrativeOrder(Guid.NewGuid(), CaseFileData.GetData.ElementAt(13), null) { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-88).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), @@ -113,7 +113,7 @@ public static class EnforcementActionData }, // 314 (14) - new AdministrativeOrder(Guid.NewGuid(), EnforcementCaseData.GetData.ElementAt(14), null) + new AdministrativeOrder(Guid.NewGuid(), CaseFileData.GetData.ElementAt(14), null) { Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), Executed = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-220).Date), @@ -168,7 +168,7 @@ private static List NestedSeedItems(List p OrderNumber = 1663, PenaltyAmount = 10_000, PenaltyComment = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), - Resolved = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).Date), + ResolvedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).Date), StipulatedPenaltiesDefined = true, }, diff --git a/tests/EfRepositoryTests/RepositoryHelper.cs b/tests/EfRepositoryTests/RepositoryHelper.cs index cb91d8ce..730ffd1e 100644 --- a/tests/EfRepositoryTests/RepositoryHelper.cs +++ b/tests/EfRepositoryTests/RepositoryHelper.cs @@ -127,7 +127,7 @@ public async Task ClearTableAsync() private static void ClearAllStaticData() { EnforcementActionData.ClearData(); - EnforcementCaseData.ClearData(); + CaseFileData.ClearData(); FceData.ClearData(); WorkEntryData.ClearData(); NotificationTypeData.ClearData(); From 3b005156c4eabd5b2165e12dd64c30a8ed415ec7 Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Tue, 17 Dec 2024 10:41:18 -0500 Subject: [PATCH 05/13] Normalize naming of Date properties --- .../Compliance/Search/FceExportDto.cs | 4 ++-- .../Compliance/Search/WorkEntryExportDto.cs | 4 ++-- .../WorkEntries/Accs/AccCommandDto.cs | 2 +- .../WorkEntries/Accs/AccCommandValidator.cs | 4 ++-- .../Compliance/WorkEntries/Accs/AccViewDto.cs | 2 +- .../WorkEntries/Accs/IAccCommandDto.cs | 2 +- .../ISourceTestReviewCommandDto.cs | 2 +- .../SourceTestReviewCommandDto.cs | 2 +- .../SourceTestReviewCommandValidator.cs | 4 ++-- .../SourceTestReviewViewDto.cs | 2 +- .../SupportingData/SourceTestSummaryDto.cs | 2 +- .../WorkEntries/WorkEntryService.Mapping.cs | 4 ++-- .../AnnualComplianceCertification.cs | 5 +++-- .../WorkEntries/SourceTestReview.cs | 4 ++-- .../EnforcementActionReview.cs | 6 ++--- .../ActionProperties/StipulatedPenalty.cs | 2 +- .../Actions/AdministrativeOrder.cs | 6 ++--- .../Actions/ConsentOrder.cs | 4 ++-- .../Actions/EnforcementAction.cs | 2 +- .../AppDbContextConfiguration.cs | 12 +++++----- .../Repositories/LocalWorkEntryRepository.cs | 2 +- src/TestData/Compliance/AccData.cs | 22 +++++++++---------- .../Compliance/SourceTestReviewData.cs | 8 +++---- .../Enforcement/EnforcementActionData.cs | 16 +++++++------- .../Pages/Compliance/SourceTest/Index.cshtml | 6 ++--- .../Pages/Compliance/Work/Acc/Add.cshtml | 2 +- .../Pages/Compliance/Work/Acc/Edit.cshtml | 2 +- .../Work/SourceTestReview/Edit.cshtml | 2 +- .../Work/_Partials/_AccDetails.cshtml | 4 ++-- .../_Partials/_SourceTestReviewDetails.cshtml | 4 ++-- src/WebApp/Pages/Print/Acc/Index.cshtml | 4 ++-- src/WebApp/Pages/Print/Acc/Index.cshtml.cs | 2 +- .../Print/Fce/_SourceTestsPartial.cshtml | 4 ++-- .../Pages/Print/_MemoHeaderPartial.cshtml | 4 ++-- .../Platform/PrintoutModels/MemoHeader.cs | 2 +- .../Validators/AccCreateValidatorTests.cs | 10 ++++----- .../SourceTestReviewCreateValidatorTests.cs | 10 ++++----- 37 files changed, 90 insertions(+), 89 deletions(-) diff --git a/src/AppServices/Compliance/Search/FceExportDto.cs b/src/AppServices/Compliance/Search/FceExportDto.cs index fbcefb11..256dd9dc 100644 --- a/src/AppServices/Compliance/Search/FceExportDto.cs +++ b/src/AppServices/Compliance/Search/FceExportDto.cs @@ -12,7 +12,7 @@ public FceExportDto(Fce fce) FacilityId = fce.FacilityId; Year = fce.Year; ReviewedBy = fce.ReviewedBy?.SortableFullName; - DateCompleted = fce.CompletedDate; + CompletedDate = fce.CompletedDate; Notes = fce.Notes; Deleted = fce.IsDeleted ? "Deleted" : "No"; } @@ -33,7 +33,7 @@ public FceExportDto(Fce fce) public string? ReviewedBy { get; init; } [XLColumn(Header = "Date Completed")] - public DateOnly? DateCompleted { get; init; } + public DateOnly? CompletedDate { get; init; } [XLColumn(Header = "Notes")] public string? Notes { get; init; } diff --git a/src/AppServices/Compliance/Search/WorkEntryExportDto.cs b/src/AppServices/Compliance/Search/WorkEntryExportDto.cs index a1195c09..ea3dab97 100644 --- a/src/AppServices/Compliance/Search/WorkEntryExportDto.cs +++ b/src/AppServices/Compliance/Search/WorkEntryExportDto.cs @@ -16,7 +16,7 @@ public WorkEntryExportDto(WorkEntry workEntry) EventDateName = workEntry.EventDateName; ResponsibleStaff = workEntry.ResponsibleStaff?.SortableFullName; Closed = workEntry.IsClosed ? "Closed" : "Open"; - DateClosed = workEntry.ClosedDate; + ClosedDate = workEntry.ClosedDate; Notes = workEntry.Notes; Deleted = workEntry.IsDeleted ? "Deleted" : "No"; } @@ -46,7 +46,7 @@ public WorkEntryExportDto(WorkEntry workEntry) public string Closed { get; init; } [XLColumn(Header = "Date Closed")] - public DateOnly? DateClosed { get; init; } + public DateOnly? ClosedDate { get; init; } [XLColumn(Header = "Notes")] public string? Notes { get; init; } diff --git a/src/AppServices/Compliance/WorkEntries/Accs/AccCommandDto.cs b/src/AppServices/Compliance/WorkEntries/Accs/AccCommandDto.cs index 63242b21..64119c49 100644 --- a/src/AppServices/Compliance/WorkEntries/Accs/AccCommandDto.cs +++ b/src/AppServices/Compliance/WorkEntries/Accs/AccCommandDto.cs @@ -15,7 +15,7 @@ public record AccCommandDto : WorkEntryCommandDto, IAccCommandDto [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:O}", ApplyFormatInEditMode = true)] [Display(Name = "Date postmarked")] - public DateOnly Postmarked { get; init; } = DateOnly.FromDateTime(DateTime.Today); + public DateOnly PostmarkDate { get; init; } = DateOnly.FromDateTime(DateTime.Today); [Display(Name = "Postmarked by deadline")] public bool PostmarkedOnTime { get; init; } diff --git a/src/AppServices/Compliance/WorkEntries/Accs/AccCommandValidator.cs b/src/AppServices/Compliance/WorkEntries/Accs/AccCommandValidator.cs index 429ec674..ab7ebc8e 100644 --- a/src/AppServices/Compliance/WorkEntries/Accs/AccCommandValidator.cs +++ b/src/AppServices/Compliance/WorkEntries/Accs/AccCommandValidator.cs @@ -18,10 +18,10 @@ public AccCommandValidator() .WithMessage("The Received Date cannot be in the future.") .Must(date => date.Year >= WorkEntry.EarliestWorkEntryYear) .WithMessage($"The Received Date cannot be earlier than {WorkEntry.EarliestWorkEntryYear}.") - .Must((dto, date) => date >= dto.Postmarked) + .Must((dto, date) => date >= dto.PostmarkDate) .WithMessage("The Received Date must be later than the Postmark Date."); - RuleFor(dto => dto.Postmarked) + RuleFor(dto => dto.PostmarkDate) .Must(date => date <= today) .WithMessage("The Postmark Date cannot be in the future.") .Must(date => date.Year >= WorkEntry.EarliestWorkEntryYear) diff --git a/src/AppServices/Compliance/WorkEntries/Accs/AccViewDto.cs b/src/AppServices/Compliance/WorkEntries/Accs/AccViewDto.cs index 72f23e76..553bfd12 100644 --- a/src/AppServices/Compliance/WorkEntries/Accs/AccViewDto.cs +++ b/src/AppServices/Compliance/WorkEntries/Accs/AccViewDto.cs @@ -11,7 +11,7 @@ public record AccViewDto : WorkEntryViewDto public int AccReportingYear { get; init; } [Display(Name = "Date postmarked")] - public DateOnly Postmarked { get; init; } + public DateOnly PostmarkDate { get; init; } [Display(Name = "Postmarked by deadline")] public bool PostmarkedOnTime { get; init; } diff --git a/src/AppServices/Compliance/WorkEntries/Accs/IAccCommandDto.cs b/src/AppServices/Compliance/WorkEntries/Accs/IAccCommandDto.cs index da7c04ea..f3ef23cf 100644 --- a/src/AppServices/Compliance/WorkEntries/Accs/IAccCommandDto.cs +++ b/src/AppServices/Compliance/WorkEntries/Accs/IAccCommandDto.cs @@ -4,7 +4,7 @@ public interface IAccCommandDto { public DateOnly ReceivedDate { get; } public int AccReportingYear { get; } - public DateOnly Postmarked { get; } + public DateOnly PostmarkDate { get; } public bool PostmarkedOnTime { get; } public bool SignedByRo { get; } public bool OnCorrectForms { get; } diff --git a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/ISourceTestReviewCommandDto.cs b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/ISourceTestReviewCommandDto.cs index 1e4a434a..5ff35608 100644 --- a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/ISourceTestReviewCommandDto.cs +++ b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/ISourceTestReviewCommandDto.cs @@ -2,7 +2,7 @@ public interface ISourceTestReviewCommandDto { - public DateOnly ReceivedByCompliance { get; } + public DateOnly ReceivedByComplianceDate { get; } public DateOnly? DueDate { get; } public bool FollowupTaken { get; } } diff --git a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandDto.cs b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandDto.cs index 98c816f5..fe7966e7 100644 --- a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandDto.cs +++ b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandDto.cs @@ -10,7 +10,7 @@ public record SourceTestReviewCommandDto : WorkEntryCommandDto, ISourceTestRevie [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:O}", ApplyFormatInEditMode = true)] [Display(Name = "Date Received By Compliance")] - public DateOnly ReceivedByCompliance { get; init; } = DateOnly.FromDateTime(DateTime.Today); + public DateOnly ReceivedByComplianceDate { get; init; } = DateOnly.FromDateTime(DateTime.Today); [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:O}", ApplyFormatInEditMode = true)] diff --git a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandValidator.cs b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandValidator.cs index 92235b3f..d530a073 100644 --- a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandValidator.cs +++ b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewCommandValidator.cs @@ -6,12 +6,12 @@ public class SourceTestReviewCommandValidator : AbstractValidator dto.ReceivedByCompliance) + RuleFor(dto => dto.ReceivedByComplianceDate) .Must(date => date <= DateOnly.FromDateTime(DateTime.Today)) .WithMessage("The Date Received By Compliance cannot be in the future."); RuleFor(dto => dto.AcknowledgmentLetterDate) - .Must((dto, date) => date is null || date >= dto.ReceivedByCompliance) + .Must((dto, date) => date is null || date >= dto.ReceivedByComplianceDate) .WithMessage("The Acknowledgment Letter Date cannot be earlier than the Date Received By Compliance."); } } diff --git a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewViewDto.cs b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewViewDto.cs index 50259ac3..8846321a 100644 --- a/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewViewDto.cs +++ b/src/AppServices/Compliance/WorkEntries/SourceTestReviews/SourceTestReviewViewDto.cs @@ -8,7 +8,7 @@ public record SourceTestReviewViewDto : WorkEntryViewDto public int ReferenceNumber { get; init; } [Display(Name = "Date Received")] - public DateOnly ReceivedByCompliance { get; init; } + public DateOnly ReceivedByComplianceDate { get; init; } [Display(Name = "Test Due Date")] public DateOnly? DueDate { get; init; } diff --git a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs index e7e70aca..ebee8254 100644 --- a/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs +++ b/src/AppServices/Compliance/WorkEntries/WorkEntryDto/Query/SupportingData/SourceTestSummaryDto.cs @@ -11,7 +11,7 @@ public record SourceTestSummaryDto public int ReferenceNumber { get; init; } [Display(Name = "Date received")] - public DateOnly ReceivedByCompliance { get; init; } + public DateOnly ReceivedByComplianceDate { get; init; } public PersonName ResponsibleStaff { get; init; } diff --git a/src/AppServices/Compliance/WorkEntries/WorkEntryService.Mapping.cs b/src/AppServices/Compliance/WorkEntries/WorkEntryService.Mapping.cs index 64f2b470..e5df204b 100644 --- a/src/AppServices/Compliance/WorkEntries/WorkEntryService.Mapping.cs +++ b/src/AppServices/Compliance/WorkEntries/WorkEntryService.Mapping.cs @@ -108,7 +108,7 @@ private static void MapAcc(IAccCommandDto resource, AnnualComplianceCertificatio { acc.ReceivedDate = resource.ReceivedDate; acc.AccReportingYear = resource.AccReportingYear; - acc.Postmarked = resource.Postmarked; + acc.PostmarkDate = resource.PostmarkDate; acc.PostmarkedOnTime = resource.PostmarkedOnTime; acc.SignedByRo = resource.SignedByRo; acc.OnCorrectForms = resource.OnCorrectForms; @@ -168,7 +168,7 @@ private static void MapReport(IReportCommandDto resource, Report report) private static void MapStr(ISourceTestReviewCommandDto resource, SourceTestReview str) { - str.ReceivedByCompliance = resource.ReceivedByCompliance; + str.ReceivedByComplianceDate = resource.ReceivedByComplianceDate; str.DueDate = resource.DueDate; str.FollowupTaken = resource.FollowupTaken; } diff --git a/src/Domain/ComplianceEntities/WorkEntries/AnnualComplianceCertification.cs b/src/Domain/ComplianceEntities/WorkEntries/AnnualComplianceCertification.cs index 5515a4b2..923e90ca 100644 --- a/src/Domain/ComplianceEntities/WorkEntries/AnnualComplianceCertification.cs +++ b/src/Domain/ComplianceEntities/WorkEntries/AnnualComplianceCertification.cs @@ -9,7 +9,8 @@ public class AnnualComplianceCertification : WorkEntry [UsedImplicitly] // Used by ORM. private AnnualComplianceCertification() { } - internal AnnualComplianceCertification(int? id, FacilityId facilityId, ApplicationUser? user=null) : base(id, facilityId, user) + internal AnnualComplianceCertification(int? id, FacilityId facilityId, ApplicationUser? user = null) : base(id, + facilityId, user) { WorkEntryType = WorkEntryType.AnnualComplianceCertification; } @@ -17,7 +18,7 @@ internal AnnualComplianceCertification(int? id, FacilityId facilityId, Applicati // Properties public DateOnly ReceivedDate { get; set; } public int AccReportingYear { get; set; } - public DateOnly Postmarked { get; set; } + public DateOnly PostmarkDate { get; set; } public bool PostmarkedOnTime { get; set; } public bool SignedByRo { get; set; } public bool OnCorrectForms { get; set; } diff --git a/src/Domain/ComplianceEntities/WorkEntries/SourceTestReview.cs b/src/Domain/ComplianceEntities/WorkEntries/SourceTestReview.cs index d7f9bb97..ca154b5a 100644 --- a/src/Domain/ComplianceEntities/WorkEntries/SourceTestReview.cs +++ b/src/Domain/ComplianceEntities/WorkEntries/SourceTestReview.cs @@ -9,7 +9,7 @@ public class SourceTestReview : ComplianceEvent [UsedImplicitly] // Used by ORM. private SourceTestReview() { } - internal SourceTestReview(int? id, FacilityId facilityId, ApplicationUser? user=null) : base(id, facilityId, user) + internal SourceTestReview(int? id, FacilityId facilityId, ApplicationUser? user = null) : base(id, facilityId, user) { WorkEntryType = WorkEntryType.SourceTestReview; Close(user); @@ -18,7 +18,7 @@ internal SourceTestReview(int? id, FacilityId facilityId, ApplicationUser? user= // Properties public int ReferenceNumber { get; set; } - public DateOnly ReceivedByCompliance { get; set; } + public DateOnly ReceivedByComplianceDate { get; set; } public DateOnly? DueDate { get; set; } public bool FollowupTaken { get; set; } } diff --git a/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs b/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs index bb4d77a6..78269b88 100644 --- a/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs +++ b/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs @@ -19,10 +19,10 @@ internal EnforcementActionReview(Guid id, EnforcementAction enforcementAction, A public EnforcementAction EnforcementAction { get; internal init; } = null!; - public DateOnly DateRequested { get; internal init; } + public DateOnly RequestedDate { get; internal init; } public ApplicationUser? ReviewedBy { get; internal init; } - public bool IsCompleted => DateCompleted.HasValue; - public DateOnly? DateCompleted { get; internal set; } + public bool IsCompleted => CompletedDate.HasValue; + public DateOnly? CompletedDate { get; internal set; } [StringLength(11)] public ReviewResult? Status { get; internal set; } diff --git a/src/Domain/EnforcementEntities/ActionProperties/StipulatedPenalty.cs b/src/Domain/EnforcementEntities/ActionProperties/StipulatedPenalty.cs index 44efd8ff..e812613f 100644 --- a/src/Domain/EnforcementEntities/ActionProperties/StipulatedPenalty.cs +++ b/src/Domain/EnforcementEntities/ActionProperties/StipulatedPenalty.cs @@ -21,7 +21,7 @@ internal StipulatedPenalty(Guid id, ConsentOrder consentOrder, ApplicationUser? [Precision(12, 2)] public decimal Amount { get; set; } - public DateOnly DateReceived { get; set; } + public DateOnly ReceivedDate { get; set; } [StringLength(7000)] public string? Notes { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs index c920ad2e..1ed9e76e 100644 --- a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs @@ -15,8 +15,8 @@ internal AdministrativeOrder(Guid id, CaseFile caseFile, ApplicationUser? user) EnforcementActionType = EnforcementActionType.AdministrativeOrder; } - public DateOnly? Executed { get; set; } - public DateOnly? Appealed { get; set; } - public DateOnly? Resolved { get; set; } + public DateOnly? ExecutedDate { get; set; } + public DateOnly? AppealedDate { get; set; } + public DateOnly? ResolvedDate { get; set; } public AoResolvedLetter? ResolvedLetter { get; set; } } diff --git a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs index eb267649..6611cacb 100644 --- a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs @@ -27,9 +27,9 @@ internal ConsentOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : public ProposedConsentOrder? ProposedConsentOrder { get; set; } public DateOnly? ReceivedFromFacility { get; set; } - public DateOnly? Executed { get; set; } + public DateOnly? ExecutedDate { get; set; } public DateOnly? ReceivedFromDirectorsOffice { get; set; } - public DateOnly? Resolved { get; set; } + public DateOnly? ResolvedDate { get; set; } public CoResolvedLetter? ResolvedLetter { get; set; } public short? OrderNumber { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs index 3d6b8e99..c8cdb6cf 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs @@ -37,7 +37,7 @@ private protected EnforcementAction(Guid id, CaseFile caseFile, ApplicationUser? public DateTimeOffset? CurrentOwnerAssignedDate { get; internal set; } public ICollection Reviews { get; } = []; public bool IsApproved { get; internal set; } - public DateOnly? DateApproved { get; internal set; } + public DateOnly? ApprovedDate { get; internal set; } public ApplicationUser? ApprovedBy { get; set; } // Status diff --git a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs index 6a42ed4e..a374ac05 100644 --- a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs +++ b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs @@ -198,12 +198,12 @@ private static ModelBuilder ConfigureEnforcementActionColumnSharing(this ModelBu var pcoEntity = builder.Entity(); // Executed date - aorEntity.Property(e => e.Executed).HasColumnName(nameof(AdministrativeOrder.Executed)); - corEntity.Property(e => e.Executed).HasColumnName(nameof(ConsentOrder.Executed)); + aorEntity.Property(e => e.ExecutedDate).HasColumnName(nameof(AdministrativeOrder.ExecutedDate)); + corEntity.Property(e => e.ExecutedDate).HasColumnName(nameof(ConsentOrder.ExecutedDate)); // Resolved date - aorEntity.Property(e => e.Resolved).HasColumnName(nameof(AdministrativeOrder.Resolved)); - corEntity.Property(e => e.Resolved).HasColumnName(nameof(ConsentOrder.Resolved)); + aorEntity.Property(e => e.ResolvedDate).HasColumnName(nameof(AdministrativeOrder.ResolvedDate)); + corEntity.Property(e => e.ResolvedDate).HasColumnName(nameof(ConsentOrder.ResolvedDate)); // Response requested enlEntity.Property(e => e.ResponseRequested).HasColumnName(nameof(EnforcementLetter.ResponseRequested)); @@ -252,7 +252,7 @@ internal static ModelBuilder ConfigureCalculatedColumns(this ModelBuilder builde when WorkEntryType in ('AnnualComplianceCertification', 'Notification', 'PermitRevocation', 'Report') then convert(date, ReceivedDate) when WorkEntryType in ('Inspection', 'RmpInspection') then convert(date, InspectionStarted) - when WorkEntryType = 'SourceTestReview' then convert(date, ReceivedByCompliance) + when WorkEntryType = 'SourceTestReview' then convert(date, ReceivedByComplianceDate) else convert(date, '1900-1-1') end """); @@ -265,7 +265,7 @@ when WorkEntryType in ('Inspection', 'RmpInspection') then convert(date, Inspect when WorkEntryType in ('AnnualComplianceCertification', 'Notification', 'PermitRevocation', 'Report') then date(ReceivedDate) when WorkEntryType in ('Inspection', 'RmpInspection') then date(InspectionStarted) - when WorkEntryType = 'SourceTestReview' then date(ReceivedByCompliance) + when WorkEntryType = 'SourceTestReview' then date(ReceivedByComplianceDate) else '1900-1-1' end """); diff --git a/src/LocalRepository/Repositories/LocalWorkEntryRepository.cs b/src/LocalRepository/Repositories/LocalWorkEntryRepository.cs index 0947da1f..11c0f081 100644 --- a/src/LocalRepository/Repositories/LocalWorkEntryRepository.cs +++ b/src/LocalRepository/Repositories/LocalWorkEntryRepository.cs @@ -64,7 +64,7 @@ public Task DeleteCommentAsync(Guid commentId, string? userId, CancellationToken WorkEntryType.PermitRevocation => (entry as PermitRevocation)!.ReceivedDate, WorkEntryType.Report => (entry as Report)!.ReceivedDate, WorkEntryType.RmpInspection => DateOnly.FromDateTime((entry as RmpInspection)!.InspectionStarted), - WorkEntryType.SourceTestReview => (entry as SourceTestReview)!.ReceivedByCompliance, + WorkEntryType.SourceTestReview => (entry as SourceTestReview)!.ReceivedByComplianceDate, _ => DateOnly.FromDateTime(entry.CreatedAt?.Date ?? DateTime.MinValue), }; } diff --git a/src/TestData/Compliance/AccData.cs b/src/TestData/Compliance/AccData.cs index b7a6a6c0..517e5c2a 100644 --- a/src/TestData/Compliance/AccData.cs +++ b/src/TestData/Compliance/AccData.cs @@ -20,7 +20,7 @@ internal static partial class WorkEntries ReceivedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-11).Date), EventDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-11).Date), AccReportingYear = 2000, - Postmarked = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-21).Date), + PostmarkDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-21).Date), PostmarkedOnTime = true, SignedByRo = true, OnCorrectForms = true, @@ -45,7 +45,7 @@ internal static partial class WorkEntries ReceivedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-11).Date), EventDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-11).Date), AccReportingYear = 2002, - Postmarked = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-21).Date), + PostmarkDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-21).Date), PostmarkedOnTime = false, SignedByRo = false, OnCorrectForms = false, @@ -59,16 +59,16 @@ internal static partial class WorkEntries }, new(5003, DomainData.GetRandomFacility().Id) { - WorkEntryType = WorkEntryType.AnnualComplianceCertification, - ResponsibleStaff = UserData.GetRandomUser(), - AcknowledgmentLetterDate = null, - Notes = "Deleted ACC", - DeleteComments = SampleText.GetRandomText(SampleText.TextLength.Paragraph), + WorkEntryType = WorkEntryType.AnnualComplianceCertification, + ResponsibleStaff = UserData.GetRandomUser(), + AcknowledgmentLetterDate = null, + Notes = "Deleted ACC", + DeleteComments = SampleText.GetRandomText(SampleText.TextLength.Paragraph), - ReceivedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-11).Date), - EventDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-11).Date), - AccReportingYear = 2002, - Postmarked = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-21).Date), + ReceivedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-11).Date), + EventDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-11).Date), + AccReportingYear = 2002, + PostmarkDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-21).Date), }, ]; } diff --git a/src/TestData/Compliance/SourceTestReviewData.cs b/src/TestData/Compliance/SourceTestReviewData.cs index f5bf876b..34b6c80a 100644 --- a/src/TestData/Compliance/SourceTestReviewData.cs +++ b/src/TestData/Compliance/SourceTestReviewData.cs @@ -9,7 +9,7 @@ internal static partial class WorkEntries { internal static IEnumerable SourceTestReviewData => [ - new(11001, SourceTestData.GetData[0].Facility!.Id, UserData.GetRandomUser()) + new(11001, SourceTestData.GetData[0].Facility!.Id, UserData.GetRandomUser()) { WorkEntryType = WorkEntryType.SourceTestReview, ReferenceNumber = SourceTestData.GetData[0].ReferenceNumber, @@ -19,7 +19,7 @@ internal static partial class WorkEntries Notes = "In compliance", ClosedDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-3).AddDays(-10)), - ReceivedByCompliance = DateOnly.FromDateTime(DateTime.Now.AddYears(-3).AddDays(-20)), + ReceivedByComplianceDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-3).AddDays(-20)), EventDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-3).AddDays(-20)), DueDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-3).AddMonths(-2)), FollowupTaken = false, @@ -34,7 +34,7 @@ internal static partial class WorkEntries Notes = "Not in compliance", ClosedDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-2)), - ReceivedByCompliance = DateOnly.FromDateTime(DateTime.Now.AddYears(-2).AddDays(-20)), + ReceivedByComplianceDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-2).AddDays(-20)), EventDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-2).AddDays(-20)), DueDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-2).AddMonths(-2)), FollowupTaken = true, @@ -48,7 +48,7 @@ internal static partial class WorkEntries Notes = "Deleted Source Test Review", DeleteComments = SampleText.GetRandomText(SampleText.TextLength.Paragraph), - ReceivedByCompliance = DateOnly.FromDateTime(DateTime.Now.AddYears(-2).AddDays(-20)), + ReceivedByComplianceDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-2).AddDays(-20)), EventDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-2).AddDays(-20)), }, ]; diff --git a/src/TestData/Enforcement/EnforcementActionData.cs b/src/TestData/Enforcement/EnforcementActionData.cs index 88c5cd0b..f741381c 100644 --- a/src/TestData/Enforcement/EnforcementActionData.cs +++ b/src/TestData/Enforcement/EnforcementActionData.cs @@ -109,14 +109,14 @@ public static class EnforcementActionData { IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-88).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), - Executed = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-90).Date), + ExecutedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-90).Date), }, // 314 (14) new AdministrativeOrder(Guid.NewGuid(), CaseFileData.GetData.ElementAt(14), null) { Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), - Executed = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-220).Date), + ExecutedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-220).Date), IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-218).Date), }, ]; @@ -150,7 +150,7 @@ private static List NestedSeedItems(List p { Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), ReceivedFromFacility = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-30).Date), - Executed = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-20).Date), + ExecutedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-20).Date), ReceivedFromDirectorsOffice = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-19).Date), OrderNumber = 1552, PenaltyAmount = 1000, @@ -163,7 +163,7 @@ private static List NestedSeedItems(List p IssueDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-18).Date), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), ReceivedFromFacility = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-30).Date), - Executed = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-20).Date), + ExecutedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-20).Date), ReceivedFromDirectorsOffice = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-19).Date), OrderNumber = 1663, PenaltyAmount = 10_000, @@ -220,7 +220,7 @@ public static IEnumerable GetData { enforcementAction.IsApproved = true; enforcementAction.ApprovedBy = UserData.GetRandomUser(); - enforcementAction.DateApproved = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-5).Date); + enforcementAction.ApprovedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-5).Date); GenerateEnforcementActionReviews(enforcementAction); } @@ -243,7 +243,7 @@ private static void GenerateStipulatedPenalties(ConsentOrder consentOrder) ConsentOrder = consentOrder, Amount = random.Next(1000, 5000), Notes = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), - DateReceived = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddMonths(i + 1).Date), + ReceivedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddMonths(i + 1).Date), }; consentOrder.StipulatedPenalties.Add(penalty); } @@ -256,8 +256,8 @@ private static void GenerateEnforcementActionReviews(EnforcementAction enforceme { var review = new EnforcementActionReview(Guid.NewGuid(), enforcementAction, UserData.GetRandomUser()) { - DateRequested = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-10 * (i + 1)).Date), - DateCompleted = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-5 * (i + 1)).Date), + RequestedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-10 * (i + 1)).Date), + CompletedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-5 * (i + 1)).Date), Status = (ReviewResult)new Random().Next(0, 4), // Random status ReviewComments = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), ReviewedBy = UserData.GetRandomUser(), diff --git a/src/WebApp/Pages/Compliance/SourceTest/Index.cshtml b/src/WebApp/Pages/Compliance/SourceTest/Index.cshtml index a0fc128b..7f2987f3 100644 --- a/src/WebApp/Pages/Compliance/SourceTest/Index.cshtml +++ b/src/WebApp/Pages/Compliance/SourceTest/Index.cshtml @@ -83,7 +83,7 @@
- @Html.EditorFor(m => m.NewComplianceReview!.ReceivedByCompliance, EditorTemplate.InputDateOnly) + @Html.EditorFor(m => m.NewComplianceReview!.ReceivedByComplianceDate, EditorTemplate.InputDateOnly)
@Html.EditorFor(m => m.NewComplianceReview!.DueDate, EditorTemplate.InputDateOnlyNullable) @@ -174,8 +174,8 @@ else

Details

-
@Html.DisplayNameFor(_ => review.ReceivedByCompliance)
-
@Html.DisplayFor(_ => review.ReceivedByCompliance, DisplayTemplate.ShortDateOnly)
+
@Html.DisplayNameFor(_ => review.ReceivedByComplianceDate)
+
@Html.DisplayFor(_ => review.ReceivedByComplianceDate, DisplayTemplate.ShortDateOnly)
@Html.DisplayNameFor(_ => review.DueDate)
@Html.DisplayFor(_ => review.DueDate, DisplayTemplate.ShortDateOnlyNullable)
@Html.DisplayNameFor(_ => review.FollowupTaken)
diff --git a/src/WebApp/Pages/Compliance/Work/Acc/Add.cshtml b/src/WebApp/Pages/Compliance/Work/Acc/Add.cshtml index 3d1715fe..bc203f70 100644 --- a/src/WebApp/Pages/Compliance/Work/Acc/Add.cshtml +++ b/src/WebApp/Pages/Compliance/Work/Acc/Add.cshtml @@ -39,7 +39,7 @@ additionalViewData: new { Min = WorkEntry.EarliestWorkEntryYear, Max = DateTime.Now.Year })
- @Html.EditorFor(m => m.Item.Postmarked, EditorTemplate.InputDateOnly) + @Html.EditorFor(m => m.Item.PostmarkDate, EditorTemplate.InputDateOnly)
diff --git a/src/WebApp/Pages/Compliance/Work/Acc/Edit.cshtml b/src/WebApp/Pages/Compliance/Work/Acc/Edit.cshtml index 8f163e16..31d0de7f 100644 --- a/src/WebApp/Pages/Compliance/Work/Acc/Edit.cshtml +++ b/src/WebApp/Pages/Compliance/Work/Acc/Edit.cshtml @@ -42,7 +42,7 @@ additionalViewData: new { Min = WorkEntry.EarliestWorkEntryYear, Max = DateTime.Now.Year })
- @Html.EditorFor(m => m.Item.Postmarked, EditorTemplate.InputDateOnly) + @Html.EditorFor(m => m.Item.PostmarkDate, EditorTemplate.InputDateOnly)
diff --git a/src/WebApp/Pages/Compliance/Work/SourceTestReview/Edit.cshtml b/src/WebApp/Pages/Compliance/Work/SourceTestReview/Edit.cshtml index 76144471..34a8c814 100644 --- a/src/WebApp/Pages/Compliance/Work/SourceTestReview/Edit.cshtml +++ b/src/WebApp/Pages/Compliance/Work/SourceTestReview/Edit.cshtml @@ -39,7 +39,7 @@
- @Html.EditorFor(m => m.Item.ReceivedByCompliance, EditorTemplate.InputDateOnly) + @Html.EditorFor(m => m.Item.ReceivedByComplianceDate, EditorTemplate.InputDateOnly)
@Html.EditorFor(m => m.Item.DueDate, EditorTemplate.InputDateOnlyNullable) diff --git a/src/WebApp/Pages/Compliance/Work/_Partials/_AccDetails.cshtml b/src/WebApp/Pages/Compliance/Work/_Partials/_AccDetails.cshtml index 2de30ce2..e0ec7a99 100644 --- a/src/WebApp/Pages/Compliance/Work/_Partials/_AccDetails.cshtml +++ b/src/WebApp/Pages/Compliance/Work/_Partials/_AccDetails.cshtml @@ -8,8 +8,8 @@
@Html.DisplayNameFor(m => m.ReceivedDate)
@Html.DisplayFor(m => m.ReceivedDate, DisplayTemplate.ShortDateOnlyNullable)
-
@Html.DisplayNameFor(m => m.Postmarked)
-
@Html.DisplayFor(m => m.Postmarked, DisplayTemplate.ShortDateOnly)
+
@Html.DisplayNameFor(m => m.PostmarkDate)
+
@Html.DisplayFor(m => m.PostmarkDate, DisplayTemplate.ShortDateOnly)
@Html.DisplayNameFor(m => m.PostmarkedOnTime)
@Html.DisplayFor(m => m.PostmarkedOnTime, DisplayTemplate.BoolYesNo)
@Html.DisplayNameFor(m => m.SignedByRo)
diff --git a/src/WebApp/Pages/Compliance/Work/_Partials/_SourceTestReviewDetails.cshtml b/src/WebApp/Pages/Compliance/Work/_Partials/_SourceTestReviewDetails.cshtml index 2bf87faa..97189198 100644 --- a/src/WebApp/Pages/Compliance/Work/_Partials/_SourceTestReviewDetails.cshtml +++ b/src/WebApp/Pages/Compliance/Work/_Partials/_SourceTestReviewDetails.cshtml @@ -8,8 +8,8 @@ @Model.ReferenceNumber.ToString() -
@Html.DisplayNameFor(m => m.ReceivedByCompliance)
-
@Html.DisplayFor(m => m.ReceivedByCompliance, DisplayTemplate.ShortDateOnly)
+
@Html.DisplayNameFor(m => m.ReceivedByComplianceDate)
+
@Html.DisplayFor(m => m.ReceivedByComplianceDate, DisplayTemplate.ShortDateOnly)
@Html.DisplayNameFor(m => m.DueDate)
@Html.DisplayFor(m => m.DueDate, DisplayTemplate.ShortDateOnlyNullable)
@Html.DisplayNameFor(m => m.FollowupTaken)
diff --git a/src/WebApp/Pages/Print/Acc/Index.cshtml b/src/WebApp/Pages/Print/Acc/Index.cshtml index b0d485c9..ee407520 100644 --- a/src/WebApp/Pages/Print/Acc/Index.cshtml +++ b/src/WebApp/Pages/Print/Acc/Index.cshtml @@ -26,8 +26,8 @@ - - + + diff --git a/src/WebApp/Pages/Print/Acc/Index.cshtml.cs b/src/WebApp/Pages/Print/Acc/Index.cshtml.cs index 531ba16e..46d2ed0f 100644 --- a/src/WebApp/Pages/Print/Acc/Index.cshtml.cs +++ b/src/WebApp/Pages/Print/Acc/Index.cshtml.cs @@ -23,7 +23,7 @@ public async Task OnGetAsync( MemoHeader = new MemoHeader { - Date = Report.ClosedDate, + MemoDate = Report.ClosedDate, From = Report.ResponsibleStaff?.DisplayName, Subject = $"Title V Annual Certification for {Report.AccReportingYear}" + Environment.NewLine + $"{Facility.Name}, {Facility.FacilityAddress?.City}" + Environment.NewLine + diff --git a/src/WebApp/Pages/Print/Fce/_SourceTestsPartial.cshtml b/src/WebApp/Pages/Print/Fce/_SourceTestsPartial.cshtml index 681c6fe8..4520b283 100644 --- a/src/WebApp/Pages/Print/Fce/_SourceTestsPartial.cshtml +++ b/src/WebApp/Pages/Print/Fce/_SourceTestsPartial.cshtml @@ -18,7 +18,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/src/WebApp/Pages/Print/_MemoHeaderPartial.cshtml b/src/WebApp/Pages/Print/_MemoHeaderPartial.cshtml index d9ba7cee..0059ad4e 100644 --- a/src/WebApp/Pages/Print/_MemoHeaderPartial.cshtml +++ b/src/WebApp/Pages/Print/_MemoHeaderPartial.cshtml @@ -3,10 +3,10 @@

Memorandum

- @if (Model.Date != null) + @if (Model.MemoDate != null) {
Date:
-
@Html.DisplayFor(m => m.Date, DisplayTemplate.LongDateOnlyNullable)
+
@Html.DisplayFor(m => m.MemoDate, DisplayTemplate.LongDateOnlyNullable)
} @if (Model.To != null) { diff --git a/src/WebApp/Platform/PrintoutModels/MemoHeader.cs b/src/WebApp/Platform/PrintoutModels/MemoHeader.cs index 71ee71a6..2b9f8dcc 100644 --- a/src/WebApp/Platform/PrintoutModels/MemoHeader.cs +++ b/src/WebApp/Platform/PrintoutModels/MemoHeader.cs @@ -2,7 +2,7 @@ public record struct MemoHeader { - public DateOnly? Date { get; init; } + public DateOnly? MemoDate { get; init; } public string? To { get; init; } public string? Through { get; init; } public string? From { get; init; } diff --git a/tests/AppServicesTests/WorkEntries/Validators/AccCreateValidatorTests.cs b/tests/AppServicesTests/WorkEntries/Validators/AccCreateValidatorTests.cs index 81ba86ad..86a89cfd 100644 --- a/tests/AppServicesTests/WorkEntries/Validators/AccCreateValidatorTests.cs +++ b/tests/AppServicesTests/WorkEntries/Validators/AccCreateValidatorTests.cs @@ -115,7 +115,7 @@ public async Task ReceivedDateBeforePostmarkDate_ReturnsAsInvalid() FacilityId = SampleText.ValidFacilityId, ResponsibleStaffId = SampleText.UnassignedGuid.ToString(), ReceivedDate = DateOnly.FromDateTime(DateTime.Today).AddDays(-2), - Postmarked = DateOnly.FromDateTime(DateTime.Today).AddDays(-1), + PostmarkDate = DateOnly.FromDateTime(DateTime.Today).AddDays(-1), }; // Act @@ -135,7 +135,7 @@ public async Task PostmarkDateInFuture_ReturnsAsInvalid() { FacilityId = SampleText.ValidFacilityId, ResponsibleStaffId = SampleText.UnassignedGuid.ToString(), - Postmarked = DateOnly.FromDateTime(DateTime.Today).AddDays(1), + PostmarkDate = DateOnly.FromDateTime(DateTime.Today).AddDays(1), }; // Act @@ -144,7 +144,7 @@ public async Task PostmarkDateInFuture_ReturnsAsInvalid() // Assert using var scope = new AssertionScope(); result.IsValid.Should().BeFalse(); - result.ShouldHaveValidationErrorFor(dto => dto.Postmarked); + result.ShouldHaveValidationErrorFor(dto => dto.PostmarkDate); } [Test] @@ -155,7 +155,7 @@ public async Task PostmarkDateTooOld_ReturnsAsInvalid() { FacilityId = SampleText.ValidFacilityId, ResponsibleStaffId = SampleText.UnassignedGuid.ToString(), - Postmarked = new DateOnly(WorkEntry.EarliestWorkEntryYear - 1, 1, 1), + PostmarkDate = new DateOnly(WorkEntry.EarliestWorkEntryYear - 1, 1, 1), }; // Act @@ -164,6 +164,6 @@ public async Task PostmarkDateTooOld_ReturnsAsInvalid() // Assert using var scope = new AssertionScope(); result.IsValid.Should().BeFalse(); - result.ShouldHaveValidationErrorFor(dto => dto.Postmarked); + result.ShouldHaveValidationErrorFor(dto => dto.PostmarkDate); } } diff --git a/tests/AppServicesTests/WorkEntries/Validators/SourceTestReviewCreateValidatorTests.cs b/tests/AppServicesTests/WorkEntries/Validators/SourceTestReviewCreateValidatorTests.cs index acc8fa20..81788b4c 100644 --- a/tests/AppServicesTests/WorkEntries/Validators/SourceTestReviewCreateValidatorTests.cs +++ b/tests/AppServicesTests/WorkEntries/Validators/SourceTestReviewCreateValidatorTests.cs @@ -65,7 +65,7 @@ public async Task ReviewAlreadyExists_ReturnsAsInvalid() { FacilityId = SampleText.ValidFacilityId, ResponsibleStaffId = SampleText.UnassignedGuid.ToString(), - ReceivedByCompliance = DateOnly.FromDateTime(DateTime.Today).AddDays(1), + ReceivedByComplianceDate = DateOnly.FromDateTime(DateTime.Today).AddDays(1), }; var entryService = Substitute.For(); @@ -80,7 +80,7 @@ public async Task ReviewAlreadyExists_ReturnsAsInvalid() // Assert using var scope = new AssertionScope(); result.IsValid.Should().BeFalse(); - result.ShouldHaveValidationErrorFor(dto => dto.ReceivedByCompliance); + result.ShouldHaveValidationErrorFor(dto => dto.ReceivedByComplianceDate); } [Test] @@ -92,7 +92,7 @@ public async Task AcknowledgmentLetterDateBeforeReceivedByCompliance_ReturnsAsIn FacilityId = SampleText.ValidFacilityId, ResponsibleStaffId = SampleText.UnassignedGuid.ToString(), AcknowledgmentLetterDate = DateOnly.FromDateTime(DateTime.Today).AddDays(-1), - ReceivedByCompliance = DateOnly.FromDateTime(DateTime.Today), + ReceivedByComplianceDate = DateOnly.FromDateTime(DateTime.Today), }; var entryService = Substitute.For(); @@ -118,7 +118,7 @@ public async Task ReceivedByComplianceInFuture_ReturnsAsInvalid() { FacilityId = SampleText.ValidFacilityId, ResponsibleStaffId = SampleText.UnassignedGuid.ToString(), - ReceivedByCompliance = DateOnly.FromDateTime(DateTime.Today).AddDays(1), + ReceivedByComplianceDate = DateOnly.FromDateTime(DateTime.Today).AddDays(1), }; var entryService = Substitute.For(); @@ -133,6 +133,6 @@ public async Task ReceivedByComplianceInFuture_ReturnsAsInvalid() // Assert using var scope = new AssertionScope(); result.IsValid.Should().BeFalse(); - result.ShouldHaveValidationErrorFor(dto => dto.ReceivedByCompliance); + result.ShouldHaveValidationErrorFor(dto => dto.ReceivedByComplianceDate); } } From 7ebdd3318465caa3d1efab9b3bd933c0bd58fc3a Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Tue, 17 Dec 2024 10:44:22 -0500 Subject: [PATCH 06/13] Start work on enforcement services and details page --- src/AppServices/AppServices.csproj | 4 -- .../AutoMapper/AutoMapperProfile.cs | 9 +++ .../Enforcement/Command/CaseFileCreateDto.cs | 30 +++++++++ .../Enforcement/EnforcementService.cs | 32 +++++++++ .../Enforcement/IEnforcementService.cs | 19 ++++++ .../Permissions/CaseFileViewRequirement.cs | 35 ++++++++++ .../Permissions/EnforcementOperation.cs | 67 +++++++++++++++++++ .../Enforcement/Query/CaseFileViewDto.cs | 64 ++++++++++++++++++ .../Actions/AdministrativeOrder.cs | 3 +- .../Actions/ConsentOrder.cs | 3 +- .../Actions/IResolvable.cs | 6 ++ .../ICaseFileRepository.cs | 21 ++++++ .../IEnforcementActionRepository.cs | 5 ++ .../Repositories/LocalCaseFileRepository.cs | 44 ++++++++++++ .../LocalEnforcementActionRepository.cs | 9 +++ .../AppConfiguration/DataPersistence.cs | 11 ++- 16 files changed, 354 insertions(+), 8 deletions(-) create mode 100644 src/AppServices/Enforcement/Command/CaseFileCreateDto.cs create mode 100644 src/AppServices/Enforcement/EnforcementService.cs create mode 100644 src/AppServices/Enforcement/IEnforcementService.cs create mode 100644 src/AppServices/Enforcement/Permissions/CaseFileViewRequirement.cs create mode 100644 src/AppServices/Enforcement/Permissions/EnforcementOperation.cs create mode 100644 src/AppServices/Enforcement/Query/CaseFileViewDto.cs create mode 100644 src/Domain/EnforcementEntities/Actions/IResolvable.cs create mode 100644 src/Domain/EnforcementEntities/ICaseFileRepository.cs create mode 100644 src/Domain/EnforcementEntities/IEnforcementActionRepository.cs create mode 100644 src/LocalRepository/Repositories/LocalCaseFileRepository.cs create mode 100644 src/LocalRepository/Repositories/LocalEnforcementActionRepository.cs diff --git a/src/AppServices/AppServices.csproj b/src/AppServices/AppServices.csproj index c2434b25..ee453f6e 100644 --- a/src/AppServices/AppServices.csproj +++ b/src/AppServices/AppServices.csproj @@ -25,10 +25,6 @@ - - - - WorkEntryService.cs diff --git a/src/AppServices/AutoMapper/AutoMapperProfile.cs b/src/AppServices/AutoMapper/AutoMapperProfile.cs index 4a84987c..adb55112 100644 --- a/src/AppServices/AutoMapper/AutoMapperProfile.cs +++ b/src/AppServices/AutoMapper/AutoMapperProfile.cs @@ -8,12 +8,14 @@ using AirWeb.AppServices.Compliance.WorkEntries.Reports; using AirWeb.AppServices.Compliance.WorkEntries.SourceTestReviews; using AirWeb.AppServices.Compliance.WorkEntries.WorkEntryDto.Query; +using AirWeb.AppServices.Enforcement.Query; using AirWeb.AppServices.NamedEntities.NotificationTypes; using AirWeb.AppServices.NamedEntities.Offices; using AirWeb.AppServices.Staff.Dto; using AirWeb.Domain.Comments; using AirWeb.Domain.ComplianceEntities.Fces; using AirWeb.Domain.ComplianceEntities.WorkEntries; +using AirWeb.Domain.EnforcementEntities.Cases; using AirWeb.Domain.Identity; using AirWeb.Domain.NamedEntities.NotificationTypes; using AirWeb.Domain.NamedEntities.Offices; @@ -38,6 +40,7 @@ public AutoMapperProfile() RmpInspections(); SourceTestReviews(); SearchResults(); + Enforcement(); } private void WorkEntries() @@ -147,4 +150,10 @@ private void SearchResults() CreateMap() .ForMember(dto => dto.FacilityName, expression => expression.Ignore()); } + + private void Enforcement() + { + CreateMap() + .ForMember(dto => dto.FacilityName, expression => expression.Ignore()); + } } diff --git a/src/AppServices/Enforcement/Command/CaseFileCreateDto.cs b/src/AppServices/Enforcement/Command/CaseFileCreateDto.cs new file mode 100644 index 00000000..b256dff6 --- /dev/null +++ b/src/AppServices/Enforcement/Command/CaseFileCreateDto.cs @@ -0,0 +1,30 @@ +using IaipDataService.Facilities; + +namespace AirWeb.AppServices.Enforcement.Command; + +public record CaseFileCreateDto +{ + public CaseFileCreateDto() { } + + public CaseFileCreateDto(FacilityId facilityId, string userId) + { + FacilityId = facilityId; + ResponsibleStaffId = userId; + } + + [Required] + [Display(Name = "Facility")] + public string? FacilityId { get; init; } + + [Required] + [Display(Name = "Staff Responsible")] + public string? ResponsibleStaffId { get; init; } + + [Required] + public DateOnly? DiscoveryDate { get; set; } + + [DataType(DataType.MultilineText)] + [StringLength(7000)] + [Display(Name = "Notes")] + public string? Notes { get; init; } +} diff --git a/src/AppServices/Enforcement/EnforcementService.cs b/src/AppServices/Enforcement/EnforcementService.cs new file mode 100644 index 00000000..28fd5db5 --- /dev/null +++ b/src/AppServices/Enforcement/EnforcementService.cs @@ -0,0 +1,32 @@ +using AirWeb.AppServices.Comments; +using AirWeb.AppServices.CommonDtos; +using AirWeb.AppServices.Enforcement.Command; +using AirWeb.AppServices.Enforcement.Query; +using AirWeb.Domain.EnforcementEntities; +using AutoMapper; + +namespace AirWeb.AppServices.Enforcement; + +public class EnforcementService( + IMapper mapper, + ICaseFileRepository repository) : IEnforcementService +{ + public async Task FindAsync(int id, CancellationToken token = default) => + mapper.Map(await repository.FindAsync(id, token).ConfigureAwait(false)); + + public Task> CreateCaseFileAsync(CaseFileCreateDto resource, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task> AddCommentAsync(int itemId, CommentAddDto resource, + CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task DeleteCommentAsync(Guid commentId, CancellationToken token = default) + { + throw new NotImplementedException(); + } +} diff --git a/src/AppServices/Enforcement/IEnforcementService.cs b/src/AppServices/Enforcement/IEnforcementService.cs new file mode 100644 index 00000000..7175ed3e --- /dev/null +++ b/src/AppServices/Enforcement/IEnforcementService.cs @@ -0,0 +1,19 @@ +using AirWeb.AppServices.Comments; +using AirWeb.AppServices.CommonDtos; +using AirWeb.AppServices.Enforcement.Command; +using AirWeb.AppServices.Enforcement.Query; + +namespace AirWeb.AppServices.Enforcement; + +public interface IEnforcementService +{ + // Query + Task FindAsync(int id, CancellationToken token = default); + + // Command + Task> CreateCaseFileAsync(CaseFileCreateDto resource, CancellationToken token = default); + + // Comments + Task> AddCommentAsync(int itemId, CommentAddDto resource, CancellationToken token = default); + Task DeleteCommentAsync(Guid commentId, CancellationToken token = default); +} diff --git a/src/AppServices/Enforcement/Permissions/CaseFileViewRequirement.cs b/src/AppServices/Enforcement/Permissions/CaseFileViewRequirement.cs new file mode 100644 index 00000000..1327b23a --- /dev/null +++ b/src/AppServices/Enforcement/Permissions/CaseFileViewRequirement.cs @@ -0,0 +1,35 @@ +using AirWeb.AppServices.Enforcement.Query; +using Microsoft.AspNetCore.Authorization; + +namespace AirWeb.AppServices.Enforcement.Permissions; + +internal class CaseFileViewRequirement(IEnforcementService service) : + AuthorizationHandler +{ + protected override Task HandleRequirementAsync( + AuthorizationHandlerContext context, + EnforcementOperation requirement, + CaseFileViewDto resource) + { + if (context.User.Identity is not { IsAuthenticated: true }) + return Task.FromResult(0); + + var success = requirement.Name switch + { + nameof(EnforcementOperation.AddComment) => EnforcementOperation.CanAddComment(context.User, resource), + nameof(EnforcementOperation.Close) => EnforcementOperation.CanClose(context.User, resource), + nameof(EnforcementOperation.Delete) => EnforcementOperation.CanDelete(context.User, resource), + nameof(EnforcementOperation.DeleteComment) => EnforcementOperation.CanDeleteComment(context.User, resource), + nameof(EnforcementOperation.Edit) => EnforcementOperation.CanEdit(context.User, resource), + nameof(EnforcementOperation.Reopen) => EnforcementOperation.CanReopen(context.User, resource), + nameof(EnforcementOperation.Restore) => EnforcementOperation.CanRestore(context.User, resource), + nameof(EnforcementOperation.View) => EnforcementOperation.CanView(context.User, resource), + nameof(EnforcementOperation.ViewDeleted) => EnforcementOperation.CanManageDeletions(context.User), + _ => false, + }; + + if (success) context.Succeed(requirement); + + return Task.FromResult(0); + } +} diff --git a/src/AppServices/Enforcement/Permissions/EnforcementOperation.cs b/src/AppServices/Enforcement/Permissions/EnforcementOperation.cs new file mode 100644 index 00000000..7335222b --- /dev/null +++ b/src/AppServices/Enforcement/Permissions/EnforcementOperation.cs @@ -0,0 +1,67 @@ +using AirWeb.AppServices.CommonInterfaces; +using AirWeb.AppServices.Permissions.Helpers; +using Microsoft.AspNetCore.Authorization.Infrastructure; +using Microsoft.Identity.Web; +using System.Security.Claims; + +namespace AirWeb.AppServices.Enforcement.Permissions; + +public class EnforcementOperation : + OperationAuthorizationRequirement // implements IAuthorizationRequirement +{ + private EnforcementOperation(string name) + { + Name = name; + AllOperations.Add(this); + } + + public static List AllOperations { get; } = []; + + public static readonly EnforcementOperation AddComment = new(nameof(AddComment)); + public static readonly EnforcementOperation Close = new(nameof(Close)); + public static readonly EnforcementOperation Delete = new(nameof(Delete)); + public static readonly EnforcementOperation DeleteComment = new(nameof(DeleteComment)); + public static readonly EnforcementOperation Edit = new(nameof(Edit)); + public static readonly EnforcementOperation Reopen = new(nameof(Reopen)); + public static readonly EnforcementOperation Restore = new(nameof(Restore)); + public static readonly EnforcementOperation View = new(nameof(View)); + public static readonly EnforcementOperation ViewDeleted = new(nameof(ViewDeleted)); + + // Operation requirement handler helpers + internal static bool CanAddComment(ClaimsPrincipal user, IDeletable item) => + user.IsComplianceStaff() && !item.IsDeleted; + + internal static bool CanClose(ClaimsPrincipal user, ICloseableAndDeletable item) => + CanCloseOrReopen(user, item) && !item.IsClosed; + + private static bool CanCloseOrReopen(ClaimsPrincipal user, IDeletable item) => + user.IsComplianceStaff() && !item.IsDeleted; + + internal static bool CanDelete(ClaimsPrincipal user, IDeletable item) => + CanManageDeletions(user) && !item.IsDeleted; + + internal static bool CanDeleteComment(ClaimsPrincipal user, IHasOwnerAndDeletable item) => + (CanManageDeletions(user) || IsOwner(user, item)) && !item.IsDeleted; + + internal static bool CanEdit(ClaimsPrincipal user, ICloseableAndDeletable item) => + user.IsComplianceStaff() && item is { IsClosed: false, IsDeleted: false }; + + internal static bool CanEdit(ClaimsPrincipal user, IDeletable item) => + user.IsComplianceStaff() && !item.IsDeleted; + + internal static bool CanManageDeletions(ClaimsPrincipal user) => user.IsComplianceManager(); + + internal static bool CanReopen(ClaimsPrincipal user, ICloseableAndDeletable item) => + CanCloseOrReopen(user, item) && item.IsClosed; + + internal static bool CanRestore(ClaimsPrincipal user, IDeletable item) => + CanManageDeletions(user) && item.IsDeleted; + + internal static bool CanView(ClaimsPrincipal user, ICloseableAndDeletable item) => + CanManageDeletions(user) || + !item.IsDeleted && user.IsComplianceStaff() || + item.IsClosed && user.IsStaff(); + + private static bool IsOwner(ClaimsPrincipal user, IHasOwner item) => + item.OwnerId.Equals(user.GetNameIdentifierId()); +} diff --git a/src/AppServices/Enforcement/Query/CaseFileViewDto.cs b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs new file mode 100644 index 00000000..ac751a99 --- /dev/null +++ b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs @@ -0,0 +1,64 @@ +using AirWeb.AppServices.Comments; +using AirWeb.AppServices.CommonInterfaces; +using AirWeb.AppServices.Compliance.WorkEntries.WorkEntryDto.Query; +using AirWeb.AppServices.Staff.Dto; +using AirWeb.Domain.EnforcementEntities.Cases; +using AirWeb.Domain.EnforcementEntities.ViolationTypes; +using IaipDataService.Facilities; + +namespace AirWeb.AppServices.Enforcement.Query; + +public record CaseFileViewDto : ICloseableAndDeletable, IHasOwnerAndDeletable +{ + public int Id { get; init; } + public bool IsClosed { get; init; } + public string FacilityId { get; init; } = null!; + public string? FacilityName { get; set; } + + [Display(Name = "Staff Responsible")] + public StaffViewDto? ResponsibleStaff { get; init; } + + public EnforcementCaseStatus Status { get; init; } + + [Display(Name = "Violation Type")] + public ViolationType? ViolationType { get; init; } + + [Display(Name = "Discovery Date")] + public DateOnly? DiscoveryDate { get; init; } + + [Display(Name = "Day Zero")] + public DateOnly? DayZero { get; init; } + + public string Notes { get; init; } = null!; + public ICollection Pollutants { get; } = []; + public ICollection AirPrograms { get; } = []; + public ICollection ComplianceEvents { get; } = []; + + [UsedImplicitly] + public List Comments { get; } = []; + + // TODO + // public ICollection EnforcementActions { get; } = []; + + // Properties: Closure + [Display(Name = "Completed By")] + public StaffViewDto? ClosedBy { get; init; } + + [Display(Name = "Date Closed")] + public DateOnly? ClosedDate { get; init; } + + // Properties: Deletion + public bool IsDeleted { get; init; } + + [Display(Name = "Deleted by")] + public StaffViewDto? DeletedBy { get; init; } + + [Display(Name = "Date deleted")] + public DateTimeOffset? DeletedAt { get; init; } + + [Display(Name = "Deletion Comments")] + public string? DeleteComments { get; init; } + + // Calculated properties + public string OwnerId => ResponsibleStaff?.Id ?? string.Empty; +} diff --git a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs index 1ed9e76e..f12932ed 100644 --- a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs @@ -3,7 +3,7 @@ namespace AirWeb.Domain.EnforcementEntities.Actions; -public class AdministrativeOrder : EnforcementAction +public class AdministrativeOrder : EnforcementAction, IResolvable { // Constructors [UsedImplicitly] // Used by ORM. @@ -18,5 +18,6 @@ internal AdministrativeOrder(Guid id, CaseFile caseFile, ApplicationUser? user) public DateOnly? ExecutedDate { get; set; } public DateOnly? AppealedDate { get; set; } public DateOnly? ResolvedDate { get; set; } + public bool IsResolved => ResolvedDate.HasValue; public AoResolvedLetter? ResolvedLetter { get; set; } } diff --git a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs index 6611cacb..7f61ddd9 100644 --- a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs @@ -5,7 +5,7 @@ namespace AirWeb.Domain.EnforcementEntities.Actions; -public class ConsentOrder : EnforcementAction +public class ConsentOrder : EnforcementAction, IResolvable { // Constructors [UsedImplicitly] // Used by ORM. @@ -30,6 +30,7 @@ internal ConsentOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : public DateOnly? ExecutedDate { get; set; } public DateOnly? ReceivedFromDirectorsOffice { get; set; } public DateOnly? ResolvedDate { get; set; } + public bool IsResolved => ResolvedDate.HasValue; public CoResolvedLetter? ResolvedLetter { get; set; } public short? OrderNumber { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/IResolvable.cs b/src/Domain/EnforcementEntities/Actions/IResolvable.cs new file mode 100644 index 00000000..9fb94e62 --- /dev/null +++ b/src/Domain/EnforcementEntities/Actions/IResolvable.cs @@ -0,0 +1,6 @@ +namespace AirWeb.Domain.EnforcementEntities.Actions; + +public interface IResolvable +{ + public bool IsResolved { get; } +} diff --git a/src/Domain/EnforcementEntities/ICaseFileRepository.cs b/src/Domain/EnforcementEntities/ICaseFileRepository.cs new file mode 100644 index 00000000..16166859 --- /dev/null +++ b/src/Domain/EnforcementEntities/ICaseFileRepository.cs @@ -0,0 +1,21 @@ +using AirWeb.Domain.EnforcementEntities.Cases; + +namespace AirWeb.Domain.EnforcementEntities; + +public interface ICaseFileRepository : IRepository, ICommentRepository +{ + public static string[] IncludeComments => [nameof(CaseFile.Comments)]; + + // Will return the next available ID if the repository requires it for adding new entities (e.g., local repository). + // Will return null if the repository creates a new ID on insert (e.g., Entity Framework). + int? GetNextId(); + + /// + /// Returns the with the given . Returns null if there are no matches. + /// The returned entity will include the Comments navigation property. + /// + /// The ID of the entity. + /// + /// A Case File with Comments included or null. + Task FindWithCommentsAsync(int id, CancellationToken token = default); +} diff --git a/src/Domain/EnforcementEntities/IEnforcementActionRepository.cs b/src/Domain/EnforcementEntities/IEnforcementActionRepository.cs new file mode 100644 index 00000000..75dc288a --- /dev/null +++ b/src/Domain/EnforcementEntities/IEnforcementActionRepository.cs @@ -0,0 +1,5 @@ +using AirWeb.Domain.EnforcementEntities.Actions; + +namespace AirWeb.Domain.EnforcementEntities; + +public interface IEnforcementActionRepository : IRepository { } diff --git a/src/LocalRepository/Repositories/LocalCaseFileRepository.cs b/src/LocalRepository/Repositories/LocalCaseFileRepository.cs new file mode 100644 index 00000000..722cce6a --- /dev/null +++ b/src/LocalRepository/Repositories/LocalCaseFileRepository.cs @@ -0,0 +1,44 @@ +using AirWeb.Domain.Comments; +using AirWeb.Domain.EnforcementEntities; +using AirWeb.Domain.EnforcementEntities.Cases; +using AirWeb.TestData.Enforcement; + +namespace AirWeb.LocalRepository.Repositories; + +public sealed class LocalCaseFileRepository(IEnforcementActionRepository actionRepository) + : BaseRepository(CaseFileData.GetData), ICaseFileRepository +{ + public new async Task GetAsync(int id, CancellationToken token = default) + { + var caseFile = await base.GetAsync(id, token).ConfigureAwait(false); + + caseFile.EnforcementActions.AddRange(await actionRepository + .GetListAsync(action => action.CaseFile.Id.Equals(id), token).ConfigureAwait(false)); + + return caseFile; + } + + + // Local repository requires ID to be manually set. + public int? GetNextId() => Items.Count == 0 ? 1 : Items.Select(caseFile => caseFile.Id).Max() + 1; + + public Task FindWithCommentsAsync(int id, CancellationToken token = default) => + FindAsync(id, token); + + public async Task AddCommentAsync(int itemId, Comment comment, CancellationToken token = default) => + (await GetAsync(itemId, token).ConfigureAwait(false)).Comments.Add(new CaseFileComment(comment, itemId)); + + public Task DeleteCommentAsync(Guid commentId, string? userId, CancellationToken token = default) + { + var comment = Items.SelectMany(caseFile => caseFile.Comments) + .FirstOrDefault(comment => comment.Id == commentId); + + if (comment != null) + { + var caseFile = Items.First(caseFile => caseFile.Comments.Contains(comment)); + caseFile.Comments.Remove(comment); + } + + return Task.CompletedTask; + } +} diff --git a/src/LocalRepository/Repositories/LocalEnforcementActionRepository.cs b/src/LocalRepository/Repositories/LocalEnforcementActionRepository.cs new file mode 100644 index 00000000..49c71fd3 --- /dev/null +++ b/src/LocalRepository/Repositories/LocalEnforcementActionRepository.cs @@ -0,0 +1,9 @@ +using AirWeb.Domain.EnforcementEntities; +using AirWeb.Domain.EnforcementEntities.Actions; +using AirWeb.TestData.Enforcement; + +namespace AirWeb.LocalRepository.Repositories; + +public class LocalEnforcementActionRepository() + : BaseRepository(EnforcementActionData.GetData), + IEnforcementActionRepository { } diff --git a/src/WebApp/Platform/AppConfiguration/DataPersistence.cs b/src/WebApp/Platform/AppConfiguration/DataPersistence.cs index e0ba43db..9d06f671 100644 --- a/src/WebApp/Platform/AppConfiguration/DataPersistence.cs +++ b/src/WebApp/Platform/AppConfiguration/DataPersistence.cs @@ -1,5 +1,6 @@ using AirWeb.Domain.ComplianceEntities.Fces; using AirWeb.Domain.ComplianceEntities.WorkEntries; +using AirWeb.Domain.EnforcementEntities; using AirWeb.Domain.NamedEntities.NotificationTypes; using AirWeb.Domain.NamedEntities.Offices; using AirWeb.Domain.Search; @@ -28,7 +29,9 @@ public static IServiceCollection AddDataPersistence(this IServiceCollection serv .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton(); + .AddSingleton() + .AddSingleton() + .AddSingleton(); return services; } @@ -61,7 +64,11 @@ public static IServiceCollection AddDataPersistence(this IServiceCollection serv .AddScoped() .AddScoped() .AddScoped() - .AddScoped(); + .AddScoped() + + // TODO: Replace these with EF repositories. + .AddSingleton() + .AddSingleton(); return services; } From f9528f747f4b339311611cf85612d24092612aa7 Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Tue, 17 Dec 2024 13:14:40 -0500 Subject: [PATCH 07/13] Continue work on enforcement details page --- .../Enforcement/EnforcementService.cs | 18 +++- .../RegisterServices/AppServices.cs | 4 + .../RegisterServices/AuthorizationPolicies.cs | 2 + .../Repositories/WorkEntryRepository.cs | 2 +- .../Pages/Compliance/FCE/Details.cshtml | 2 +- .../Pages/Compliance/Work/Details.cshtml | 5 +- src/WebApp/Pages/Enforcement/Details.cshtml | 93 +++++++++++++++++++ .../Pages/Enforcement/Details.cshtml.cs | 91 ++++++++++++++++++ 8 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 src/WebApp/Pages/Enforcement/Details.cshtml create mode 100644 src/WebApp/Pages/Enforcement/Details.cshtml.cs diff --git a/src/AppServices/Enforcement/EnforcementService.cs b/src/AppServices/Enforcement/EnforcementService.cs index 28fd5db5..b5c4db46 100644 --- a/src/AppServices/Enforcement/EnforcementService.cs +++ b/src/AppServices/Enforcement/EnforcementService.cs @@ -4,15 +4,27 @@ using AirWeb.AppServices.Enforcement.Query; using AirWeb.Domain.EnforcementEntities; using AutoMapper; +using IaipDataService.Facilities; namespace AirWeb.AppServices.Enforcement; public class EnforcementService( IMapper mapper, - ICaseFileRepository repository) : IEnforcementService + ICaseFileRepository repository, + IFacilityService facilityService) : IEnforcementService { - public async Task FindAsync(int id, CancellationToken token = default) => - mapper.Map(await repository.FindAsync(id, token).ConfigureAwait(false)); + public async Task FindAsync(int id, CancellationToken token = default) + { + var caseFile = mapper.Map(await repository.FindAsync(id, token).ConfigureAwait(false)); + + if (caseFile != null) + { + caseFile.FacilityName = + await facilityService.GetNameAsync((FacilityId)caseFile.FacilityId).ConfigureAwait(false); + } + + return caseFile; + } public Task> CreateCaseFileAsync(CaseFileCreateDto resource, CancellationToken token = default) { diff --git a/src/AppServices/RegisterServices/AppServices.cs b/src/AppServices/RegisterServices/AppServices.cs index 539c4e32..369160eb 100644 --- a/src/AppServices/RegisterServices/AppServices.cs +++ b/src/AppServices/RegisterServices/AppServices.cs @@ -3,6 +3,7 @@ using AirWeb.AppServices.Compliance.Fces; using AirWeb.AppServices.Compliance.Search; using AirWeb.AppServices.Compliance.WorkEntries; +using AirWeb.AppServices.Enforcement; using AirWeb.AppServices.NamedEntities.NotificationTypes; using AirWeb.AppServices.NamedEntities.Offices; using AirWeb.Domain.ComplianceEntities.Fces; @@ -34,6 +35,9 @@ public static IServiceCollection AddAppServices(this IServiceCollection services .AddScoped() .AddScoped() + // Enforcement + .AddScoped() + // Email .AddScoped() diff --git a/src/AppServices/RegisterServices/AuthorizationPolicies.cs b/src/AppServices/RegisterServices/AuthorizationPolicies.cs index 0ecf50fa..a391ad0c 100644 --- a/src/AppServices/RegisterServices/AuthorizationPolicies.cs +++ b/src/AppServices/RegisterServices/AuthorizationPolicies.cs @@ -1,5 +1,6 @@ using AirWeb.AppServices.Compliance.Fces; using AirWeb.AppServices.Compliance.WorkEntries.WorkEntryDto.Permissions; +using AirWeb.AppServices.Enforcement.Permissions; using AirWeb.AppServices.Permissions; using AirWeb.AppServices.Permissions.AppClaims; using Microsoft.AspNetCore.Authentication; @@ -20,6 +21,7 @@ public static void AddAuthorizationHandlers(this IServiceCollection services) // var canAssign = await authorization.Succeeded(User, entryView, WorkEntryOperation.EditWorkEntry); // ViewRequirements are added scoped if they consume scoped services. + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/src/EfRepository/Repositories/WorkEntryRepository.cs b/src/EfRepository/Repositories/WorkEntryRepository.cs index 98079efa..11052776 100644 --- a/src/EfRepository/Repositories/WorkEntryRepository.cs +++ b/src/EfRepository/Repositories/WorkEntryRepository.cs @@ -18,7 +18,7 @@ public sealed class WorkEntryRepository(AppDbContext context) public Task FindWithCommentsAsync(int id, CancellationToken token = default) where TEntry : WorkEntry => Context.Set().AsNoTracking() - .Include(fce => fce.Comments + .Include(entry => entry.Comments .Where(comment => !comment.DeletedAt.HasValue) .OrderBy(comment => comment.CommentedAt).ThenBy(comment => comment.Id)) .SingleOrDefaultAsync(entry => entry.Id.Equals(id), token); diff --git a/src/WebApp/Pages/Compliance/FCE/Details.cshtml b/src/WebApp/Pages/Compliance/FCE/Details.cshtml index 89722ec4..eeb94785 100644 --- a/src/WebApp/Pages/Compliance/FCE/Details.cshtml +++ b/src/WebApp/Pages/Compliance/FCE/Details.cshtml @@ -7,7 +7,7 @@ @model DetailsModel @{ var report = Model.Item!; - ViewData["Title"] = $"FCE Report for {report.Year.ToString()}, Facility {report.FacilityId}"; + ViewData["Title"] = $"{report.Year.ToString()} FCE Report for Facility {report.FacilityId}"; } @if (report.IsDeleted) diff --git a/src/WebApp/Pages/Compliance/Work/Details.cshtml b/src/WebApp/Pages/Compliance/Work/Details.cshtml index 649843c6..a797942f 100644 --- a/src/WebApp/Pages/Compliance/Work/Details.cshtml +++ b/src/WebApp/Pages/Compliance/Work/Details.cshtml @@ -1,4 +1,4 @@ -@page "{id:int?}" +@page "{id:int?}" @using AirWeb.AppServices.Compliance.Permissions @using AirWeb.AppServices.Compliance.WorkEntries.Accs @using AirWeb.AppServices.Compliance.WorkEntries.Inspections @@ -84,7 +84,8 @@
Facility
- +
@Html.DisplayNameFor(_ => report.ResponsibleStaff)
@Html.DisplayFor(_ => report.ResponsibleStaff, DisplayTemplate.NameOrPlaceholder)
diff --git a/src/WebApp/Pages/Enforcement/Details.cshtml b/src/WebApp/Pages/Enforcement/Details.cshtml new file mode 100644 index 00000000..91150a65 --- /dev/null +++ b/src/WebApp/Pages/Enforcement/Details.cshtml @@ -0,0 +1,93 @@ +@page "{id:int?}" +@using AirWeb.AppServices.Enforcement.Permissions +@using AirWeb.WebApp.Pages.Shared.DisplayTemplates +@using Microsoft.AspNetCore.Mvc.TagHelpers +@model DetailsModel +@{ + var report = Model.Item!; + ViewData["Title"] = $"Facility {report.FacilityId} – Enforcement ({Model.Id})"; +} + +@if (report.IsDeleted) +{ +
+
+
+
+

This Enforcement has been deleted.

+
+ @if (Model.UserCan[EnforcementOperation.Restore]) + { + + } +
+
+

+ Deleted by @Html.DisplayFor(_ => report.DeletedBy, DisplayTemplate.NameOrPlaceholder) + on @Html.DisplayFor(_ => report.DeletedAt, DisplayTemplate.LongDateTimeOffsetNullable) +

+
Comments
+

@Html.DisplayFor(_ => report.DeleteComments, DisplayTemplate.TextOrPlaceholder)

+
+} + +
+
+

Enforcement

+
+ @if (!report.IsDeleted) + { +
+ @if (Model.UserCan[EnforcementOperation.Close]) + { + Close + } + @if (Model.UserCan[EnforcementOperation.Reopen]) + { + Reopen + } + @if (Model.UserCan[EnforcementOperation.Edit]) + { + Edit + } + @if (Model.UserCan[EnforcementOperation.Delete]) + { + Delete + } +
+ } +
+

Tracking #@Model.Id.ToString()

+ +
+
Facility
+
+ +
+
@Html.DisplayNameFor(_ => report.ResponsibleStaff)
+
@Html.DisplayFor(_ => report.ResponsibleStaff, DisplayTemplate.NameOrPlaceholder)
+
Status
+
+ @if (report.IsClosed) + { + @:Closed by @Html.DisplayFor(_ => report.ClosedBy, DisplayTemplate.NameOrPlaceholder) + @:on @Html.DisplayFor(_ => report.ClosedDate, DisplayTemplate.ShortDateOnlyNullable) + } + else + { + @:Open + } +
+
@Html.DisplayNameFor(_ => report.Notes)
+
@Html.DisplayFor(_ => report.Notes, DisplayTemplate.TextOrPlaceholder)
+
+ + + +@section Scripts { + +} diff --git a/src/WebApp/Pages/Enforcement/Details.cshtml.cs b/src/WebApp/Pages/Enforcement/Details.cshtml.cs new file mode 100644 index 00000000..fb856dfa --- /dev/null +++ b/src/WebApp/Pages/Enforcement/Details.cshtml.cs @@ -0,0 +1,91 @@ +using AirWeb.AppServices.Comments; +using AirWeb.AppServices.Enforcement; +using AirWeb.AppServices.Enforcement.Permissions; +using AirWeb.AppServices.Enforcement.Query; +using AirWeb.AppServices.Permissions; +using AirWeb.AppServices.Permissions.Helpers; +using AirWeb.WebApp.Models; + +namespace AirWeb.WebApp.Pages.Enforcement; + +[Authorize(Policy = nameof(Policies.Staff))] +public class DetailsModel(IEnforcementService enforcementService, IAuthorizationService authorization) : PageModel +{ + [FromRoute] + public int Id { get; set; } + + public CaseFileViewDto? Item { get; private set; } + public CommentsSectionModel CommentSection { get; set; } = null!; + public Dictionary UserCan { get; set; } = new(); + + [TempData] + public Guid NewCommentId { get; set; } + + [TempData] + public string? NotificationFailureMessage { get; set; } + + public async Task OnGetAsync() + { + if (Id == 0) return RedirectToPage("Index"); + Item = await enforcementService.FindAsync(Id); + if (Item is null) return NotFound(); + + await SetPermissionsAsync(); + if (Item.IsDeleted && !UserCan[EnforcementOperation.ViewDeleted]) return NotFound(); + if (!Item.IsClosed && !UserCan[EnforcementOperation.View]) return NotFound(); + + CommentSection = new CommentsSectionModel + { + Comments = Item.Comments, + NewComment = new CommentAddDto(Id), + NewCommentId = NewCommentId, + NotificationFailureMessage = NotificationFailureMessage, + CanAddComment = UserCan[EnforcementOperation.AddComment], + CanDeleteComment = UserCan[EnforcementOperation.DeleteComment], + }; + return Page(); + } + + public async Task OnPostNewCommentAsync(CommentAddDto newComment, + CancellationToken token) + { + Item = await enforcementService.FindAsync(Id, token); + if (Item is null || Item.IsDeleted) return BadRequest(); + + await SetPermissionsAsync(); + if (!UserCan[EnforcementOperation.AddComment]) return BadRequest(); + + if (!ModelState.IsValid) + { + CommentSection = new CommentsSectionModel + { + Comments = Item.Comments, + NewComment = newComment, + CanAddComment = UserCan[EnforcementOperation.AddComment], + CanDeleteComment = UserCan[EnforcementOperation.DeleteComment], + }; + return Page(); + } + + var addCommentResult = await enforcementService.AddCommentAsync(Id, newComment, token); + NewCommentId = addCommentResult.Id; + if (addCommentResult.AppNotificationResult is { Success: false }) + NotificationFailureMessage = addCommentResult.AppNotificationResult.FailureMessage; + return RedirectToPage("Details", pageHandler: null, routeValues: new { Id }, fragment: NewCommentId.ToString()); + } + + public async Task OnPostDeleteCommentAsync(Guid commentId, CancellationToken token) + { + Item = await enforcementService.FindAsync(Id, token); + if (Item is null || Item.IsDeleted) return BadRequest(); + + await SetPermissionsAsync(); + if (!UserCan[EnforcementOperation.DeleteComment]) return BadRequest(); + + await enforcementService.DeleteCommentAsync(commentId, token); + return RedirectToPage("Details", pageHandler: null, routeValues: new { Id }, fragment: "comments"); + } + + private async Task SetPermissionsAsync() => + UserCan = await authorization.SetPermissions(EnforcementOperation.AllOperations, User, Item); +} From 86e8d436a4b1b8463419e834b59712079ba8be80 Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Wed, 18 Dec 2024 11:46:25 -0500 Subject: [PATCH 08/13] Refactor some formatting CSS --- .../Pages/Compliance/FCE/Details.cshtml | 14 +++++----- .../Pages/Compliance/SourceTest/Index.cshtml | 8 +++--- .../Pages/Compliance/Work/Details.cshtml | 4 +-- src/WebApp/Pages/Facility/Details.cshtml | 26 +++++++++---------- .../CompliancePartials/_FceSearchTable.cshtml | 2 +- .../_SourceTestsTable.cshtml | 2 +- .../_WorkEntrySearchTable.cshtml | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/WebApp/Pages/Compliance/FCE/Details.cshtml b/src/WebApp/Pages/Compliance/FCE/Details.cshtml index eeb94785..fd9fea65 100644 --- a/src/WebApp/Pages/Compliance/FCE/Details.cshtml +++ b/src/WebApp/Pages/Compliance/FCE/Details.cshtml @@ -38,12 +38,12 @@ }
-
+

Full Compliance Evaluation

@if (!report.IsDeleted) { -
+
@if (Model.UserCan[ComplianceWorkOperation.Edit]) { Edit @@ -64,7 +64,7 @@

Tracking #@Model.Id.ToString()

-
+
Facility
@@ -90,13 +90,13 @@
-
-
-
+
+
+

Supporting data for @Html.DisplayFor(_ => report.SupportingDataDateRange, DisplayTemplate.DateRange, additionalViewData: new { Connector = " through ", Format = DateTimeFormatConstants.ShortDateFormat })

-
@Html.DisplayNameFor(_ => report.Postmarked)@Html.DisplayFor(_ => report.Postmarked, DisplayTemplate.LongDateOnly)@Html.DisplayNameFor(_ => report.PostmarkDate)@Html.DisplayFor(_ => report.PostmarkDate, DisplayTemplate.LongDateOnly)
@Html.DisplayNameFor(_ => report.ReceivedDate)
@Html.DisplayNameFor(_ => firstItem.Id) @Html.DisplayNameFor(_ => firstItem.ReferenceNumber)@Html.DisplayNameFor(_ => firstItem.ReceivedByCompliance)@Html.DisplayNameFor(_ => firstItem.ReceivedByComplianceDate) @Html.DisplayNameFor(_ => firstItem.ResponsibleStaff) @Html.DisplayNameFor(_ => firstItem.ComplianceStatus)
@i.Id.ToString() @i.ReferenceNumber.ToString()@Html.DisplayFor(_ => i.ReceivedByCompliance, DisplayTemplate.LongDateOnly)@Html.DisplayFor(_ => i.ReceivedByComplianceDate, DisplayTemplate.LongDateOnly) @i.ResponsibleStaff.SortableFullName @i.ComplianceStatus
+
@if (Model.Spec is null) diff --git a/src/WebApp/Pages/Shared/CompliancePartials/_SourceTestsTable.cshtml b/src/WebApp/Pages/Shared/CompliancePartials/_SourceTestsTable.cshtml index 32e78b37..1f23fae6 100644 --- a/src/WebApp/Pages/Shared/CompliancePartials/_SourceTestsTable.cshtml +++ b/src/WebApp/Pages/Shared/CompliancePartials/_SourceTestsTable.cshtml @@ -3,7 +3,7 @@ @model IList
-
+
diff --git a/src/WebApp/Pages/Shared/CompliancePartials/_WorkEntrySearchTable.cshtml b/src/WebApp/Pages/Shared/CompliancePartials/_WorkEntrySearchTable.cshtml index 628d69dd..647e7963 100644 --- a/src/WebApp/Pages/Shared/CompliancePartials/_WorkEntrySearchTable.cshtml +++ b/src/WebApp/Pages/Shared/CompliancePartials/_WorkEntrySearchTable.cshtml @@ -6,7 +6,7 @@ @model (IList Items, AirWeb.AppServices.Compliance.Search.WorkEntrySearchDto? Spec)
-
Reference Number
+
@if (Model.Spec is null) From dd0042238b07fd0c3ef9113b6d38018a0a509bf3 Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Wed, 18 Dec 2024 11:47:41 -0500 Subject: [PATCH 09/13] Continue work on enforcement details page --- .../AutoMapper/AutoMapperProfile.cs | 4 + .../Enforcement/EnforcementService.cs | 7 +- .../Enforcement/IEnforcementService.cs | 2 +- .../Enforcement/Query/CaseFileViewDto.cs | 3 +- .../Query/EnforcementActionViewDto.cs | 44 +++++++++ .../Enforcement/Query/ReviewDto.cs | 19 ++++ .../EnforcementActionReview.cs | 5 +- .../Actions/EnforcementAction.cs | 4 +- .../ICaseFileRepository.cs | 12 +-- .../AppDbContextConfiguration.cs | 2 +- .../Repositories/LocalCaseFileRepository.cs | 13 ++- .../Enforcement/EnforcementActionData.cs | 36 +++++--- src/WebApp/Pages/Enforcement/Details.cshtml | 89 ++++++++++++++----- .../Pages/Enforcement/Details.cshtml.cs | 6 +- src/WebApp/Pages/Index.cshtml | 20 +++-- 15 files changed, 199 insertions(+), 67 deletions(-) create mode 100644 src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs create mode 100644 src/AppServices/Enforcement/Query/ReviewDto.cs diff --git a/src/AppServices/AutoMapper/AutoMapperProfile.cs b/src/AppServices/AutoMapper/AutoMapperProfile.cs index adb55112..d90211e3 100644 --- a/src/AppServices/AutoMapper/AutoMapperProfile.cs +++ b/src/AppServices/AutoMapper/AutoMapperProfile.cs @@ -15,6 +15,8 @@ using AirWeb.Domain.Comments; using AirWeb.Domain.ComplianceEntities.Fces; using AirWeb.Domain.ComplianceEntities.WorkEntries; +using AirWeb.Domain.EnforcementEntities.ActionProperties; +using AirWeb.Domain.EnforcementEntities.Actions; using AirWeb.Domain.EnforcementEntities.Cases; using AirWeb.Domain.Identity; using AirWeb.Domain.NamedEntities.NotificationTypes; @@ -155,5 +157,7 @@ private void Enforcement() { CreateMap() .ForMember(dto => dto.FacilityName, expression => expression.Ignore()); + CreateMap(); + CreateMap(); } } diff --git a/src/AppServices/Enforcement/EnforcementService.cs b/src/AppServices/Enforcement/EnforcementService.cs index b5c4db46..914b9710 100644 --- a/src/AppServices/Enforcement/EnforcementService.cs +++ b/src/AppServices/Enforcement/EnforcementService.cs @@ -10,12 +10,13 @@ namespace AirWeb.AppServices.Enforcement; public class EnforcementService( IMapper mapper, - ICaseFileRepository repository, + ICaseFileRepository caseFileRepository, IFacilityService facilityService) : IEnforcementService { - public async Task FindAsync(int id, CancellationToken token = default) + public async Task FindDetailedCaseFileAsync(int id, CancellationToken token = default) { - var caseFile = mapper.Map(await repository.FindAsync(id, token).ConfigureAwait(false)); + var caseFile = mapper.Map(await caseFileRepository.FindDetailedCaseFileAsync(id, token) + .ConfigureAwait(false)); if (caseFile != null) { diff --git a/src/AppServices/Enforcement/IEnforcementService.cs b/src/AppServices/Enforcement/IEnforcementService.cs index 7175ed3e..e5fc843a 100644 --- a/src/AppServices/Enforcement/IEnforcementService.cs +++ b/src/AppServices/Enforcement/IEnforcementService.cs @@ -8,7 +8,7 @@ namespace AirWeb.AppServices.Enforcement; public interface IEnforcementService { // Query - Task FindAsync(int id, CancellationToken token = default); + Task FindDetailedCaseFileAsync(int id, CancellationToken token = default); // Command Task> CreateCaseFileAsync(CaseFileCreateDto resource, CancellationToken token = default); diff --git a/src/AppServices/Enforcement/Query/CaseFileViewDto.cs b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs index ac751a99..04cc3432 100644 --- a/src/AppServices/Enforcement/Query/CaseFileViewDto.cs +++ b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs @@ -37,8 +37,7 @@ public record CaseFileViewDto : ICloseableAndDeletable, IHasOwnerAndDeletable [UsedImplicitly] public List Comments { get; } = []; - // TODO - // public ICollection EnforcementActions { get; } = []; + public List EnforcementActions { get; } = []; // Properties: Closure [Display(Name = "Completed By")] diff --git a/src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs b/src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs new file mode 100644 index 00000000..38360fb4 --- /dev/null +++ b/src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs @@ -0,0 +1,44 @@ +using AirWeb.AppServices.Staff.Dto; +using AirWeb.Domain.EnforcementEntities.Actions; + +namespace AirWeb.AppServices.Enforcement.Query; + +public record EnforcementActionViewDto +{ + public Guid Id { get; init; } + public EnforcementActionType EnforcementActionType { get; init; } + public string Notes { get; init; } = null!; + public StaffViewDto? ResponsibleStaff { get; set; } + + // Status + + // -- Issued + public DateOnly? IssueDate { get; internal set; } + public bool IsIssued => IssueDate.HasValue; + + // -- Approved + public bool IsApproved { get; internal set; } + public DateOnly? ApprovedDate { get; internal set; } + public StaffViewDto? ApprovedBy { get; set; } + + // -- Under Review + public StaffViewDto? CurrentReviewer { get; set; } + public DateOnly? ReviewRequestedDate { get; set; } + public ICollection Reviews { get; } = []; + + // -- Closed as Unsent + public DateOnly? ClosedAsUnsent { get; internal set; } + public bool IsClosedAsUnsent => ClosedAsUnsent.HasValue; + + // -- Deleted + public bool IsDeleted { get; init; } + + [Display(Name = "Deleted by")] + public StaffViewDto? DeletedBy { get; init; } + + [Display(Name = "Date deleted")] + public DateTimeOffset? DeletedAt { get; init; } + + [Display(Name = "Deletion Comments")] + public string? DeleteComments { get; init; } +} diff --git a/src/AppServices/Enforcement/Query/ReviewDto.cs b/src/AppServices/Enforcement/Query/ReviewDto.cs new file mode 100644 index 00000000..4ef01b19 --- /dev/null +++ b/src/AppServices/Enforcement/Query/ReviewDto.cs @@ -0,0 +1,19 @@ +using AirWeb.AppServices.Staff.Dto; +using AirWeb.Domain.EnforcementEntities.ActionProperties; + +namespace AirWeb.AppServices.Enforcement.Query; + +public record ReviewDto +{ + public DateOnly RequestedDate { get; internal init; } + public StaffViewDto RequestedTo { get; internal init; } = null!; + public StaffViewDto? ReviewedBy { get; internal init; } + public bool IsCompleted => CompletedDate.HasValue; + public DateOnly? CompletedDate { get; internal set; } + + [StringLength(11)] + public ReviewResult? Status { get; internal set; } + + [StringLength(7000)] + public string? ReviewComments { get; internal set; } +} diff --git a/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs b/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs index 78269b88..09b1f24a 100644 --- a/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs +++ b/src/Domain/EnforcementEntities/ActionProperties/EnforcementActionReview.cs @@ -10,16 +10,19 @@ public class EnforcementActionReview : AuditableEntity [UsedImplicitly] // Used by ORM. private EnforcementActionReview() { } - internal EnforcementActionReview(Guid id, EnforcementAction enforcementAction, ApplicationUser? user) + internal EnforcementActionReview(Guid id, EnforcementAction enforcementAction, ApplicationUser reviewer, + ApplicationUser? user) { Id = id; EnforcementAction = enforcementAction; + RequestedTo = reviewer; SetCreator(user?.Id); } public EnforcementAction EnforcementAction { get; internal init; } = null!; public DateOnly RequestedDate { get; internal init; } + public ApplicationUser RequestedTo { get; internal init; } = null!; public ApplicationUser? ReviewedBy { get; internal init; } public bool IsCompleted => CompletedDate.HasValue; public DateOnly? CompletedDate { get; internal set; } diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs index c8cdb6cf..3608f340 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs @@ -33,8 +33,8 @@ private protected EnforcementAction(Guid id, CaseFile caseFile, ApplicationUser? public ApplicationUser? ResponsibleStaff { get; set; } // Review process - public ApplicationUser? CurrentOwner { get; internal set; } - public DateTimeOffset? CurrentOwnerAssignedDate { get; internal set; } + public ApplicationUser? CurrentReviewer { get; internal set; } + public DateOnly? ReviewRequestedDate { get; internal set; } public ICollection Reviews { get; } = []; public bool IsApproved { get; internal set; } public DateOnly? ApprovedDate { get; internal set; } diff --git a/src/Domain/EnforcementEntities/ICaseFileRepository.cs b/src/Domain/EnforcementEntities/ICaseFileRepository.cs index 16166859..bd4800c3 100644 --- a/src/Domain/EnforcementEntities/ICaseFileRepository.cs +++ b/src/Domain/EnforcementEntities/ICaseFileRepository.cs @@ -1,4 +1,5 @@ -using AirWeb.Domain.EnforcementEntities.Cases; +using AirWeb.Domain.EnforcementEntities.Actions; +using AirWeb.Domain.EnforcementEntities.Cases; namespace AirWeb.Domain.EnforcementEntities; @@ -12,10 +13,11 @@ public interface ICaseFileRepository : IRepository, ICommentRepos /// /// Returns the with the given . Returns null if there are no matches. - /// The returned entity will include the Comments navigation property. + /// The returned entity will include all navigation properties (, + /// ). /// - /// The ID of the entity. + /// The ID (tracking number) of the Case File. /// - /// A Case File with Comments included or null. - Task FindWithCommentsAsync(int id, CancellationToken token = default); + /// A Case File with all properties included or null. + Task FindDetailedCaseFileAsync(int id, CancellationToken token = default); } diff --git a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs index a374ac05..abd07aa5 100644 --- a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs +++ b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs @@ -40,7 +40,7 @@ internal static ModelBuilder ConfigureNavigationAutoIncludes(this ModelBuilder b var enforcementActionEntity = builder.Entity(); enforcementActionEntity.Navigation(enforcementAction => enforcementAction.ResponsibleStaff).AutoInclude(); enforcementActionEntity.Navigation(enforcementAction => enforcementAction.ApprovedBy).AutoInclude(); - enforcementActionEntity.Navigation(enforcementAction => enforcementAction.CurrentOwner).AutoInclude(); + enforcementActionEntity.Navigation(enforcementAction => enforcementAction.CurrentReviewer).AutoInclude(); var enforcementActionReviewEntity = builder.Entity(); enforcementActionReviewEntity.Navigation(review => review.ReviewedBy).AutoInclude(); diff --git a/src/LocalRepository/Repositories/LocalCaseFileRepository.cs b/src/LocalRepository/Repositories/LocalCaseFileRepository.cs index 722cce6a..d103a36f 100644 --- a/src/LocalRepository/Repositories/LocalCaseFileRepository.cs +++ b/src/LocalRepository/Repositories/LocalCaseFileRepository.cs @@ -8,23 +8,20 @@ namespace AirWeb.LocalRepository.Repositories; public sealed class LocalCaseFileRepository(IEnforcementActionRepository actionRepository) : BaseRepository(CaseFileData.GetData), ICaseFileRepository { - public new async Task GetAsync(int id, CancellationToken token = default) + // Local repository requires ID to be manually set. + public int? GetNextId() => Items.Count == 0 ? 1 : Items.Select(caseFile => caseFile.Id).Max() + 1; + + public async Task FindDetailedCaseFileAsync(int id, CancellationToken token = default) { var caseFile = await base.GetAsync(id, token).ConfigureAwait(false); + caseFile.EnforcementActions.Clear(); caseFile.EnforcementActions.AddRange(await actionRepository .GetListAsync(action => action.CaseFile.Id.Equals(id), token).ConfigureAwait(false)); return caseFile; } - - // Local repository requires ID to be manually set. - public int? GetNextId() => Items.Count == 0 ? 1 : Items.Select(caseFile => caseFile.Id).Max() + 1; - - public Task FindWithCommentsAsync(int id, CancellationToken token = default) => - FindAsync(id, token); - public async Task AddCommentAsync(int itemId, Comment comment, CancellationToken token = default) => (await GetAsync(itemId, token).ConfigureAwait(false)).Comments.Add(new CaseFileComment(comment, itemId)); diff --git a/src/TestData/Enforcement/EnforcementActionData.cs b/src/TestData/Enforcement/EnforcementActionData.cs index f741381c..8378c4a7 100644 --- a/src/TestData/Enforcement/EnforcementActionData.cs +++ b/src/TestData/Enforcement/EnforcementActionData.cs @@ -2,6 +2,7 @@ using AirWeb.Domain.EnforcementEntities.Actions; using AirWeb.TestData.Identity; using AirWeb.TestData.SampleData; +using Random = System.Random; namespace AirWeb.TestData.Enforcement; @@ -212,8 +213,8 @@ public static IEnumerable GetData foreach (var enforcementAction in _enforcementActions) { enforcementAction.ResponsibleStaff = UserData.GetRandomUser(); - enforcementAction.CurrentOwner = UserData.GetRandomUser(); - enforcementAction.CurrentOwnerAssignedDate = DateTimeOffset.Now.AddDays(-10); + enforcementAction.CurrentReviewer = UserData.GetRandomUser(); + enforcementAction.ReviewRequestedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-10).Date); } foreach (var enforcementAction in _enforcementActions.Where(action => action.IsIssued)) @@ -251,20 +252,33 @@ private static void GenerateStipulatedPenalties(ConsentOrder consentOrder) private static void GenerateEnforcementActionReviews(EnforcementAction enforcementAction) { - var reviewCount = new Random().Next(1, 3); // Generate 1 or 2 reviews + var random = new Random(); + var reviewCount = random.Next(1, 4); // Generate 1 to 3 reviews. for (var i = 0; i < reviewCount; i++) { - var review = new EnforcementActionReview(Guid.NewGuid(), enforcementAction, UserData.GetRandomUser()) - { - RequestedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-10 * (i + 1)).Date), - CompletedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-5 * (i + 1)).Date), - Status = (ReviewResult)new Random().Next(0, 4), // Random status - ReviewComments = SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), - ReviewedBy = UserData.GetRandomUser(), - }; + var incomplete = i + 1 == reviewCount && random.NextBoolean(); // Final review may be incomplete. + var review = GenerateReview(i, incomplete, enforcementAction, random); enforcementAction.Reviews.Add(review); } } + private static EnforcementActionReview GenerateReview(int i, bool incomplete, EnforcementAction enforcementAction, + Random random) + { + var requestedDate = DateOnly.FromDateTime(DateTime.Now).AddDays(-10 * (i + 1)); + return new EnforcementActionReview(Guid.NewGuid(), enforcementAction, UserData.GetRandomUser(), null) + { + RequestedDate = requestedDate, + CompletedDate = incomplete ? null : requestedDate.AddDays(random.Next(1, 5)), + Status = incomplete ? null : (ReviewResult)random.Next(0, 4), // Random status + ReviewComments = incomplete ? null : SampleText.GetRandomText(SampleText.TextLength.Paragraph, true), + ReviewedBy = incomplete ? null : UserData.GetRandomUser(), + }; + } + + // Next() returns an int in the range [0..Int32.MaxValue] + private const int HalfMaxValue = int.MaxValue / 2; + private static bool NextBoolean(this Random random) => random.Next() > HalfMaxValue; + public static void ClearData() => _enforcementActions = null; } diff --git a/src/WebApp/Pages/Enforcement/Details.cshtml b/src/WebApp/Pages/Enforcement/Details.cshtml index 91150a65..d4cc3ee3 100644 --- a/src/WebApp/Pages/Enforcement/Details.cshtml +++ b/src/WebApp/Pages/Enforcement/Details.cshtml @@ -1,20 +1,22 @@ @page "{id:int?}" @using AirWeb.AppServices.Enforcement.Permissions +@using AirWeb.Domain.EnforcementEntities.Cases @using AirWeb.WebApp.Pages.Shared.DisplayTemplates +@using GaEpd.AppLibrary.Extensions @using Microsoft.AspNetCore.Mvc.TagHelpers @model DetailsModel @{ - var report = Model.Item!; - ViewData["Title"] = $"Facility {report.FacilityId} – Enforcement ({Model.Id})"; + var caseFile = Model.Item!; + ViewData["Title"] = $"Facility {caseFile.FacilityId} – Enforcement ({Model.Id})"; } -@if (report.IsDeleted) +@if (caseFile.IsDeleted) {
-

This Enforcement has been deleted.

+

This Enforcement has been deleted.

@if (Model.UserCan[EnforcementOperation.Restore]) { @@ -27,21 +29,21 @@

- Deleted by @Html.DisplayFor(_ => report.DeletedBy, DisplayTemplate.NameOrPlaceholder) - on @Html.DisplayFor(_ => report.DeletedAt, DisplayTemplate.LongDateTimeOffsetNullable) + Deleted by @Html.DisplayFor(_ => caseFile.DeletedBy, DisplayTemplate.NameOrPlaceholder) + on @Html.DisplayFor(_ => caseFile.DeletedAt, DisplayTemplate.LongDateTimeOffsetNullable)

-
Comments
-

@Html.DisplayFor(_ => report.DeleteComments, DisplayTemplate.TextOrPlaceholder)

+

Comments

+

@Html.DisplayFor(_ => caseFile.DeleteComments, DisplayTemplate.TextOrPlaceholder)

}
-
+

Enforcement

- @if (!report.IsDeleted) + @if (!caseFile.IsDeleted) { -
-

Tracking #@Model.Id.ToString()

-
+
+
+ @caseFile.Status.GetDescription() +
+
Tracking #@Model.Id.ToString()
+
+ +
Facility
- +
-
@Html.DisplayNameFor(_ => report.ResponsibleStaff)
-
@Html.DisplayFor(_ => report.ResponsibleStaff, DisplayTemplate.NameOrPlaceholder)
+
@Html.DisplayNameFor(_ => caseFile.ResponsibleStaff)
+
@Html.DisplayFor(_ => caseFile.ResponsibleStaff, DisplayTemplate.NameOrPlaceholder)
Status
- @if (report.IsClosed) + @if (caseFile.IsClosed) { - @:Closed by @Html.DisplayFor(_ => report.ClosedBy, DisplayTemplate.NameOrPlaceholder) - @:on @Html.DisplayFor(_ => report.ClosedDate, DisplayTemplate.ShortDateOnlyNullable) + @:Closed by @Html.DisplayFor(_ => caseFile.ClosedBy, DisplayTemplate.NameOrPlaceholder) + @:on @Html.DisplayFor(_ => caseFile.ClosedDate, DisplayTemplate.ShortDateOnlyNullable) } else { @:Open }
-
@Html.DisplayNameFor(_ => report.Notes)
-
@Html.DisplayFor(_ => report.Notes, DisplayTemplate.TextOrPlaceholder)
+
@Html.DisplayNameFor(_ => caseFile.Notes)
+
+
@Html.DisplayFor(_ => caseFile.Notes, DisplayTemplate.TextOrPlaceholder)
+
+
+

Enforcement Actions

+ + @if (!caseFile.EnforcementActions.Any()) + { +

+ None. +

+ } + else + { +
+ @foreach (var action in caseFile.EnforcementActions) + { +
+
+
+
@action.EnforcementActionType.GetDescription()
+
+ +
+
+ } +
+ } +
+ @section Scripts { diff --git a/src/WebApp/Pages/Enforcement/Details.cshtml.cs b/src/WebApp/Pages/Enforcement/Details.cshtml.cs index fb856dfa..06ad31a0 100644 --- a/src/WebApp/Pages/Enforcement/Details.cshtml.cs +++ b/src/WebApp/Pages/Enforcement/Details.cshtml.cs @@ -27,7 +27,7 @@ public class DetailsModel(IEnforcementService enforcementService, IAuthorization public async Task OnGetAsync() { if (Id == 0) return RedirectToPage("Index"); - Item = await enforcementService.FindAsync(Id); + Item = await enforcementService.FindDetailedCaseFileAsync(Id); if (Item is null) return NotFound(); await SetPermissionsAsync(); @@ -49,7 +49,7 @@ public async Task OnGetAsync() public async Task OnPostNewCommentAsync(CommentAddDto newComment, CancellationToken token) { - Item = await enforcementService.FindAsync(Id, token); + Item = await enforcementService.FindDetailedCaseFileAsync(Id, token); if (Item is null || Item.IsDeleted) return BadRequest(); await SetPermissionsAsync(); @@ -76,7 +76,7 @@ public async Task OnPostNewCommentAsync(CommentAddDto newComment, public async Task OnPostDeleteCommentAsync(Guid commentId, CancellationToken token) { - Item = await enforcementService.FindAsync(Id, token); + Item = await enforcementService.FindDetailedCaseFileAsync(Id, token); if (Item is null || Item.IsDeleted) return BadRequest(); await SetPermissionsAsync(); diff --git a/src/WebApp/Pages/Index.cshtml b/src/WebApp/Pages/Index.cshtml index 9f2ec832..285fa9dc 100644 --- a/src/WebApp/Pages/Index.cshtml +++ b/src/WebApp/Pages/Index.cshtml @@ -23,15 +23,6 @@
  • Compliance Work search page
  • -
  • - Your account page -
  • -
  • - All users -
  • -
  • - Site maintenance -
  • Printouts
      @@ -46,6 +37,17 @@
  • +
  • + Enforcement + +
  • From 8a0457962132d9481e5d3e2c9e2698c76189eafe Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Wed, 18 Dec 2024 15:11:46 -0500 Subject: [PATCH 10/13] Continue work on enforcement details page --- .../Enforcement/Query/CaseFileViewDto.cs | 14 +- .../Actions/EnforcementAction.cs | 26 ++-- .../EnforcementEntities/Cases/CaseFile.cs | 28 ++-- .../AppDbContextConfiguration.cs | 2 +- src/TestData/Compliance/WorkEntryData.cs | 3 +- src/TestData/Enforcement/CaseFileData.cs | 17 +-- src/WebApp/Pages/Enforcement/Details.cshtml | 122 ++++++++++++++---- .../CompliancePartials/_FceSearchTable.cshtml | 4 +- .../_WorkEntrySearchTable.cshtml | 4 +- .../DisplayTemplates/ViolationType.cshtml | 12 ++ 10 files changed, 156 insertions(+), 76 deletions(-) create mode 100644 src/WebApp/Pages/Shared/DisplayTemplates/ViolationType.cshtml diff --git a/src/AppServices/Enforcement/Query/CaseFileViewDto.cs b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs index 04cc3432..8da91183 100644 --- a/src/AppServices/Enforcement/Query/CaseFileViewDto.cs +++ b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs @@ -1,7 +1,8 @@ using AirWeb.AppServices.Comments; using AirWeb.AppServices.CommonInterfaces; -using AirWeb.AppServices.Compliance.WorkEntries.WorkEntryDto.Query; +using AirWeb.AppServices.Compliance.Search; using AirWeb.AppServices.Staff.Dto; +using AirWeb.Domain.EnforcementEntities.Actions; using AirWeb.Domain.EnforcementEntities.Cases; using AirWeb.Domain.EnforcementEntities.ViolationTypes; using IaipDataService.Facilities; @@ -18,7 +19,7 @@ public record CaseFileViewDto : ICloseableAndDeletable, IHasOwnerAndDeletable [Display(Name = "Staff Responsible")] public StaffViewDto? ResponsibleStaff { get; init; } - public EnforcementCaseStatus Status { get; init; } + public EnforcementCaseStatus CaseStatus { get; init; } [Display(Name = "Violation Type")] public ViolationType? ViolationType { get; init; } @@ -29,10 +30,17 @@ public record CaseFileViewDto : ICloseableAndDeletable, IHasOwnerAndDeletable [Display(Name = "Day Zero")] public DateOnly? DayZero { get; init; } + public bool HasFormalEnforcement => EnforcementActions.Exists(action => + action is { IsDeleted: false, IsIssued: true } && + EnforcementAction.IsFormalEnforcementAction(action.EnforcementActionType)); + public string Notes { get; init; } = null!; public ICollection Pollutants { get; } = []; + + [Display(Name = "Air Programs")] public ICollection AirPrograms { get; } = []; - public ICollection ComplianceEvents { get; } = []; + + public IList ComplianceEvents { get; } = []; [UsedImplicitly] public List Comments { get; } = []; diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs index 3608f340..9537b404 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs @@ -48,31 +48,33 @@ private protected EnforcementAction(Guid id, CaseFile caseFile, ApplicationUser? // Data flow properties public bool IsDataFlowEnabled => - !IsDeleted && - EnforcementActionType - is EnforcementActionType.AdministrativeOrder - or EnforcementActionType.ConsentOrder - or EnforcementActionType.ProposedConsentOrder - or EnforcementActionType.NoticeOfViolation; + !IsDeleted && IsFormalEnforcementAction(EnforcementActionType); public short? ActionNumber { get; set; } [JsonIgnore] [StringLength(1)] public DataExchangeStatus DataExchangeStatus { get; init; } + + public static bool IsFormalEnforcementAction(EnforcementActionType type) => + type is EnforcementActionType.AdministrativeOrder + or EnforcementActionType.ConsentOrder + or EnforcementActionType.NoticeOfViolation + or EnforcementActionType.NovNfaLetter + or EnforcementActionType.ProposedConsentOrder; } [SuppressMessage("ReSharper", "InconsistentNaming")] public enum EnforcementActionType { + [Description("Administrative Order")] AdministrativeOrder, + [Description("Administrative Order Resolved")] AoResolvedLetter, + [Description("Consent Order")] ConsentOrder, + [Description("Consent Order Resolved")] CoResolvedLetter, + [Description("Letter")] EnforcementLetter, [Description("Letter of Noncompliance")] LetterOfNoncompliance, - [Description("Notice of Violation")] NoticeOfViolation, [Description("No Further Action Letter")] NoFurtherAction, + [Description("Notice of Violation")] NoticeOfViolation, [Description("Combined NOV/NFA Letter")] NovNfaLetter, [Description("Proposed Consent Order")] ProposedConsentOrder, - [Description("Consent Order")] ConsentOrder, - [Description("Consent Order Resolved")] CoResolvedLetter, - [Description("Administrative Order")] AdministrativeOrder, - [Description("Administrative Order Resolved")] AoResolvedLetter, - [Description("Letter")] EnforcementLetter, } diff --git a/src/Domain/EnforcementEntities/Cases/CaseFile.cs b/src/Domain/EnforcementEntities/Cases/CaseFile.cs index 429677a3..52692bac 100644 --- a/src/Domain/EnforcementEntities/Cases/CaseFile.cs +++ b/src/Domain/EnforcementEntities/Cases/CaseFile.cs @@ -48,26 +48,26 @@ public ViolationType? ViolationType // Status [StringLength(27)] - public EnforcementCaseStatus Status { get; set; } - - public EnforcementCaseStatus StatusCalc + public EnforcementCaseStatus CaseStatus { - // TODO: Review the logic for this property. get { + // TODO: Review the logic for this method. if (IsClosed) return EnforcementCaseStatus.CaseClosed; - - if (EnforcementActions.Exists(action => - action.EnforcementActionType is EnforcementActionType.ConsentOrder - or EnforcementActionType.AdministrativeOrder && - action.IsIssued)) + else { - return EnforcementActions.Exists(action => !((IResolvable)action).IsResolved) - ? EnforcementCaseStatus.SubjectToComplianceSchedule - : EnforcementCaseStatus.CaseResolved; + if (EnforcementActions.Exists(action => + action.EnforcementActionType is EnforcementActionType.ConsentOrder + or EnforcementActionType.AdministrativeOrder && + action.IsIssued)) + { + return EnforcementActions.Exists(action => !((IResolvable)action).IsResolved) + ? EnforcementCaseStatus.SubjectToComplianceSchedule + : EnforcementCaseStatus.CaseResolved; + } + + return EnforcementCaseStatus.CaseOpen; } - - return EnforcementCaseStatus.CaseOpen; } } diff --git a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs index abd07aa5..22edb8e6 100644 --- a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs +++ b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs @@ -231,7 +231,7 @@ internal static ModelBuilder ConfigureEnumValues(this ModelBuilder builder) builder.Entity().Property(e => e.EnforcementActionType).HasConversion(); // Status - builder.Entity().Property(e => e.Status).HasConversion(); + builder.Entity().Property(e => e.CaseStatus).HasConversion(); builder.Entity().Property(e => e.Status).HasConversion(); // Data exchange status diff --git a/src/TestData/Compliance/WorkEntryData.cs b/src/TestData/Compliance/WorkEntryData.cs index 90f00f77..a0c7df58 100644 --- a/src/TestData/Compliance/WorkEntryData.cs +++ b/src/TestData/Compliance/WorkEntryData.cs @@ -26,7 +26,8 @@ private static IEnumerable WorkEntrySeedItems private static IEnumerable? _workEntries; public static ComplianceEvent GetRandomComplianceEvent() => - (ComplianceEvent)GetData.Where(entry => entry is ComplianceEvent).OrderBy(_ => Guid.NewGuid()).First(); + (ComplianceEvent)GetData.Where(entry => entry is ComplianceEvent && !entry.IsDeleted) + .OrderBy(_ => Guid.NewGuid()).First(); public static IEnumerable GetData { diff --git a/src/TestData/Enforcement/CaseFileData.cs b/src/TestData/Enforcement/CaseFileData.cs index 2068af72..feb483f9 100644 --- a/src/TestData/Enforcement/CaseFileData.cs +++ b/src/TestData/Enforcement/CaseFileData.cs @@ -17,89 +17,77 @@ private static ViolationType GetRandomViolationType() => new(300, DomainData.GetRandomFacility().Id, null) { Notes = "Unspecified enforcement case", - Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-1).Date), }, new(301, DomainData.GetRandomFacility().Id, null) { Notes = "LON - draft", - Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-2).Date), }, new(302, DomainData.GetRandomFacility().Id, null) { Notes = "LON - open", - Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddDays(-2).Date), }, new(303, DomainData.GetRandomFacility().Id, null) { Notes = "LON - closed", - Status = EnforcementCaseStatus.CaseClosed, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-10).Date), }, new(304, DomainData.GetRandomFacility().Id, null) { Notes = "Unsent LON + NOV - draft", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-9).Date), }, new(305, DomainData.GetRandomFacility().Id, null) { Notes = "NOV - no response", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-9).Date), }, new(306, DomainData.GetRandomFacility().Id, null) { Notes = "NOV + NFA", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.CaseResolved, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-100).Date), }, new(307, DomainData.GetRandomFacility().Id, null) { ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-60).Date), + ClosedBy = UserData.GetRandomUser(), Notes = "Combined NOV/NFA", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.CaseResolved, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-3).AddDays(-100).Date), }, new(308, DomainData.GetRandomFacility().Id, null) { Notes = "NOV + Proposed Consent Order - draft", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(309, DomainData.GetRandomFacility().Id, null) { Notes = "Straight to Proposed CO - no response received", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(310, DomainData.GetRandomFacility().Id, null) { Notes = "Proposed CO + signed Consent Order received", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(311, DomainData.GetRandomFacility().Id, null) { Notes = "Consent Order - executed", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(41).Date), }, new(312, DomainData.GetRandomFacility().Id, null) { Notes = "Consent Order + Stipulated Penalties - closed", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.CaseClosed, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-4).AddDays(-210).Date), ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddMonths(-6).Date), }, @@ -107,7 +95,6 @@ private static ViolationType GetRandomViolationType() => { Notes = "Administrative Order - executed", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.SubjectToComplianceSchedule, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-320).Date), ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddMonths(-9).Date), }, @@ -115,14 +102,12 @@ private static ViolationType GetRandomViolationType() => { Notes = "Administrative Order - closed", ViolationType = GetRandomViolationType(), - Status = EnforcementCaseStatus.CaseClosed, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-320).Date), ClosedDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-2).AddDays(-200).Date), }, new(329, DomainData.GetRandomFacility().Id, null) { Notes = "Deleted Enforcement Case", - Status = EnforcementCaseStatus.CaseOpen, DiscoveryDate = DateOnly.FromDateTime(DateTimeOffset.Now.AddYears(-1).AddDays(-4).Date), }, ]; diff --git a/src/WebApp/Pages/Enforcement/Details.cshtml b/src/WebApp/Pages/Enforcement/Details.cshtml index d4cc3ee3..42471c0b 100644 --- a/src/WebApp/Pages/Enforcement/Details.cshtml +++ b/src/WebApp/Pages/Enforcement/Details.cshtml @@ -1,7 +1,9 @@ @page "{id:int?}" +@using AirWeb.AppServices.Compliance.Search @using AirWeb.AppServices.Enforcement.Permissions @using AirWeb.Domain.EnforcementEntities.Cases @using AirWeb.WebApp.Pages.Shared.DisplayTemplates +@using AirWeb.WebApp.Platform.PageModelHelpers @using GaEpd.AppLibrary.Extensions @using Microsoft.AspNetCore.Mvc.TagHelpers @model DetailsModel @@ -64,41 +66,111 @@ } -
    -
    - @caseFile.Status.GetDescription() +
    +
    + @caseFile.CaseStatus.GetDescription()
    Tracking #@Model.Id.ToString()
    -
    -
    Facility
    -
    - -
    -
    @Html.DisplayNameFor(_ => caseFile.ResponsibleStaff)
    -
    @Html.DisplayFor(_ => caseFile.ResponsibleStaff, DisplayTemplate.NameOrPlaceholder)
    -
    Status
    -
    - @if (caseFile.IsClosed) +
    +

    Details

    +
    +
    Facility
    +
    + +
    +
    @Html.DisplayNameFor(_ => caseFile.ResponsibleStaff)
    +
    @Html.DisplayFor(_ => caseFile.ResponsibleStaff, DisplayTemplate.NameOrPlaceholder)
    +
    Status
    +
    + @if (caseFile.IsClosed) + { + @:Closed by @Html.DisplayFor(_ => caseFile.ClosedBy, DisplayTemplate.NameOrPlaceholder) + @:on @Html.DisplayFor(_ => caseFile.ClosedDate, DisplayTemplate.ShortDateOnlyNullable) + } + else + { + @:Open + } +
    +
    @Html.DisplayNameFor(_ => caseFile.DiscoveryDate)
    +
    @Html.DisplayFor(_ => caseFile.DiscoveryDate, DisplayTemplate.ShortDateOnlyNullable)
    + @if (caseFile.HasFormalEnforcement) { - @:Closed by @Html.DisplayFor(_ => caseFile.ClosedBy, DisplayTemplate.NameOrPlaceholder) - @:on @Html.DisplayFor(_ => caseFile.ClosedDate, DisplayTemplate.ShortDateOnlyNullable) +
    @Html.DisplayNameFor(_ => caseFile.DayZero)
    +
    @Html.DisplayFor(_ => caseFile.DayZero, DisplayTemplate.ShortDateOnlyNullable)
    +
    @Html.DisplayNameFor(_ => caseFile.ViolationType)
    +
    @Html.DisplayFor(_ => caseFile.ViolationType)
    + } +
    @Html.DisplayNameFor(_ => caseFile.Notes)
    +
    +
    @Html.DisplayFor(_ => caseFile.Notes, DisplayTemplate.TextOrPlaceholder)
    +
    +
    + +
    +

    Discovery Events

    + @if (!caseFile.ComplianceEvents.Any()) + { +

    + None. +

    } else { - @:Open + } -
    -
    @Html.DisplayNameFor(_ => caseFile.Notes)
    -
    -
    @Html.DisplayFor(_ => caseFile.Notes, DisplayTemplate.TextOrPlaceholder)
    -
    -
    + -
    + @if (caseFile.HasFormalEnforcement) + { +
    +

    Associated Pollutants & Programs

    +
    +
    @Html.DisplayNameFor(_ => caseFile.Pollutants)
    +
    + @if (caseFile.Pollutants.Count == 0) + { + @DefaultText.PlaceholderNone + } + else + { +
      + @foreach (var pollutant in caseFile.Pollutants) + { +
    • @pollutant.Description (@pollutant.Code) +
    • + } +
    + } +
    +
    @Html.DisplayNameFor(_ => caseFile.AirPrograms)
    +
    + @if (caseFile.AirPrograms.Count == 0) + { + @DefaultText.PlaceholderNone + } + else + { +
      + @foreach (var airProgram in caseFile.AirPrograms) + { +
    • @airProgram.GetDescription()
    • + } +
    + } +
    +
    +
    + } +
    + +

    Enforcement Actions

    @if (!caseFile.EnforcementActions.Any()) diff --git a/src/WebApp/Pages/Shared/CompliancePartials/_FceSearchTable.cshtml b/src/WebApp/Pages/Shared/CompliancePartials/_FceSearchTable.cshtml index 5d697525..5c44bf6d 100644 --- a/src/WebApp/Pages/Shared/CompliancePartials/_FceSearchTable.cshtml +++ b/src/WebApp/Pages/Shared/CompliancePartials/_FceSearchTable.cshtml @@ -10,13 +10,13 @@
    @if (Model.Spec is null) { - + } else { + model='new SearchResultsColumnDisplay("Tracking #", SortBy.IdAsc, SortBy.IdDesc, Model.Spec)' /> @if (Model.Spec is null) { - + } else { + model='new SearchResultsColumnDisplay("Tracking #", SortBy.IdAsc, SortBy.IdDesc, Model.Spec)' /> @DefaultText.PlaceholderNotEntered +} +else +{ + @Model.SeverityCode: @Model.Description + (@Model.Code) + +} From 80b189efcd20dace94d284457f1aaa4caaae41cd Mon Sep 17 00:00:00 2001 From: Doug Waldron Date: Wed, 18 Dec 2024 15:30:07 -0500 Subject: [PATCH 11/13] Refactor Enforcement Action type and status --- .../Enforcement/Query/CaseFileViewDto.cs | 9 +++++++- .../Query/EnforcementActionViewDto.cs | 2 +- .../Actions/AdministrativeOrder.cs | 5 +++-- .../Actions/AoResolvedLetter.cs | 2 +- .../Actions/CoResolvedLetter.cs | 2 +- .../Actions/ConsentOrder.cs | 7 +++--- .../Actions/EnforcementAction.cs | 4 ++-- .../Actions/EnforcementLetter.cs | 2 +- .../{IResolvable.cs => IExecutable.cs} | 3 ++- .../Actions/LetterOfNoncompliance.cs | 2 +- .../Actions/NoFurtherActionLetter.cs | 2 +- .../Actions/NoticeOfViolation.cs | 2 +- .../Actions/NovNfaLetter.cs | 2 +- .../Actions/ProposedConsentOrder.cs | 4 ++-- .../EnforcementEntities/Cases/CaseFile.cs | 22 +++++++++---------- .../AppDbContextConfiguration.cs | 4 ++-- src/WebApp/Pages/Enforcement/Details.cshtml | 5 ++--- 17 files changed, 43 insertions(+), 36 deletions(-) rename src/Domain/EnforcementEntities/Actions/{IResolvable.cs => IExecutable.cs} (59%) diff --git a/src/AppServices/Enforcement/Query/CaseFileViewDto.cs b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs index 8da91183..6e515d9e 100644 --- a/src/AppServices/Enforcement/Query/CaseFileViewDto.cs +++ b/src/AppServices/Enforcement/Query/CaseFileViewDto.cs @@ -21,6 +21,13 @@ public record CaseFileViewDto : ICloseableAndDeletable, IHasOwnerAndDeletable public EnforcementCaseStatus CaseStatus { get; init; } + public string CaseStatusClass => CaseStatus switch + { + EnforcementCaseStatus.CaseOpen => "bg-warning-subtle", + EnforcementCaseStatus.CaseClosed => "bg-info-subtle", + _ => "bg-success-subtle", + }; + [Display(Name = "Violation Type")] public ViolationType? ViolationType { get; init; } @@ -32,7 +39,7 @@ public record CaseFileViewDto : ICloseableAndDeletable, IHasOwnerAndDeletable public bool HasFormalEnforcement => EnforcementActions.Exists(action => action is { IsDeleted: false, IsIssued: true } && - EnforcementAction.IsFormalEnforcementAction(action.EnforcementActionType)); + EnforcementAction.IsFormalEnforcementAction(action.ActionType)); public string Notes { get; init; } = null!; public ICollection Pollutants { get; } = []; diff --git a/src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs b/src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs index 38360fb4..f98a1939 100644 --- a/src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs +++ b/src/AppServices/Enforcement/Query/EnforcementActionViewDto.cs @@ -6,7 +6,7 @@ namespace AirWeb.AppServices.Enforcement.Query; public record EnforcementActionViewDto { public Guid Id { get; init; } - public EnforcementActionType EnforcementActionType { get; init; } + public EnforcementActionType ActionType { get; init; } public string Notes { get; init; } = null!; public StaffViewDto? ResponsibleStaff { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs index f12932ed..b6290057 100644 --- a/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/AdministrativeOrder.cs @@ -3,7 +3,7 @@ namespace AirWeb.Domain.EnforcementEntities.Actions; -public class AdministrativeOrder : EnforcementAction, IResolvable +public class AdministrativeOrder : EnforcementAction, IExecutable { // Constructors [UsedImplicitly] // Used by ORM. @@ -12,10 +12,11 @@ private AdministrativeOrder() { } internal AdministrativeOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : base(id, caseFile, user) { - EnforcementActionType = EnforcementActionType.AdministrativeOrder; + ActionType = EnforcementActionType.AdministrativeOrder; } public DateOnly? ExecutedDate { get; set; } + public bool IsExecuted => ExecutedDate.HasValue; public DateOnly? AppealedDate { get; set; } public DateOnly? ResolvedDate { get; set; } public bool IsResolved => ResolvedDate.HasValue; diff --git a/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs b/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs index e14391a2..211bed07 100644 --- a/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/AoResolvedLetter.cs @@ -11,7 +11,7 @@ private AoResolvedLetter() { } internal AoResolvedLetter(Guid id, AdministrativeOrder administrativeOrder, ApplicationUser? user) : base(id, administrativeOrder.CaseFile, user) { - EnforcementActionType = EnforcementActionType.AoResolvedLetter; + ActionType = EnforcementActionType.AoResolvedLetter; AdministrativeOrder = administrativeOrder; } diff --git a/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs b/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs index c7a68d38..f221ab50 100644 --- a/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/CoResolvedLetter.cs @@ -11,7 +11,7 @@ private CoResolvedLetter() { } internal CoResolvedLetter(Guid id, ConsentOrder consentOrder, ApplicationUser? user) : base(id, consentOrder.CaseFile, user) { - EnforcementActionType = EnforcementActionType.CoResolvedLetter; + ActionType = EnforcementActionType.CoResolvedLetter; ConsentOrder = consentOrder; } diff --git a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs index 7f61ddd9..c8e8aab8 100644 --- a/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/ConsentOrder.cs @@ -5,7 +5,7 @@ namespace AirWeb.Domain.EnforcementEntities.Actions; -public class ConsentOrder : EnforcementAction, IResolvable +public class ConsentOrder : EnforcementAction, IExecutable { // Constructors [UsedImplicitly] // Used by ORM. @@ -14,20 +14,21 @@ private ConsentOrder() { } internal ConsentOrder(Guid id, ProposedConsentOrder proposedConsentOrder, ApplicationUser? user) : base(id, proposedConsentOrder.CaseFile, user) { - EnforcementActionType = EnforcementActionType.ConsentOrder; + ActionType = EnforcementActionType.ConsentOrder; ProposedConsentOrder = proposedConsentOrder; } internal ConsentOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : base(id, caseFile, user) { - EnforcementActionType = EnforcementActionType.ConsentOrder; + ActionType = EnforcementActionType.ConsentOrder; } public ProposedConsentOrder? ProposedConsentOrder { get; set; } public DateOnly? ReceivedFromFacility { get; set; } public DateOnly? ExecutedDate { get; set; } + public bool IsExecuted => ExecutedDate.HasValue; public DateOnly? ReceivedFromDirectorsOffice { get; set; } public DateOnly? ResolvedDate { get; set; } public bool IsResolved => ResolvedDate.HasValue; diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs index 9537b404..b00ebd15 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementAction.cs @@ -24,7 +24,7 @@ private protected EnforcementAction(Guid id, CaseFile caseFile, ApplicationUser? // Basic data public CaseFile CaseFile { get; init; } = null!; - public EnforcementActionType EnforcementActionType { get; protected init; } + public EnforcementActionType ActionType { get; protected init; } [StringLength(7000)] public string? Notes { get; set; } @@ -48,7 +48,7 @@ private protected EnforcementAction(Guid id, CaseFile caseFile, ApplicationUser? // Data flow properties public bool IsDataFlowEnabled => - !IsDeleted && IsFormalEnforcementAction(EnforcementActionType); + !IsDeleted && IsFormalEnforcementAction(ActionType); public short? ActionNumber { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs b/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs index 1fff37e0..2867b5f3 100644 --- a/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/EnforcementLetter.cs @@ -12,7 +12,7 @@ private EnforcementLetter() { } internal EnforcementLetter(Guid id, CaseFile caseFile, ApplicationUser? user) : base(id, caseFile, user) { - EnforcementActionType = EnforcementActionType.EnforcementLetter; + ActionType = EnforcementActionType.EnforcementLetter; } public bool ResponseRequested { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/IResolvable.cs b/src/Domain/EnforcementEntities/Actions/IExecutable.cs similarity index 59% rename from src/Domain/EnforcementEntities/Actions/IResolvable.cs rename to src/Domain/EnforcementEntities/Actions/IExecutable.cs index 9fb94e62..25555e61 100644 --- a/src/Domain/EnforcementEntities/Actions/IResolvable.cs +++ b/src/Domain/EnforcementEntities/Actions/IExecutable.cs @@ -1,6 +1,7 @@ namespace AirWeb.Domain.EnforcementEntities.Actions; -public interface IResolvable +public interface IExecutable { + public bool IsExecuted { get; } public bool IsResolved { get; } } diff --git a/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs b/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs index b31c570d..d84c7936 100644 --- a/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs +++ b/src/Domain/EnforcementEntities/Actions/LetterOfNoncompliance.cs @@ -12,7 +12,7 @@ private LetterOfNoncompliance() { } internal LetterOfNoncompliance(Guid id, CaseFile caseFile, ApplicationUser? user) : base(id, caseFile, user) { - EnforcementActionType = EnforcementActionType.LetterOfNoncompliance; + ActionType = EnforcementActionType.LetterOfNoncompliance; } public bool ResponseRequested { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs b/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs index 65de8d6b..e3f8124e 100644 --- a/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/NoFurtherActionLetter.cs @@ -11,7 +11,7 @@ private NoFurtherActionLetter() { } internal NoFurtherActionLetter(Guid id, NoticeOfViolation noticeOfViolation, ApplicationUser? user) : base(id, noticeOfViolation.CaseFile, user) { - EnforcementActionType = EnforcementActionType.NoFurtherAction; + ActionType = EnforcementActionType.NoFurtherAction; NoticeOfViolation = noticeOfViolation; } diff --git a/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs b/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs index f57cc19f..028336e1 100644 --- a/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs +++ b/src/Domain/EnforcementEntities/Actions/NoticeOfViolation.cs @@ -12,7 +12,7 @@ private NoticeOfViolation() { } internal NoticeOfViolation(Guid id, CaseFile caseFile, ApplicationUser? user) : base(id, caseFile, user) { - EnforcementActionType = EnforcementActionType.NoticeOfViolation; + ActionType = EnforcementActionType.NoticeOfViolation; } public bool ResponseRequested { get; set; } = true; diff --git a/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs b/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs index be09cc01..15931741 100644 --- a/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs +++ b/src/Domain/EnforcementEntities/Actions/NovNfaLetter.cs @@ -12,7 +12,7 @@ private NovNfaLetter() { } internal NovNfaLetter(Guid id, CaseFile caseFile, ApplicationUser? user) : base(id, caseFile, user) { - EnforcementActionType = EnforcementActionType.NovNfaLetter; + ActionType = EnforcementActionType.NovNfaLetter; } public bool ResponseRequested { get; set; } diff --git a/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs b/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs index 3aac842c..76c8e412 100644 --- a/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs +++ b/src/Domain/EnforcementEntities/Actions/ProposedConsentOrder.cs @@ -12,14 +12,14 @@ private ProposedConsentOrder() { } internal ProposedConsentOrder(Guid id, NoticeOfViolation noticeOfViolation, ApplicationUser? user) : base(id, noticeOfViolation.CaseFile, user) { - EnforcementActionType = EnforcementActionType.ProposedConsentOrder; + ActionType = EnforcementActionType.ProposedConsentOrder; NoticeOfViolation = noticeOfViolation; } internal ProposedConsentOrder(Guid id, CaseFile caseFile, ApplicationUser? user) : base(id, caseFile, user) { - EnforcementActionType = EnforcementActionType.ProposedConsentOrder; + ActionType = EnforcementActionType.ProposedConsentOrder; } public NoticeOfViolation? NoticeOfViolation { get; set; } diff --git a/src/Domain/EnforcementEntities/Cases/CaseFile.cs b/src/Domain/EnforcementEntities/Cases/CaseFile.cs index 52692bac..e164e4f7 100644 --- a/src/Domain/EnforcementEntities/Cases/CaseFile.cs +++ b/src/Domain/EnforcementEntities/Cases/CaseFile.cs @@ -54,20 +54,18 @@ public EnforcementCaseStatus CaseStatus { // TODO: Review the logic for this method. if (IsClosed) return EnforcementCaseStatus.CaseClosed; - else + + if (EnforcementActions.Exists(action => + action.ActionType is EnforcementActionType.ConsentOrder + or EnforcementActionType.AdministrativeOrder && ((IExecutable)action).IsExecuted)) { - if (EnforcementActions.Exists(action => - action.EnforcementActionType is EnforcementActionType.ConsentOrder - or EnforcementActionType.AdministrativeOrder && - action.IsIssued)) - { - return EnforcementActions.Exists(action => !((IResolvable)action).IsResolved) - ? EnforcementCaseStatus.SubjectToComplianceSchedule - : EnforcementCaseStatus.CaseResolved; - } - - return EnforcementCaseStatus.CaseOpen; + return EnforcementActions.Exists(action => action.ActionType is EnforcementActionType.ConsentOrder + or EnforcementActionType.AdministrativeOrder && ((IExecutable)action).IsResolved) + ? EnforcementCaseStatus.CaseResolved + : EnforcementCaseStatus.SubjectToComplianceSchedule; } + + return EnforcementCaseStatus.CaseOpen; } } diff --git a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs index 22edb8e6..76f04a93 100644 --- a/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs +++ b/src/EfRepository/DbContext/Configuration/AppDbContextConfiguration.cs @@ -138,7 +138,7 @@ internal static ModelBuilder ConfigureEnforcementActionMapping(this ModelBuilder builder.Entity() .UseTphMappingStrategy() // This is already the default, but making it explicit here for future clarity. .ToTable("EnforcementActions") - .HasDiscriminator(action => action.EnforcementActionType) + .HasDiscriminator(action => action.ActionType) .HasValue(EnforcementActionType.AdministrativeOrder) .HasValue(EnforcementActionType.AoResolvedLetter) .HasValue(EnforcementActionType.ConsentOrder) @@ -228,7 +228,7 @@ internal static ModelBuilder ConfigureEnumValues(this ModelBuilder builder) // Discriminator builder.Entity().Property(e => e.WorkEntryType).HasConversion(); - builder.Entity().Property(e => e.EnforcementActionType).HasConversion(); + builder.Entity().Property(e => e.ActionType).HasConversion(); // Status builder.Entity().Property(e => e.CaseStatus).HasConversion(); diff --git a/src/WebApp/Pages/Enforcement/Details.cshtml b/src/WebApp/Pages/Enforcement/Details.cshtml index 42471c0b..bfa5db49 100644 --- a/src/WebApp/Pages/Enforcement/Details.cshtml +++ b/src/WebApp/Pages/Enforcement/Details.cshtml @@ -1,7 +1,6 @@ @page "{id:int?}" @using AirWeb.AppServices.Compliance.Search @using AirWeb.AppServices.Enforcement.Permissions -@using AirWeb.Domain.EnforcementEntities.Cases @using AirWeb.WebApp.Pages.Shared.DisplayTemplates @using AirWeb.WebApp.Platform.PageModelHelpers @using GaEpd.AppLibrary.Extensions @@ -68,7 +67,7 @@
    + class="col-sm-auto lead rounded ms-2 @(caseFile.CaseStatusClass)"> @caseFile.CaseStatus.GetDescription()
    Tracking #@Model.Id.ToString()
    @@ -187,7 +186,7 @@
    -
    @action.EnforcementActionType.GetDescription()
    +
    @action.ActionType.GetDescription()
    IDTracking # FCE YearIDTracking # Work Type Event Date