From affbf034d2cd545bdf4eac2c875853fbee9e9e7b Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 4 Apr 2024 15:30:40 -0700 Subject: [PATCH] PSP-7886 : Prevent users from adding new takes, and/or deleting completed takes from a non-active (e.g. draft or active) acquisition file (#3923) Co-authored-by: Herrera --- source/backend/api/Services/TakeService.cs | 30 +++- .../unit/api/Services/TakeServiceTest.cs | 61 +++++++- .../src/constants/acquisitionFileStatus.ts | 9 -- .../common/AcquisitionMenu.test.tsx | 6 +- ...CompensationRequisitionDetailView.test.tsx | 6 +- .../list/CompensationListView.test.tsx | 8 +- .../fileDetails/detail/statusUpdateSolver.ts | 134 +++++++++--------- .../takes/detail/TakesDetailView.test.tsx | 4 +- .../tabs/takes/detail/TakesDetailView.tsx | 8 +- .../tabs/takes/update/TakeSubForm.tsx | 67 ++++++--- .../takes/update/TakesUpdateForm.test.tsx | 38 +++++ .../TakesUpdateForm.test.tsx.snap | 2 +- ...en_CodeTypes_AcquisitionTakeStatusTypes.ts | 9 ++ 13 files changed, 262 insertions(+), 120 deletions(-) delete mode 100644 source/frontend/src/constants/acquisitionFileStatus.ts create mode 100644 source/frontend/src/models/api/generated/ApiGen_CodeTypes_AcquisitionTakeStatusTypes.ts diff --git a/source/backend/api/Services/TakeService.cs b/source/backend/api/Services/TakeService.cs index e179a27f98..def6c80ef2 100644 --- a/source/backend/api/Services/TakeService.cs +++ b/source/backend/api/Services/TakeService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Security.Claims; using Microsoft.Extensions.Logging; -using Pims.Api.Constants; using Pims.Api.Models.CodeTypes; using Pims.Core.Exceptions; using Pims.Dal.Entities; @@ -61,11 +61,35 @@ public IEnumerable UpdateAcquisitionPropertyTakes(long acquisitionFile _user.ThrowIfNotAuthorized(Permissions.PropertyView, Permissions.AcquisitionFileView); var currentAcquistionFile = _acqFileRepository.GetByAcquisitionFilePropertyId(acquisitionFilePropertyId); + var currentFilePropertyTakes = _takeRepository.GetAllByPropertyAcquisitionFileId(acquisitionFilePropertyId); var currentAcquisitionStatus = Enum.Parse(currentAcquistionFile.AcquisitionFileStatusTypeCode); - if (!_statusSolver.CanEditTakes(currentAcquisitionStatus) && !_user.HasPermission(Permissions.SystemAdmin)) + + // No user can update the takes when the File is not Active/Draft + if (!_statusSolver.CanEditTakes(currentAcquisitionStatus)) + { + throw new BusinessRuleViolationException("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion."); + } + else { - throw new BusinessRuleViolationException("The file you are editing is not active or draft, so you cannot save changes. Refresh your browser to see file state."); + // Complete Takes can only be deleted or set to InProgress by Admins when File is Active/Draft + if (!_user.HasPermission(Permissions.SystemAdmin)) + { + var currentCompleteTakes = currentFilePropertyTakes + .Where(x => x.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString()).ToList(); + + if (currentCompleteTakes.Count > 0) + { + foreach (var completeTake in currentCompleteTakes) + { + var updatedTake = takes.FirstOrDefault(x => x.TakeId == completeTake.TakeId); + if (updatedTake is null || updatedTake?.TakeStatusTypeCode != completeTake.TakeStatusTypeCode) + { + throw new BusinessRuleViolationException("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion."); + } + } + } + } } _takeRepository.UpdateAcquisitionPropertyTakes(acquisitionFilePropertyId, takes); diff --git a/source/backend/tests/unit/api/Services/TakeServiceTest.cs b/source/backend/tests/unit/api/Services/TakeServiceTest.cs index f2759aba9c..5e5845af86 100644 --- a/source/backend/tests/unit/api/Services/TakeServiceTest.cs +++ b/source/backend/tests/unit/api/Services/TakeServiceTest.cs @@ -157,7 +157,7 @@ public void Update_NoPermission() } [Fact] - public void Update_InvalidStatus() + public void Update_InvalidStatus_AcquisitionFile_Complete() { // Arrange var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView); @@ -175,7 +175,64 @@ public void Update_InvalidStatus() Action act = () => service.UpdateAcquisitionPropertyTakes(1, new List()); // Assert - act.Should().Throw(); + act.Should().Throw().WithMessage("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion."); + } + + [Fact] + public void Update_InvalidStatus_AcquisitionFile_Active_DeleteCompleteTake_NotAdmin() + { + // Arrange + var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView); + + var acqRepository = this._helper.GetService>(); + acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(new PimsAcquisitionFile() { AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString() }); + + PimsTake completedTake = new() + { + TakeId = 100, + TakeStatusTypeCode = AcquisitionTakeStatusTypes.COMPLETE.ToString(), + }; + + var takeRepository = this._helper.GetService>(); + takeRepository.Setup(x => x.GetAllByPropertyAcquisitionFileId(It.IsAny())).Returns(new List() { completedTake }); + + var solver = this._helper.GetService>(); + solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(true); + + // Act + Action act = () => service.UpdateAcquisitionPropertyTakes(1, new List()); + + // Assert + act.Should().Throw().WithMessage("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion."); + } + + [Fact] + public void Update_AcquisitionFile_Active_DeleteCompleteTake_Admin_Success() + { + // Arrange + var service = this.CreateWithPermissions(Permissions.SystemAdmin, Permissions.PropertyView, Permissions.AcquisitionFileView); + + var acqRepository = this._helper.GetService>(); + acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(new PimsAcquisitionFile() { AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString() }); + + PimsTake completedTake = new() + { + TakeId = 100, + TakeStatusTypeCode = AcquisitionTakeStatusTypes.COMPLETE.ToString(), + }; + + var takeRepository = this._helper.GetService>(); + takeRepository.Setup(x => x.GetAllByPropertyAcquisitionFileId(It.IsAny())).Returns(new List() { completedTake }); + + var solver = this._helper.GetService>(); + solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(true); + + // Act + var result = service.UpdateAcquisitionPropertyTakes(1, new List()); + + // Assert + Assert.NotNull(result); + takeRepository.Verify(x => x.UpdateAcquisitionPropertyTakes(1, new List()), Times.Once); } } } diff --git a/source/frontend/src/constants/acquisitionFileStatus.ts b/source/frontend/src/constants/acquisitionFileStatus.ts deleted file mode 100644 index 25e1847189..0000000000 --- a/source/frontend/src/constants/acquisitionFileStatus.ts +++ /dev/null @@ -1,9 +0,0 @@ -export enum AcquisitionStatus { - Active = 'ACTIVE', - Archived = 'ARCHIV', - Cancelled = 'CANCEL', - Closed = 'CLOSED', - Complete = 'COMPLT', - Draft = 'DRAFT', - Hold = 'HOLD', -} diff --git a/source/frontend/src/features/mapSideBar/acquisition/common/AcquisitionMenu.test.tsx b/source/frontend/src/features/mapSideBar/acquisition/common/AcquisitionMenu.test.tsx index b98017da50..8e4af5a191 100644 --- a/source/frontend/src/features/mapSideBar/acquisition/common/AcquisitionMenu.test.tsx +++ b/source/frontend/src/features/mapSideBar/acquisition/common/AcquisitionMenu.test.tsx @@ -1,10 +1,10 @@ -import { AcquisitionStatus } from '@/constants/acquisitionFileStatus'; import { Claims, Roles } from '@/constants/index'; import { mockAcquisitionFileResponse } from '@/mocks/acquisitionFiles.mock'; import { toTypeCode } from '@/utils/formUtils'; import { act, render, RenderOptions, userEvent } from '@/utils/test-utils'; import AcquisitionMenu, { IAcquisitionMenuProps } from './AcquisitionMenu'; +import { ApiGen_CodeTypes_AcquisitionStatusTypes } from '@/models/api/generated/ApiGen_CodeTypes_AcquisitionStatusTypes'; // mock auth library jest.mock('@react-keycloak/web'); @@ -129,7 +129,7 @@ describe('AcquisitionMenu component', () => { { acquisitionFile: { ...mockAcquisitionFileResponse(), - fileStatusTypeCode: toTypeCode(AcquisitionStatus.Complete), + fileStatusTypeCode: toTypeCode(ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT), }, items: testData, selectedIndex: 1, @@ -148,7 +148,7 @@ describe('AcquisitionMenu component', () => { { acquisitionFile: { ...mockAcquisitionFileResponse(), - fileStatusTypeCode: toTypeCode(AcquisitionStatus.Complete), + fileStatusTypeCode: toTypeCode(ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT), }, items: testData, selectedIndex: 1, diff --git a/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/detail/CompensationRequisitionDetailView.test.tsx b/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/detail/CompensationRequisitionDetailView.test.tsx index d9aa184218..9318b56e48 100644 --- a/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/detail/CompensationRequisitionDetailView.test.tsx +++ b/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/detail/CompensationRequisitionDetailView.test.tsx @@ -1,6 +1,5 @@ import { createMemoryHistory } from 'history'; -import { AcquisitionStatus } from '@/constants/acquisitionFileStatus'; import Claims from '@/constants/claims'; import { Roles } from '@/constants/index'; import { mockAcquisitionFileResponse } from '@/mocks/acquisitionFiles.mock'; @@ -15,6 +14,7 @@ import { act, render, RenderOptions, userEvent, waitFor } from '@/utils/test-uti import CompensationRequisitionDetailView, { CompensationRequisitionDetailViewProps, } from './CompensationRequisitionDetailView'; +import { ApiGen_CodeTypes_AcquisitionStatusTypes } from '@/models/api/generated/ApiGen_CodeTypes_AcquisitionStatusTypes'; const setEditMode = jest.fn(); @@ -128,7 +128,7 @@ describe('Compensation Detail View Component', () => { props: { acquisitionFile: { ...acquistionFile, - fileStatusTypeCode: toTypeCodeNullable(AcquisitionStatus.Active), + fileStatusTypeCode: toTypeCodeNullable(ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE), }, compensation: { ...mockFinalCompensation, isDraft: true }, }, @@ -164,7 +164,7 @@ describe('Compensation Detail View Component', () => { props: { acquisitionFile: { ...acquistionFile, - fileStatusTypeCode: toTypeCodeNullable(AcquisitionStatus.Complete), + fileStatusTypeCode: toTypeCodeNullable(ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT), }, compensation: { ...mockFinalCompensation, isDraft: false }, }, diff --git a/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/list/CompensationListView.test.tsx b/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/list/CompensationListView.test.tsx index f23c0d53b0..3cb329901b 100644 --- a/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/list/CompensationListView.test.tsx +++ b/source/frontend/src/features/mapSideBar/acquisition/tabs/compensation/list/CompensationListView.test.tsx @@ -1,6 +1,5 @@ import { createMemoryHistory } from 'history'; -import { AcquisitionStatus } from '@/constants/acquisitionFileStatus'; import Claims from '@/constants/claims'; import Roles from '@/constants/roles'; import { @@ -15,6 +14,7 @@ import { toTypeCode, toTypeCodeNullable } from '@/utils/formUtils'; import { act, render, RenderOptions, userEvent, waitFor } from '@/utils/test-utils'; import CompensationListView, { ICompensationListViewProps } from './CompensationListView'; +import { ApiGen_CodeTypes_AcquisitionStatusTypes } from '@/models/api/generated/ApiGen_CodeTypes_AcquisitionStatusTypes'; const storeState = { [lookupCodesSlice.name]: { lookupCodes: mockLookups }, @@ -118,7 +118,7 @@ describe('compensation list view', () => { const { findAllByTitle } = setup({ acquisitionFile: { ...mockAcquisitionFileResponse(), - fileStatusTypeCode: toTypeCodeNullable(AcquisitionStatus.Active), + fileStatusTypeCode: toTypeCodeNullable(ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE), }, compensations: compensations, claims: [Claims.COMPENSATION_REQUISITION_DELETE], @@ -136,7 +136,7 @@ describe('compensation list view', () => { const { queryByTestId } = setup({ acquisitionFile: { ...mockAcquisitionFileResponse(), - fileStatusTypeCode: toTypeCode(AcquisitionStatus.Active), + fileStatusTypeCode: toTypeCode(ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE), }, compensations: compensations, claims: [Claims.COMPENSATION_REQUISITION_DELETE], @@ -151,7 +151,7 @@ describe('compensation list view', () => { const { queryByTestId } = setup({ acquisitionFile: { ...mockAcquisitionFileResponse(), - fileStatusTypeCode: toTypeCode(AcquisitionStatus.Active), + fileStatusTypeCode: toTypeCode(ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE), }, compensations: compensations, claims: [Claims.COMPENSATION_REQUISITION_DELETE], diff --git a/source/frontend/src/features/mapSideBar/acquisition/tabs/fileDetails/detail/statusUpdateSolver.ts b/source/frontend/src/features/mapSideBar/acquisition/tabs/fileDetails/detail/statusUpdateSolver.ts index cdffd24d28..ff3b7a8bfe 100644 --- a/source/frontend/src/features/mapSideBar/acquisition/tabs/fileDetails/detail/statusUpdateSolver.ts +++ b/source/frontend/src/features/mapSideBar/acquisition/tabs/fileDetails/detail/statusUpdateSolver.ts @@ -1,4 +1,4 @@ -import { AcquisitionStatus } from '@/constants/acquisitionFileStatus'; +import { ApiGen_CodeTypes_AcquisitionStatusTypes } from '@/models/api/generated/ApiGen_CodeTypes_AcquisitionStatusTypes'; import { ApiGen_CodeTypes_AgreementStatusTypes } from '@/models/api/generated/ApiGen_CodeTypes_AgreementStatusTypes'; import { ApiGen_Concepts_AcquisitionFile } from '@/models/api/generated/ApiGen_Concepts_AcquisitionFile'; @@ -16,15 +16,15 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: canEdit = true; break; - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: canEdit = false; break; default: @@ -44,15 +44,15 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: canEdit = true; break; - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: canEdit = false; break; default: @@ -72,16 +72,16 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: - canEdit = isDraftCompensation !== false; + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: + canEdit = isDraftCompensation ?? true; break; - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: - canEdit = isDraftCompensation !== false; + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: + canEdit = isDraftCompensation ?? true; break; default: canEdit = false; @@ -100,16 +100,16 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: canEdit = true; break; - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: - canEdit = agreementStatusCode !== ApiGen_CodeTypes_AgreementStatusTypes.FINAL; + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: + canEdit = agreementStatusCode !== ApiGen_CodeTypes_AgreementStatusTypes.FINAL ?? true; break; default: canEdit = false; @@ -128,13 +128,13 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: default: canEdit = true; break; @@ -152,13 +152,13 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: default: canEdit = true; break; @@ -176,13 +176,13 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: default: canEdit = true; break; @@ -200,13 +200,13 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: default: canEdit = true; break; @@ -224,15 +224,15 @@ class StatusUpdateSolver { let canEdit = false; switch (statusCode) { - case AcquisitionStatus.Active: - case AcquisitionStatus.Draft: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ACTIVE: + case ApiGen_CodeTypes_AcquisitionStatusTypes.DRAFT: canEdit = true; break; - case AcquisitionStatus.Archived: - case AcquisitionStatus.Cancelled: - case AcquisitionStatus.Closed: - case AcquisitionStatus.Complete: - case AcquisitionStatus.Hold: + case ApiGen_CodeTypes_AcquisitionStatusTypes.ARCHIV: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CANCEL: + case ApiGen_CodeTypes_AcquisitionStatusTypes.CLOSED: + case ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT: + case ApiGen_CodeTypes_AcquisitionStatusTypes.HOLD: canEdit = false; break; } diff --git a/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.test.tsx b/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.test.tsx index 9742aeede3..5701fdee1a 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.test.tsx @@ -1,6 +1,5 @@ import { createMemoryHistory } from 'history'; -import { AcquisitionStatus } from '@/constants/acquisitionFileStatus'; import { Claims } from '@/constants/claims'; import { mockLookups } from '@/mocks/lookups.mock'; import { getMockApiPropertyFiles } from '@/mocks/properties.mock'; @@ -11,6 +10,7 @@ import { toTypeCodeNullable } from '@/utils/formUtils'; import { act, render, RenderOptions, screen, userEvent, within } from '@/utils/test-utils'; import TakesDetailView, { ITakesDetailViewProps } from './TakesDetailView'; +import { ApiGen_CodeTypes_AcquisitionStatusTypes } from '@/models/api/generated/ApiGen_CodeTypes_AcquisitionStatusTypes'; const history = createMemoryHistory(); const storeState = { @@ -77,7 +77,7 @@ describe('TakesDetailView component', () => { ...fileProperty, file: { ...file, - fileStatusTypeCode: toTypeCodeNullable(AcquisitionStatus.Complete), + fileStatusTypeCode: toTypeCodeNullable(ApiGen_CodeTypes_AcquisitionStatusTypes.COMPLT), }, }, }, diff --git a/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.tsx b/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.tsx index faa63d6d25..5ccdab3b13 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/takes/detail/TakesDetailView.tsx @@ -12,10 +12,8 @@ import TooltipIcon from '@/components/common/TooltipIcon'; import AreaContainer from '@/components/measurements/AreaContainer'; import * as API from '@/constants/API'; import { Claims } from '@/constants/claims'; -import Roles from '@/constants/roles'; import { TakesStatusTypes } from '@/constants/takesStatusTypes'; import { isAcquisitionFile } from '@/features/mapSideBar/acquisition/add/models'; -import { cannotEditMessage } from '@/features/mapSideBar/acquisition/common/constants'; import StatusUpdateSolver from '@/features/mapSideBar/acquisition/tabs/fileDetails/detail/statusUpdateSolver'; import useKeycloakWrapper from '@/hooks/useKeycloakWrapper'; import useLookupCodeHelpers from '@/hooks/useLookupCodeHelpers'; @@ -49,14 +47,14 @@ export const TakesDetailView: React.FunctionComponent = ( const takesNotInFile = allTakesCount - (takes?.length ?? 0); const { getCodeById } = useLookupCodeHelpers(); - const { hasClaim, hasRole } = useKeycloakWrapper(); + const { hasClaim } = useKeycloakWrapper(); const file = fileProperty.file; const statusSolver = new StatusUpdateSolver(isAcquisitionFile(file) ? file : null); const canEditDetails = () => { - if (hasRole(Roles.SYSTEM_ADMINISTRATOR) || statusSolver.canEditDetails()) { + if (statusSolver.canEditDetails()) { return true; } return false; @@ -77,7 +75,7 @@ export const TakesDetailView: React.FunctionComponent = ( {!canEditDetails() && ( )} diff --git a/source/frontend/src/features/mapSideBar/property/tabs/takes/update/TakeSubForm.tsx b/source/frontend/src/features/mapSideBar/property/tabs/takes/update/TakeSubForm.tsx index 4aeec7198e..1333696c52 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/takes/update/TakeSubForm.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/takes/update/TakeSubForm.tsx @@ -8,9 +8,12 @@ import { RadioGroup, yesNoRadioGroupValues } from '@/components/common/form/Radi import { Section } from '@/components/common/Section/Section'; import { SectionField } from '@/components/common/Section/SectionField'; import AreaContainer from '@/components/measurements/AreaContainer'; +import { Roles } from '@/constants'; import * as API from '@/constants/API'; +import useKeycloakWrapper from '@/hooks/useKeycloakWrapper'; import useLookupCodeHelpers from '@/hooks/useLookupCodeHelpers'; import { getDeleteModalProps, useModalContext } from '@/hooks/useModalContext'; +import { ApiGen_CodeTypes_AcquisitionTakeStatusTypes } from '@/models/api/generated/ApiGen_CodeTypes_AcquisitionTakeStatusTypes'; import { withNameSpace } from '@/utils/formUtils'; import { StyledBorderSection, StyledNoTabSection } from '../styles'; @@ -31,6 +34,7 @@ const TakeSubForm: React.FunctionComponent = ({ const currentTake = getIn(values, withNameSpace(nameSpace)); const { getOptionsByType } = useLookupCodeHelpers(); const { setModalContent, setDisplayModal } = useModalContext(); + const { hasRole } = useKeycloakWrapper(); const takeTypeOptions = getOptionsByType(API.TAKE_TYPES); const takeStatusTypeOptions = getOptionsByType(API.TAKE_STATUS_TYPES); @@ -48,6 +52,7 @@ const TakeSubForm: React.FunctionComponent = ({ values, withNameSpace(nameSpace, 'isNewLicenseToConstruct'), ); + const takeStatusTypeCode = getIn(values, withNameSpace(nameSpace, 'takeStatusTypeCode')); const getModalWarning = (onOk: () => void) => { return (e: React.ChangeEvent) => { @@ -70,6 +75,11 @@ const TakeSubForm: React.FunctionComponent = ({ }; }; + const canEditTake = + currentTake?.id === 0 || + takeStatusTypeCode !== ApiGen_CodeTypes_AcquisitionTakeStatusTypes.COMPLETE || + hasRole(Roles.SYSTEM_ADMINISTRATOR); + return (
= ({ isCollapsable={true} initiallyExpanded={true} > - } - onClick={() => { - setModalContent({ - ...getDeleteModalProps(), - handleOk: () => { - onRemove(takeIndex); - setDisplayModal(false); - }, - }); - setDisplayModal(true); - }} - > + {canEditTake && ( + } + onClick={() => { + setModalContent({ + ...getDeleteModalProps(), + handleOk: () => { + onRemove(takeIndex); + setDisplayModal(false); + }, + }); + setDisplayModal(true); + }} + > + )} +