diff --git a/services/common/src/components/documents/DocumentTable.tsx b/services/common/src/components/documents/DocumentTable.tsx index 7645c4de88..3502c88311 100644 --- a/services/common/src/components/documents/DocumentTable.tsx +++ b/services/common/src/components/documents/DocumentTable.tsx @@ -82,18 +82,13 @@ export const DocumentTable: FC = ({ const isMinimalView: boolean = view === "minimal"; const parseDocuments = (docs: any[]): MineDocument[] => { - let parsedDocs: MineDocument[]; if (docs.length && docs[0] instanceof MineDocument) { - parsedDocs = docs; + return docs; } else { - parsedDocs = docs.map((doc) => new MineDocument(doc)); + return docs.map((doc) => new MineDocument(doc)); } - return parsedDocs.map((doc) => { - doc.setAllowedActions(userRoles); - return doc; - }); }; - + const [documents, setDocuments] = useState(parseDocuments(props.documents ?? [])); useEffect(() => { diff --git a/services/common/src/components/projectSummary/AuthorizationsInvolved.tsx b/services/common/src/components/projectSummary/AuthorizationsInvolved.tsx index 422b8eee56..99205e9817 100644 --- a/services/common/src/components/projectSummary/AuthorizationsInvolved.tsx +++ b/services/common/src/components/projectSummary/AuthorizationsInvolved.tsx @@ -58,7 +58,8 @@ import { SystemFlagEnum } from "@mds/common/constants/enums"; import { getSystemFlag } from "@mds/common/redux/selectors/authenticationSelectors"; import { FormContext } from "../forms/FormWrapper"; import { ProjectSummaryFormComponentProps } from "./ProjectSummaryForm"; -import { areAuthEnvFieldsDisabled, areDocumentFieldsDisabled } from "../projects/projectUtils"; +import { areAuthEnvFieldsDisabled, areDocumentFieldsDisabled, isDocumentDeletionEnabled } from "../projects/projectUtils"; +import { removeDocumentFromProjectSummary } from "@mds/common/redux/actionCreators/projectActionCreator"; const RenderEMAPermitCommonSections = ({ code, isAmendment, index, isDisabled }) => { const dispatch = useDispatch(); @@ -79,11 +80,27 @@ const RenderEMAPermitCommonSections = ({ code, isAmendment, index, isDisabled }) const projectSummaryDocumentTypesHash = useSelector(getProjectSummaryDocumentTypesHash); const docFieldsDisabled = areDocumentFieldsDisabled(systemFlag, status_code); + const { isEditMode } = useContext(FormContext); + const deletionEnabled = isDocumentDeletionEnabled(systemFlag, status_code); const onChange = (value) => { setShowExemptionSection(value); }; + const onDeleteDocument = (event, key: string) => { + const document = tableDocuments.find( (doc) => key === doc.key); + if(document){ + dispatch( + removeDocumentFromProjectSummary( + project_guid, + project_summary_guid, + document.mine_document_guid + )).then( () => { + removeAmendmentDocument(tableDocuments.indexOf(document),document.category,document.document_manager_guid) + }) + } + } + const removeAmendmentDocument = ( amendmentDocumentsIndex: number, category: string, @@ -231,6 +248,7 @@ const RenderEMAPermitCommonSections = ({ code, isAmendment, index, isDisabled }) documents={tableDocuments} documentParent="project summary authorization" documentColumns={documentColumns} + removeDocument={deletionEnabled && isEditMode ? onDeleteDocument : undefined} /> ); diff --git a/services/common/src/components/projectSummary/DocumentUpload.spec.tsx b/services/common/src/components/projectSummary/DocumentUpload.spec.tsx index 84860e2331..1629b9ba2e 100644 --- a/services/common/src/components/projectSummary/DocumentUpload.spec.tsx +++ b/services/common/src/components/projectSummary/DocumentUpload.spec.tsx @@ -28,7 +28,7 @@ describe("DocumentUpload", () => { initialValues={MOCK.PROJECT_SUMMARY} onSubmit={() => { }} > - + ); diff --git a/services/common/src/components/projectSummary/DocumentUpload.tsx b/services/common/src/components/projectSummary/DocumentUpload.tsx index 10c1c1701f..98b191ff19 100644 --- a/services/common/src/components/projectSummary/DocumentUpload.tsx +++ b/services/common/src/components/projectSummary/DocumentUpload.tsx @@ -24,6 +24,7 @@ import SpatialDocumentTable from "../documents/spatial/SpatialDocumentTable"; import { FormContext } from "../forms/FormWrapper"; import { useFeatureFlag } from "@mds/common/providers/featureFlags/useFeatureFlag"; import { Feature, IProjectSummaryForm } from "../.."; +import { removeDocumentFromProjectSummary } from "@mds/common/redux/actionCreators/projectActionCreator"; const RenderOldDocuments = ({ documents, @@ -67,9 +68,10 @@ const RenderOldDocuments = ({ interface DocumentUploadProps { docFieldsDisabled: boolean; + deleteEnabled: boolean; } -export const DocumentUpload: FC = ({ docFieldsDisabled }) => { +export const DocumentUpload: FC = ({ docFieldsDisabled, deleteEnabled }) => { const dispatch = useDispatch(); const { spatial_documents = [], @@ -145,29 +147,45 @@ export const DocumentUpload: FC = ({ docFieldsDisabled }) = } }; + const removeFile = (document) => { + if (document.project_summary_document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SPATIAL) { + const newSpatialDocuments = [...spatial_documents].filter( + (file) => document.document_manager_guid !== file.document_manager_guid + ); + dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "spatial_documents", newSpatialDocuments)); + } else if (document.project_summary_document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SUPPORTING) { + const newSupportDocuments = [...support_documents].filter( + (file) => document.document_manager_guid !== file.document_manager_guid + ); + dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "support_documents", newSupportDocuments)); + } + } + const onRemoveFile = (err, fileItem) => { if (err) { console.log(err); } - if (fileItem.serverId) { - const document_type_code = documents.find( + removeFile(documents.find( (file) => fileItem.serverId === file.document_manager_guid - )?.project_summary_document_type_code; - if (document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SPATIAL) { - const newSpatialDocuments = [...spatial_documents].filter( - (file) => fileItem.serverId !== file.document_manager_guid - ); - dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "spatial_documents", newSpatialDocuments)); - } else if (document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SUPPORTING) { - const newSupportDocuments = [...support_documents].filter( - (file) => fileItem.serverId !== file.document_manager_guid - ); - dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "support_documents", newSupportDocuments)); - } + )); } }; + const onDeleteDocument = (event, key: string) => { + const document = documents.find( (doc) => key === doc.mine_document_guid); + if(document){ + dispatch( + removeDocumentFromProjectSummary( + project_guid, + project_summary_guid, + document.mine_document_guid + )).then( () => { + removeFile(document); + }) + } + } + const downloadIRTTemplate = (url) => { const anchor = document.createElement("a"); anchor.href = url; @@ -283,6 +301,7 @@ export const DocumentUpload: FC = ({ docFieldsDisabled }) = documents={support_documents} documentParent="project summary" documentColumns={documentColumns} + removeDocument={deleteEnabled && isEditMode ? onDeleteDocument : undefined} /> ); diff --git a/services/common/src/components/projectSummary/ProjectSummaryFileUpload.tsx b/services/common/src/components/projectSummary/ProjectSummaryFileUpload.tsx index 6e8095a09e..305f223e09 100644 --- a/services/common/src/components/projectSummary/ProjectSummaryFileUpload.tsx +++ b/services/common/src/components/projectSummary/ProjectSummaryFileUpload.tsx @@ -69,7 +69,7 @@ export const ProjectSummaryFileUpload: FC { - if (existingFiles.length === 0) { + if (existingFiles.length === 0 || props.documents.length < existingFiles.length) { setExistingFiles(props.documents); } }, [props.documents]); diff --git a/services/common/src/components/projectSummary/ProjectSummaryForm.tsx b/services/common/src/components/projectSummary/ProjectSummaryForm.tsx index b3914d75b7..923f6d36fa 100644 --- a/services/common/src/components/projectSummary/ProjectSummaryForm.tsx +++ b/services/common/src/components/projectSummary/ProjectSummaryForm.tsx @@ -24,7 +24,7 @@ import { ProjectManagement } from "./ProjectManagement"; import { getSystemFlag } from "@mds/common/redux/selectors/authenticationSelectors"; import { SystemFlagEnum } from "../.."; import { formatProjectPayload } from "@mds/common/utils/helpers"; -import { areAuthFieldsDisabled, areDocumentFieldsDisabled, areFieldsDisabled } from "../projects/projectUtils"; +import { areAuthFieldsDisabled, areDocumentFieldsDisabled, areFieldsDisabled, isDocumentDeletionEnabled } from "../projects/projectUtils"; interface ProjectSummaryFormProps { initialValues: IProjectSummary; @@ -104,6 +104,7 @@ export const ProjectSummaryForm: FC = ({ const fieldsDisabled = areFieldsDisabled(systemFlag, status_code, confirmation_of_submission); const docFieldsDisabled = areDocumentFieldsDisabled(systemFlag, status_code); const authFieldsDisabled = areAuthFieldsDisabled(systemFlag, status_code, confirmation_of_submission); + const deleteEnabled = isDocumentDeletionEnabled(systemFlag, status_code); const handleTransformPayload = (valuesFromForm: any) => { return formatProjectPayload(valuesFromForm, { projectSummaryAuthorizationTypesArray }); @@ -128,7 +129,7 @@ export const ProjectSummaryForm: FC = ({ "representing-agent": , "mine-components-and-offsite-infrastructure": , "purpose-and-authorization": , - "document-upload": , + "document-upload": , "application-summary": , declaration: , }[tab]); diff --git a/services/common/src/components/projectSummary/ProjectSummaryFormComponents.spec.tsx b/services/common/src/components/projectSummary/ProjectSummaryFormComponents.spec.tsx index f777711dbe..bd085eee6d 100644 --- a/services/common/src/components/projectSummary/ProjectSummaryFormComponents.spec.tsx +++ b/services/common/src/components/projectSummary/ProjectSummaryFormComponents.spec.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render } from "@testing-library/react"; +import { render, fireEvent } from "@testing-library/react"; import FormWrapper from "../forms/FormWrapper"; import { FORM, SystemFlagEnum } from "@mds/common/constants"; import { ProjectManagement } from "./ProjectManagement"; @@ -20,10 +20,10 @@ import Declaration from "./Declaration"; import DocumentUpload from "./DocumentUpload"; import { FacilityOperator } from "./FacilityOperator"; import { BrowserRouter } from "react-router-dom"; +import * as modalActions from "@mds/common/redux/actions/modalActions"; const { formatProjectSummary } = exportForTesting; - const amsAuthTypes = ['AIR_EMISSIONS_DISCHARGE_PERMIT', 'EFFLUENT_DISCHARGE_PERMIT', 'REFUSE_DISCHARGE_PERMIT']; const project = { project_lead_party_guid: "project_lead_party_guid" }; const formattedProjectSummary = formatProjectSummary(MOCK.PROJECT_SUMMARY, project, amsAuthTypes); @@ -62,12 +62,14 @@ const mockFields = jest.fn(); const mockDocFields = jest.fn(); const mockAuthFields = jest.fn(); const mockEnvFields = jest.fn(); +const mockDocDeletion = jest.fn(); jest.mock("@mds/common/components/projects/projectUtils", () => ({ areFieldsDisabled: () => mockFields(), areDocumentFieldsDisabled: () => mockDocFields(), areAuthFieldsDisabled: () => mockAuthFields(), areAuthEnvFieldsDisabled: () => mockEnvFields(), + isDocumentDeletionEnabled: () => mockDocDeletion(), getProjectStatusDescription: () => jest.fn().mockReturnValue("Status Description") })); @@ -106,12 +108,13 @@ const isEnvMatch = (id: string) => { return match && !isDoc; }; -describe("ProjectSummaryForm components disable accurately accoring to functions", () => { +describe("ProjectSummaryForm components disable accurately according to functions", () => { const renderedComponents = ({ fieldsDisabled, authFieldsDisabled, docFieldsDisabled, envFieldsDisabled }) => { mockFields.mockReturnValue(fieldsDisabled); mockDocFields.mockReturnValue(docFieldsDisabled); mockAuthFields.mockReturnValue(authFieldsDisabled); mockEnvFields.mockReturnValue(envFieldsDisabled); + mockDocDeletion.mockReturnValue(false); return @@ -125,7 +128,7 @@ describe("ProjectSummaryForm components disable accurately accoring to functions - + @@ -268,4 +271,72 @@ describe("ProjectSummaryForm components disable accurately accoring to functions expect(enabledAuthIds).toEqual([]); }); -}); \ No newline at end of file + + describe("ProjectSummaryForm document deletion disables accurately according to functions", () => { + const renderedComponents = ({ deletionEnabled }) => { + mockDocDeletion.mockReturnValue(deletionEnabled); + + return + + + + + + }; + + const openModalSpy = jest.spyOn(modalActions, "openModal"); + const keys = [ + ...MOCK.PROJECT_SUMMARY.authorizations.flatMap(auth => auth.amendment_documents.map(doc => doc.document_manager_guid)), + ...MOCK.PROJECT_SUMMARY.documents.filter(doc => doc.project_summary_document_type_code === "SPR").map(doc => doc.document_manager_guid) + ]; + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("Document deletion enabled", async () => { + const params = { + deletionEnabled: true + }; + + const { container, findByTestId} = render( + + {renderedComponents(params)} + + ); + + for (const key of keys){ + const row = container.querySelector(`tr[data-row-key="${key}"]`) + expect(row).toBeInTheDocument(); + const actionsButton = row.querySelector('button[data-cy="menu-actions-button"]') + fireEvent.mouseEnter(actionsButton); + const deleteAction = await findByTestId("action-button-delete"); + expect(deleteAction).toBeInTheDocument(); + fireEvent.click(deleteAction) + } + expect(openModalSpy).toHaveBeenCalledTimes(keys.length) + }); + + test("Document deletion disabled", async () => { + const params = { + deletionEnabled: false + }; + + const { container } = render( + + {renderedComponents(params)} + + ); + + for (const key of keys){ + const row = container.querySelector(`tr[data-row-key="${key}"]`) + expect(row).toBeInTheDocument(); + const actionsButton = row.querySelector('button[data-cy="menu-actions-button"]') + fireEvent.mouseEnter(actionsButton); + const deleteAction = container.querySelector('[data-testid="action-button-delete"]'); + expect(deleteAction).not.toBeInTheDocument(); + } + expect(openModalSpy).toHaveBeenCalledTimes(0) + }); + }); +}); diff --git a/services/common/src/components/projects/__snapshots__/ProjectDocumentsTab.spec.tsx.snap b/services/common/src/components/projects/__snapshots__/ProjectDocumentsTab.spec.tsx.snap index c9932139cf..241d64c04e 100644 --- a/services/common/src/components/projects/__snapshots__/ProjectDocumentsTab.spec.tsx.snap +++ b/services/common/src/components/projects/__snapshots__/ProjectDocumentsTab.spec.tsx.snap @@ -44,6 +44,29 @@ exports[`ProjectDocumentsTab renders properly 1`] = ` + +
+
+
+

+ Air Emissions Discharge Permit +

+
+
+
+
+
+ +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + + File Name + + + + + + + + + + + + +
+
+ Category + +
+ + File Type + + + + + + + + + + + +
+
+
+ + Last Modified + + + + + + + + + + + +
+
+
+ + Created By + + + + + + + + + + + +
+
+
+ + + + + +
+ N/A +
+
+
+ .png +
+
+
+ Dec 12 2024 +
+
+
+ idir\\username +
+
+
+ +
+
+ + + + + +
+ N/A +
+
+
+ .pdf +
+
+
+ Dec 12 2024 +
+
+
+ idir\\username +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
`${systemFlag}_${projectSummaryStatusCode}`); +export const isDocumentDeletionEnabled = memoize((systemFlag: SystemFlagEnum, projectSummaryStatusCode: string) => { + return systemFlag === SystemFlagEnum.ms && projectSummaryStatusCode == PROJECT_STATUS_CODES.DFT; +}, (systemFlag: SystemFlagEnum, projectSummaryStatusCode: string) => `${systemFlag}_${projectSummaryStatusCode}`); + export const areDocumentFieldsDisabled = memoize((systemFlag: SystemFlagEnum, projectSummaryStatusCode: string) => { // Return false (enabled) if status = "" => "Not Started" const isStatusInEnum = (Object).values(PROJECT_STATUS_CODES).includes(projectSummaryStatusCode) diff --git a/services/common/src/redux/actionCreators/projectActionCreator.ts b/services/common/src/redux/actionCreators/projectActionCreator.ts index 68c5426fe6..2709d972dd 100644 --- a/services/common/src/redux/actionCreators/projectActionCreator.ts +++ b/services/common/src/redux/actionCreators/projectActionCreator.ts @@ -167,7 +167,7 @@ export const removeDocumentFromProjectSummary = ( ) .then((response: AxiosResponse) => { notification.success({ - message: "Successfully deleted project description document.", + message: "Successfully deleted project document.", duration: 10, }); dispatch(success(NetworkReducerTypes.REMOVE_DOCUMENT_FROM_PROJECT_SUMMARY)); diff --git a/services/common/src/tests/mocks/dataMocks.tsx b/services/common/src/tests/mocks/dataMocks.tsx index 8c86e82d24..dd4608da94 100644 --- a/services/common/src/tests/mocks/dataMocks.tsx +++ b/services/common/src/tests/mocks/dataMocks.tsx @@ -7716,12 +7716,82 @@ export const PROJECT_SUMMARY: IProjectSummary = { new_type: "PER", authorization_description: "sdfa", exemption_reason: "zxczxczx", - amendment_documents: [], exemption_requested: false, ams_tracking_number: null, ams_outcome: null, ams_status_code: null, ams_submission_timestamp: "2024-05-24T19:10:09.825194+00:00", + amendment_documents: [ + { + project_summary_id: null, + project_summary_document_type_code: "MAP", + mine_document_guid: "1bf1884f-84b0-44a1-ba76-2c8aa2403480", + mine_guid: "83a8045c-37be-4ec4-8888-f633af902472", + document_manager_guid: "5066b2b5-6f92-4a4b-9771-22f8a13e3297", + document_name: "Location Document.png", + upload_date: "2024-12-12 22:00:35.119953+00:00", + update_timestamp: "2024-12-12 22:00:35.119943+00:00", + create_user: "idir\\username", + is_archived: false, + archived_date: null, + archived_by: null, + mine_document_bundle_id: null, + versions: [] + }, + { + project_summary_id: null, + project_summary_document_type_code: "DFA", + mine_document_guid: "c00f29ce-4507-4f5b-b822-8c6a4c7af676", + mine_guid: "83a8045c-37be-4ec4-8888-f633af902472", + document_manager_guid: "1de57298-0583-46f6-8f3d-29044bd6aeb3", + document_name: "Discharge Document.pdf", + upload_date: "2024-12-12 22:00:35.119968+00:00", + update_timestamp: "2024-12-12 22:00:35.119968+00:00", + create_user: "idir\\username", + is_archived: false, + archived_date: null, + archived_by: null, + mine_document_bundle_id: null, + versions: [] + } + ], + discharge_documents: [ + { + project_summary_id: null, + project_summary_document_type_code: "DFA", + mine_document_guid: "c00f29ce-4507-4f5b-b822-8c6a4c7af676", + mine_guid: "83a8045c-37be-4ec4-8888-f633af902472", + document_manager_guid: "1de57298-0583-46f6-8f3d-29044bd6aeb3", + document_name: "Discharge Document.pdf", + upload_date: "2024-12-12 22:00:35.119968+00:00", + update_timestamp: "2024-12-12 22:00:35.119968+00:00", + create_user: "idir\\username", + is_archived: false, + archived_date: null, + archived_by: null, + mine_document_bundle_id: null, + versions: [] + } + ], + location_documents: [ + { + project_summary_id: null, + project_summary_document_type_code: "MAP", + mine_document_guid: "1bf1884f-84b0-44a1-ba76-2c8aa2403480", + mine_guid: "83a8045c-37be-4ec4-8888-f633af902472", + document_manager_guid: "5066b2b5-6f92-4a4b-9771-22f8a13e3297", + document_name: "Location Document.png", + upload_date: "2024-12-12 22:00:35.119953+00:00", + update_timestamp: "2024-12-12 22:00:35.119943+00:00", + create_user: "idir\\username", + is_archived: false, + archived_date: null, + archived_by: null, + mine_document_bundle_id: null, + versions: [] + } + ], + support_documents: [] }, { project_summary_authorization_guid: "624d3acc-b62b-491e-82a3-67ef3b1bbf88", @@ -7858,6 +7928,9 @@ export const PROJECT: IProject = { major_mine_application_guid: "305ea694-e601-44a4-8994-fc2604c8c19e", project_guid: "35633148-57f8-4967-be35-7f89abfbd02e", status_code: MAJOR_MINE_APPLICATION_AND_IRT_STATUS_CODE_CODES.CHR, + primary_documents: [], + spatial_documents: [], + supporting_documents: [], documents: [ { major_mine_application_id: 2, diff --git a/services/core-api/app/api/projects/project_summary/resources/project_summary_uploaded_document.py b/services/core-api/app/api/projects/project_summary/resources/project_summary_uploaded_document.py index 934f6afc46..5f905c15a6 100644 --- a/services/core-api/app/api/projects/project_summary/resources/project_summary_uploaded_document.py +++ b/services/core-api/app/api/projects/project_summary/resources/project_summary_uploaded_document.py @@ -1,8 +1,8 @@ -from werkzeug.exceptions import NotFound +from werkzeug.exceptions import NotFound, Forbidden from flask_restx import Resource from app.extensions import api -from app.api.utils.access_decorators import (requires_any_of, MINE_ADMIN, EDIT_PROJECT_SUMMARIES) +from app.api.utils.access_decorators import (requires_any_of, MINE_ADMIN, EDIT_PROJECT_SUMMARIES,MINESPACE_PROPONENT) from app.api.utils.resources_mixins import UserMixin from app.api.mines.documents.models.mine_document import MineDocument @@ -12,7 +12,7 @@ class ProjectSummaryUploadedDocumentResource(Resource, UserMixin): @api.doc(description='Delete a document from a project description.') @api.response(204, 'Successfully deleted.') - @requires_any_of([MINE_ADMIN, EDIT_PROJECT_SUMMARIES]) + @requires_any_of([MINE_ADMIN, EDIT_PROJECT_SUMMARIES, MINESPACE_PROPONENT]) def delete(self, project_guid, project_summary_guid, mine_document_guid): project_summary = ProjectSummary.find_by_project_summary_guid(project_summary_guid) mine_document = MineDocument.find_by_mine_document_guid(mine_document_guid) @@ -21,10 +21,20 @@ def delete(self, project_guid, project_summary_guid, mine_document_guid): raise NotFound('Project Description not found.') if mine_document is None: raise NotFound('Mine document not found.') + if mine_document not in project_summary.mine_documents: + + for auth in project_summary.authorizations: + for doc in auth.amendment_documents: + if doc.mine_document == mine_document: + if project_summary.status_code != "DFT": + raise Forbidden('Cannot delete document unless project application is in draft state') + doc.delete() + mine_document.delete() + return None, 204 + raise NotFound('Mine document not found on Project Description.') project_summary.mine_documents.remove(mine_document) project_summary.save() - return None, 204 diff --git a/services/core-api/tests/factories.py b/services/core-api/tests/factories.py index ecd06c99ff..e618b63b9c 100644 --- a/services/core-api/tests/factories.py +++ b/services/core-api/tests/factories.py @@ -59,6 +59,7 @@ from app.api.projects.project_summary.models.project_summary_contact import ProjectSummaryContact from app.api.projects.project_summary.models.project_summary_authorization import ProjectSummaryAuthorization from app.api.projects.project_summary.models.project_summary_document_xref import ProjectSummaryDocumentXref +from app.api.projects.project_summary.models.project_summary_authorization_document_xref import ProjectSummaryAuthorizationDocumentXref from app.api.projects.information_requirements_table.models.information_requirements_table import InformationRequirementsTable from app.api.projects.information_requirements_table.models.information_requirements_table_document_xref import InformationRequirementsTableDocumentXref from app.api.projects.project_decision_package.models.project_decision_package_document_xref import ProjectDecisionPackageDocumentXref @@ -380,6 +381,20 @@ class Params: project_summary_id = factory.SelfAttribute('project_summary.project_summary_id') project_summary_document_type_code = factory.LazyFunction(RandomProjectSummaryDocumentTypeCode) +class ProjectSummaryAuthorizationDocumentFactory(BaseFactory): + + class Meta: + model = ProjectSummaryAuthorizationDocumentXref + + class Params: + project_summary = factory.SubFactory('tests.factories.ProjectSummaryFactory') + project_summary_authorization = factory.SubFactory('tests.factories.ProjectSummaryAuthorizationFactory') + mine_document = factory.SubFactory(MineDocumentFactory,mine_guid=factory.SelfAttribute('..project_summary.mine_guid')) + + project_summary_authorization_document_xref_guid = GUID + project_summary_authorization_guid = factory.SelfAttribute('project_summary_authorization.project_summary_authorization_guid') + mine_document_guid = factory.SelfAttribute('mine_document.mine_document_guid') + project_summary_document_type_code = factory.LazyFunction(RandomProjectSummaryDocumentTypeCode) class InformationRequirementsTableDocumentFactory(BaseFactory): @@ -1413,7 +1428,6 @@ class Params: existing_permits_authorizations = [] deleted_ind = False - class EMLIContactTypeFactory(BaseFactory): class Meta: diff --git a/services/core-api/tests/projects/project_summaries/resources/test_project_summary_uploaded_document_resource.py b/services/core-api/tests/projects/project_summaries/resources/test_project_summary_uploaded_document_resource.py index b9da4ba05a..bffcb246f8 100644 --- a/services/core-api/tests/projects/project_summaries/resources/test_project_summary_uploaded_document_resource.py +++ b/services/core-api/tests/projects/project_summaries/resources/test_project_summary_uploaded_document_resource.py @@ -3,7 +3,7 @@ import uuid from tests.factories import (ProjectSummaryFactory, MineFactory, MineDocumentFactory, - ProjectSummaryDocumentFactory) + ProjectSummaryAuthorizationDocumentFactory,ProjectSummaryAuthorizationFactory) # DELETE @@ -19,6 +19,38 @@ def test_delete_file(test_client, db_session, auth_headers): assert delete_resp.status_code == 204 assert len(project_summary.documents) == document_count - 1 +def test_delete_amendment_file(test_client, db_session, auth_headers): + project_summary = ProjectSummaryFactory() + project_summary.status_code = 'DFT' + project_summary_authorization = ProjectSummaryAuthorizationFactory(project_summary=project_summary) + project_summary.authorizations.append(project_summary_authorization) + amendment_document = ProjectSummaryAuthorizationDocumentFactory(project_summary=project_summary,project_summary_authorization=project_summary_authorization) + + document_count = len(project_summary_authorization.amendment_documents) + assert amendment_document.mine_document_guid is not None + + delete_resp = test_client.delete( + f'/projects/{project_summary.project_guid}/project-summaries/{project_summary.project_summary_guid}/documents/{amendment_document.mine_document_guid}', + headers=auth_headers['full_auth_header']) + assert delete_resp.status_code == 204 + assert len(project_summary_authorization.amendment_documents) == document_count - 1 + + +def test_delete_amendment_not_in_draft(test_client, db_session, auth_headers): + project_summary = ProjectSummaryFactory() + project_summary.status_code = 'APR' + project_summary_authorization = ProjectSummaryAuthorizationFactory(project_summary=project_summary) + project_summary.authorizations.append(project_summary_authorization) + amendment_document = ProjectSummaryAuthorizationDocumentFactory(project_summary=project_summary,project_summary_authorization=project_summary_authorization) + + document_count = len(project_summary_authorization.amendment_documents) + assert amendment_document.mine_document_guid is not None + + delete_resp = test_client.delete( + f'/projects/{project_summary.project_guid}/project-summaries/{project_summary.project_summary_guid}/documents/{amendment_document.mine_document_guid}', + headers=auth_headers['full_auth_header']) + assert delete_resp.status_code == 403 + assert len(project_summary_authorization.amendment_documents) == document_count def test_delete_file_not_on_project_summary(test_client, db_session, auth_headers): project_summary = ProjectSummaryFactory() diff --git a/services/minespace-web/src/styles/components/Tables.scss b/services/minespace-web/src/styles/components/Tables.scss index 2dc68dd9d7..92286bf875 100644 --- a/services/minespace-web/src/styles/components/Tables.scss +++ b/services/minespace-web/src/styles/components/Tables.scss @@ -33,6 +33,10 @@ font-size: 16px; } +.ant-dropdown-menu-item:hover, .ant-dropdown-menu-item button:hover{ + cursor: pointer; +} + @include screen-md { .ant-table table { min-width: 100%;