From 47619a31944b6d95d5f62cfe7e616013a6274666 Mon Sep 17 00:00:00 2001 From: Milos Despotovic Date: Thu, 30 May 2024 14:02:17 -0700 Subject: [PATCH 01/89] redlining.js changes from branch dev-AHMD-2646 --- web/src/components/FOI/Home/Redlining.js | 719 +++++++++++++++++++---- 1 file changed, 610 insertions(+), 109 deletions(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index c3c4eca3a..9068d09bd 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -21,6 +21,7 @@ import IconButton from "@mui/material/IconButton"; import Switch from "@mui/material/Switch"; import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; +import Grid from '@mui/material/Grid'; import { styled } from "@mui/material/styles"; import { fetchAnnotationsByPagination, @@ -72,6 +73,10 @@ import { getJoinedSections, isObjectNotEmpty, getValidObject, + constructPageFlags, + skipDocument, + skipDuplicateDocument, + skipNRDocument, constructPageFlags } from "./utils"; import { Edit, MultiSelectEdit } from "./Edit"; @@ -107,6 +112,8 @@ const Redlining = React.forwardRef( (state) => state.documents?.requestnumber ); + const allPublicBodies = useAppSelector((state) => state.documents?.allPublicBodies) + document.title = requestnumber + " - FOI Document Reviewer" const pageFlags = useAppSelector((state) => state.documents?.pageFlags); @@ -211,7 +218,7 @@ const Redlining = React.forwardRef( stopLoop = true; return false; //stop loop } else { - // artial Disclosure, Full Disclosure, Withheld in Full, Duplicate, Not Responsive + // Partial Disclosure, Full Disclosure, Withheld in Full, Duplicate, Not Responsive pageFlagArray = pageFlagInfo.pageflag?.filter((flag) => [ pageFlagTypes["Partial Disclosure"], @@ -268,7 +275,7 @@ const Redlining = React.forwardRef( const isValidRedlineDivisionDownload = (divisionid, divisionDocuments) => { let isvalid = false; - for (let divObj of divisionDocuments) { + for (let divObj of divisionDocuments) { if (divObj.divisionid == divisionid) { // enable the Redline for Sign off if a division has only Incompatable files if (divObj?.incompatableList?.length > 0) { @@ -279,8 +286,26 @@ const Redlining = React.forwardRef( else { for (let doc of divObj.documentlist) { for (const flagInfo of doc.pageFlag) { + if (modalFor == "consult") { + for (let consult of doc.consult) { + if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ( + (flagInfo.flagid !== pageFlagTypes["Consult"] && + flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid !== pageFlagTypes["Not Responsive"]) || + ( + (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || + (includeNRPages && flagInfo.flagid === pageFlagTypes["Not Responsive"]) + ) + ) { + if(isvalid == false) { + isvalid = true; + } + } + } + } + } // Added condition to handle Duplicate/NR clicked for Redline for Sign off Modal - if ( + else if ( (flagInfo.flagid != pageFlagTypes["Duplicate"] && flagInfo.flagid != pageFlagTypes["Not Responsive"]) || ( (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || @@ -296,6 +321,7 @@ const Redlining = React.forwardRef( } } } + console.log(divisionid, isvalid) return isvalid; }; @@ -312,16 +338,19 @@ const Redlining = React.forwardRef( } } setIsDisableNRDuplicate(isDisabled); - if (isDisabled) { - setIncludeNRPages(isDisabled) - setIncludeDuplicatePages(isDisabled); - } + setIncludeNRPages(isDisabled) + setIncludeDuplicatePages(isDisabled); } const [enableSavingRedline, setEnableSavingRedline] = useState(false); const [enableSavingOipcRedline, setEnableSavingOipcRedline] = useState(false) const [enableSavingFinal, setEnableSavingFinal] = useState(false); + const [enableSavingConsults, setEnableSavingConsults] = useState(false); + const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); + const [documentPublicBodies, setDocumentPublicBodies] = useState([]); + const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const [filteredComments, setFilteredComments] = useState({}); const [pagesRemoved, setPagesRemoved] = useState([]); @@ -434,6 +463,36 @@ const Redlining = React.forwardRef( menu.appendChild(redlineForSignOffBtn); + const consultPackageButton = document.createElement("button"); + consultPackageButton.textContent = "Consult Public Body"; + consultPackageButton.id = "consult_package"; + consultPackageButton.className = "consult_package"; + consultPackageButton.style.backgroundColor = "transparent"; + consultPackageButton.style.border = "none"; + consultPackageButton.style.padding = "8px 8px 8px 10px"; + consultPackageButton.style.cursor = "pointer"; + consultPackageButton.style.alignItems = "left"; + consultPackageButton.disabled = !enableSavingConsults; + consultPackageButton.onclick = () => { + // Save to s3 + setModalFor("consult"); + setModalTitle("Consult Public Body"); + setIncludeDuplicatePages(true); + setIncludeNRPages(true); + setModalMessage([ + "Are you sure want to create a consult? A PDF will be created for each public body selected and your web browser page will automatically refresh", +
, +
, + + Select one or more Ministry you wish to send the selected page(s) to for consult* + , + ]); + setModalButtonLabel("Create Consult"); + setRedlineModalOpen(true); + }; + + menu.appendChild(consultPackageButton); + const finalPackageBtn = document.createElement("button"); finalPackageBtn.textContent = "Final Package for Applicant"; finalPackageBtn.id = "final_package"; @@ -1601,6 +1660,12 @@ const Redlining = React.forwardRef( setEnableSavingFinal( _enableSavingRedline && requestStatus == RequestStates["Response"] ); + //consults validation + const publicBodyList = getPublicBodyList() + setDocumentPublicBodies(publicBodyList) + setEnableSavingConsults( + publicBodyList.length > 0 + ); if (_instance) { //oipc changes - begin const document = _instance.UI.iframeWindow.document; @@ -1621,6 +1686,8 @@ const Redlining = React.forwardRef( document.getElementById("final_package").disabled = !_enableSavingRedline || requestStatus !== RequestStates["Response"]; //oipc changes - end + // conults validation + document.getElementById("consult_package").disabled = !(publicBodyList.length > 0) } }; @@ -2376,6 +2443,7 @@ const Redlining = React.forwardRef( } ); } + setNewRedaction(null) } setEditAnnot(null); }; @@ -2682,23 +2750,58 @@ const Redlining = React.forwardRef( const getDivisionDocumentMappingForRedline = (divisions) => { let newDocList = []; - for (let div of divisions) { - let divDocList = documentList.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - - // sort based on sortorder as the sortorder added based on the LastModified - divDocList = sortBySortOrder(divDocList); - - let incompatableList = incompatibleFiles.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - newDocList.push({ - divisionid: div.divisionid, - divisionname: div.name, - documentlist: divDocList, - incompatableList: incompatableList, - }); + if (modalFor == "redline" || modalFor == "oipcreview") { + for (let div of divisions) { + let divDocList = documentList.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + + // sort based on sortorder as the sortorder added based on the LastModified + divDocList = sortBySortOrder(divDocList); + + let incompatableList = incompatibleFiles.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + newDocList.push({ + divisionid: div.divisionid, + divisionname: div.name, + documentlist: divDocList, + incompatableList: incompatableList, + }); + } + } else if (modalFor == "consult") { + // map documents to publicBodies (Divisions) for consults + for (let publicBodyId of divisions) { + let publicBodyDocList = []; + documentList.forEach((doc) => { + let programareaids = new Set(); + if (doc.consult && doc.consult.length) { + doc.consult.forEach((consult) => { + consult.programareaid.forEach((programareaid) => { + if (programareaid === publicBodyId) { + programareaids.add(programareaid); + } + }) + }); + } + for (let programareaid of programareaids) { + if (programareaid === publicBodyId) { + publicBodyDocList.push({...doc}) + } + } + }) + publicBodyDocList = sortBySortOrder(publicBodyDocList); + + let incompatableList = []; + + const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId) + newDocList.push({ + divisionid: publicBodyId, + divisionname: publicBodyInfo.name, + documentlist: publicBodyDocList, + incompatableList: incompatableList, + }) + } } return newDocList; }; @@ -2725,6 +2828,8 @@ const Redlining = React.forwardRef( } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments)); + } else if (modalFor == 'consult') { + prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); } @@ -2845,7 +2950,7 @@ const Redlining = React.forwardRef( let duplicateWatermarkPagesEachDiv = []; let NRWatermarksPages = {}; let NRWatermarksPagesEachDiv = []; - for (let divObj of divisionDocuments) { + for (let divObj of divisionDocuments) { divisionCount++; // sort based on sortorder as the sortorder added based on the LastModified for (let doc of sortBySortOrder(divObj.documentlist)) { @@ -2855,6 +2960,18 @@ const Redlining = React.forwardRef( let pageIndex = 1; //gather pages that need to be removed doc.pageFlag.sort((a, b) => a.page - b.page); //sort pageflag by page # + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } //if(isIgnoredDocument(doc, doc['pagecount'], divisionDocuments) == false) { for (const flagInfo of doc.pageFlag) { if (flagInfo.flagid !== pageFlagTypes["Consult"]) { // ignore consult flag to fix bug FOIMOD-3062 @@ -2868,10 +2985,11 @@ const Redlining = React.forwardRef( pagesToRemoveEachDoc.length; } else { pagesToRemoveEachDoc.push(flagInfo.page); - - pagesToRemove.push( - pageIndex + totalPageCountIncludeRemoved - ); + if (!skipDocumentPages && !skipOnlyDuplicateDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } } } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { if(includeNRPages) { @@ -2883,10 +3001,11 @@ const Redlining = React.forwardRef( pagesToRemoveEachDoc.length; } else { pagesToRemoveEachDoc.push(flagInfo.page); - - pagesToRemove.push( - pageIndex + totalPageCountIncludeRemoved - ); + if (!skipDocumentPages && !skipOnlyNRDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } } } else { if (flagInfo.flagid !== pageFlagTypes["Consult"]) { @@ -2905,7 +3024,9 @@ const Redlining = React.forwardRef( totalPageCount += Object.keys( pageMappings[doc.documentid] ).length; - totalPageCountIncludeRemoved += doc.pagecount; + if (!skipDocumentPages) { + totalPageCountIncludeRemoved += doc.pagecount; + } //} } @@ -2933,10 +3054,197 @@ const Redlining = React.forwardRef( }); } + const prepareRedlinePageMappingByConsult = (divisionDocuments) => { + let removepages = {}; + let pageMappings = {}; + let divPageMappings = {}; + let pagesToRemove = []; + let totalPageCount = 0; + let totalPageCountIncludeRemoved = 0; + let duplicateWatermarkPages = {}; + let duplicateWatermarkPagesEachDiv = []; + let NRWatermarksPages = {}; + let NRWatermarksPagesEachDiv = []; + for (let divObj of divisionDocuments) { + // sort based on sortorder as the sortorder added based on the LastModified + for (let doc of sortBySortOrder(divObj.documentlist)) { + if (doc.pagecount > 0) { + let pagesToRemoveEachDoc = []; + pageMappings[doc.documentid] = {}; + let pageIndex = 1; + //gather pages that need to be removed + doc.pageFlag.sort((a, b) => a.page - b.page); //sort pageflag by page # + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + + // for consults, go through all pages + for (const page of doc.pages) { + //find pageflags for this page + const pageFlagsOnPage = doc.pageFlag.filter((pageFlag) => { + return pageFlag.page === page; + }) + const notConsultPageFlagsOnPage = pageFlagsOnPage.filter((pageFlag) => { + return pageFlag.flagid !== pageFlagTypes["Consult"]; + }) + + // if the page has no pageflags, remove it + if (pageFlagsOnPage.length == 0) { + pagesToRemoveEachDoc.push(page); + if (!skipDocumentPages) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + pageIndex ++; + } + + //differences in pagemapping for consults begin here + //for pages with only consult flags, remove if page doesn't belong to current consult body + if (pageFlagsOnPage.length > 0 && notConsultPageFlagsOnPage.length == 0) { + for (let flagInfo of pageFlagsOnPage) { + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } + } + pageIndex ++; + } + + // if the page does have pageflags, process it + for (let flagInfo of notConsultPageFlagsOnPage) { + if (flagInfo.flagid == pageFlagTypes["Duplicate"]) { + if(includeDuplicatePages) { + duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyDuplicateDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + + } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { + if(includeNRPages) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyNRDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } + + // Check if the page has relevant consult flag, if not remove the page + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageIndex ++; + } + } + } + //End of pageMappingsByConsults + + totalPageCount += Object.keys( + pageMappings[doc.documentid] + ).length; + if (!skipDocumentPages) { + totalPageCountIncludeRemoved += doc.pagecount; + } + } + } + divPageMappings[divObj.divisionid] = pageMappings; + removepages[divObj.divisionid] = pagesToRemove; + duplicateWatermarkPages[divObj.divisionid] = duplicateWatermarkPagesEachDiv; + NRWatermarksPages[divObj.divisionid] = NRWatermarksPagesEachDiv; + pagesToRemove = []; + duplicateWatermarkPagesEachDiv = []; + NRWatermarksPagesEachDiv = []; + totalPageCount = 0; + totalPageCountIncludeRemoved = 0; + pageMappings = {} + } + + setRedlinepageMappings({ + 'divpagemappings': divPageMappings, + 'pagemapping': pageMappings, + 'pagestoremove': removepages + }); + setRedlineWatermarkPageMapping({ + 'duplicatewatermark': duplicateWatermarkPages, + 'NRwatermark': NRWatermarksPages + }); + } + const prepareRedlineIncompatibleMapping = (redlineAPIResponse) => { let divIncompatableMapping = {}; let incompatibleFiles = []; let divCounter = 0; + if (redlineAPIResponse.consultdocumentlist) { + redlineAPIResponse.divdocumentList = redlineAPIResponse.consultdocumentlist + } for (let divObj of redlineAPIResponse.divdocumentList) { divCounter++; @@ -2958,6 +3266,7 @@ const Redlining = React.forwardRef( }); incompatibleFiles = incompatibleFiles.concat(divIncompatableFiles); } + if (divObj.publicBody && !divObj.divisionid) divObj.divisionid = divObj.publicBody; if (redlineAPIResponse.issingleredlinepackage == "Y") { if (divCounter == redlineAPIResponse.divdocumentList.length) { incompatableObj["divisionid"] = "0"; @@ -3066,20 +3375,23 @@ const Redlining = React.forwardRef( let annotationManager = docInstance?.Core.annotationManager; let annotList = await annotationManager.importAnnotations(xfdfString); let sectionStamps = {}; - let annotationpagenumbers = annotationpagemapping(formattedAnnotationXML); - for (const annot of annotList) { - let parentRedaction = annot.getCustomData("parentRedaction"); - if (parentRedaction) { - if (annot.Subject == "Free Text") { - let parentRedactionId = parentRedaction.replace(/"/g, '"').replace(/\\/g, "") - let sections = getAnnotationSections(annot); - if (sections.some(item => item.section === 's. 14')) { + let annotationpagenumbers = annotationpagemapping(formattedAnnotationXML); + for (const annot of annotList) { + let parentRedaction = annot.getCustomData("parentRedaction"); + if (parentRedaction) { + if (annot.Subject == "Free Text") { + let parentRedactionId = parentRedaction.replace(/"/g, '"').replace(/\\/g, "") + let sections = getAnnotationSections(annot); + if (redlineCategory === "oipcreview" && sections.some(item => item.section === 's. 14')) { sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; - } + } + if (modalFor == "consult" && sections.some(item => item.section === 'NR')) { + sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; + } + } } } - } - return sectionStamps; + return sectionStamps; } const annotationpagemapping = (formattedAnnotationXML) => { @@ -3236,9 +3548,10 @@ const Redlining = React.forwardRef( } const cancelSaveRedlineDoc = () => { - setIncludeDuplicatePages(false); - setIncludeNRPages(false); + disableNRDuplicate(); + setSelectedPublicBodyIDs([]); setRedlineModalOpen(false); + setConsultApplyRedactions(false); }; const saveDoc = () => { @@ -3257,6 +3570,9 @@ const Redlining = React.forwardRef( case "responsepackage": saveResponsePackage(docViewer, annotManager, docInstance); break; + case "consult": + saveRedlineDocument(docInstance, modalFor); + break; default: } setIncludeDuplicatePages(false); @@ -3264,6 +3580,9 @@ const Redlining = React.forwardRef( }; const getzipredlinecategory = (layertype) => { + if (modalFor == "consult") { + return "consultpackage"; + } if (currentLayer.name.toLowerCase() === "oipc") { return layertype === "oipcreview" ? "oipcreviewredline" : "oipcredline"; } @@ -3272,6 +3591,34 @@ const Redlining = React.forwardRef( } /*Redline download & stitching code starts */ + const getPublicBodyList = () => { + let publicBodyIdList = []; + if (documentList?.length > 0) { + for (const doc of documentList) { + if ('pageFlag' in doc) { + for (let pageflag of doc['pageFlag']) { + if ('programareaid' in pageflag) { + for (let programareaid of pageflag['programareaid']) { + publicBodyIdList.push(programareaid) + } + } + } + } + } + const filteredPublicBodyIdList = [...new Set(publicBodyIdList)] + return getPublicBodyObjs(filteredPublicBodyIdList); + } + } + + const getPublicBodyObjs = (publicBodyIDList) => { + const publicBodies = []; + for (const publicBody of allPublicBodies) { + if (publicBodyIDList.includes(publicBody.programareaid)) { + publicBodies.push(publicBody); + } + } + return publicBodies; + } const saveRedlineDocument = async (_instance, layertype) => { toastId.current = toast(`Start saving redline...`, { @@ -3281,7 +3628,13 @@ const Redlining = React.forwardRef( }); const divisionFilesList = [...documentList, ...incompatibleFiles]; - const divisions = getDivisionsForSaveRedline(divisionFilesList); + let divisions; + if (modalFor == "consult") { + //Key consult logic, uses preexisting division reldine logic for consults + divisions = selectedPublicBodyIDs; + } else { + divisions = getDivisionsForSaveRedline(divisionFilesList); + } const divisionDocuments = getDivisionDocumentMappingForRedline(divisions); const documentids = documentList.map((obj) => obj.documentid); getFOIS3DocumentRedlinePreSignedUrl( @@ -3317,17 +3670,52 @@ const Redlining = React.forwardRef( for (let doc of div.documentlist) { docCount++; documentsObjArr.push(doc); - if (docCount == div.documentlist.length) { - if (pageMappedDocs != undefined) { - let divisionsdocpages = Object.values( + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + if (pageMappedDocs != undefined) { + let divisionsdocpages = []; + // for consults, no need to filter by division/consult + if (modalFor == "consult") { + Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .forEach((obj) => { + divisionsdocpages = Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .filter((obj) => { + return obj.docId == doc.documentid; + }) + .map((obj) => { + if (res.issingleredlinepackage == "Y" || (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + return obj.pageMappings; + } + }); + }) + } else { + divisionsdocpages = Object.values( pageMappedDocs.redlineDocIdLookup ) .filter((obj) => { - return obj.division.includes(div.divisionid); + return obj.division.includes(div.divisionid) && obj.docId == doc.documentid; }) .map((obj) => { - return obj.pageMappings; + if (res.issingleredlinepackage == "Y" || (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + return obj.pageMappings; + } }); + } + if (divisionsdocpages[0]) { divisionsdocpages.forEach(function (_arr) { _arr.forEach(function (value) { divisionstitchpages.push(value); @@ -3447,7 +3835,9 @@ const Redlining = React.forwardRef( // sort based on sortorder as the sortorder added based on the LastModified let sorteddocs = sortBySortOrder(alldocuments) for (const sorteddoc of sorteddocs) { + if (!sorteddocids.includes(sorteddoc['documentid'])) { sorteddocids.push(sorteddoc['documentid']); + } } return {"sorteddocuments": sorteddocids, "pkgdocuments": summarylist} @@ -3468,6 +3858,8 @@ const Redlining = React.forwardRef( for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; + // added this vopy variable for validating the first document of a division with NR/Duplicate + let docCountCopy = 0; let division = key; let documentlist = stitchlist[key]; if (redlineSinglePkg == "N") { @@ -3483,27 +3875,47 @@ const Redlining = React.forwardRef( } if(documentlist.length > 0) { for (let doc of documentlist) { + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } await _instance.Core.createDocument(doc.s3path_load, { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue - }).then(async (docObj) => { - applyRotations(docObj, doc.attributes.rotatedpages) + }).then(async (docObj) => { //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { + docCountCopy++; docCount++; - if (docCount == 1) { + if (docCountCopy == 1) { // Delete pages from the first document const deletedPages = getDeletedPagesBeforeStitching(doc.documentid); if (deletedPages.length > 0) { docObj.removePages(deletedPages); - } - stitchedDocObj = docObj; + } + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { + stitchedDocObj = docObj; + } + else { + docCountCopy--; + } + } else { - let pageIndexToInsert = stitchedDocObj?.getPageCount() + 1; - await stitchedDocObj.insertPages( - docObj, - doc.pages, - pageIndexToInsert - ); + if (stitchedDocObj && (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + let pageIndexToInsert = stitchedDocObj?.getPageCount() + 1; + await stitchedDocObj.insertPages( + docObj, + doc.pages, + pageIndexToInsert + ); + } } //} }); @@ -3700,11 +4112,44 @@ const Redlining = React.forwardRef( } }; + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + let annotationManager = docInstance?.Core.annotationManager; + const rarr = []; + let rects = []; + for (const [key, value] of Object.entries(appliedSectionStamps)) { + let sectionAnnotation = annotationManager.getAnnotationById(key); + if (sectionAnnotation.Subject === "Redact") { + rects = rects.concat( + sectionAnnotation.getQuads().map((q) => { + return { + pageno: appliedSectionStamps[key], + recto: q.toRect(), + vpageno: sectionAnnotation.getPageNumber() + }; + }) + ); + } + } + for (const rect of rects) { + let height = docViewer.getPageHeight(rect.vpageno); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + } + if (rarr.length > 0) { + const app = {}; + app.redaction_overlay = true; + app.border = false; + app.show_redacted_content_regions = false; + const doc = await stitchObject.getPDFDoc(); + await PDFNet.Redactor.redact(doc, rarr, app); + } + } + useEffect(() => { const StitchAndUploadDocument = async () => { const { PDFNet } = docInstance.Core; const downloadType = "pdf"; let currentDivisionCount = 0; + // keep track of the starting page number for consult packages const divisionCountForToast = Object.keys(redlineStitchObject).length; for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; @@ -3722,7 +4167,7 @@ const Redlining = React.forwardRef( if (stitchObject == null) { triggerRedlineZipper( redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], + null, // stitchObject == null then no stichedDocPath available divisionCountForToast, redlineSinglePackage ); @@ -3732,17 +4177,18 @@ const Redlining = React.forwardRef( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview") { + if(redlineCategory !== "oipcreview" || modalFor == "consult") { await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - redlineSinglePackage + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + redlineSinglePackage ); } if ( redlinepageMappings["pagestoremove"][divisionid] && - redlinepageMappings["pagestoremove"][divisionid].length > 0 + redlinepageMappings["pagestoremove"][divisionid].length > 0 && + stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length ) { await stitchObject.removePages( redlinepageMappings["pagestoremove"][divisionid] @@ -3767,38 +4213,8 @@ const Redlining = React.forwardRef( //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { - const rarr = []; - let annotationManager = docInstance?.Core.annotationManager; let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - let rects = []; - for (const [key, value] of Object.entries(s14_sectionStamps)) { - let s14annoation = annotationManager.getAnnotationById(key); - if ( s14annoation.Subject === "Redact") { - rects = rects.concat( - s14annoation.getQuads().map((q) => { - return { - pageno: s14_sectionStamps[key], - recto: q.toRect(), - vpageno: s14annoation.getPageNumber() - }; - }) - ); - } - - - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); - } + await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); await stampPageNumberRedline( stitchObject, PDFNet, @@ -3807,8 +4223,15 @@ const Redlining = React.forwardRef( ); } //OIPC - Special Block : End - - + + //Consults - Redactions Block (Redact S.NR) : Start + if(modalFor == "consult") { + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } + } + //Consults - Redactions Block (Redact S.NR) : End stitchObject .getFileData({ @@ -3984,7 +4407,9 @@ const Redlining = React.forwardRef( let doc = documentViewer.getDocument(); await annotationManager.applyRedactions(); /**must apply redactions before removing pages*/ - await doc.removePages(pagesToRemove); + if (pagesToRemove.length > 0) { + await doc.removePages(pagesToRemove); + } const { PDFNet } = _instance.Core; PDFNet.initialize(); @@ -4095,7 +4520,9 @@ const Redlining = React.forwardRef( // sort based on sortorder as the sortorder added based on the LastModified let sorteddocs = sortBySortOrder(alldocuments) for (const sorteddoc of sorteddocs) { - sorteddocids.push(sorteddoc['documentid']); + if (!sorteddocids.includes(sorteddoc['documentid'])) { + sorteddocids.push(sorteddoc['documentid']); + } } return {"sorteddocuments": sorteddocids, "pkgdocuments": summarylist} } @@ -4163,6 +4590,24 @@ const Redlining = React.forwardRef( const handleIncludeDuplicantePages = (e) => { setIncludeDuplicatePages(e.target.checked); } + + const handleApplyRedactions = (e) => { + setConsultApplyRedactions(e.target.checked); + } + + const handleSelectedPublicBodies = (e) => { + const publicBodyId = parseInt(e.target.value); + if (selectedPublicBodyIDs.includes(publicBodyId)) { + setSelectedPublicBodyIDs((prev) => { + return [...prev.filter(id => id !== publicBodyId)] + }); + } + else { + setSelectedPublicBodyIDs((prev) => { + return [...prev, publicBodyId] + }); + } + } @@ -4288,7 +4733,7 @@ const Redlining = React.forwardRef( initHeight={300} minWidth={600} minHeight={250} - className={"state-change-dialog" + (modalFor == "redline"?" redline-modal":"")} + className={"state-change-dialog" + (modalFor === "redline" ? " redline-modal" : modalFor === "consult" ? " consult-modal" : "")} onRequestClose={cancelRedaction} isOpen={redlineModalOpen} > @@ -4306,7 +4751,7 @@ const Redlining = React.forwardRef( > {modalMessage}

- {modalFor == "redline" && <> + {modalFor === "redline" && <> } + {modalFor === "consult" && + <> + + {documentPublicBodies?.map((publicBody) => { + return (<> + + + + + ) + })} + +
+

More Options:

+ + +
+ + +
+ + + + }
- + + +

{modalTitle}

+ + Close + + +
+ + + + {modalMessage} + {isOverride && <> +

+ + + } +
+
+
+ + {!isOverride && + + } + {isOverride && + + } + + +
); } From e9dbd91979919a2ce43fdebd51444533868a6f7c Mon Sep 17 00:00:00 2001 From: Aparna Date: Mon, 10 Jun 2024 15:31:24 -0700 Subject: [PATCH 07/89] Removed debug codes and updated changes from code review --- api/reviewer_api/services/jobrecordservice.py | 7 +------ api/reviewer_api/services/radactionservice.py | 20 +++++-------------- web/src/components/FOI/Home/Redlining.js | 16 +++------------ 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/api/reviewer_api/services/jobrecordservice.py b/api/reviewer_api/services/jobrecordservice.py index 863a1e03b..09a74039e 100644 --- a/api/reviewer_api/services/jobrecordservice.py +++ b/api/reviewer_api/services/jobrecordservice.py @@ -141,13 +141,8 @@ def insertfeeoverridereason(self, message, pdfstitchjobid, userid): ) job = PDFStitchJobAttributes.insert(row) return job - - def __getpdfstitchjobattributesbyid(self, requestid): - job = PDFStitchJobAttributes().getpdfstitchjobattributesbyid(requestid) - return job def isbalancefeeoverrodforrequest(self, requestid): - pdfstitchjobattributes= self.__getpdfstitchjobattributesbyid(requestid) + pdfstitchjobattributes= PDFStitchJobAttributes().getpdfstitchjobattributesbyid(requestid) isbalancefeeoverrode= False if pdfstitchjobattributes is None or not pdfstitchjobattributes else True - #print("\nisbalancefeeoverrode:",isbalancefeeoverrode) return isbalancefeeoverrode diff --git a/api/reviewer_api/services/radactionservice.py b/api/reviewer_api/services/radactionservice.py index 27a3b9844..570145bfa 100644 --- a/api/reviewer_api/services/radactionservice.py +++ b/api/reviewer_api/services/radactionservice.py @@ -122,16 +122,12 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): job = jobrecordservice().insertpdfstitchjobstatus( _jobmessage, userinfo["userid"] ) - print("job:: ",job.message) - print("job-2:: ",job.identifier) if job.success: if finalpackageschema['pdfstitchjobattributes'] is not None: - feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] - print("feeoverridereason:",feeoverridereason) - if feeoverridereason is not None and feeoverridereason != '': - feeoverridereasonresult= jobrecordservice().insertfeeoverridereason(finalpackageschema,job.identifier,userinfo["userid"]) - #print("feeoverridereasonresult:",feeoverridereasonresult) - #Add here the reason- comment text and a boolean + if 'feeoverridereason' in finalpackageschema['pdfstitchjobattributes']: + feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] + if feeoverridereason is not None and feeoverridereason != '': + jobrecordservice().insertfeeoverridereason(finalpackageschema,job.identifier,userinfo["userid"]) _message = self.__preparemessageforsummaryservice( finalpackageschema, userinfo, job ) @@ -139,17 +135,12 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): # redline/final package download: prepare message for zipping service def __preparemessageforsummaryservice(self, messageschema, userinfo, job): + feeoverridereason= None pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) - print("pdf_stitch_job_attributes:",pdf_stitch_job_attributes) if pdf_stitch_job_attributes is not None: feeoverridereason= json.loads(pdf_stitch_job_attributes).get("feeoverridereason", None) if feeoverridereason is not None and feeoverridereason != '': feeoverridereason= userinfo["firstname"]+" "+userinfo["lastname"]+" overrode balance outstanding warning for the following reason: "+feeoverridereason - print("feeoverridereason:",feeoverridereason) - else: - feeoverridereason= "" - else: - feeoverridereason= "" _message = { "jobid": job.identifier, "requestid": -1, @@ -167,7 +158,6 @@ def __preparemessageforsummaryservice(self, messageschema, userinfo, job): "redactionlayerid": json.dumps(messageschema["redactionlayerid"]), "feeoverridereason":feeoverridereason } - print("_message:",_message) return _message # redline/final package download: prepare message for zipping service diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 3fa98cb00..babf9df43 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -507,7 +507,6 @@ const Redlining = React.forwardRef( parent.appendChild(menu); menuBtn.onclick = async () => { - console.log("Menu button clicked"); if (menu.style.display == "flex") { menu.style.display = "none"; } else { @@ -3182,7 +3181,6 @@ const Redlining = React.forwardRef( }; const saveDoc = () => { - console.log("Inside saveDoc!") setIsOverride(false) setOutstandingBalanceModal(false) setRedlineModalOpen(false); @@ -3198,7 +3196,6 @@ const Redlining = React.forwardRef( saveRedlineDocument(docInstance, modalFor); break; case "responsepackage": - console.log("Inside responsepackage -- ", feeOverrideReason) saveResponsePackage(docViewer, annotManager, docInstance,feeOverrideReason); break; default: @@ -4032,9 +4029,9 @@ const Redlining = React.forwardRef( res.s3path_save, zipServiceMessage ); - // setTimeout(() => { - // window.location.reload(true); - // }, 3000); + setTimeout(() => { + window.location.reload(true); + }, 3000); }, (_err) => { console.log(_err); @@ -4153,13 +4150,6 @@ const Redlining = React.forwardRef( setIsOverride(true) } - // const saveOverrideReason = () => { - // console.log("Saved override reason!",feeOverrideReason) - // saveDoc("responsepackage") - // setIsOverride(false) - // setOutstandingBalanceModal(false) - // } - const handleOverrideReasonChange = (event) => { setFeeOverrideReason(event.target.value); }; From d32f10fdcd17d4c2ae1f72494819e9a388025725 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 11 Jun 2024 12:52:51 -0700 Subject: [PATCH 08/89] Merge issue -fix --- api/reviewer_api/resources/document.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 596204759..4163e45bc 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -107,8 +107,8 @@ def get(requestid): "validoipcreviewlayer": documentservice().validate_oipcreviewlayer(jsonobj, requestid), "balancefeeoverrodforrequest": balancefeeoverrodforrequest } - documentdivisionslist,result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) - return json.dumps({"requeststatuslabel": "", "documents": result, "requestnumber":"", "requestinfo":requestinfo,"documentdivisions":documentdivisionslist}), 200 + result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) + return json.dumps({"requeststatuslabel": "", "documents": result, "requestnumber":"", "requestinfo":requestinfo}), 200 except KeyError as error: return {'status': False, 'message': CUSTOM_KEYERROR_MESSAGE + str(error)}, 400 except BusinessException as exception: From daa67b7a51a2a8de1e61e0f1b570079356edc08b Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 11 Jun 2024 21:53:08 -0700 Subject: [PATCH 09/89] Fetching & displaying balance due amount added --- api/reviewer_api/resources/document.py | 5 +++++ web/src/components/FOI/Home/Home.js | 3 +++ web/src/components/FOI/Home/Redlining.js | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 4163e45bc..defc92d79 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -100,11 +100,16 @@ def get(requestid): response.raise_for_status() # get request status jsonobj = response.json() + print("jsonobj:", jsonobj) balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) + outstandingbalance=0 + if 'cfrfee' in jsonobj and 'feedata' in jsonobj['cfrfee'] and "balanceDue" in jsonobj['cfrfee']['feedata']: + outstandingbalance= jsonobj['cfrfee']['feedata']["balanceDue"] requestinfo = { "bcgovcode": jsonobj["bcgovcode"], "requesttype": jsonobj["requestType"], "validoipcreviewlayer": documentservice().validate_oipcreviewlayer(jsonobj, requestid), + "outstandingbalance": outstandingbalance, "balancefeeoverrodforrequest": balancefeeoverrodforrequest } result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index bfe6697cb..f92749366 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -44,6 +44,7 @@ function Home() { const [isStitchingLoaded, setIsStitchingLoaded] = useState(false); const [warningModalOpen, setWarningModalOpen] = useState(false); const [isBalanceFeeOverrode , setIsBalanceFeeOverrode] = useState(false); + const [outstandingBalance, setOutstandingBalance]= useState(0) const redliningRef = useRef(); const selectorRef = useRef(); @@ -67,6 +68,7 @@ function Home() { fetchDocuments( parseInt(foiministryrequestid), async (data) => { + setOutstandingBalance(outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") @@ -278,6 +280,7 @@ function Home() { setWarningModalOpen={setWarningModalOpen} scrollLeftPanel={scrollLeftPanel} isBalanceFeeOverrode={isBalanceFeeOverrode} + outstandingBalance={outstandingBalance} /> ) // :
Loading
diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 7825224cc..e780c5b80 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -98,7 +98,8 @@ const Redlining = React.forwardRef( licenseKey, setWarningModalOpen, scrollLeftPanel, - isBalanceFeeOverrode + isBalanceFeeOverrode, + outstandingBalance }, ref ) => { @@ -195,7 +196,6 @@ const Redlining = React.forwardRef( const [enableRedactionPanel, setEnableRedactionPanel] = useState(false); const [clickRedactionPanel, setClickRedactionPanel] = useState(false); const [outstandingBalanceModal, setOutstandingBalanceModal] = useState(false); - const [outstandingBalance, setOutstandingBalance]= useState(1) const [isOverride, setIsOverride]= useState(false); const [feeOverrideReason, setFeeOverrideReason]= useState(""); From 1c0ea5ba2c121d473f4fe31bfe81ece2d79ed169 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 11 Jun 2024 22:10:45 -0700 Subject: [PATCH 10/89] Fix error with object --- web/src/components/FOI/Home/Home.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index f92749366..bfab6e1b5 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -68,7 +68,7 @@ function Home() { fetchDocuments( parseInt(foiministryrequestid), async (data) => { - setOutstandingBalance(outstandingbalance) + setOutstandingBalance(data.requestinfo.outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") From b107a9226ce1b52240478b0dd9be889d965d8326 Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 09:31:28 -0700 Subject: [PATCH 11/89] String value conversion --- api/reviewer_api/resources/document.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index defc92d79..0694375e6 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -102,9 +102,10 @@ def get(requestid): jsonobj = response.json() print("jsonobj:", jsonobj) balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) - outstandingbalance=0 + outstandingbalance=0.0 if 'cfrfee' in jsonobj and 'feedata' in jsonobj['cfrfee'] and "balanceDue" in jsonobj['cfrfee']['feedata']: - outstandingbalance= jsonobj['cfrfee']['feedata']["balanceDue"] + outstandingbalancestr = jsonobj['cfrfee']['feedata']["balanceDue"] + outstandingbalance = float(outstandingbalancestr) requestinfo = { "bcgovcode": jsonobj["bcgovcode"], "requesttype": jsonobj["requestType"], From 3683264e39d5b59b241bb1ed89b519dd80e6ec19 Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 12:09:00 -0700 Subject: [PATCH 12/89] Debug code fixes --- api/reviewer_api/resources/document.py | 2 +- api/reviewer_api/resources/redaction.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 0694375e6..59087ef36 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -114,7 +114,7 @@ def get(requestid): "balancefeeoverrodforrequest": balancefeeoverrodforrequest } result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) - return json.dumps({"requeststatuslabel": "", "documents": result, "requestnumber":"", "requestinfo":requestinfo}), 200 + return json.dumps({"requeststatuslabel": jsonobj["requeststatuslabel"], "documents": result, "requestnumber":jsonobj["axisRequestId"], "requestinfo":requestinfo}), 200 except KeyError as error: return {'status': False, 'message': CUSTOM_KEYERROR_MESSAGE + str(error)}, 400 except BusinessException as exception: diff --git a/api/reviewer_api/resources/redaction.py b/api/reviewer_api/resources/redaction.py index 694ffb87a..220cf62c5 100644 --- a/api/reviewer_api/resources/redaction.py +++ b/api/reviewer_api/resources/redaction.py @@ -230,7 +230,7 @@ class AnnotationMetadata(Resource): @staticmethod @TRACER.trace() @cross_origin(origins=allowedorigins()) - @auth.require + #@auth.require def get(ministryrequestid, redactionlayer): try: result = redactionservice().getannotationinfobyrequest(ministryrequestid, redactionlayer) From 495b25b75f103b0b5d5060007fa143ae9fbc539a Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 14:08:44 -0700 Subject: [PATCH 13/89] Missing field added in summary --- .../rstreamio/message/schemas/redactionsummary.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py b/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py index 979e4d18f..954d4ce33 100644 --- a/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py +++ b/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py @@ -30,7 +30,7 @@ def __init__(self, sorteddocuments, pkgdocuments) -> None: class RedactionSummaryMessage(object): def __init__(self, jobid, requestid, ministryrequestid, category, requestnumber, - bcgovcode, createdby, filestozip, finaloutput, attributes, summarydocuments ,redactionlayerid) -> None: + bcgovcode, createdby, filestozip, finaloutput, attributes, summarydocuments ,redactionlayerid, feeoverridereason) -> None: self.jobid = jobid self.requestid = requestid self.ministryrequestid = ministryrequestid @@ -43,6 +43,7 @@ def __init__(self, jobid, requestid, ministryrequestid, category, requestnumber, self.attributes = attributes self.summarydocuments = summarydocuments self.redactionlayerid = redactionlayerid + self.feeoverridereason = feeoverridereason def get_in_redactionsummary_msg(producer_json): From bf944019835caa5f75f29817594ee4c9e92d40c2 Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 15:31:11 -0700 Subject: [PATCH 14/89] Issue fixed in migration script --- api/migrations/versions/9d45ce57481e_.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/migrations/versions/9d45ce57481e_.py b/api/migrations/versions/9d45ce57481e_.py index 25bda2114..03e94fea5 100644 --- a/api/migrations/versions/9d45ce57481e_.py +++ b/api/migrations/versions/9d45ce57481e_.py @@ -19,7 +19,7 @@ def upgrade(): op.create_table('PDFStitchJobAttributes', sa.Column('attributesid', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('pdfstitchjobid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False), + sa.Column('pdfstitchjobid', sa.Integer(), nullable=False), sa.Column('version', sa.Integer(), nullable=False), sa.Column('ministryrequestid', sa.Integer(), nullable=False), sa.Column('attributes', postgresql.JSON(astext_type=sa.Text()), nullable=False), From d1147aa4e6ff3ff40a488959860f6700a3f042c0 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 14 Jun 2024 16:23:33 -0700 Subject: [PATCH 15/89] small bug fixes added to this logic with Aparna to adjust redline creation --- api/reviewer_api/services/radactionservice.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/reviewer_api/services/radactionservice.py b/api/reviewer_api/services/radactionservice.py index 570145bfa..fe91d7620 100644 --- a/api/reviewer_api/services/radactionservice.py +++ b/api/reviewer_api/services/radactionservice.py @@ -123,7 +123,7 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): _jobmessage, userinfo["userid"] ) if job.success: - if finalpackageschema['pdfstitchjobattributes'] is not None: + if 'pdfstitchjobattributes' in finalpackageschema and finalpackageschema['pdfstitchjobattributes'] is not None: if 'feeoverridereason' in finalpackageschema['pdfstitchjobattributes']: feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] if feeoverridereason is not None and feeoverridereason != '': @@ -135,8 +135,10 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): # redline/final package download: prepare message for zipping service def __preparemessageforsummaryservice(self, messageschema, userinfo, job): - feeoverridereason= None - pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) + feeoverridereason= '' + pdf_stitch_job_attributes = None + if 'pdfstitchjobattributes' in messageschema: + pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) if pdf_stitch_job_attributes is not None: feeoverridereason= json.loads(pdf_stitch_job_attributes).get("feeoverridereason", None) if feeoverridereason is not None and feeoverridereason != '': From bcc1f7ed1807d488111f1e09477c4d3264947704 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 19 Jun 2024 16:20:21 -0700 Subject: [PATCH 16/89] adjusted modal for consult to account for include redlines feature --- web/src/components/FOI/Home/Redlining.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 914489e66..6fba96220 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -353,6 +353,7 @@ const Redlining = React.forwardRef( const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); const [documentPublicBodies, setDocumentPublicBodies] = useState([]); const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const [consultApplyRedlines, setConsultApplyRedlines] = useState(false); const [filteredComments, setFilteredComments] = useState({}); const [pagesRemoved, setPagesRemoved] = useState([]); @@ -3585,6 +3586,7 @@ const Redlining = React.forwardRef( setRedlineModalOpen(false); setSelectedPublicBodyIDs([]); setConsultApplyRedactions(false); + setConsultApplyRedlines(false); } }; @@ -4637,6 +4639,9 @@ const Redlining = React.forwardRef( const handleApplyRedactions = (e) => { setConsultApplyRedactions(e.target.checked); } + const handleApplyRedlines = (e) => { + setConsultApplyRedlines(e.target.checked); + } const handleSelectedPublicBodies = (e) => { const publicBodyId = parseInt(e.target.value); @@ -4869,6 +4874,16 @@ const Redlining = React.forwardRef( />
+ + +
- + } From 40f4c5cf0b551904a2a3d7ccd240265a9394345e Mon Sep 17 00:00:00 2001 From: nkan-aot2 <156717133+nkan-aot2@users.noreply.github.com> Date: Mon, 24 Jun 2024 09:42:13 -0700 Subject: [PATCH 17/89] turn on sourcemap in test-marshal for debug --- web/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/Dockerfile b/web/Dockerfile index eaf8db1ea..b2d2af972 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -17,7 +17,7 @@ ARG REACT_APP_REDACTION_SELECT_LIMIT ENV NODE_ENV ${NODE_ENV} -ENV GENERATE_SOURCEMAP false +ENV GENERATE_SOURCEMAP true ENV REACT_APP_KEYCLOAK_CLIENT ${REACT_APP_KEYCLOAK_CLIENT} ENV REACT_APP_KEYCLOAK_URL_REALM ${REACT_APP_KEYCLOAK_URL_REALM} ENV REACT_APP_KEYCLOAK_URL ${REACT_APP_KEYCLOAK_URL} From 1954a44648799f9cf3aed04fe68c2e90dbdd1aef Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 3 Jul 2024 15:43:54 -0700 Subject: [PATCH 18/89] Consult Changes: 1. redline.js adjusted to fix redline package creation bug for single div packages (copied bug fix in dev/test) 2. Adjusted valid redline divison dl function for consults 3. Added new biz features (verbage changes, ability to exclude or incl. redlines) --- web/src/components/FOI/Home/ConsultModal.tsx | 4 +- web/src/components/FOI/Home/Redlining.js | 59 ++++++++++++++------ 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/web/src/components/FOI/Home/ConsultModal.tsx b/web/src/components/FOI/Home/ConsultModal.tsx index 0695226b9..9f1206104 100644 --- a/web/src/components/FOI/Home/ConsultModal.tsx +++ b/web/src/components/FOI/Home/ConsultModal.tsx @@ -100,7 +100,7 @@ const ConsultModal = ({ -
Select one or more Ministry you with the send the selected page(s) to for consult.
+
Select one or more public bodies you wish to consult with on the selected page(s).
{programAreaList.programareas?.map((programArea: any, index: number) => (
-
If you do not see the name of the Ministry you would like to send for consult above please type it below.
+
If you do not see the name of the public body you wish to consult with, please type it below.
flagId === pageFlagTypes["Duplicate"])) || (!includeNRPages && pageFlagsOnPage.some((flagId) => flagId === pageFlagTypes["Not Responsive"]))) { + isvalid = false; + } else { + isvalid = true; + } + } } } } @@ -484,11 +498,11 @@ const Redlining = React.forwardRef( setIncludeDuplicatePages(true); setIncludeNRPages(true); setModalMessage([ - "Are you sure want to create a consult? A PDF will be created for each public body selected and your web browser page will automatically refresh", + "Are you sure you want to create a consult package? A PDF will be created for each public body selected, and your web browser will automatically refresh after package creation.",
,
, - Select one or more Ministry you wish to send the selected page(s) to for consult* + Select one or more public bodies you wish to create a consult package for: , ]); setModalButtonLabel("Create Consult"); @@ -2850,7 +2864,7 @@ const Redlining = React.forwardRef( } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments)); - } else if (modalFor == 'consult') { + } else if (modalFor == "consult") { prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); @@ -3041,7 +3055,7 @@ const Redlining = React.forwardRef( if (flagInfo.flagid !== pageFlagTypes["Consult"]) { pageIndex ++; } - } + } } //End of pageMappingsByDivisions totalPageCount += Object.keys( @@ -3052,7 +3066,7 @@ const Redlining = React.forwardRef( } //} } - + } divPageMappings[divObj.divisionid] = pageMappings; removepages[divObj.divisionid] = pagesToRemove; @@ -3829,7 +3843,7 @@ const Redlining = React.forwardRef( redactionlayerid: currentLayer.redactionlayerid }); - if(res.issingleredlinepackage == 'Y' || divisions.length == 1){ + if(res.issingleredlinepackage == 'Y'){ stitchSingleDivisionRedlineExport( _instance, divisionDocuments, @@ -3931,7 +3945,8 @@ const Redlining = React.forwardRef( await _instance.Core.createDocument(doc.s3path_load, { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue - }).then(async (docObj) => { + }).then(async (docObj) => { + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -4055,13 +4070,11 @@ const Redlining = React.forwardRef( }).then(async (newDoc) => { applyRotations(newDoc, filerow.attributes.rotatedpages) docCount++; - setredlineDocCount(docCount); - if (isIgnoredDocument(filerow, newDoc, divisionDocuments) === false) { + // if (isIgnoredDocument(filerow, newDoc, divisionDocuments) === false) { if (filerow.stitchIndex === 1) { // Delete pages from the first document const deletedPages = getDeletedPagesBeforeStitching(filerow?.documentid); if (deletedPages.length > 0) { - setSkipDeletePages(true); await newDoc.removePages(deletedPages); } stitchedDocObj = newDoc; @@ -4080,7 +4093,7 @@ const Redlining = React.forwardRef( } ]) } - } + // } }); } catch (error) { console.error("An error occurred during create document:", error); @@ -4266,14 +4279,22 @@ const Redlining = React.forwardRef( } //OIPC - Special Block : End - //Consults - Redactions Block (Redact S.NR) : Start + //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(modalFor == "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); + } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); } } - //Consults - Redactions Block (Redact S.NR) : End + //Consults - Redlines + Redactions (Redact S.NR) Block : End stitchObject .getFileData({ @@ -4294,7 +4315,7 @@ const Redlining = React.forwardRef( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, + render: `${modalFor == "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -4641,6 +4662,9 @@ const Redlining = React.forwardRef( } const handleApplyRedlines = (e) => { setConsultApplyRedlines(e.target.checked); + if (consultApplyRedactions) { + setConsultApplyRedactions(false); + } } const handleSelectedPublicBodies = (e) => { @@ -4891,6 +4915,7 @@ const Redlining = React.forwardRef( id="redaction-checkbox" checked={consultApplyRedactions} onChange={handleApplyRedactions} + disabled={!consultApplyRedlines} /> From cd7291dd835f60995a229901b51922e6806ecef5 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 16 Jul 2024 13:08:15 -0700 Subject: [PATCH 19/89] Added richards bug fix (ticket 3299) to consults page mapping --- web/src/components/FOI/Home/Redlining.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8429f54ab..39869fd2e 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -3061,7 +3061,7 @@ const Redlining = React.forwardRef( totalPageCount += Object.keys( pageMappings[doc.documentid] ).length; - if (!skipDocumentPages) { + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { totalPageCountIncludeRemoved += doc.pagecount; } //} @@ -3253,7 +3253,7 @@ const Redlining = React.forwardRef( totalPageCount += Object.keys( pageMappings[doc.documentid] ).length; - if (!skipDocumentPages) { + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { totalPageCountIncludeRemoved += doc.pagecount; } } From 48aecc93eabc4b326b0f6ca18716207a4b74671f Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 7 Aug 2024 16:42:32 -0700 Subject: [PATCH 20/89] Added consult code from PR 1001 / PR 1054 / PR 1036 for ticket 2646 to test-rook --- .../resources/foiflowmasterdata.py | 7 +- api/reviewer_api/utils/util.py | 2 + .../services/redactionsummaryservice.py | 3 + .../services/zippingservice.py | 2 +- web/public/stylesheets/webviewer.css | 5 + web/src/actions/actionConstants.ts | 1 + web/src/actions/documentActions.ts | 14 + .../services/docReviewerService.tsx | 3 +- web/src/apiManager/services/foiOSSService.tsx | 2 + web/src/components/FOI/App.scss | 4 + .../components/FOI/Home/ConfirmationModal.js | 65 ++- .../CreateResponsePDF/CreateResponsePDF.js | 39 ++ .../useSaveRedlineForSignOff.js | 451 +++++++++++++++--- web/src/components/FOI/Home/Redlining.js | 43 +- web/src/modules/documentReducer.ts | 5 +- 15 files changed, 583 insertions(+), 63 deletions(-) diff --git a/api/reviewer_api/resources/foiflowmasterdata.py b/api/reviewer_api/resources/foiflowmasterdata.py index b617d6746..2500357a7 100644 --- a/api/reviewer_api/resources/foiflowmasterdata.py +++ b/api/reviewer_api/resources/foiflowmasterdata.py @@ -200,6 +200,8 @@ def post(ministryrequestid, redactionlayer="redline", layertype="redline"): packagetype = "redline" if redactionlayer == "oipc": packagetype = "oipcreview" if layertype == "oipcreview" else "oipcredline" + if layertype == "consult": + packagetype = "consult" #check if is single redline package is_single_redline = is_single_redline_package(_bcgovcode, packagetype, requesttype) @@ -215,7 +217,10 @@ def post(ministryrequestid, redactionlayer="redline", layertype="redline"): filepath_put = "{0}/{2}/{1}/{0} - {2} - {1}.pdf".format( filepathlist[0], division_name, packagetype ) - + if packagetype == "consult": + filepath_put = "{0}/{2}/{2} - {1} - {0}.pdf".format( + filepathlist[0], division_name, packagetype + ) s3path_save = s3client.generate_presigned_url( ClientMethod="get_object", Params={ diff --git a/api/reviewer_api/utils/util.py b/api/reviewer_api/utils/util.py index 0a5f52954..796561c9f 100644 --- a/api/reviewer_api/utils/util.py +++ b/api/reviewer_api/utils/util.py @@ -137,6 +137,8 @@ def getbatchconfig(): return _begin, _size, _limit def is_single_redline_package(bcgovcode, packagetype, requesttype): + if packagetype == "consult": + return False if (packagetype == "oipcreview"): return True if REDLINE_SINGLE_PKG_MINISTRIES not in (None, ""): diff --git a/computingservices/DocumentServices/services/redactionsummaryservice.py b/computingservices/DocumentServices/services/redactionsummaryservice.py index fbf158207..701d096f1 100644 --- a/computingservices/DocumentServices/services/redactionsummaryservice.py +++ b/computingservices/DocumentServices/services/redactionsummaryservice.py @@ -13,6 +13,9 @@ class redactionsummaryservice(): def processmessage(self,incomingmessage): summaryfilestozip = [] message = get_in_redactionsummary_msg(incomingmessage) + #Condition to handle consults packaages (no summary files to be created) + if message.category == "consultpackage": + return summaryfilestozip try: pdfstitchjobactivity().recordjobstatus(message,3,"redactionsummarystarted") summarymsg = message.summarydocuments diff --git a/computingservices/DocumentServices/services/zippingservice.py b/computingservices/DocumentServices/services/zippingservice.py index c997af363..f29c000a5 100644 --- a/computingservices/DocumentServices/services/zippingservice.py +++ b/computingservices/DocumentServices/services/zippingservice.py @@ -14,7 +14,7 @@ def preparemessageforzipperservice(self,summaryfiles, message): if summaryfiles and len(summaryfiles) > 0: filestozip_list = json.loads(msgjson['filestozip'])+summaryfiles else: - filestozip_list = msgjson['filestozip'] + filestozip_list = json.loads(msgjson['filestozip']) print('filestozip_list: ', filestozip_list) msgjson['filestozip'] = self.to_json(filestozip_list) msgjson['attributes'] = self.to_json(msgjson['attributes']) diff --git a/web/public/stylesheets/webviewer.css b/web/public/stylesheets/webviewer.css index 9084bb2bc..bbf51b3c6 100644 --- a/web/public/stylesheets/webviewer.css +++ b/web/public/stylesheets/webviewer.css @@ -19,6 +19,11 @@ cursor: not-allowed !important; } +.consult_package:disabled { + color: #999999 !important; + cursor: not-allowed !important; +} + .file-upload-toast { .Toastify__toast-body { > div:last-child { diff --git a/web/src/actions/actionConstants.ts b/web/src/actions/actionConstants.ts index cbae36c3d..a93f87dce 100644 --- a/web/src/actions/actionConstants.ts +++ b/web/src/actions/actionConstants.ts @@ -20,6 +20,7 @@ const ACTION_CONSTANTS = { INC_REDACTION_LAYER: "INC_REDACTION_LAYER", SET_REQUEST_NUMBER:"SET_REQUEST_NUMBER", SET_DELETED_PAGES: "SET_DELETED_PAGES", + SET_PUBLIC_BODIES: "SET_PUBLIC_BODIES", FOI_PERSONAL_SECTIONS: "FOI_PERSONAL_SECTIONS", FOI_PERSONAL_PEOPLE: "FOI_PERSONAL_PEOPLE", FOI_PERSONAL_FILETYPES: "FOI_PERSONAL_FILETYPES", diff --git a/web/src/actions/documentActions.ts b/web/src/actions/documentActions.ts index da519f073..4bb4067a6 100644 --- a/web/src/actions/documentActions.ts +++ b/web/src/actions/documentActions.ts @@ -1,5 +1,13 @@ import ACTION_CONSTANTS from "./actionConstants"; +type PublicBody = { + bcgovcode: string, + iaocode: string, + name: string, + isactive: boolean, + type: string, + programareaid: number +} export const setRedactionInfo = (data: any) => (dispatch:any) =>{ dispatch({ @@ -8,6 +16,12 @@ export const setRedactionInfo = (data: any) => (dispatch:any) =>{ }) } +export const setPublicBodies = (data: PublicBody[]) => (dispatch:any) =>{ + dispatch({ + type:ACTION_CONSTANTS.SET_PUBLIC_BODIES, + payload:data + }) +} export const setIsPageLeftOff = (data: any) => (dispatch:any) =>{ dispatch({ diff --git a/web/src/apiManager/services/docReviewerService.tsx b/web/src/apiManager/services/docReviewerService.tsx index 823191efc..62b1d3898 100644 --- a/web/src/apiManager/services/docReviewerService.tsx +++ b/web/src/apiManager/services/docReviewerService.tsx @@ -4,7 +4,7 @@ import API from "../endpoints"; import UserService from "../../services/UserService"; import { setRedactionInfo, setIsPageLeftOff, setSections, setDocumentList, setRequestStatus, setRedactionLayers, incrementLayerCount, setRequestNumber, setRequestInfo, setDeletedPages, - setFOIPersonalSections, setFOIPersonalPeople, setFOIPersonalFiletypes, setFOIPersonalVolumes + setFOIPersonalSections, setFOIPersonalPeople, setFOIPersonalFiletypes, setFOIPersonalVolumes, setPublicBodies } from "../../actions/documentActions"; import { store } from "../../services/StoreService"; import { number } from "yargs"; @@ -295,6 +295,7 @@ export const fetchPageFlagsMasterData = ( .then((res:any) => { if (res.data || res.data === "") { callback(res.data); + store.dispatch(setPublicBodies(res.data.find((flag: any) => flag.name === 'Consult').programareas)); } else { throw new Error(); } diff --git a/web/src/apiManager/services/foiOSSService.tsx b/web/src/apiManager/services/foiOSSService.tsx index bb170b92a..82a79a962 100644 --- a/web/src/apiManager/services/foiOSSService.tsx +++ b/web/src/apiManager/services/foiOSSService.tsx @@ -59,6 +59,8 @@ export const getFOIS3DocumentRedlinePreSignedUrl = ( if (layertype === "oipcreview") { apiurl = apiurl + "/oipcreview" + } else if (layertype === "consult") { + apiurl = apiurl + "/consult" } else { apiurl = apiurl + "/" + layer } diff --git a/web/src/components/FOI/App.scss b/web/src/components/FOI/App.scss index f518f21da..11ebe19d8 100644 --- a/web/src/components/FOI/App.scss +++ b/web/src/components/FOI/App.scss @@ -221,6 +221,10 @@ li.modal-message-list-item { min-height: 350px !important; } +.consult-modal { + min-height: 500px !important; +} + .redline-checkmark { height:14px; width:14px; diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index 651cf6e8c..841093e3d 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -9,6 +9,7 @@ import DialogContentText from "@mui/material/DialogContentText"; import DialogTitle from "@mui/material/DialogTitle"; import CloseIcon from "@mui/icons-material/Close"; import IconButton from "@mui/material/IconButton"; +import Grid from '@mui/material/Grid'; //import type { ReactModalProps } from './types'; @@ -22,7 +23,12 @@ export const ConfirmationModal= ({ handleIncludeDuplicantePages, isDisableNRDuplicate, saveDoc, - modalData + modalData, + documentPublicBodies, + handleSelectedPublicBodies, + selectedPublicBodyIDs, + consultApplyRedactions, + handleApplyRedactions }) => { return ( @@ -31,7 +37,7 @@ export const ConfirmationModal= ({ initHeight={300} minWidth={600} minHeight={250} - className={"state-change-dialog" + (modalData?.modalFor == "redline"?" redline-modal":"")} + className={"state-change-dialog" + (modalData?.modalFor === "redline" ? " redline-modal" : modalData?.modalFor === "consult" ? " consult-modal" : "")} onRequestClose={cancelRedaction} isOpen={redlineModalOpen} > @@ -72,6 +78,61 @@ export const ConfirmationModal= ({ /> } + {modalData.modalFor === "consult" && + <> + + {documentPublicBodies?.map((publicBody) => { + return (<> + + + + + ) + })} + +
+

More Options:

+ + +
+ + +
+ + + } diff --git a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js index e1d6feff3..f77d9b71a 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js @@ -59,6 +59,21 @@ export const createFinalPackageSelection = (document, enableSave) => { return finalPackageBtn; }; +export const createConsultPackageSelection = (document, enableSave) => { + const consultPackageButton = document.createElement("button"); + consultPackageButton.textContent = "Consult Public Body"; + consultPackageButton.id = "consult_package"; + consultPackageButton.className = "consult_package"; + consultPackageButton.style.backgroundColor = "transparent"; + consultPackageButton.style.border = "none"; + consultPackageButton.style.padding = "8px 8px 8px 10px"; + consultPackageButton.style.cursor = "pointer"; + consultPackageButton.style.alignItems = "left"; + consultPackageButton.disabled = !enableSave; + + return consultPackageButton; +} + export const renderCustomButton = (document, menu) => { const menuBtn = document.createElement("button"); menuBtn.textContent = "Create Response PDF"; @@ -155,6 +170,30 @@ export const handleFinalPackageClick = ( setRedlineModalOpen(true); }; +export const handleConsultPackageClick = ( + updateModalData, + setRedlineModalOpen, + setIncludeDuplicatePages, + setIncludeNRPages +) => { + updateModalData({ + modalFor: "consult", + modalTitle: "Consult Public Body", + modalMessage: [ + "Are you sure you want to create a consult package? A PDF will be created for each public body selected, and your web browser will automatically refresh after package creation.", +
, +
, + + Select one or more public bodies you wish to create a consult package for: + , + ], + modalButtonLabel: "Create Consult" + }); + setIncludeDuplicatePages(true); + setIncludeNRPages(true); + setRedlineModalOpen(true); +} + export const isReadyForSignOff = (documentList, pageFlags) => { let pageFlagArray = []; let stopLoop = false; diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 8b81c5c90..1c5443ddf 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -34,6 +34,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const requestnumber = useAppSelector( (state) => state.documents?.requestnumber ); + const allPublicBodies = useAppSelector((state) => state.documents?.allPublicBodies); const toastId = React.useRef(null); const { foiministryrequestid } = useParams(); @@ -67,6 +68,11 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const [redlineCategory, setRedlineCategory] = useState(false); const [filteredComments, setFilteredComments] = useState({}); const [alreadyStitchedList, setAlreadyStitchedList] = useState([]); + const [enableSavingConsults, setEnableSavingConsults] = useState(false); + const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); + const [documentPublicBodies, setDocumentPublicBodies] = useState([]); + const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const requestInfo = useAppSelector((state) => state.documents?.requestinfo); const requestType = requestInfo?.requesttype ? requestInfo.requesttype : "public"; @@ -84,8 +90,26 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { else { for (let doc of divObj.documentlist) { for (const flagInfo of doc.pageFlag) { + if (modalFor == "consult") { + for (let consult of doc.consult) { + if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ( + ( + flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid !== pageFlagTypes["Not Responsive"]) || + ( + (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || + (includeNRPages && flagInfo.flagid === pageFlagTypes["Not Responsive"]) + ) + ) { + if(isvalid == false) { + isvalid = true; + } + } + } + } + } // Added condition to handle Duplicate/NR clicked for Redline for Sign off Modal - if ( + else if ( (flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid != pageFlagTypes["Not Responsive"]) || ( (includeDuplicatePages && flagInfo.flagid === pageFlagTypes["Duplicate"]) || @@ -153,21 +177,58 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { incompatibleFiles ) => { let newDocList = []; - for (let div of divisions) { - let divDocList = documentList?.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - // sort based on sortorder as the sortorder added based on the LastModified - divDocList = sortBySortOrder(divDocList); - let incompatableList = incompatibleFiles.filter((doc) => - doc.divisions.map((d) => d.divisionid).includes(div.divisionid) - ); - newDocList.push({ - divisionid: div.divisionid, - divisionname: div.name, - documentlist: divDocList, - incompatableList: incompatableList, - }); + if (modalFor == "redline" || modalFor == "oipcreview") { + for (let div of divisions) { + let divDocList = documentList?.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + + // sort based on sortorder as the sortorder added based on the LastModified + divDocList = sortBySortOrder(divDocList); + + let incompatableList = incompatibleFiles.filter((doc) => + doc.divisions.map((d) => d.divisionid).includes(div.divisionid) + ); + newDocList.push({ + divisionid: div.divisionid, + divisionname: div.name, + documentlist: divDocList, + incompatableList: incompatableList, + }); + } + } else if (modalFor == "consult") { + // map documents to publicBodies (Divisions) for consults + for (let publicBodyId of divisions) { + let publicBodyDocList = []; + documentList.forEach((doc) => { + let programareaids = new Set(); + if (doc.consult && doc.consult.length) { + doc.consult.forEach((consult) => { + consult.programareaid.forEach((programareaid) => { + if (programareaid === publicBodyId) { + programareaids.add(programareaid); + } + }) + }); + } + for (let programareaid of programareaids) { + if (programareaid === publicBodyId) { + publicBodyDocList.push({...doc}) + } + } + }) + publicBodyDocList = sortBySortOrder(publicBodyDocList); + + let incompatableList = []; + + const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId) + newDocList.push({ + divisionid: publicBodyId, + divisionname: publicBodyInfo.name, + documentlist: publicBodyDocList, + incompatableList: incompatableList, + }) + } } return newDocList; }; @@ -185,6 +246,8 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments), pageMappedDocs); + } else if (modalFor == "consult") { + prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); } @@ -414,11 +477,203 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); } + const prepareRedlinePageMappingByConsult = (divisionDocuments) => { + let removepages = {}; + let pageMappings = {}; + let divPageMappings = {}; + let pagesToRemove = []; + let totalPageCount = 0; + let totalPageCountIncludeRemoved = 0; + let duplicateWatermarkPages = {}; + let duplicateWatermarkPagesEachDiv = []; + let NRWatermarksPages = {}; + let NRWatermarksPagesEachDiv = []; + for (let divObj of divisionDocuments) { + // sort based on sortorder as the sortorder added based on the LastModified + for (let doc of sortBySortOrder(divObj.documentlist)) { + if (doc.pagecount > 0) { + let pagesToRemoveEachDoc = []; + pageMappings[doc.documentid] = {}; + let pageIndex = 1; + //gather pages that need to be removed + doc.pageFlag.sort((a, b) => a.page - b.page); //sort pageflag by page # + let skipDocumentPages = false; + let skipOnlyDuplicateDocument = false; + let skipOnlyNRDocument = false; + if (!includeDuplicatePages && !includeNRPages) { + skipDocumentPages = skipDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeDuplicatePages) { + skipOnlyDuplicateDocument = skipDuplicateDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + else if (!includeNRPages) { + skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); + } + + // for consults, go through all pages + for (const page of doc.pages) { + //find pageflags for this page + const pageFlagsOnPage = doc.pageFlag.filter((pageFlag) => { + return pageFlag.page === page; + }) + const notConsultPageFlagsOnPage = pageFlagsOnPage.filter((pageFlag) => { + return pageFlag.flagid !== pageFlagTypes["Consult"]; + }) + + // if the page has no pageflags, remove it + if (pageFlagsOnPage.length == 0) { + pagesToRemoveEachDoc.push(page); + if (!skipDocumentPages) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + pageIndex ++; + } + + //differences in pagemapping for consults begin here + //for pages with only consult flags, remove if page doesn't belong to current consult body + if (pageFlagsOnPage.length > 0 && notConsultPageFlagsOnPage.length == 0) { + for (let flagInfo of pageFlagsOnPage) { + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } else { + // add page as it will match the curent publicBody / division id + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } + pageIndex ++; + } + + // if the page does have pageflags, process it + for (let flagInfo of notConsultPageFlagsOnPage) { + if (flagInfo.flagid == pageFlagTypes["Duplicate"]) { + if(includeDuplicatePages) { + duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyDuplicateDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + + } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { + if(includeNRPages) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + pagesToRemoveEachDoc.push(flagInfo.page); + if (!skipDocumentPages && !skipOnlyNRDocument) { + pagesToRemove.push( + pageIndex + totalPageCountIncludeRemoved + ); + } + } + } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } else { + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } + + // Check if the page has relevant consult flag, if not remove the page + let hasConsult = false; + for (let consult of doc.consult) { + if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + hasConsult = true; + break; + } + } + if (!hasConsult) { + if (!pagesToRemoveEachDoc.includes(flagInfo.page)) { + pagesToRemoveEachDoc.push(flagInfo.page); + if(!skipDocumentPages) { + delete pageMappings[doc.documentid][flagInfo.page]; + pagesToRemove.push(pageIndex + totalPageCountIncludeRemoved) + } + } + } + if (flagInfo.flagid !== pageFlagTypes["Consult"]) { + pageIndex ++; + } + } + } + //End of pageMappingsByConsults + + totalPageCount += Object.keys( + pageMappings[doc.documentid] + ).length; + if (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument) { + totalPageCountIncludeRemoved += doc.pagecount; + } + } + } + divPageMappings[divObj.divisionid] = pageMappings; + removepages[divObj.divisionid] = pagesToRemove; + duplicateWatermarkPages[divObj.divisionid] = duplicateWatermarkPagesEachDiv; + NRWatermarksPages[divObj.divisionid] = NRWatermarksPagesEachDiv; + pagesToRemove = []; + duplicateWatermarkPagesEachDiv = []; + NRWatermarksPagesEachDiv = []; + totalPageCount = 0; + totalPageCountIncludeRemoved = 0; + pageMappings = {} + } + + setRedlinepageMappings({ + 'divpagemappings': divPageMappings, + 'pagemapping': pageMappings, + 'pagestoremove': removepages + }); + setRedlineWatermarkPageMapping({ + 'duplicatewatermark': duplicateWatermarkPages, + 'NRwatermark': NRWatermarksPages + }); + } const prepareRedlineIncompatibleMapping = (redlineAPIResponse) => { let divIncompatableMapping = {}; let incompatibleFiles = []; let divCounter = 0; + if (redlineAPIResponse.consultdocumentlist) { + redlineAPIResponse.divdocumentList = redlineAPIResponse.consultdocumentlist + } for (let divObj of redlineAPIResponse.divdocumentList) { divCounter++; @@ -443,6 +698,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); incompatibleFiles = incompatibleFiles.concat(divIncompatableFiles); } + if (divObj.publicBody && !divObj.divisionid) divObj.divisionid = divObj.publicBody; if (redlineAPIResponse.issingleredlinepackage == "Y") { if (divCounter == redlineAPIResponse.divdocumentList.length) { incompatableObj["divisionid"] = "0"; @@ -480,6 +736,9 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }; const getzipredlinecategory = (layertype) => { + if (modalFor == "consult") { + return "consultpackage"; + } if (currentLayer.name.toLowerCase() === "oipc") { return layertype === "oipcreview" ? "oipcreviewredline" : "oipcredline"; } @@ -738,6 +997,33 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); return sortedList; }; + const getPublicBodyList = (documentList) => { + let publicBodyIdList = []; + if (documentList?.length > 0) { + for (const doc of documentList) { + if ('pageFlag' in doc) { + for (let pageflag of doc['pageFlag']) { + if ('programareaid' in pageflag) { + for (let programareaid of pageflag['programareaid']) { + publicBodyIdList.push(programareaid) + } + } + } + } + } + const filteredPublicBodyIdList = [...new Set(publicBodyIdList)] + return getPublicBodyObjs(filteredPublicBodyIdList); + } + } + const getPublicBodyObjs = (publicBodyIDList) => { + const publicBodies = []; + for (const publicBody of allPublicBodies) { + if (publicBodyIDList.includes(publicBody.programareaid)) { + publicBodies.push(publicBody); + } + } + return publicBodies; + } const saveRedlineDocument = async ( @@ -755,7 +1041,13 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); const divisionFilesList = [...documentList, ...incompatibleFiles]; - const divisions = getDivisionsForSaveRedline(divisionFilesList); + let divisions; + if (modalFor == "consult") { + //Key consult logic, uses preexisting division reldine logic for consults + divisions = selectedPublicBodyIDs; + } else { + divisions = getDivisionsForSaveRedline(divisionFilesList); + } const divisionDocuments = getDivisionDocumentMappingForRedline(divisions, documentList, incompatibleFiles); const documentids = documentList.map((obj) => obj.documentid); getFOIS3DocumentRedlinePreSignedUrl( @@ -805,9 +1097,29 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { skipOnlyNRDocument = skipNRDocument(doc.pageFlag, doc.pagecount, pageFlagTypes); } if (pageMappedDocs != undefined) { - let divisionsdocpages = Object.values( - pageMappedDocs.redlineDocIdLookup - ) + let divisionsdocpages = []; + // for consults, no need to filter by division/consult + if (modalFor == "consult") { + Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .forEach((obj) => { + divisionsdocpages = Object.values( + pageMappedDocs.redlineDocIdLookup + ) + .filter((obj) => { + return obj.docId == doc.documentid; + }) + .map((obj) => { + if (res.issingleredlinepackage == "Y" || (!skipDocumentPages && !skipOnlyDuplicateDocument && !skipOnlyNRDocument)) { + return obj.pageMappings; + } + }); + }) + } else { + divisionsdocpages = Object.values( + pageMappedDocs.redlineDocIdLookup + ) .filter((obj) => { return obj.division.includes(div.divisionid) && obj.docId == doc.documentid; }) @@ -816,6 +1128,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { return obj.pageMappings; } }); + } if (divisionsdocpages[0]) { divisionsdocpages.forEach(function (_arr) { _arr.forEach(function (value) { @@ -918,7 +1231,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { ); }; - const checkSavingRedline = (redlineReadyAndValid, instance) => { const validRedlineStatus = [ RequestStates["Records Review"], @@ -932,7 +1244,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { !redlineReadyAndValid || !validRedlineStatus; } }; - const checkSavingOIPCRedline = ( oipcRedlineReadyAndValid, instance, @@ -953,6 +1264,13 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { !readyForSignOff; } }; + const checkSavingConsults = (documentList) => { + const publicBodyList = getPublicBodyList(documentList); + setDocumentPublicBodies(publicBodyList); + setEnableSavingConsults( + publicBodyList.length > 0 + ); + } const triggerRedlineZipper = ( divObj, stitchedDocPath, @@ -1335,10 +1653,13 @@ const stampPageNumberRedline = async ( .replace(/"/g, '"') .replace(/\\/g, ""); let sections = getAnnotationSections(annot); - if (sections.some((item) => item.section === "s. 14")) { + if (redlineCategory === "oipcreview" && sections.some((item) => item.section === "s. 14")) { sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; } + if (modalFor == "consult" && sections.some(item => item.section === 'NR')) { + sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; + } } } } @@ -1391,6 +1712,37 @@ const stampPageNumberRedline = async ( } } }; + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + let annotationManager = docInstance?.Core.annotationManager; + const rarr = []; + let rects = []; + for (const [key, value] of Object.entries(appliedSectionStamps)) { + let sectionAnnotation = annotationManager.getAnnotationById(key); + if (sectionAnnotation.Subject === "Redact") { + rects = rects.concat( + sectionAnnotation.getQuads().map((q) => { + return { + pageno: appliedSectionStamps[key], + recto: q.toRect(), + vpageno: sectionAnnotation.getPageNumber() + }; + }) + ); + } + } + for (const rect of rects) { + let height = docViewer.getPageHeight(rect.vpageno); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + } + if (rarr.length > 0) { + const app = {}; + app.redaction_overlay = true; + app.border = false; + app.show_redacted_content_regions = false; + const doc = await stitchObject.getPDFDoc(); + await PDFNet.Redactor.redact(doc, rarr, app); + } + } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1431,7 +1783,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview") { + if(redlineCategory !== "oipcreview" || modalFor == "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1471,38 +1823,8 @@ const stampPageNumberRedline = async ( //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { - const rarr = []; - let annotationManager = docInstance?.Core.annotationManager; let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - let rects = []; - for (const [key, value] of Object.entries(s14_sectionStamps)) { - let s14annoation = annotationManager.getAnnotationById(key); - if ( s14annoation.Subject === "Redact") { - rects = rects.concat( - s14annoation.getQuads().map((q) => { - return { - pageno: s14_sectionStamps[key], - recto: q.toRect(), - vpageno: s14annoation.getPageNumber() - }; - }) - ); - } - - - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); - } + await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); await stampPageNumberRedline( stitchObject, PDFNet, @@ -1510,7 +1832,17 @@ const stampPageNumberRedline = async ( isSingleRedlinePackage ); } - //OIPC - Special Block : End + //OIPC - Special Block : End + + //Consults - Redactions Block (Redact S.NR) : Start + if(modalFor == "consult") { + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } + } + //Consults - Redactions Block (Redact S.NR) : End + stitchObject .getFileData({ // saves the document with annotations in it @@ -1651,10 +1983,17 @@ const stampPageNumberRedline = async ( saveRedlineDocument, enableSavingOipcRedline, enableSavingRedline, + enableSavingConsults, checkSavingRedline, checkSavingOIPCRedline, + checkSavingConsults, setRedlineCategory, setFilteredComments, + setSelectedPublicBodyIDs, + setConsultApplyRedactions, + selectedPublicBodyIDs, + documentPublicBodies, + consultApplyRedactions, }; }; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8d9c010e6..8825547ed 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -52,10 +52,12 @@ import { createFinalPackageSelection, createOIPCForReviewSelection, createRedlineForSignOffSelection, - createResponsePDFMenu, + createResponsePDFMenu, + createConsultPackageSelection, handleFinalPackageClick, handleRedlineForOipcClick, handleRedlineForSignOffClick, + handleConsultPackageClick, renderCustomButton, isValidRedlineDownload, isReadyForSignOff } from "./CreateResponsePDF/CreateResponsePDF"; @@ -148,10 +150,17 @@ const Redlining = React.forwardRef( saveRedlineDocument, enableSavingOipcRedline, enableSavingRedline, + enableSavingConsults, checkSavingRedline, checkSavingOIPCRedline, + checkSavingConsults, setRedlineCategory, setFilteredComments, + setSelectedPublicBodyIDs, + setConsultApplyRedactions, + selectedPublicBodyIDs, + documentPublicBodies, + consultApplyRedactions } = useSaveRedlineForSignoff(docInstance, docViewer); const { saveResponsePackage, @@ -206,6 +215,7 @@ const Redlining = React.forwardRef( const redlineForSignOffBtn = createRedlineForSignOffSelection(document, enableSavingRedline); const redlineForOipcBtn = createOIPCForReviewSelection(document, enableSavingOipcRedline); const finalPackageBtn = createFinalPackageSelection(document, enableSavingFinal); + const consultPackageButton = createConsultPackageSelection(document, enableSavingConsults); redlineForOipcBtn.onclick = () => { handleRedlineForOipcClick(updateModalData, setRedlineModalOpen); }; @@ -215,9 +225,13 @@ const Redlining = React.forwardRef( finalPackageBtn.onclick = () => { handleFinalPackageClick(updateModalData, setRedlineModalOpen); }; + consultPackageButton.onClick = () => { + handleConsultPackageClick(updateModalData, setRedlineModalOpen, setIncludeDuplicatePages, setIncludeNRPages) + }; menu.appendChild(redlineForOipcBtn); menu.appendChild(redlineForSignOffBtn); menu.appendChild(finalPackageBtn); + menu.appendChild(consultPackageButton); parent.appendChild(menu); //Create render function to render custom Create Reseponse PDF button @@ -1320,6 +1334,7 @@ const Redlining = React.forwardRef( const validRedlineDownload = isValidRedlineDownload(pageFlags); const redlineReadyAndValid = readyForSignOff && validRedlineDownload; const oipcRedlineReadyAndValid = (validoipcreviewlayer === true && currentLayer.name.toLowerCase() === "oipc") && readyForSignOff; + checkSavingConsults(documentList); checkSavingRedline(redlineReadyAndValid, _instance); checkSavingOIPCRedline(oipcRedlineReadyAndValid, _instance, readyForSignOff); checkSavingFinalPackage(redlineReadyAndValid, _instance); @@ -2182,6 +2197,8 @@ const Redlining = React.forwardRef( const cancelSaveRedlineDoc = () => { disableNRDuplicate(); setRedlineModalOpen(false); + setSelectedPublicBodyIDs([]); + setConsultApplyRedactions(false); }; const handleIncludeNRPages = (e) => { @@ -2191,6 +2208,24 @@ const Redlining = React.forwardRef( const handleIncludeDuplicantePages = (e) => { setIncludeDuplicatePages(e.target.checked); }; + + const handleApplyRedactions = (e) => { + setConsultApplyRedactions(e.target.checked); + } + + const handleSelectedPublicBodies = (e) => { + const publicBodyId = parseInt(e.target.value); + if (selectedPublicBodyIDs.includes(publicBodyId)) { + setSelectedPublicBodyIDs((prev) => { + return [...prev.filter(id => id !== publicBodyId)] + }); + } + else { + setSelectedPublicBodyIDs((prev) => { + return [...prev, publicBodyId] + }); + } + } const saveDoc = () => { setRedlineModalOpen(false); @@ -2202,6 +2237,7 @@ const Redlining = React.forwardRef( switch (modalFor) { case "oipcreview": case "redline": + case "consult": saveRedlineDocument( docInstance, modalFor, @@ -2307,6 +2343,11 @@ const Redlining = React.forwardRef( isDisableNRDuplicate={isDisableNRDuplicate} saveDoc={saveDoc} modalData={modalData} + documentPublicBodies={documentPublicBodies} + handleSelectedPublicBodies={handleSelectedPublicBodies} + selectedPublicBodyIDs={selectedPublicBodyIDs} + consultApplyRedactions={consultApplyRedactions} + handleApplyRedactions={handleApplyRedactions} /> } {messageModalOpen && diff --git a/web/src/modules/documentReducer.ts b/web/src/modules/documentReducer.ts index 302df096f..be98b7a97 100644 --- a/web/src/modules/documentReducer.ts +++ b/web/src/modules/documentReducer.ts @@ -8,7 +8,8 @@ const initialState = { "description": "Redline", // "sortorder": 1, // "count": 0 - } + }, + allPublicBodies: [], } const documents = (state = initialState, action:any)=> { @@ -41,6 +42,8 @@ const documents = (state = initialState, action:any)=> { return {...state, redactionLayers: state.redactionLayers }; case ACTION_CONSTANTS.SET_DELETED_PAGES: return {...state, deletedDocPages: action.payload}; + case ACTION_CONSTANTS.SET_PUBLIC_BODIES: + return {...state, allPublicBodies: action.payload}; case ACTION_CONSTANTS.FOI_PERSONAL_SECTIONS: return { ...state, foiPersonalSections: action.payload }; case ACTION_CONSTANTS.FOI_PERSONAL_PEOPLE: From dbdbaaa8cb481a74c06e3277de21c7fd5a26a515 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 7 Aug 2024 17:18:45 -0700 Subject: [PATCH 21/89] Added consult code from PR 1036 for ticket 2646 to test-rook --- .../components/FOI/Home/ConfirmationModal.js | 17 +++++++-- web/src/components/FOI/Home/ConsultModal.tsx | 4 +-- .../useSaveRedlineForSignOff.js | 35 ++++++++++++++++--- web/src/components/FOI/Home/Redlining.js | 14 +++++++- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index 841093e3d..f25d82f68 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -28,7 +28,9 @@ export const ConfirmationModal= ({ handleSelectedPublicBodies, selectedPublicBodyIDs, consultApplyRedactions, - handleApplyRedactions + handleApplyRedactions, + consultApplyRedlines, + handleApplyRedlines }) => { return ( @@ -123,6 +125,16 @@ export const ConfirmationModal= ({ />
+ + +
- + } diff --git a/web/src/components/FOI/Home/ConsultModal.tsx b/web/src/components/FOI/Home/ConsultModal.tsx index 31da7b236..39ca4a0b9 100644 --- a/web/src/components/FOI/Home/ConsultModal.tsx +++ b/web/src/components/FOI/Home/ConsultModal.tsx @@ -100,7 +100,7 @@ const ConsultModal = ({ -
Select one or more Ministry you with the send the selected page(s) to for consult.
+
Select one or more public bodies you wish to consult with on the selected page(s).
{programAreaList.programareas?.map((programArea: any, index: number) => (
-
If you do not see the name of the Ministry you would like to send for consult above please type it below.
+
If you do not see the name of the public body you wish to consult with, please type it below.
{ const [selectedPublicBodyIDs, setSelectedPublicBodyIDs] = useState([]); const [documentPublicBodies, setDocumentPublicBodies] = useState([]); const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); + const [consultApplyRedlines, setConsultApplyRedlines] = useState(false); const requestInfo = useAppSelector((state) => state.documents?.requestinfo); @@ -89,8 +90,18 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else { for (let doc of divObj.documentlist) { + //page to pageFlag mappings logic for consults + const pagePageFlagMappings = {}; + for (let pageFlag of doc.pageFlag) { + if (pageFlag.page in pagePageFlagMappings) { + pagePageFlagMappings[pageFlag.page].push(pageFlag.flagid); + } else { + pagePageFlagMappings[pageFlag.page] = [pageFlag.flagid]; + } + } for (const flagInfo of doc.pageFlag) { if (modalFor == "consult") { + const pageFlagsOnPage = pagePageFlagMappings[flagInfo.page]; for (let consult of doc.consult) { if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { if ( @@ -101,8 +112,12 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { (includeNRPages && flagInfo.flagid === pageFlagTypes["Not Responsive"]) ) ) { - if(isvalid == false) { - isvalid = true; + if(isvalid === false) { + if ((!includeDuplicatePages && pageFlagsOnPage.some((flagId) => flagId === pageFlagTypes["Duplicate"])) || (!includeNRPages && pageFlagsOnPage.some((flagId) => flagId === pageFlagTypes["Not Responsive"]))) { + isvalid = false; + } else { + isvalid = true; + } } } } @@ -1834,14 +1849,22 @@ const stampPageNumberRedline = async ( } //OIPC - Special Block : End - //Consults - Redactions Block (Redact S.NR) : Start + //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(modalFor == "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); + } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); } } - //Consults - Redactions Block (Redact S.NR) : End + //Consults - Redlines + Redactions (Redact S.NR) Block : End stitchObject .getFileData({ @@ -1862,7 +1885,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, + render: `${modalFor == "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -1994,6 +2017,8 @@ const stampPageNumberRedline = async ( selectedPublicBodyIDs, documentPublicBodies, consultApplyRedactions, + setConsultApplyRedlines, + consultApplyRedlines, }; }; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8825547ed..b3f0b4a85 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -160,7 +160,9 @@ const Redlining = React.forwardRef( setConsultApplyRedactions, selectedPublicBodyIDs, documentPublicBodies, - consultApplyRedactions + consultApplyRedactions, + setConsultApplyRedlines, + consultApplyRedlines, } = useSaveRedlineForSignoff(docInstance, docViewer); const { saveResponsePackage, @@ -2199,6 +2201,7 @@ const Redlining = React.forwardRef( setRedlineModalOpen(false); setSelectedPublicBodyIDs([]); setConsultApplyRedactions(false); + setConsultApplyRedlines(false); }; const handleIncludeNRPages = (e) => { @@ -2213,6 +2216,13 @@ const Redlining = React.forwardRef( setConsultApplyRedactions(e.target.checked); } + const handleApplyRedlines = (e) => { + setConsultApplyRedlines(e.target.checked); + if (consultApplyRedactions) { + setConsultApplyRedactions(false); + } + } + const handleSelectedPublicBodies = (e) => { const publicBodyId = parseInt(e.target.value); if (selectedPublicBodyIDs.includes(publicBodyId)) { @@ -2348,6 +2358,8 @@ const Redlining = React.forwardRef( selectedPublicBodyIDs={selectedPublicBodyIDs} consultApplyRedactions={consultApplyRedactions} handleApplyRedactions={handleApplyRedactions} + handleApplyRedlines={handleApplyRedlines} + consultApplyRedlines={consultApplyRedlines} /> } {messageModalOpen && From 3b581eabb83162ffa82745de6b87fb75f363d80c Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Thu, 8 Aug 2024 14:45:46 -0700 Subject: [PATCH 22/89] Added small changes to confirmation modal in merge of test-rook/marshal --- web/src/components/FOI/Home/ConfirmationModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index f25d82f68..41b6c66d0 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -80,7 +80,7 @@ export const ConfirmationModal= ({ /> } - {modalData.modalFor === "consult" && + {modalData?.modalFor === "consult" && <> {documentPublicBodies?.map((publicBody) => { From 70729724e74e87d98c4646b085d9379c043544be Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 9 Aug 2024 13:17:34 -0700 Subject: [PATCH 23/89] completed manual addition of consults to test-rook. WIP merge to test-marshal --- .../useSaveRedlineForSignOff.js | 30 +++++++++++-------- web/src/components/FOI/Home/Redlining.js | 5 ++-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e7a00b248..5c40ed071 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -100,7 +100,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } } for (const flagInfo of doc.pageFlag) { - if (modalFor == "consult") { + if (redlineCategory === "consult") { const pageFlagsOnPage = pagePageFlagMappings[flagInfo.page]; for (let consult of doc.consult) { if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { @@ -192,7 +192,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { incompatibleFiles ) => { let newDocList = []; - if (modalFor == "redline" || modalFor == "oipcreview") { + if (redlineCategory === "redline" || redlineCategory === "oipcreview") { for (let div of divisions) { let divDocList = documentList?.filter((doc) => doc.divisions.map((d) => d.divisionid).includes(div.divisionid) @@ -211,7 +211,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { incompatableList: incompatableList, }); } - } else if (modalFor == "consult") { + } else if (redlineCategory === "consult") { // map documents to publicBodies (Divisions) for consults for (let publicBodyId of divisions) { let publicBodyDocList = []; @@ -261,7 +261,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } // sort based on sortorder as the sortorder added based on the LastModified prepareRedlinePageMappingByRequest(sortBySortOrder(reqdocuments), pageMappedDocs); - } else if (modalFor == "consult") { + } else if (redlineCategory === "consult") { prepareRedlinePageMappingByConsult(divisionDocuments); } else { prepareRedlinePageMappingByDivision(divisionDocuments); @@ -751,7 +751,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }; const getzipredlinecategory = (layertype) => { - if (modalFor == "consult") { + if (redlineCategory === "consult") { return "consultpackage"; } if (currentLayer.name.toLowerCase() === "oipc") { @@ -1057,7 +1057,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const divisionFilesList = [...documentList, ...incompatibleFiles]; let divisions; - if (modalFor == "consult") { + if (redlineCategory === "consult") { //Key consult logic, uses preexisting division reldine logic for consults divisions = selectedPublicBodyIDs; } else { @@ -1077,7 +1077,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); setIsSingleRedlinePackage(res.issingleredlinepackage); let stitchDoc = {}; - + prepareRedlinePageMapping( res['divdocumentList'], res.issingleredlinepackage, @@ -1114,7 +1114,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (pageMappedDocs != undefined) { let divisionsdocpages = []; // for consults, no need to filter by division/consult - if (modalFor == "consult") { + if (redlineCategory === "consult") { Object.values( pageMappedDocs.redlineDocIdLookup ) @@ -1279,12 +1279,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { !readyForSignOff; } }; - const checkSavingConsults = (documentList) => { + const checkSavingConsults = (documentList, instance) => { const publicBodyList = getPublicBodyList(documentList); setDocumentPublicBodies(publicBodyList); setEnableSavingConsults( publicBodyList.length > 0 ); + if (instance) { + const document = instance.UI.iframeWindow.document; + document.getElementById("consult_package").disabled = !(publicBodyList.length > 0); + } } const triggerRedlineZipper = ( divObj, @@ -1672,7 +1676,7 @@ const stampPageNumberRedline = async ( sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; } - if (modalFor == "consult" && sections.some(item => item.section === 'NR')) { + if (redlineCategory === "consult" && sections.some(item => item.section === 'NR')) { sectionStamps[parentRedactionId] = annotationpagenumbers[parentRedactionId]; } } @@ -1798,7 +1802,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || modalFor == "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1850,7 +1854,7 @@ const stampPageNumberRedline = async ( //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(modalFor == "consult") { + if(redlineCategory === "consult") { if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { @@ -1885,7 +1889,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `${modalFor == "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, + render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index b3f0b4a85..f2e6278b0 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -227,7 +227,7 @@ const Redlining = React.forwardRef( finalPackageBtn.onclick = () => { handleFinalPackageClick(updateModalData, setRedlineModalOpen); }; - consultPackageButton.onClick = () => { + consultPackageButton.onclick = () => { handleConsultPackageClick(updateModalData, setRedlineModalOpen, setIncludeDuplicatePages, setIncludeNRPages) }; menu.appendChild(redlineForOipcBtn); @@ -550,6 +550,7 @@ const Redlining = React.forwardRef( }, []); const updateModalData = (newModalData) => { + setRedlineCategory(newModalData.modalFor); setModalData(newModalData); }; @@ -1336,7 +1337,7 @@ const Redlining = React.forwardRef( const validRedlineDownload = isValidRedlineDownload(pageFlags); const redlineReadyAndValid = readyForSignOff && validRedlineDownload; const oipcRedlineReadyAndValid = (validoipcreviewlayer === true && currentLayer.name.toLowerCase() === "oipc") && readyForSignOff; - checkSavingConsults(documentList); + checkSavingConsults(documentList, _instance); checkSavingRedline(redlineReadyAndValid, _instance); checkSavingOIPCRedline(oipcRedlineReadyAndValid, _instance, readyForSignOff); checkSavingFinalPackage(redlineReadyAndValid, _instance); From 793160f72bffd31a2ab64235ef4ba2026972c548 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 10:52:37 -0700 Subject: [PATCH 24/89] fixed small bug relating to data.documentdivisions --- web/src/components/FOI/Home/Home.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index 5d394a647..c243be96c 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -71,7 +71,7 @@ function Home() { async (data) => { setOutstandingBalance(data.requestinfo.outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) - setDivisions(data.documentDivisions); + setDivisions(data.documentdivisions); const getFileExt = (filepath) => { const parts = filepath.split(".") const fileExt = parts.pop() From 5793726cc25421d7e3d65d73179550d735450895 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 13:52:16 -0700 Subject: [PATCH 25/89] refactored feeoverride modal to its own component --- .../components/FOI/Home/FeeOverrideModal.jsx | 94 +++++++++++++++++++ web/src/components/FOI/Home/Redlining.js | 79 +++------------- 2 files changed, 106 insertions(+), 67 deletions(-) create mode 100644 web/src/components/FOI/Home/FeeOverrideModal.jsx diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx new file mode 100644 index 000000000..db1341bbd --- /dev/null +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -0,0 +1,94 @@ +import ReactModal from "react-modal-resizable-draggable"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; +import DialogContentText from "@mui/material/DialogContentText"; +import DialogTitle from "@mui/material/DialogTitle"; +import CloseIcon from "@mui/icons-material/Close"; +import IconButton from "@mui/material/IconButton"; + +const FeeOverrideModal = ({ + modalData, + cancelRedaction, + outstandingBalanceModal, + cancelSaveRedlineDoc, + isOverride, + feeOverrideReason, + handleOverrideReasonChange, + saveDoc, + overrideOutstandingBalance, +}) => { + return ( + <> + + +

{modalData?.modalTitle}

+ + Close + + +
+ + + + {modalData?.modalMessage} + {isOverride && ( + <> +
+
+ + + + )} +
+
+
+ + {!isOverride && ( + + )} + {isOverride && ( + + )} + + +
+ + ); +}; + +export default FeeOverrideModal; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index a7530c4c6..e068d950d 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -66,14 +66,7 @@ import useSaveResponsePackage from "./CreateResponsePDF/useSaveResponsePackage"; import {ConfirmationModal} from "./ConfirmationModal"; import { FOIPPASectionsModal } from "./FOIPPASectionsModal"; import { NRWarningModal } from "./NRWarningModal"; - -import ReactModal from "react-modal-resizable-draggable"; -import DialogActions from "@mui/material/DialogActions"; -import DialogContent from "@mui/material/DialogContent"; -import DialogContentText from "@mui/material/DialogContentText"; -import DialogTitle from "@mui/material/DialogTitle"; -import CloseIcon from "@mui/icons-material/Close"; -import IconButton from "@mui/material/IconButton"; +import FeeOverrideModal from "./FeeOverrideModal"; const Redlining = React.forwardRef( ( @@ -101,8 +94,6 @@ const Redlining = React.forwardRef( (state) => state.documents?.requestnumber ); - const allPublicBodies = useAppSelector((state) => state.documents?.allPublicBodies) - document.title = requestnumber + " - FOI Document Reviewer" const redactionInfo = useSelector( @@ -2401,63 +2392,17 @@ const Redlining = React.forwardRef( modalData={modalData} /> } - - -

{modalData?.modalTitle}

- - Close - - -
- - - - {modalData?.modalMessage} - {isOverride && <> -

- - - } -
-
-
- - {!isOverride && - - } - {isOverride && - - } - - -
+
); } From 31a9060413d9f1eeb57653549d68eea140953267 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 14:12:20 -0700 Subject: [PATCH 26/89] Small code clean --- .../useSaveRedlineForSignOff.js | 1 - .../components/FOI/Home/FeeOverrideModal.jsx | 130 +++++++++--------- 2 files changed, 63 insertions(+), 68 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 5c40ed071..849cc59fd 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1091,7 +1091,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let documentsObjArr = []; let divisionstitchpages = []; let divCount = 0; - console.log("RES:",res) for (let div of res.divdocumentList) { divCount++; let docCount = 0; diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx index db1341bbd..a64862710 100644 --- a/web/src/components/FOI/Home/FeeOverrideModal.jsx +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -18,76 +18,72 @@ const FeeOverrideModal = ({ overrideOutstandingBalance, }) => { return ( - <> - - -

{modalData?.modalTitle}

- - Close - - -
- - - - {modalData?.modalMessage} - {isOverride && ( - <> -
-
- - - - )} -
-
-
- - {!isOverride && ( - - )} - {isOverride && ( - - )} + + +

{modalData?.modalTitle}

+ + Close + + +
+ + + + {modalData?.modalMessage} + {isOverride && ( + <> +
+
+ + + + )} +
+
+
+ + {!isOverride && ( + )} + {isOverride && ( + - -
- + )} + +
+
); }; From caf216dbcc48d995240380dd77b1f7a5e5f5944d Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 20 Aug 2024 15:03:55 -0700 Subject: [PATCH 27/89] bug fix involved with 10.1 release --- web/src/components/FOI/Home/utils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/src/components/FOI/Home/utils.js b/web/src/components/FOI/Home/utils.js index fe926edf5..ef736a94f 100644 --- a/web/src/components/FOI/Home/utils.js +++ b/web/src/components/FOI/Home/utils.js @@ -783,6 +783,9 @@ export const skipNRDocument = (documentPageFlags, pagecount, pageFlagTypes) => { export const findNROrDuplicatePageFlag = (pageFlags, docObj, pageFlagTypes) => { const docPageFlags = pageFlags.find(pageFlagObj => pageFlagObj.documentid === docObj.docid); + if (!docPageFlags) { + return false; + } for (let pageFlag of docPageFlags.pageflag) { if ((pageFlag.page === docObj.page && pageFlag.flagid === pageFlagTypes["Duplicate"]) || (pageFlag.page === docObj.page && pageFlag.flagid === pageFlagTypes["Not Responsive"])) { return pageFlag; From 16d2db1985a53ddedf5df98ce96e5aac325c6723 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Thu, 29 Aug 2024 16:35:59 -0700 Subject: [PATCH 28/89] QA observation / bug fixes 2 and 3 fixed. WIP 1,4,5 observations --- api/reviewer_api/resources/foiflowmasterdata.py | 2 +- web/src/components/FOI/Home/ConfirmationModal.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/reviewer_api/resources/foiflowmasterdata.py b/api/reviewer_api/resources/foiflowmasterdata.py index 7fe29a3ac..1d50eb851 100644 --- a/api/reviewer_api/resources/foiflowmasterdata.py +++ b/api/reviewer_api/resources/foiflowmasterdata.py @@ -219,7 +219,7 @@ def post(ministryrequestid, redactionlayer="redline", layertype="redline"): ) if packagetype == "consult": filepath_put = "{0}/{2}/{2} - {1} - {0}.pdf".format( - filepathlist[0], division_name, packagetype + filepathlist[0], division_name, 'Consult' ) s3path_save = s3client.generate_presigned_url( ClientMethod="get_object", diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index 41b6c66d0..add1e746b 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -91,12 +91,12 @@ export const ConfirmationModal= ({ type="checkbox" style={{ marginRight: 10 }} className="redline-checkmark" - id={`${publicBody.bcgovcode}-checkbox`} + id={`${publicBody.iaocode}-checkbox`} value={publicBody.programareaid} checked={selectedPublicBodyIDs.includes(publicBody.programareaid)} onClick={handleSelectedPublicBodies} /> - + ) })} From 16666949a0a2df2ab3592a49a384b78e24204c6b Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 3 Sep 2024 13:55:02 -0700 Subject: [PATCH 29/89] Obervation 5 issue from QA solved. Custom public body packages can now be created --- .../components/FOI/Home/ConfirmationModal.js | 6 +-- .../useSaveRedlineForSignOff.js | 51 +++++++++++++++---- web/src/components/FOI/Home/Redlining.js | 2 +- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index add1e746b..ab49df08a 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -87,13 +87,13 @@ export const ConfirmationModal= ({ return (<> diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 849cc59fd..e604e39da 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -103,7 +103,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (redlineCategory === "consult") { const pageFlagsOnPage = pagePageFlagMappings[flagInfo.page]; for (let consult of doc.consult) { - if (consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { if ( ( flagInfo.flagid !== pageFlagTypes["Duplicate"] && flagInfo.flagid !== pageFlagTypes["Not Responsive"]) || @@ -212,7 +212,9 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); } } else if (redlineCategory === "consult") { - // map documents to publicBodies (Divisions) for consults + // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. + // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package + console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -225,6 +227,13 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) }); + for (let consult of doc.consult) { + for (let customPublicBody of consult.other) { + if (customPublicBody === publicBodyId) { + programareaids.add(customPublicBody); + } + } + } } for (let programareaid of programareaids) { if (programareaid === publicBodyId) { @@ -233,18 +242,22 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); + console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; - const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId) + // Custom public bodies/consults do not exist in allPublicBodies data (BE program area data) and are stored as simple strings with pageflag data (in other array attribute). + // Therefore, if publicBodyInfo cannot be found in allPublicBodies, the publicbody is a custom one and we will create its 'divison' data in the FE with a random unique id (date.now()), and its publicBodyID (which is its name as a string) for consult package creation purposes + const publicBodyInfo = allPublicBodies.find((body) => body.programareaid === publicBodyId); newDocList.push({ - divisionid: publicBodyId, - divisionname: publicBodyInfo.name, + divisionid: publicBodyInfo ? publicBodyInfo.programareaid : Date.now(), + divisionname: publicBodyInfo ? publicBodyInfo.name : publicBodyId, documentlist: publicBodyDocList, incompatableList: incompatableList, }) } } + console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -552,7 +565,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { for (let flagInfo of pageFlagsOnPage) { let hasConsult = false; for (let consult of doc.consult) { - if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { hasConsult = true; break; } @@ -630,7 +643,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { // Check if the page has relevant consult flag, if not remove the page let hasConsult = false; for (let consult of doc.consult) { - if (consult.page == flagInfo.page && consult.programareaid.includes(divObj.divisionid)) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { hasConsult = true; break; } @@ -1020,23 +1033,39 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { for (let pageflag of doc['pageFlag']) { if ('programareaid' in pageflag) { for (let programareaid of pageflag['programareaid']) { - publicBodyIdList.push(programareaid) + publicBodyIdList.push(programareaid); + } + } + // Logic to include custom consults/public bodies as they are stored in another array (other) and not with programareaids + if ('other' in pageflag) { + for (let customPublicBody of pageflag['other']) { + publicBodyIdList.push(customPublicBody); } } } } } - const filteredPublicBodyIdList = [...new Set(publicBodyIdList)] + const filteredPublicBodyIdList = [...new Set(publicBodyIdList)]; return getPublicBodyObjs(filteredPublicBodyIdList); } } const getPublicBodyObjs = (publicBodyIDList) => { const publicBodies = []; - for (const publicBody of allPublicBodies) { - if (publicBodyIDList.includes(publicBody.programareaid)) { + for (let publicBodyId of publicBodyIDList) { + const publicBody = allPublicBodies.find(publicBody => publicBody.programareaid === publicBodyId); + if (publicBody) { publicBodies.push(publicBody); + } else { + // Custom public bodies/consults will not exist in allPublicBodies data (BE data for program areas) as they are not stored in the BE as programe areas (but rather as basic pageflags) + const customPublicBody = { + name: publicBodyId, + programareaid: null, + iaocode: publicBodyId + }; + publicBodies.push(customPublicBody); } } + console.log("pubbodies", publicBodies) return publicBodies; } diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8d95c53fe..c31d2c62b 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -2241,7 +2241,7 @@ const Redlining = React.forwardRef( } const handleSelectedPublicBodies = (e) => { - const publicBodyId = parseInt(e.target.value); + let publicBodyId = !isNaN(parseInt(e.target.value)) ? parseInt(e.target.value) : e.target.value; if (selectedPublicBodyIDs.includes(publicBodyId)) { setSelectedPublicBodyIDs((prev) => { return [...prev.filter(id => id !== publicBodyId)] From 8afeec865a9393b28eb75d001320d59beb51c907 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 3 Sep 2024 16:33:18 -0700 Subject: [PATCH 30/89] FOIMOD-3073- Fees - Remaining Balance Check- Merge issues solved Test marshal - Feature not working due to Merge issues : resolved --- api/reviewer_api/schemas/finalpackage.py | 1 + .../CreateResponsePDF/CreateResponsePDF.js | 76 ++++++++++++------- .../useSaveResponsePackage.js | 5 +- web/src/components/FOI/Home/Redlining.js | 12 ++- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/api/reviewer_api/schemas/finalpackage.py b/api/reviewer_api/schemas/finalpackage.py index 3f8b3be0b..a4500e585 100644 --- a/api/reviewer_api/schemas/finalpackage.py +++ b/api/reviewer_api/schemas/finalpackage.py @@ -57,3 +57,4 @@ class MCFFinalPackageSchema(Schema): ) summarydocuments = fields.Nested(MCFSummarySchema, allow_none=True) redactionlayerid = fields.Int(data_key="redactionlayerid", allow_none=False) + pdfstitchjobattributes = fields.Nested(FeeOverrideSchema, allow_none=True, many=False) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js index f77d9b71a..5bbfa33e0 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js @@ -139,35 +139,55 @@ export const handleRedlineForOipcClick = ( export const handleFinalPackageClick = ( updateModalData, - setRedlineModalOpen + setRedlineModalOpen, + outstandingBalance, + isBalanceFeeOverrode, + setOutstandingBalanceModal, + setIsOverride ) => { - updateModalData({ - modalFor: "responsepackage", - modalTitle: "Create Package for Applicant", - modalMessage: [ - "This should only be done when all redactions are finalized and ready to ", - - be - , - " sent to the ", - - Applicant - , - ". This will ", - - permanently - , - " apply the redactions and automatically create page stamps.", -
, -
, - - When you create the response package, your web browser page - will automatically refresh - , - ], - modalButtonLabel: "Create Applicant Package" - }); - setRedlineModalOpen(true); + + if(outstandingBalance > 0 && !isBalanceFeeOverrode){ + updateModalData({ + modalFor: "responsepackage", + modalTitle: "Create Package for Applicant", + modalMessage:[ + "There is an outstanding balance of fees, please cancel to resolve, or click override to proceed", + ], + modalButtonLabel: "Override" + }); + setOutstandingBalanceModal(true); + setIsOverride(false) + } + else{ + // Download + updateModalData({ + modalFor: "responsepackage", + modalTitle: "Create Package for Applicant", + modalMessage: [ + "This should only be done when all redactions are finalized and ready to ", + + be + , + " sent to the ", + + Applicant + , + ". This will ", + + permanently + , + " apply the redactions and automatically create page stamps.", +
, +
, + + When you create the response package, your web browser page + will automatically refresh + , + ], + modalButtonLabel: "Create Applicant Package" + }); + setRedlineModalOpen(true); + } }; export const handleConsultPackageClick = ( diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js index 3a2a6a4c4..6b003abe3 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js @@ -212,7 +212,8 @@ const useSaveResponsePackage = () => { _instance, documentList, pageMappedDocs, - pageFlags + pageFlags, + feeOverrideReason ) => { const downloadType = "pdf"; let zipServiceMessage = { @@ -223,6 +224,7 @@ const useSaveResponsePackage = () => { bcgovcode: "", summarydocuments: {} , redactionlayerid: currentLayer.redactionlayerid, + pdfstitchjobattributes:{"feeoverridereason":""} }; getResponsePackagePreSignedUrl( foiministryrequestid, @@ -232,6 +234,7 @@ const useSaveResponsePackage = () => { zipServiceMessage.requestnumber = res.requestnumber; zipServiceMessage.bcgovcode = res.bcgovcode; zipServiceMessage.summarydocuments= prepareresponseredlinesummarylist(documentList,zipServiceMessage.bcgovcode) + zipServiceMessage.pdfstitchjobattributes= {"feeoverridereason":feeOverrideReason} let annotList = annotationManager.getAnnotationsList(); annotationManager.ungroupAnnotations(annotList); /** remove duplicate and not responsive pages */ diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 8d95c53fe..ea2c110e8 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -233,7 +233,8 @@ const Redlining = React.forwardRef( handleRedlineForSignOffClick(updateModalData, setRedlineModalOpen); }; finalPackageBtn.onclick = () => { - handleFinalPackageClick(updateModalData, setRedlineModalOpen); + handleFinalPackageClick(updateModalData, setRedlineModalOpen, outstandingBalance, + isBalanceFeeOverrode,setOutstandingBalanceModal,setIsOverride); }; consultPackageButton.onclick = () => { handleConsultPackageClick(updateModalData, setRedlineModalOpen, setIncludeDuplicatePages, setIncludeNRPages) @@ -2219,6 +2220,12 @@ const Redlining = React.forwardRef( setSelectedPublicBodyIDs([]); setConsultApplyRedactions(false); setConsultApplyRedlines(false); + if(outstandingBalance > 0 && !isBalanceFeeOverrode){ + setOutstandingBalanceModal(false) + setIsOverride(false) + } + else + setRedlineModalOpen(false); }; const handleIncludeNRPages = (e) => { @@ -2283,7 +2290,8 @@ const Redlining = React.forwardRef( docInstance, documentList, pageMappedDocs, - pageFlags + pageFlags, + feeOverrideReason ); break; default: From c4f39764805fcbadf47e3ab8d69a46a328ccf4db Mon Sep 17 00:00:00 2001 From: Abin Antony Date: Wed, 4 Sep 2024 17:25:05 -0700 Subject: [PATCH 31/89] #FOIMOD-3439 TEst build to test-marshal for removing sensitive content --- .../ZippingServices/requirements.txt | Bin 760 -> 790 bytes .../ZippingServices/services/zipperservice.py | 29 ++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/computingservices/ZippingServices/requirements.txt b/computingservices/ZippingServices/requirements.txt index 6e93668753e3922077ce2411f35c45e150eb823a..a08f010df70dbc95af321746348195b932952cee 100644 GIT binary patch delta 38 pcmeytI*o0^4< Date: Mon, 9 Sep 2024 13:22:48 -0700 Subject: [PATCH 32/89] Adjusted redline creation process to fix bug where redactions were showing for NR consults when page rotated. Redline creation process for stitch and upload is now 1. apply redlines 2. remove pages 3. apply redactions (if any) 4. apply rotations 5. apply stamping 5. apply watermark. Previously it was 1. apply rotations, 2. apply reldines, 3. stamp pages 4. remove pages 5. apply watermakr 6. apply redactions --- .../useSaveRedlineForSignOff.js | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e604e39da..b3fb36f9d 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -214,7 +214,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (redlineCategory === "consult") { // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package - console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -242,7 +241,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); - console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; @@ -257,7 +255,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }) } } - console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -813,6 +810,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; + setTotalStitchList(stitchlist) for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -849,7 +847,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - applyRotations(docObj, doc.attributes.rotatedpages) + // applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1065,7 +1063,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { publicBodies.push(customPublicBody); } } - console.log("pubbodies", publicBodies) return publicBodies; } @@ -1349,7 +1346,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { includenrpages: includeNRPages, }; if (stitchedDocPath) { - console.log("stitchedDocPath:",stitchedDocPath) const stitchedDocPathArray = stitchedDocPath?.split("/"); let fileName = stitchedDocPathArray[stitchedDocPathArray.length - 1].split("?")[0]; @@ -1830,14 +1826,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } if ( redlinepageMappings["pagestoremove"][divisionid] && redlinepageMappings["pagestoremove"][divisionid].length > 0 && @@ -1847,14 +1835,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline") { - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } - let string = await stitchObject.extractXFDF() let xmlObj = parser.parseFromString(string.xfdfString); @@ -1897,6 +1877,32 @@ const stampPageNumberRedline = async ( } } //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages + for (const [key, value] of Object.entries(totalStitchList)) { + let documentlist = totalStitchList[key]; + if(documentlist.length > 0) { + for (let doc of documentlist) { + applyRotations(stitchObject, doc.attributes.rotatedpages) + } + } + } + // Stamp and apply watermark + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } + if (redlineCategory === "redline" || redlineCategory === "consult") { + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } stitchObject .getFileData({ @@ -1955,9 +1961,16 @@ const stampPageNumberRedline = async ( } } }; + + const applyRotations = (document, rotatedpages) => { + for (let page in rotatedpages) { + let existingrotation = document.getPageRotation(page); + let rotation = (rotatedpages[page] - existingrotation + 360) / 90; + document.rotatePages([page], rotation); + } + } useEffect(() => { - if ( redlineStitchObject && redlineDocumentAnnotations && From afe3817d40a6d15a7d074b2553cf45210366bf8d Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 10 Sep 2024 17:17:14 -0700 Subject: [PATCH 33/89] page rotation logic in redline adjusted / moved to end of redline creation (originally it was done before) to allow for redaactions to be applied (if any) before rotations. WIP code clean --- .../useSaveRedlineForSignOff.js | 172 +++++++++++------- 1 file changed, 111 insertions(+), 61 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index b3fb36f9d..44a0e61f8 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -214,6 +214,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (redlineCategory === "consult") { // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package + console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -241,6 +242,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); + console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; @@ -255,6 +257,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }) } } + console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -817,6 +820,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { // added this vopy variable for validating the first document of a division with NR/Duplicate let docCountCopy = 0; let division = key; + console.log("stitchlist", stitchlist) let documentlist = stitchlist[key]; if (redlineSinglePkg == "N") { toast.update(toastId.current, { @@ -1063,6 +1067,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { publicBodies.push(customPublicBody); } } + console.log("pubbodies", publicBodies) return publicBodies; } @@ -1369,7 +1374,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - window.location.reload(); + // window.location.reload(); }); } return zipServiceMessage; @@ -1775,6 +1780,30 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); + let x1 = rect.recto.x1 + let y1 = rect.recto.y1 + let x2 = rect.recto.x2 + let y2 = rect.recto.y2 + console.log("coords", x1,y1,x2,y2) + // const sectionAnnotation = rect.sectionAnnotation; + // // let quad = sectionAnnotation.getQuads()[0]; + // // let rect = new docInstance.Core.Math.Rect(quad.x1, quad.y3, quad.x2, quad.y2); + // const doc = docViewer.getDocument(); + // // const pageInfo = doc.getPageInfo(sectionAnnotation.PageNumber); + // // const pageMatrix = doc.getPageMatrix(sectionAnnotation.PageNumber); + // const pageRotation = doc.getPageRotation(sectionAnnotation.PageNumber); + // // _annot.FontSize = Math.min(parseInt(_redaction.FontSize), 9) + "pt"; + // sectionAnnotation.Rotation = 0; // reset rotation before resizing + // // _annot.fitText(pageInfo, pageMatrix, pageRotation); + // let annotrect = sectionAnnotation.getRect(); + // annotrect.x2 = Math.ceil(annotrect.x2); + // sectionAnnotation.setRect(annotrect); + // if (pageRotation === 180) { + // x1 = x2 - sectionAnnotation.Width + // y1 = y2 - sectionAnnotation.Height + // rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(x1,height-y1,x2,height-y2)), false, '')); + // sectionAnnotation.Rotation = pageRotation; + // } else { rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); } if (rarr.length > 0) { @@ -1796,6 +1825,7 @@ const stampPageNumberRedline = async ( }, [initDocViewer]); const StitchAndUploadDocument = async () => { + console.log("STITCH AND UPLOAD YE") const { PDFNet } = docInstance.Core; const downloadType = "pdf"; let currentDivisionCount = 0; @@ -1810,8 +1840,8 @@ const stampPageNumberRedline = async ( isLoading: true, autoClose: 5000, }); - let divisionid = key; + console.log("redlinepageMappings", redlinepageMappings) let stitchObject = redlineStitchObject[key]; if (stitchObject == null) { triggerRedlineZipper( @@ -1826,6 +1856,14 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } if ( redlinepageMappings["pagestoremove"][divisionid] && redlinepageMappings["pagestoremove"][divisionid].length > 0 && @@ -1835,6 +1873,14 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } + if (redlineCategory === "redline") { // WATER MARK CONSULTS? + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } + let string = await stitchObject.extractXFDF() let xmlObj = parser.parseFromString(string.xfdfString); @@ -1844,65 +1890,50 @@ const stampPageNumberRedline = async ( annotsObj[0].children = annotsObj[0].children.concat(annots.children) } else { xmlObj.children.push(annots) - } - + } let xfdfString = parser.toString(xmlObj); - - //OIPC - Special Block (Redact S.14) : Begin - if(redlineCategory === "oipcreview") { - let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - //OIPC - Special Block : End - - //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { - if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; - const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { - return annot.name !== "freetext" && annot.name !== 'redact' - }); - xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString = parser.toString(xmlObj); + + //Apply Redactions (if any) + //OIPC - Special Block (Redact S.14) : Begin + if(redlineCategory === "oipcreview") { + let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); } - if (consultApplyRedactions) { - let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + //OIPC - Special Block : End + + //Consults - Redlines + Redactions (Redact S.NR) Block : Start + if(redlineCategory === "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); + } + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } } - } - //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - for (const [key, value] of Object.entries(totalStitchList)) { - let documentlist = totalStitchList[key]; - if(documentlist.length > 0) { - for (let doc of documentlist) { - applyRotations(stitchObject, doc.attributes.rotatedpages) + //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages + console.log("totalStithclist", totalStitchList) + for (const doc of totalStitchList[divisionid]) { + let documentlist = totalStitchList[divisionid]; + let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + if(documentlist.length > 0) { + console.log("doc2", doc) + applyRotations(stitchObject, doc, divDocPageMappings); } } - } - // Stamp and apply watermark - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - if (redlineCategory === "redline" || redlineCategory === "consult") { - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } stitchObject .getFileData({ @@ -1962,11 +1993,30 @@ const stampPageNumberRedline = async ( } }; - const applyRotations = (document, rotatedpages) => { - for (let page in rotatedpages) { - let existingrotation = document.getPageRotation(page); - let rotation = (rotatedpages[page] - existingrotation + 360) / 90; - document.rotatePages([page], rotation); + const applyRotations = (document, doc, divDocPageMappings) => { + const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} + const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} + const rotatedStitchedPages = {}; + console.log("NEW LINE") + console.log("docPageMappings", docPageMappings) + console.log("rotatedObj", rotatedpages) + if (rotatedpages) { + for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { + let rotation = rotatedpages[originalPage]; + console.log("BANG", stitchedPage, rotation) + if (rotation) { + rotatedStitchedPages[stitchedPage] = rotation; + } + } + console.log("NEW", rotatedStitchedPages) + for (let page in rotatedStitchedPages) { + let existingrotation = document.getPageRotation(page); + console.log("page", page, existingrotation) + console.log('rootatedpages', rotatedStitchedPages[page] ) + let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; + console.log("rotation", rotation) + document.rotatePages([page], rotation); + } } } From 3515db02886d6068eb3c6df8e10e6b65c959252a Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 11 Sep 2024 14:09:17 -0700 Subject: [PATCH 34/89] Moved redaction and apply rotation to pages after redline formatting in redline creation. New order for stith and upload for redlines is: 1. format redlines 2. apply redactions 3. rotate pages 4. stamp pages 5. remove pages 6. add watermarks --- .../useSaveRedlineForSignOff.js | 102 ++++++------------ 1 file changed, 31 insertions(+), 71 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 44a0e61f8..5abb51700 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -214,7 +214,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (redlineCategory === "consult") { // map documents to publicBodies and custom public bodies (treated as Divisions) for consults package. // Consult Package logic will treat publicbodies (program areas + custom consults) as DIVISIONS and will incorporate the existing division mapping + redline logic to generate the consult package - console.log("DIV", divisions) for (let publicBodyId of divisions) { let publicBodyDocList = []; documentList.forEach((doc) => { @@ -242,7 +241,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }) publicBodyDocList = sortBySortOrder(publicBodyDocList); - console.log("sorteddoclist",publicBodyDocList ) let incompatableList = []; @@ -257,7 +255,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }) } } - console.log("newdoclist", newDocList) return newDocList; }; const prepareRedlinePageMapping = ( @@ -820,7 +817,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { // added this vopy variable for validating the first document of a division with NR/Duplicate let docCountCopy = 0; let division = key; - console.log("stitchlist", stitchlist) let documentlist = stitchlist[key]; if (redlineSinglePkg == "N") { toast.update(toastId.current, { @@ -1067,7 +1063,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { publicBodies.push(customPublicBody); } } - console.log("pubbodies", publicBodies) return publicBodies; } @@ -1374,7 +1369,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - // window.location.reload(); + window.location.reload(); }); } return zipServiceMessage; @@ -1780,30 +1775,6 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - let x1 = rect.recto.x1 - let y1 = rect.recto.y1 - let x2 = rect.recto.x2 - let y2 = rect.recto.y2 - console.log("coords", x1,y1,x2,y2) - // const sectionAnnotation = rect.sectionAnnotation; - // // let quad = sectionAnnotation.getQuads()[0]; - // // let rect = new docInstance.Core.Math.Rect(quad.x1, quad.y3, quad.x2, quad.y2); - // const doc = docViewer.getDocument(); - // // const pageInfo = doc.getPageInfo(sectionAnnotation.PageNumber); - // // const pageMatrix = doc.getPageMatrix(sectionAnnotation.PageNumber); - // const pageRotation = doc.getPageRotation(sectionAnnotation.PageNumber); - // // _annot.FontSize = Math.min(parseInt(_redaction.FontSize), 9) + "pt"; - // sectionAnnotation.Rotation = 0; // reset rotation before resizing - // // _annot.fitText(pageInfo, pageMatrix, pageRotation); - // let annotrect = sectionAnnotation.getRect(); - // annotrect.x2 = Math.ceil(annotrect.x2); - // sectionAnnotation.setRect(annotrect); - // if (pageRotation === 180) { - // x1 = x2 - sectionAnnotation.Width - // y1 = y2 - sectionAnnotation.Height - // rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(x1,height-y1,x2,height-y2)), false, '')); - // sectionAnnotation.Rotation = pageRotation; - // } else { rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); } if (rarr.length > 0) { @@ -1825,7 +1796,6 @@ const stampPageNumberRedline = async ( }, [initDocViewer]); const StitchAndUploadDocument = async () => { - console.log("STITCH AND UPLOAD YE") const { PDFNet } = docInstance.Core; const downloadType = "pdf"; let currentDivisionCount = 0; @@ -1841,7 +1811,6 @@ const stampPageNumberRedline = async ( autoClose: 5000, }); let divisionid = key; - console.log("redlinepageMappings", redlinepageMappings) let stitchObject = redlineStitchObject[key]; if (stitchObject == null) { triggerRedlineZipper( @@ -1856,41 +1825,18 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - if ( - redlinepageMappings["pagestoremove"][divisionid] && - redlinepageMappings["pagestoremove"][divisionid].length > 0 && - stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length - ) { - await stitchObject.removePages( - redlinepageMappings["pagestoremove"][divisionid] - ); - } - if (redlineCategory === "redline") { // WATER MARK CONSULTS? - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } - let string = await stitchObject.extractXFDF() + let string = await stitchObject.extractXFDF(); let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); - let annotsObj = xmlObj.getElementsByTagName('annots') + let annotsObj = xmlObj.getElementsByTagName('annots'); if (annotsObj.length > 0) { - annotsObj[0].children = annotsObj[0].children.concat(annots.children) + annotsObj[0].children = annotsObj[0].children.concat(annots.children); } else { - xmlObj.children.push(annots) + xmlObj.children.push(annots); } + let xfdfString = parser.toString(xmlObj); //Apply Redactions (if any) @@ -1906,7 +1852,6 @@ const stampPageNumberRedline = async ( ); } //OIPC - Special Block : End - //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(redlineCategory === "consult") { if (!consultApplyRedlines) { @@ -1925,16 +1870,39 @@ const stampPageNumberRedline = async ( //Consults - Redlines + Redactions (Redact S.NR) Block : End // Rotate pages - console.log("totalStithclist", totalStitchList) for (const doc of totalStitchList[divisionid]) { let documentlist = totalStitchList[divisionid]; let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; if(documentlist.length > 0) { - console.log("doc2", doc) applyRotations(stitchObject, doc, divDocPageMappings); } } + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } + if ( + redlinepageMappings["pagestoremove"][divisionid] && + redlinepageMappings["pagestoremove"][divisionid].length > 0 && + stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length + ) { + await stitchObject.removePages( + redlinepageMappings["pagestoremove"][divisionid] + ); + } + if (redlineCategory === "redline" || redlineCategory === "consult") { + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } + stitchObject .getFileData({ // saves the document with annotations in it @@ -1997,24 +1965,16 @@ const stampPageNumberRedline = async ( const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} const rotatedStitchedPages = {}; - console.log("NEW LINE") - console.log("docPageMappings", docPageMappings) - console.log("rotatedObj", rotatedpages) if (rotatedpages) { for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { let rotation = rotatedpages[originalPage]; - console.log("BANG", stitchedPage, rotation) if (rotation) { rotatedStitchedPages[stitchedPage] = rotation; } } - console.log("NEW", rotatedStitchedPages) for (let page in rotatedStitchedPages) { let existingrotation = document.getPageRotation(page); - console.log("page", page, existingrotation) - console.log('rootatedpages', rotatedStitchedPages[page] ) let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; - console.log("rotation", rotation) document.rotatePages([page], rotation); } } From f92bcc52cc502092999af8c47930a8f9f25e729c Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Thu, 12 Sep 2024 12:21:55 -0700 Subject: [PATCH 35/89] Adjust redline processing back to original order but with applyrotations happening after redactions + added watermark logic to consults --- .../useSaveRedlineForSignOff.js | 92 ++++++++++--------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 5abb51700..84ba7d3e7 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -590,12 +590,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { for (let flagInfo of notConsultPageFlagsOnPage) { if (flagInfo.flagid == pageFlagTypes["Duplicate"]) { if(includeDuplicatePages) { - duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + for (let consult of doc.consult) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { + duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = - pageIndex + - totalPageCount - - pagesToRemoveEachDoc.length; + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } } else { pagesToRemoveEachDoc.push(flagInfo.page); if (!skipDocumentPages && !skipOnlyDuplicateDocument) { @@ -607,12 +611,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (flagInfo.flagid == pageFlagTypes["Not Responsive"]) { if(includeNRPages) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + for (let consult of doc.consult) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = - pageIndex + - totalPageCount - - pagesToRemoveEachDoc.length; + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } } else { pagesToRemoveEachDoc.push(flagInfo.page); if (!skipDocumentPages && !skipOnlyNRDocument) { @@ -622,12 +630,16 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } } } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); + for (let consult of doc.consult) { + if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { + NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = - pageIndex + - totalPageCount - - pagesToRemoveEachDoc.length; + pageMappings[doc.documentid][flagInfo.page] = + pageIndex + + totalPageCount - + pagesToRemoveEachDoc.length; + } + } } else { if (flagInfo.flagid !== pageFlagTypes["Consult"]) { pageMappings[doc.documentid][flagInfo.page] = @@ -1825,9 +1837,32 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + await stampPageNumberRedline( + stitchObject, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + } + if ( + redlinepageMappings["pagestoremove"][divisionid] && + redlinepageMappings["pagestoremove"][divisionid].length > 0 && + stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length + ) { + await stitchObject.removePages( + redlinepageMappings["pagestoremove"][divisionid] + ); + } + if (redlineCategory === "redline" || redlineCategory === "consult") { + await addWatermarkToRedline( + stitchObject, + redlineWatermarkPageMapping, + key + ); + } let string = await stitchObject.extractXFDF(); - let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1878,31 +1913,6 @@ const stampPageNumberRedline = async ( } } - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - } - if ( - redlinepageMappings["pagestoremove"][divisionid] && - redlinepageMappings["pagestoremove"][divisionid].length > 0 && - stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length - ) { - await stitchObject.removePages( - redlinepageMappings["pagestoremove"][divisionid] - ); - } - if (redlineCategory === "redline" || redlineCategory === "consult") { - await addWatermarkToRedline( - stitchObject, - redlineWatermarkPageMapping, - key - ); - } - stitchObject .getFileData({ // saves the document with annotations in it From d6b899ca35c8da2b3f6f68fb1073f08e1d44f844 Mon Sep 17 00:00:00 2001 From: Milos Despotovic Date: Wed, 18 Sep 2024 09:53:44 -0700 Subject: [PATCH 36/89] Disable button if there is no text --- web/src/components/FOI/Home/FeeOverrideModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx index a64862710..379a78a3d 100644 --- a/web/src/components/FOI/Home/FeeOverrideModal.jsx +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -72,7 +72,7 @@ const FeeOverrideModal = ({ )} {isOverride && ( - )} From 9abc9dc5d94e4d7b470c5aa0e5843d0e0c7e28cc Mon Sep 17 00:00:00 2001 From: nkan-aot2 <156717133+nkan-aot2@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:31:33 -0700 Subject: [PATCH 37/89] refresh docviewer on watermark addition --- web/src/components/FOI/Home/Redlining.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 5d916353e..2bea8a861 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -1373,6 +1373,8 @@ const Redlining = React.forwardRef( } }, }); + docViewer.refreshAll(); + docViewer.updateView(); } //Cleanup Function: removes previous event listeiner to ensure handleCreateResponsePDFClick event is not called multiple times on click return () => { From 34c9f8db3278d151bc19301dab64112dc5631406 Mon Sep 17 00:00:00 2001 From: Abin Antony Date: Fri, 20 Sep 2024 12:59:14 -0700 Subject: [PATCH 38/89] #FOIMOD-3469 handinling MSG one off SENT date scenario --- MCS.FOI.S3FileConversion/MCS.FOI.MSGToPDF/MSGFileProcessor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MCS.FOI.S3FileConversion/MCS.FOI.MSGToPDF/MSGFileProcessor.cs b/MCS.FOI.S3FileConversion/MCS.FOI.MSGToPDF/MSGFileProcessor.cs index 19ad3c9ab..4fc11c07a 100644 --- a/MCS.FOI.S3FileConversion/MCS.FOI.MSGToPDF/MSGFileProcessor.cs +++ b/MCS.FOI.S3FileConversion/MCS.FOI.MSGToPDF/MSGFileProcessor.cs @@ -521,6 +521,10 @@ private string GenerateHtmlfromMsg(Storage.Message msg) " + msg.Subject + ""); DateTime sentDate = Convert.ToDateTime(msg.SentOn); + if(sentDate == DateTime.MinValue) + { + sentDate = Convert.ToDateTime(msg.CreationTime); + } if (TimeZone.CurrentTimeZone.StandardName != "Pacific Standard Time") { From f40e68ccc6b3a9da6b2d4d8545ad5667a82ca547 Mon Sep 17 00:00:00 2001 From: nkan-aot2 <156717133+nkan-aot2@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:10:47 -0700 Subject: [PATCH 39/89] fix watermark persisting after removed nr and dupe pages --- .../FOI/Home/CreateResponsePDF/useSaveResponsePackage.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js index 5d12ea826..aeb885798 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js @@ -264,7 +264,12 @@ const useSaveResponsePackage = () => { /**must apply redactions before removing pages*/ if (pagesToRemove.length > 0) { await doc.removePages(pagesToRemove); - } + } + doc.setWatermark({ + diagonal: { + text: '' + } + }) const { PDFNet } = _instance.Core; PDFNet.initialize(); From f15aac50f683f66fd3054396ae0e74a83c3d9349 Mon Sep 17 00:00:00 2001 From: nkan-aot2 <156717133+nkan-aot2@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:12:55 -0700 Subject: [PATCH 40/89] add optional chaining to refresh call after applying watermark --- web/src/components/FOI/Home/Redlining.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 2bea8a861..3dad804af 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -1373,8 +1373,8 @@ const Redlining = React.forwardRef( } }, }); - docViewer.refreshAll(); - docViewer.updateView(); + docViewer?.refreshAll(); + docViewer?.updateView(); } //Cleanup Function: removes previous event listeiner to ensure handleCreateResponsePDFClick event is not called multiple times on click return () => { From a8e1774d8515060ec60255360260d65c48590d84 Mon Sep 17 00:00:00 2001 From: Aparna Date: Fri, 20 Sep 2024 16:07:51 -0700 Subject: [PATCH 41/89] Rotation-s.14 fix --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index f926f9663..9fe835e5c 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1492,9 +1492,10 @@ const stampPageNumberRedline = async ( } + const doc = await stitchObject.getPDFDoc(); for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = docViewer.getDocument()?.getPageRotation(rect.vpageno); + let pageRotation = doc?.getPageRotation(rect.vpageno); let pageWidth = docViewer.getPageWidth(rect.vpageno); /**Fix for oipc redline displaying s.14 marked page content partially */ let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); @@ -1506,7 +1507,7 @@ const stampPageNumberRedline = async ( app.redaction_overlay = true; app.border = false; app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); + // const doc = await stitchObject.getPDFDoc(); await PDFNet.Redactor.redact(doc, rarr, app); } await stampPageNumberRedline( From 9815dafed3901c8ef90b2f43db04b9c228d9a4df Mon Sep 17 00:00:00 2001 From: Aparna <71481254+aparna-aot@users.noreply.github.com> Date: Fri, 20 Sep 2024 16:35:45 -0700 Subject: [PATCH 42/89] Revert "Page Rotation fix for OIPC Redline S.14" --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 9fe835e5c..f926f9663 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1492,10 +1492,9 @@ const stampPageNumberRedline = async ( } - const doc = await stitchObject.getPDFDoc(); for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = doc?.getPageRotation(rect.vpageno); + let pageRotation = docViewer.getDocument()?.getPageRotation(rect.vpageno); let pageWidth = docViewer.getPageWidth(rect.vpageno); /**Fix for oipc redline displaying s.14 marked page content partially */ let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); @@ -1507,7 +1506,7 @@ const stampPageNumberRedline = async ( app.redaction_overlay = true; app.border = false; app.show_redacted_content_regions = false; - // const doc = await stitchObject.getPDFDoc(); + const doc = await stitchObject.getPDFDoc(); await PDFNet.Redactor.redact(doc, rarr, app); } await stampPageNumberRedline( From 301ea850ca96d0571a20a0721138d09b42224dde Mon Sep 17 00:00:00 2001 From: Aparna Date: Mon, 23 Sep 2024 09:05:01 -0700 Subject: [PATCH 43/89] S.14 - Rotation page issue fix --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index f926f9663..43bfb9745 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1494,7 +1494,7 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = docViewer.getDocument()?.getPageRotation(rect.vpageno); + let pageRotation = stitchObject?.getPageRotation(rect.vpageno); let pageWidth = docViewer.getPageWidth(rect.vpageno); /**Fix for oipc redline displaying s.14 marked page content partially */ let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); From 3ccc94c169d3e26bfa314f10a605cec7053d07d3 Mon Sep 17 00:00:00 2001 From: Aparna Date: Mon, 23 Sep 2024 14:27:03 -0700 Subject: [PATCH 44/89] S.14- Page Removed scenario fix --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 43bfb9745..c0265056b 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1494,7 +1494,7 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = stitchObject?.getPageRotation(rect.vpageno); + let pageRotation = stitchObject?.getPageRotation(rect.pageno); let pageWidth = docViewer.getPageWidth(rect.vpageno); /**Fix for oipc redline displaying s.14 marked page content partially */ let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); From 3f7a5dbc3d74b8ec11f724c45af3bb8c97634629 Mon Sep 17 00:00:00 2001 From: Milos Despotovic Date: Wed, 25 Sep 2024 09:55:22 -0700 Subject: [PATCH 45/89] Revert 3350 remove NR and duplicate from summary --- .../DocumentServices/services/dts/redactionsummary.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/computingservices/DocumentServices/services/dts/redactionsummary.py b/computingservices/DocumentServices/services/dts/redactionsummary.py index 539a53e9c..89fded2ef 100644 --- a/computingservices/DocumentServices/services/dts/redactionsummary.py +++ b/computingservices/DocumentServices/services/dts/redactionsummary.py @@ -7,11 +7,6 @@ class redactionsummary(): def prepareredactionsummary(self, message, documentids, pageflags, programareas): - def removeduplicateandnr(pageflag): - if pageflag['name'] != 'Duplicate' and pageflag['name'] != 'Not Responsive': - return True - return False - pageflags = list(filter(removeduplicateandnr, pageflags)) _ismcfpersonalrequest = True if message.bcgovcode == 'mcf' and message.requesttype == 'personal' else False if _ismcfpersonalrequest and message.category == "responsepackage": redactionsummary = self.__packagesummaryforcfdrequests(message, documentids) From 72132c89f2ee4fb7d11e5325642c98eb00633d35 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 11:12:14 -0700 Subject: [PATCH 46/89] removed new test-marshal/consult code which moved rotation of pages to end of redline creation process --- .../useSaveRedlineForSignOff.js | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 682fb718d..035bb22fd 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - setTotalStitchList(stitchlist) + // setTotalStitchList(stitchlist); //if you want to rotate pages at end of redline process for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -859,7 +859,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - // applyRotations(docObj, doc.attributes.rotatedpages) + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1905,14 +1905,14 @@ const stampPageNumberRedline = async ( } //Consults - Redlines + Redactions (Redact S.NR) Block : End - // Rotate pages - for (const doc of totalStitchList[divisionid]) { - let documentlist = totalStitchList[divisionid]; - let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - if(documentlist.length > 0) { - applyRotations(stitchObject, doc, divDocPageMappings); - } - } + // Rotate pages - After all redline work is completed + // for (const doc of totalStitchList[divisionid]) { + // let documentlist = totalStitchList[divisionid]; + // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + // if(documentlist.length > 0) { + // applyRotations(stitchObject, doc, divDocPageMappings); + // } + // } stitchObject .getFileData({ @@ -1972,24 +1972,24 @@ const stampPageNumberRedline = async ( } }; - const applyRotations = (document, doc, divDocPageMappings) => { - const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} - const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} - const rotatedStitchedPages = {}; - if (rotatedpages) { - for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { - let rotation = rotatedpages[originalPage]; - if (rotation) { - rotatedStitchedPages[stitchedPage] = rotation; - } - } - for (let page in rotatedStitchedPages) { - let existingrotation = document.getPageRotation(page); - let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; - document.rotatePages([page], rotation); - } - } - } + // const applyRotations = (document, doc, divDocPageMappings) => { + // const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} + // const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} + // const rotatedStitchedPages = {}; + // if (rotatedpages) { + // for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { + // let rotation = rotatedpages[originalPage]; + // if (rotation) { + // rotatedStitchedPages[stitchedPage] = rotation; + // } + // } + // for (let page in rotatedStitchedPages) { + // let existingrotation = document.getPageRotation(page); + // let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; + // document.rotatePages([page], rotation); + // } + // } + // } useEffect(() => { if ( From 64ffcfab7e5cfddadfd8d8a5080fa2320566cbe3 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 11:30:29 -0700 Subject: [PATCH 47/89] manually added dev-AS-oipc-section14-fix pr --- .../useSaveRedlineForSignOff.js | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 035bb22fd..0ab3b3a2d 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1788,7 +1788,12 @@ const stampPageNumberRedline = async ( } for (const rect of rects) { let height = docViewer.getPageHeight(rect.vpageno); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + let pageRotation = stitchObject?.getPageRotation(rect.pageno); + let pageWidth = docViewer.getPageWidth(rect.vpageno); + /**Fix for oipc redline displaying s.14 marked page content partially */ + let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); + //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); } if (rarr.length > 0) { const app = {}; @@ -1990,6 +1995,34 @@ const stampPageNumberRedline = async ( // } // } // } + + const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { + let x1 = recto.x1; + let y1 = recto.y1; + let x2 = recto.x2; + let y2 = recto.y2; + // Adjust Y-coordinates to account for the flipped Y-axis in PDF + y1 = pageHeight - y1; + y2 = pageHeight - y2; + // Adjust for page rotation (90, 180, 270 degrees) + switch (pageRotation) { + case 90: + [x1, y1] = [y1, x1]; + [x2, y2] = [y2, x2]; + break; + case 180: + x1 = pageWidth - x1; + y1 = pageHeight - y1; + x2 = pageWidth - x2; + y2 = pageHeight - y2; + break; + case 270: + [x1, y1] = [pageHeight - y1, x1]; + [x2, y2] = [pageHeight - y2, x2]; + break; + } + return await PDFNet.Rect.init(x1, y1, x2, y2); + } useEffect(() => { if ( From 24986ce9c324fb5dfdebb35e24fbfc9a889b67b0 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 16:00:44 -0700 Subject: [PATCH 48/89] commented out applyrotations to redlines logic to reduce vunerability of data breaches (redlines for s.14 and NR not being applied to redline packages --- .../Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 0ab3b3a2d..e6b918c39 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to rotate pages at end of redline process + // setTotalStitchList(stitchlist); //if you want to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -859,7 +859,10 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - applyRotations(docObj, doc.attributes.rotatedpages) + + // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur + // applyRotations(docObj, doc.attributes.rotatedpages) + //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1910,7 +1913,7 @@ const stampPageNumberRedline = async ( } //Consults - Redlines + Redactions (Redact S.NR) Block : End - // Rotate pages - After all redline work is completed + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed // for (const doc of totalStitchList[divisionid]) { // let documentlist = totalStitchList[divisionid]; // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; From fb90af65a44f7353759a55aa89f7db88ebcd1b26 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 16:06:53 -0700 Subject: [PATCH 49/89] added additonal comments --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e6b918c39..8eb1df5b1 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to applyrotations at end of redline process uncomment this + // setTotalStitchList(stitchlist); //if you want to the solution to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -1913,7 +1913,7 @@ const stampPageNumberRedline = async ( } //Consults - Redlines + Redactions (Redact S.NR) Block : End - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. // for (const doc of totalStitchList[divisionid]) { // let documentlist = totalStitchList[divisionid]; // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; @@ -1980,6 +1980,7 @@ const stampPageNumberRedline = async ( } }; + // This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. // const applyRotations = (document, doc, divDocPageMappings) => { // const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} // const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} From 55b6cd469b62bc692eb33babf9c3d3c0b4abb0a6 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 25 Sep 2024 16:07:34 -0700 Subject: [PATCH 50/89] added additonal comments --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 8eb1df5b1..e98cd1b03 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -822,7 +822,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to the solution to applyrotations at end of redline process uncomment this + // setTotalStitchList(stitchlist); //if you want to apply the solution to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; From c2f6975964490913749b2d27ab3833fa221e47f5 Mon Sep 17 00:00:00 2001 From: Milos Despotovic Date: Wed, 2 Oct 2024 09:41:41 -0700 Subject: [PATCH 51/89] Remove NR and duplicate from summary --- .../services/dts/redactionsummary.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/computingservices/DocumentServices/services/dts/redactionsummary.py b/computingservices/DocumentServices/services/dts/redactionsummary.py index 89fded2ef..bb08b2a84 100644 --- a/computingservices/DocumentServices/services/dts/redactionsummary.py +++ b/computingservices/DocumentServices/services/dts/redactionsummary.py @@ -72,6 +72,14 @@ def __packaggesummary(self, message, documentids, pageflags, programareas): _data["pagecount"] = len(pageflag['docpageflags']) _data["sections"] = self.__format_redaction_summary(pageflag["description"], pageflag['docpageflags'], message.category) summarydata.append(_data) + #remove duplicate and NR for oipc review redline + def removeduplicateandnr(pageflag): + if pageflag['flagname'].lower() != 'duplicate' and pageflag['flagname'].lower() != 'not responsive': + return True + return False + if message.category == "oipcreviewredline": + print("\n removing duplicate and not responsive pages from summary") + summarydata = list(filter(removeduplicateandnr, summarydata)) except (Exception) as err: traceback.print_exc() print('error occured in __packaggesummary redaction dts service: ', err) @@ -451,7 +459,7 @@ def __get_pages_by_flagid(self, _docpageflags, deletedpages, totalpages, flagid, def __get_skippagenos(self, _docpageflags, category): skippages = [] - if category in ['responsepackage', 'CFD_responsepackage']: + if category in ['responsepackage', 'CFD_responsepackage', 'oipcreviewredline']: for x in _docpageflags: if x['flagid'] in (5,6) and x['page'] not in skippages: skippages.append(x['page']) @@ -459,7 +467,7 @@ def __get_skippagenos(self, _docpageflags, category): def __calcstitchedpageno(self, pageno, totalpages, category, skippages, deletedpages): skipcount = 0 - if category in ["responsepackage", 'CFD_responsepackage']: + if category in ["responsepackage", 'CFD_responsepackage', 'oipcreviewredline']: skipcount = self.__calculateskipcount(pageno, skippages) skipcount = self.__calculateskipcount(pageno, deletedpages, skipcount) return (pageno+totalpages)-skipcount From 79d00876d6c1d087318e504acedd47d2a4c811ed Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Wed, 2 Oct 2024 14:16:24 -0700 Subject: [PATCH 52/89] bug fix for FOIMOD-3472 & FOIMOD-3476 --- .../useSaveRedlineForSignOff.js | 134 +++++++++++++----- 1 file changed, 97 insertions(+), 37 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index c0265056b..b35bcab3d 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -784,7 +784,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let documentsObjArr = []; let divisionstitchpages = []; let divCount = 0; - console.log("RES:",res) + // console.log("RES:",res) for (let div of res.divdocumentList) { divCount++; let docCount = 0; @@ -985,7 +985,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { includenrpages: includeNRPages, }; if (stitchedDocPath) { - console.log("stitchedDocPath:",stitchedDocPath) + // console.log("stitchedDocPath:",stitchedDocPath) const stitchedDocPathArray = stitchedDocPath?.split("/"); let fileName = stitchedDocPathArray[stitchedDocPathArray.length - 1].split("?")[0]; @@ -1457,8 +1457,9 @@ const stampPageNumberRedline = async ( ); } - let string = await stitchObject.extractXFDF() + let string = await stitchObject.extractXFDF(); + // for redline - formatted annots let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots') @@ -1467,57 +1468,115 @@ const stampPageNumberRedline = async ( } else { xmlObj.children.push(annots) } - let xfdfString = parser.toString(xmlObj); + // for oipc review - re-apply annots after redaction - annots only no widgets/form fields + let xmlObj1 = parser.parseFromString(string.xfdfString); + xmlObj1.children = []; + xmlObj1.children.push(annots); + let xfdfString1 = parser.toString(xmlObj1); + //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { - const rarr = []; let annotationManager = docInstance?.Core.annotationManager; let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - let rects = []; + let s14annots = []; for (const [key, value] of Object.entries(s14_sectionStamps)) { let s14annoation = annotationManager.getAnnotationById(key); if ( s14annoation.Subject === "Redact") { - rects = rects.concat( - s14annoation.getQuads().map((q) => { - return { - pageno: s14_sectionStamps[key], - recto: q.toRect(), - vpageno: s14annoation.getPageNumber() - }; - }) - ); - } - - - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = stitchObject?.getPageRotation(rect.pageno); - let pageWidth = docViewer.getPageWidth(rect.vpageno); - /**Fix for oipc redline displaying s.14 marked page content partially */ - let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); - //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); + s14annots.push(s14annoation); + } } + + let doc = docViewer.getDocument(); + await annotationManager.applyRedactions(s14annots); + await stampPageNumberRedline( stitchObject, PDFNet, redlineStitchInfo[divisionid]["stitchpages"], isSingleRedlinePackage ); - } + + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Redline PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); + }); + }); //OIPC - Special Block : End - stitchObject + } else { + stitchObject .getFileData({ // saves the document with annotations in it xfdfString: xfdfString, @@ -1571,6 +1630,7 @@ const stampPageNumberRedline = async ( } ); }); + } } } }; From cfbbd3bd4154ae4012c9891108f2bfb4ce150a0b Mon Sep 17 00:00:00 2001 From: Aparna Date: Mon, 10 Jun 2024 13:25:20 -0700 Subject: [PATCH 53/89] FOIMOD-3073 - Fees - Remaining Balance Check Added new table - PDFStitchJobAttributes Updates in notification manager Added new frontend modal before response package download --- api/migrations/versions/9d45ce57481e_.py | 35 ++++++++++ .../models/PDFStitchJobAttributes.py | 66 +++++++++++++++++++ api/reviewer_api/resources/document.py | 3 + api/reviewer_api/schemas/finalpackage.py | 5 +- api/reviewer_api/services/jobrecordservice.py | 22 +++++++ api/reviewer_api/services/radactionservice.py | 22 +++++++ .../services/zippingservice.py | 3 +- .../redlineresponsenotificationmessage.py | 3 +- .../models/zipperproducermessage.py | 3 +- .../services/notificationservice.py | 1 + web/src/components/FOI/App.scss | 6 ++ web/src/components/FOI/Home/Home.js | 8 ++- web/src/components/FOI/Home/Redlining.js | 31 +++++++-- 13 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 api/migrations/versions/9d45ce57481e_.py create mode 100644 api/reviewer_api/models/PDFStitchJobAttributes.py diff --git a/api/migrations/versions/9d45ce57481e_.py b/api/migrations/versions/9d45ce57481e_.py new file mode 100644 index 000000000..25bda2114 --- /dev/null +++ b/api/migrations/versions/9d45ce57481e_.py @@ -0,0 +1,35 @@ +"""empty message + +Revision ID: 9d45ce57481e +Revises: 18a45d1b33cc +Create Date: 2024-06-06 10:19:45.739225 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '9d45ce57481e' +down_revision = '18a45d1b33cc' +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_table('PDFStitchJobAttributes', + sa.Column('attributesid', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('pdfstitchjobid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False), + sa.Column('version', sa.Integer(), nullable=False), + sa.Column('ministryrequestid', sa.Integer(), nullable=False), + sa.Column('attributes', postgresql.JSON(astext_type=sa.Text()), nullable=False), + sa.Column('createdat', sa.TIMESTAMP, nullable=False, server_default=sa.func.now()), + sa.Column('createdby', sa.String(length=120), nullable=True), + sa.PrimaryKeyConstraint('attributesid'), + sa.ForeignKeyConstraint(['pdfstitchjobid', 'version'], ['PDFStitchJob.pdfstitchjobid', 'PDFStitchJob.version'], ) + ) + + +def downgrade(): + op.drop_table('PDFStitchJobAttributes') + diff --git a/api/reviewer_api/models/PDFStitchJobAttributes.py b/api/reviewer_api/models/PDFStitchJobAttributes.py new file mode 100644 index 000000000..899a7199a --- /dev/null +++ b/api/reviewer_api/models/PDFStitchJobAttributes.py @@ -0,0 +1,66 @@ +from .db import db, ma +from datetime import datetime as datetime2 +from sqlalchemy.dialects.postgresql import JSON +from sqlalchemy import func, and_ +from .default_method_result import DefaultMethodResult +from .DocumentDeleted import DocumentDeleted +from .DocumentMaster import DocumentMaster +import logging + + +class PDFStitchJobAttributes(db.Model): + __tablename__ = "PDFStitchJobAttributes" + # Defining the columns + attributesid = db.Column(db.Integer, primary_key=True, autoincrement=True) + pdfstitchjobid = db.Column(db.Integer, db.ForeignKey("PDFStitchJob.pdfstitchjobid")) + version = db.Column(db.Integer, db.ForeignKey("PDFStitchJob.version")) + ministryrequestid = db.Column(db.Integer, nullable=False) + attributes = db.Column(JSON, unique=False, nullable=False) + createdat = db.Column(db.DateTime, default=datetime2.now, nullable=False) + createdby = db.Column(db.String(120), nullable=False) + + + @classmethod + def insert(cls, row): + try: + db.session.add(row) + db.session.commit() + return DefaultMethodResult( + True, + "PDF Stitch Job Attributes recorded for ministryrequestid: {0}".format( + row.ministryrequestid + ), + row.pdfstitchjobid, + ) + except Exception as ex: + logging.error(ex) + finally: + db.session.close() + + @classmethod + def getpdfstitchjobattributesbyid(cls, requestid): + try: + pdfstitchjobattributesschema = PDFStitchJobAttributesSchema(many=False) + query = db.session.query(PDFStitchJobAttributes).filter( + PDFStitchJobAttributes.ministryrequestid == requestid + ).first() + return pdfstitchjobattributesschema.dump(query) + except Exception as ex: + logging.error(ex) + finally: + db.session.close() + + + + +class PDFStitchJobAttributesSchema(ma.Schema): + class Meta: + fields = ( + "attributesid", + "pdfstitchjobid", + "version", + "ministryrequestid", + "attributes", + "createdat", + "createdby", + ) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 2cd9b7d8c..e5f02d134 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -29,6 +29,7 @@ from reviewer_api.services.documentservice import documentservice from reviewer_api.services.docdeletedpageservice import docdeletedpageservice +from reviewer_api.services.jobrecordservice import jobrecordservice API = Namespace('Document Services', description='Endpoints for deleting and replacing documents') TRACER = Tracer.get_instance() @@ -122,10 +123,12 @@ def get(requestid): response.raise_for_status() # get request status jsonobj = response.json() + balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) requestinfo = { "bcgovcode": jsonobj["bcgovcode"], "requesttype": jsonobj["requestType"], "validoipcreviewlayer": documentservice().validate_oipcreviewlayer(jsonobj, requestid), + "balancefeeoverrodforrequest": balancefeeoverrodforrequest } documentdivisionslist,result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) return json.dumps({"requeststatuslabel": jsonobj["requeststatuslabel"], "documents": result, "requestnumber":jsonobj["axisRequestId"], "requestinfo":requestinfo, "documentdivisions":documentdivisionslist}), 200 diff --git a/api/reviewer_api/schemas/finalpackage.py b/api/reviewer_api/schemas/finalpackage.py index 0cf5ee155..0ad45bf4d 100644 --- a/api/reviewer_api/schemas/finalpackage.py +++ b/api/reviewer_api/schemas/finalpackage.py @@ -10,6 +10,8 @@ class FileSchema(Schema): class AttributeSchema(Schema): files = fields.Nested(FileSchema, many=True, required=True, allow_none=False) +class FeeOverrideSchema(Schema): + feeoverridereason = fields.Str(data_key="feeoverridereason", allow_none=True) class SummaryPkgSchema(Schema): divisionid = fields.Int(data_key="divisionid", allow_none=True) @@ -55,4 +57,5 @@ class MCFFinalPackageSchema(Schema): ) summarydocuments = fields.Nested(MCFSummarySchema, allow_none=True) redactionlayerid = fields.Int(data_key="redactionlayerid", allow_none=False) - requesttype = fields.Str(data_key="requesttype", allow_none=False) \ No newline at end of file + requesttype = fields.Str(data_key="requesttype", allow_none=False) + pdfstitchjobattributes = fields.Nested(FeeOverrideSchema, allow_none=True, many=False) diff --git a/api/reviewer_api/services/jobrecordservice.py b/api/reviewer_api/services/jobrecordservice.py index 587c94bc4..863a1e03b 100644 --- a/api/reviewer_api/services/jobrecordservice.py +++ b/api/reviewer_api/services/jobrecordservice.py @@ -6,6 +6,7 @@ from reviewer_api.models.DocumentAttributes import DocumentAttributes from reviewer_api.services.annotationservice import annotationservice from reviewer_api.services.documentpageflagservice import documentpageflagservice +from reviewer_api.models.PDFStitchJobAttributes import PDFStitchJobAttributes from reviewer_api.auth import auth, AuthHelper from datetime import datetime as datetime2 from reviewer_api.utils.constants import FILE_CONVERSION_FILE_TYPES, DEDUPE_FILE_TYPES @@ -129,3 +130,24 @@ def insertpagecalculatorjobstatus(self, message, userid): ) job = PageCalculatorJob.insert(row) return job + + def insertfeeoverridereason(self, message, pdfstitchjobid, userid): + row = PDFStitchJobAttributes( + pdfstitchjobid=pdfstitchjobid, + version=1, + ministryrequestid=message['ministryrequestid'], + attributes=message['pdfstitchjobattributes'], + createdby=userid + ) + job = PDFStitchJobAttributes.insert(row) + return job + + def __getpdfstitchjobattributesbyid(self, requestid): + job = PDFStitchJobAttributes().getpdfstitchjobattributesbyid(requestid) + return job + + def isbalancefeeoverrodforrequest(self, requestid): + pdfstitchjobattributes= self.__getpdfstitchjobattributesbyid(requestid) + isbalancefeeoverrode= False if pdfstitchjobattributes is None or not pdfstitchjobattributes else True + #print("\nisbalancefeeoverrode:",isbalancefeeoverrode) + return isbalancefeeoverrode diff --git a/api/reviewer_api/services/radactionservice.py b/api/reviewer_api/services/radactionservice.py index cd63eab93..5253b8972 100644 --- a/api/reviewer_api/services/radactionservice.py +++ b/api/reviewer_api/services/radactionservice.py @@ -123,7 +123,16 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): job = jobrecordservice().insertpdfstitchjobstatus( _jobmessage, userinfo["userid"] ) + print("job:: ",job.message) + print("job-2:: ",job.identifier) if job.success: + if finalpackageschema['pdfstitchjobattributes'] is not None: + feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] + print("feeoverridereason:",feeoverridereason) + if feeoverridereason is not None and feeoverridereason != '': + feeoverridereasonresult= jobrecordservice().insertfeeoverridereason(finalpackageschema,job.identifier,userinfo["userid"]) + #print("feeoverridereasonresult:",feeoverridereasonresult) + #Add here the reason- comment text and a boolean _message = self.__preparemessageforsummaryservice( finalpackageschema, userinfo, job ) @@ -131,6 +140,17 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): # redline/final package download: prepare message for zipping service def __preparemessageforsummaryservice(self, messageschema, userinfo, job): + pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) + print("pdf_stitch_job_attributes:",pdf_stitch_job_attributes) + if pdf_stitch_job_attributes is not None: + feeoverridereason= json.loads(pdf_stitch_job_attributes).get("feeoverridereason", None) + if feeoverridereason is not None and feeoverridereason != '': + feeoverridereason= userinfo["firstname"]+" "+userinfo["lastname"]+" overrode balance outstanding warning for the following reason: "+feeoverridereason + print("feeoverridereason:",feeoverridereason) + else: + feeoverridereason= "" + else: + feeoverridereason= "" _message = { "jobid": job.identifier, "requestid": -1, @@ -147,7 +167,9 @@ def __preparemessageforsummaryservice(self, messageschema, userinfo, job): "summarydocuments": json.dumps(messageschema["summarydocuments"]), "redactionlayerid": json.dumps(messageschema["redactionlayerid"]), "requesttype": messageschema["requesttype"], + "feeoverridereason":feeoverridereason } + print("_message:",_message) return _message # redline/final package download: prepare message for zipping service diff --git a/computingservices/DocumentServices/services/zippingservice.py b/computingservices/DocumentServices/services/zippingservice.py index 49def91ae..761f6dcc3 100644 --- a/computingservices/DocumentServices/services/zippingservice.py +++ b/computingservices/DocumentServices/services/zippingservice.py @@ -19,7 +19,8 @@ def preparemessageforzipperservice(self,summaryfiles, message): print('filestozip_list: ', filestozip_list) msgjson['filestozip'] = self.to_json(filestozip_list) msgjson['attributes'] = self.to_json(msgjson['attributes']) - msgjson['summarydocuments'] = self.to_json(msgjson['summarydocuments']) + msgjson['summarydocuments'] = self.to_json(msgjson['summarydocuments']) + return msgjson except (Exception) as error: print('error occured in zipping service: ', error) diff --git a/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py b/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py index 5028e8783..ccb851933 100644 --- a/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py +++ b/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py @@ -1,6 +1,7 @@ class redlineresponsenotificationmessage(object): - def __init__(self, ministryrequestid, serviceid, errorflag, createdby) -> None: + def __init__(self, ministryrequestid, serviceid, errorflag, createdby,feeoverridereason) -> None: self.ministryrequestid = ministryrequestid self.serviceid = serviceid self.errorflag = errorflag self.createdby = createdby + self.feeoverridereason=feeoverridereason diff --git a/computingservices/ZippingServices/models/zipperproducermessage.py b/computingservices/ZippingServices/models/zipperproducermessage.py index deee421e1..73b4b795c 100644 --- a/computingservices/ZippingServices/models/zipperproducermessage.py +++ b/computingservices/ZippingServices/models/zipperproducermessage.py @@ -1,5 +1,5 @@ class zipperproducermessage(object): - def __init__(self,jobid,requestid,category,requestnumber,bcgovcode,createdby,ministryrequestid,filestozip,finaloutput,attributes,summarydocuments=None,redactionlayerid=None,foldername=None) -> None: + def __init__(self,jobid,requestid,category,requestnumber,bcgovcode,createdby,ministryrequestid,filestozip,finaloutput,attributes,feeoverridereason,summarydocuments=None,redactionlayerid=None,foldername=None) -> None: self.jobid = jobid self.requestid = requestid self.category=category @@ -13,3 +13,4 @@ def __init__(self,jobid,requestid,category,requestnumber,bcgovcode,createdby,min self.foldername = foldername self.summarydocuments = summarydocuments self.redactionlayerid = redactionlayerid + self.feeoverridereason= feeoverridereason \ No newline at end of file diff --git a/computingservices/ZippingServices/services/notificationservice.py b/computingservices/ZippingServices/services/notificationservice.py index f237393f9..5fc5f1c5c 100644 --- a/computingservices/ZippingServices/services/notificationservice.py +++ b/computingservices/ZippingServices/services/notificationservice.py @@ -44,6 +44,7 @@ def __responsepackagepublishtostream(self, message, error=False): serviceid="pdfstitchforresponsepackage", createdby=message.createdby, errorflag=self.__booltostr(error), + feeoverridereason= message.feeoverridereason ) logging.info( diff --git a/web/src/components/FOI/App.scss b/web/src/components/FOI/App.scss index 92b7f3fab..0e2ef0f20 100644 --- a/web/src/components/FOI/App.scss +++ b/web/src/components/FOI/App.scss @@ -145,6 +145,12 @@ li.modal-message-list-item { height: calc(100% - 198px); } +.modal-content{ + padding: 20px 30px !important; + overflow-y: visible !important; + height: calc(100% - 198px); +} + .section-list{ >li:nth-child(odd) { background-color: #E5EAEF; diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index e1b7ec441..9bea587a7 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -45,6 +45,7 @@ function Home() { const [warningModalOpen, setWarningModalOpen] = useState(false); const [divisions, setDivisions] = useState([]); const [pageFlags, setPageFlags]= useState([]); + const [isBalanceFeeOverrode , setIsBalanceFeeOverrode] = useState(false); const redliningRef = useRef(); const selectorRef = useRef(); @@ -68,6 +69,7 @@ function Home() { parseInt(foiministryrequestid), async (data, documentDivisions, _requestInfo) => { setDivisions(documentDivisions); + setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") const fileExt = parts.pop() @@ -76,7 +78,7 @@ function Home() { // New code added to get the incompatable files for download redline // data has all the files including incompatable ones // _files has all files except incompatable ones - const _incompatableFiles = data.filter( + const _incompatableFiles = data.documents.filter( (d) => { const isPdfFile = getFileExt(d.filepath) === "pdf" if (isPdfFile) { @@ -87,7 +89,7 @@ function Home() { } ); setIncompatibleFiles(_incompatableFiles); - const _files = data.filter((d) => { + const _files = data.documents.filter((d) => { const isPdfFile = getFileExt(d.filepath) === "pdf" const isCompatible = !d.attributes.incompatible || isPdfFile return isCompatible @@ -301,7 +303,7 @@ function Home() { scrollLeftPanel={scrollLeftPanel} pageFlags={pageFlags} syncPageFlagsOnAction={syncPageFlagsOnAction} - + isBalanceFeeOverrode={isBalanceFeeOverrode} /> ) // :
Loading
diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 3dad804af..5b1a398d2 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -81,7 +81,8 @@ const Redlining = React.forwardRef( setWarningModalOpen, scrollLeftPanel, pageFlags, - syncPageFlagsOnAction + syncPageFlagsOnAction, + isBalanceFeeOverrode }, ref ) => { @@ -141,6 +142,11 @@ const Redlining = React.forwardRef( const [redlineModalOpen, setRedlineModalOpen] = useState(false); const [isDisableNRDuplicate, setIsDisableNRDuplicate] = useState(false); const [pageSelectionsContainNRDup, setPageSelectionsContainNRDup] = useState(false); + const [outstandingBalanceModal, setOutstandingBalanceModal] = useState(false); + const [outstandingBalance, setOutstandingBalance]= useState(1) + const [isOverride, setIsOverride]= useState(false); + const [feeOverrideReason, setFeeOverrideReason]= useState(""); + //xml parser const parser = new XMLParser(); /**Response Package && Redline download and saving logic (react custom hooks)*/ @@ -2134,8 +2140,14 @@ const Redlining = React.forwardRef( }, [deleteQueue, newRedaction]); const cancelRedaction = () => { - setModalOpen(false); - setMessageModalOpen(false); + if(outstandingBalance > 0 && !isBalanceFeeOverrode){ + setIsOverride(false) + setOutstandingBalanceModal(false) + } + else{ + setModalOpen(false); + setMessageModalOpen(false); + } setSelectedPageFlagId(null); setSelectedSections([]); setSaveDisabled(true); @@ -2271,7 +2283,12 @@ const Redlining = React.forwardRef( const cancelSaveRedlineDoc = () => { disableNRDuplicate(); - setRedlineModalOpen(false); + if(outstandingBalance > 0 && !isBalanceFeeOverrode){ + setOutstandingBalanceModal(false) + setIsOverride(false) + } + else + setRedlineModalOpen(false); }; const handleIncludeNRPages = (e) => { @@ -2283,6 +2300,9 @@ const Redlining = React.forwardRef( }; const saveDoc = () => { + console.log("Inside saveDoc!") + setIsOverride(false) + setOutstandingBalanceModal(false) setRedlineModalOpen(false); setRedlineSaving(true); let modalFor= modalData? modalData.modalFor : "" @@ -2309,7 +2329,8 @@ const Redlining = React.forwardRef( documentList, pageMappedDocs, pageFlags, - requestType + requestType, + feeOverrideReason ); break; default: From 203d0f07eb566461dfd8d54e3509ed46e6bf59bc Mon Sep 17 00:00:00 2001 From: Aparna Date: Mon, 10 Jun 2024 15:31:24 -0700 Subject: [PATCH 54/89] Removed debug codes and updated changes from code review --- api/reviewer_api/services/jobrecordservice.py | 7 +------ api/reviewer_api/services/radactionservice.py | 20 +++++-------------- web/src/components/FOI/Home/Redlining.js | 1 - 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/api/reviewer_api/services/jobrecordservice.py b/api/reviewer_api/services/jobrecordservice.py index 863a1e03b..09a74039e 100644 --- a/api/reviewer_api/services/jobrecordservice.py +++ b/api/reviewer_api/services/jobrecordservice.py @@ -141,13 +141,8 @@ def insertfeeoverridereason(self, message, pdfstitchjobid, userid): ) job = PDFStitchJobAttributes.insert(row) return job - - def __getpdfstitchjobattributesbyid(self, requestid): - job = PDFStitchJobAttributes().getpdfstitchjobattributesbyid(requestid) - return job def isbalancefeeoverrodforrequest(self, requestid): - pdfstitchjobattributes= self.__getpdfstitchjobattributesbyid(requestid) + pdfstitchjobattributes= PDFStitchJobAttributes().getpdfstitchjobattributesbyid(requestid) isbalancefeeoverrode= False if pdfstitchjobattributes is None or not pdfstitchjobattributes else True - #print("\nisbalancefeeoverrode:",isbalancefeeoverrode) return isbalancefeeoverrode diff --git a/api/reviewer_api/services/radactionservice.py b/api/reviewer_api/services/radactionservice.py index 5253b8972..2ec5b88d8 100644 --- a/api/reviewer_api/services/radactionservice.py +++ b/api/reviewer_api/services/radactionservice.py @@ -123,16 +123,12 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): job = jobrecordservice().insertpdfstitchjobstatus( _jobmessage, userinfo["userid"] ) - print("job:: ",job.message) - print("job-2:: ",job.identifier) if job.success: if finalpackageschema['pdfstitchjobattributes'] is not None: - feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] - print("feeoverridereason:",feeoverridereason) - if feeoverridereason is not None and feeoverridereason != '': - feeoverridereasonresult= jobrecordservice().insertfeeoverridereason(finalpackageschema,job.identifier,userinfo["userid"]) - #print("feeoverridereasonresult:",feeoverridereasonresult) - #Add here the reason- comment text and a boolean + if 'feeoverridereason' in finalpackageschema['pdfstitchjobattributes']: + feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] + if feeoverridereason is not None and feeoverridereason != '': + jobrecordservice().insertfeeoverridereason(finalpackageschema,job.identifier,userinfo["userid"]) _message = self.__preparemessageforsummaryservice( finalpackageschema, userinfo, job ) @@ -140,17 +136,12 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): # redline/final package download: prepare message for zipping service def __preparemessageforsummaryservice(self, messageschema, userinfo, job): + feeoverridereason= None pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) - print("pdf_stitch_job_attributes:",pdf_stitch_job_attributes) if pdf_stitch_job_attributes is not None: feeoverridereason= json.loads(pdf_stitch_job_attributes).get("feeoverridereason", None) if feeoverridereason is not None and feeoverridereason != '': feeoverridereason= userinfo["firstname"]+" "+userinfo["lastname"]+" overrode balance outstanding warning for the following reason: "+feeoverridereason - print("feeoverridereason:",feeoverridereason) - else: - feeoverridereason= "" - else: - feeoverridereason= "" _message = { "jobid": job.identifier, "requestid": -1, @@ -169,7 +160,6 @@ def __preparemessageforsummaryservice(self, messageschema, userinfo, job): "requesttype": messageschema["requesttype"], "feeoverridereason":feeoverridereason } - print("_message:",_message) return _message # redline/final package download: prepare message for zipping service diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 5b1a398d2..f0b47f2e4 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -2300,7 +2300,6 @@ const Redlining = React.forwardRef( }; const saveDoc = () => { - console.log("Inside saveDoc!") setIsOverride(false) setOutstandingBalanceModal(false) setRedlineModalOpen(false); From 5b33f0d1c00624c773b9b5a314a22b61a8f01ec9 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 11 Jun 2024 21:53:08 -0700 Subject: [PATCH 55/89] Fetching & displaying balance due amount added --- api/reviewer_api/resources/document.py | 5 +++++ web/src/components/FOI/Home/Home.js | 3 +++ web/src/components/FOI/Home/Redlining.js | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index e5f02d134..d308cdbac 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -123,11 +123,16 @@ def get(requestid): response.raise_for_status() # get request status jsonobj = response.json() + print("jsonobj:", jsonobj) balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) + outstandingbalance=0 + if 'cfrfee' in jsonobj and 'feedata' in jsonobj['cfrfee'] and "balanceDue" in jsonobj['cfrfee']['feedata']: + outstandingbalance= jsonobj['cfrfee']['feedata']["balanceDue"] requestinfo = { "bcgovcode": jsonobj["bcgovcode"], "requesttype": jsonobj["requestType"], "validoipcreviewlayer": documentservice().validate_oipcreviewlayer(jsonobj, requestid), + "outstandingbalance": outstandingbalance, "balancefeeoverrodforrequest": balancefeeoverrodforrequest } documentdivisionslist,result = documentservice().getdocuments(requestid, requestinfo["bcgovcode"]) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index 9bea587a7..c9e21eccd 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -46,6 +46,7 @@ function Home() { const [divisions, setDivisions] = useState([]); const [pageFlags, setPageFlags]= useState([]); const [isBalanceFeeOverrode , setIsBalanceFeeOverrode] = useState(false); + const [outstandingBalance, setOutstandingBalance]= useState(0) const redliningRef = useRef(); const selectorRef = useRef(); @@ -69,6 +70,7 @@ function Home() { parseInt(foiministryrequestid), async (data, documentDivisions, _requestInfo) => { setDivisions(documentDivisions); + setOutstandingBalance(outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") @@ -304,6 +306,7 @@ function Home() { pageFlags={pageFlags} syncPageFlagsOnAction={syncPageFlagsOnAction} isBalanceFeeOverrode={isBalanceFeeOverrode} + outstandingBalance={outstandingBalance} /> ) // :
Loading
diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index f0b47f2e4..69f4d11cf 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -82,7 +82,8 @@ const Redlining = React.forwardRef( scrollLeftPanel, pageFlags, syncPageFlagsOnAction, - isBalanceFeeOverrode + isBalanceFeeOverrode, + outstandingBalance }, ref ) => { @@ -143,7 +144,6 @@ const Redlining = React.forwardRef( const [isDisableNRDuplicate, setIsDisableNRDuplicate] = useState(false); const [pageSelectionsContainNRDup, setPageSelectionsContainNRDup] = useState(false); const [outstandingBalanceModal, setOutstandingBalanceModal] = useState(false); - const [outstandingBalance, setOutstandingBalance]= useState(1) const [isOverride, setIsOverride]= useState(false); const [feeOverrideReason, setFeeOverrideReason]= useState(""); From 064e9fe13438534fe6fd85404e6d9fdca173b62a Mon Sep 17 00:00:00 2001 From: Aparna <71481254+aparna-aot@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:54:41 -0700 Subject: [PATCH 56/89] Merge pull request #1011 from bcgov/dev-AS-FOIMOD-3073 Fetching & displaying balance due amount added From 4b165bce3838eff95b8a2cad59330e9bbce09fb4 Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 14:08:44 -0700 Subject: [PATCH 57/89] Missing field added in summary --- .../rstreamio/message/schemas/redactionsummary.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py b/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py index c981780ec..71877038a 100644 --- a/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py +++ b/computingservices/DocumentServices/rstreamio/message/schemas/redactionsummary.py @@ -30,7 +30,7 @@ def __init__(self, sorteddocuments, pkgdocuments) -> None: class RedactionSummaryMessage(object): def __init__(self, jobid, requestid, ministryrequestid, category, requestnumber, - bcgovcode, createdby, filestozip, finaloutput, attributes, summarydocuments ,redactionlayerid,requesttype) -> None: + bcgovcode, createdby, filestozip, finaloutput, attributes, summarydocuments ,redactionlayerid, requesttype, feeoverridereason) -> None: self.jobid = jobid self.requestid = requestid self.ministryrequestid = ministryrequestid @@ -44,6 +44,7 @@ def __init__(self, jobid, requestid, ministryrequestid, category, requestnumber, self.summarydocuments = summarydocuments self.redactionlayerid = redactionlayerid self.requesttype = requesttype + self.feeoverridereason = feeoverridereason def get_in_redactionsummary_msg(producer_json): From 81b46b1a98b23d140f2295b3027bb480fd5eb16d Mon Sep 17 00:00:00 2001 From: Aparna <71481254+aparna-aot@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:20:56 -0700 Subject: [PATCH 58/89] Merge pull request #1016 from bcgov/dev-AS-FOIMOD-3073 Missing field added in summary From 0581e42f72758cfd94764d613918128d42cff86b Mon Sep 17 00:00:00 2001 From: Aparna <71481254+aparna-aot@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:35:17 -0700 Subject: [PATCH 59/89] Merge pull request #1023 from bcgov/test-marshal-AH-3073 Ticket 3073: triggerdownloadredline bug fixes --- api/reviewer_api/services/radactionservice.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/reviewer_api/services/radactionservice.py b/api/reviewer_api/services/radactionservice.py index 2ec5b88d8..47fe31538 100644 --- a/api/reviewer_api/services/radactionservice.py +++ b/api/reviewer_api/services/radactionservice.py @@ -124,7 +124,7 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): _jobmessage, userinfo["userid"] ) if job.success: - if finalpackageschema['pdfstitchjobattributes'] is not None: + if 'pdfstitchjobattributes' in finalpackageschema and finalpackageschema['pdfstitchjobattributes'] is not None: if 'feeoverridereason' in finalpackageschema['pdfstitchjobattributes']: feeoverridereason= finalpackageschema['pdfstitchjobattributes']['feeoverridereason'] if feeoverridereason is not None and feeoverridereason != '': @@ -136,8 +136,10 @@ def triggerdownloadredlinefinalpackage(self, finalpackageschema, userinfo): # redline/final package download: prepare message for zipping service def __preparemessageforsummaryservice(self, messageschema, userinfo, job): - feeoverridereason= None - pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) + feeoverridereason= '' + pdf_stitch_job_attributes = None + if 'pdfstitchjobattributes' in messageschema: + pdf_stitch_job_attributes = to_json(messageschema['pdfstitchjobattributes']) if pdf_stitch_job_attributes is not None: feeoverridereason= json.loads(pdf_stitch_job_attributes).get("feeoverridereason", None) if feeoverridereason is not None and feeoverridereason != '': From 76d0fe3ec06b4b007e2f583337485f3ff72e7a90 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 14 Jun 2024 16:23:33 -0700 Subject: [PATCH 60/89] small bug fixes added to this logic with Aparna to adjust redline creation From e429237fdf9623ca7b17ba2c6b1e2371d3238da5 Mon Sep 17 00:00:00 2001 From: Aparna <71481254+aparna-aot@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:19:25 -0700 Subject: [PATCH 61/89] Merge pull request #1127 from bcgov/test-marshal-AS-FOIMOD-3073-merge-fixes FOIMOD-3073- Fees - Remaining Balance Check- Merge issues solved --- .../CreateResponsePDF/CreateResponsePDF.js | 76 ++++++++++++------- .../useSaveResponsePackage.js | 7 +- web/src/components/FOI/Home/Redlining.js | 7 +- 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js index e1d6feff3..60675d0c1 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/CreateResponsePDF.js @@ -124,35 +124,55 @@ export const handleRedlineForOipcClick = ( export const handleFinalPackageClick = ( updateModalData, - setRedlineModalOpen + setRedlineModalOpen, + outstandingBalance, + isBalanceFeeOverrode, + setOutstandingBalanceModal, + setIsOverride ) => { - updateModalData({ - modalFor: "responsepackage", - modalTitle: "Create Package for Applicant", - modalMessage: [ - "This should only be done when all redactions are finalized and ready to ", - - be - , - " sent to the ", - - Applicant - , - ". This will ", - - permanently - , - " apply the redactions and automatically create page stamps.", -
, -
, - - When you create the response package, your web browser page - will automatically refresh - , - ], - modalButtonLabel: "Create Applicant Package" - }); - setRedlineModalOpen(true); + + if(outstandingBalance > 0 && !isBalanceFeeOverrode){ + updateModalData({ + modalFor: "responsepackage", + modalTitle: "Create Package for Applicant", + modalMessage:[ + "There is an outstanding balance of fees, please cancel to resolve, or click override to proceed", + ], + modalButtonLabel: "Override" + }); + setOutstandingBalanceModal(true); + setIsOverride(false) + } + else{ + // Download + updateModalData({ + modalFor: "responsepackage", + modalTitle: "Create Package for Applicant", + modalMessage: [ + "This should only be done when all redactions are finalized and ready to ", + + be + , + " sent to the ", + + Applicant + , + ". This will ", + + permanently + , + " apply the redactions and automatically create page stamps.", +
, +
, + + When you create the response package, your web browser page + will automatically refresh + , + ], + modalButtonLabel: "Create Applicant Package" + }); + setRedlineModalOpen(true); + } }; export const isReadyForSignOff = (documentList, pageFlags) => { diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js index aeb885798..665b75216 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveResponsePackage.js @@ -217,7 +217,8 @@ const useSaveResponsePackage = () => { documentList, pageMappedDocs, pageFlags, - requestType + requestType, + feeOverrideReason ) => { const downloadType = "pdf"; let zipServiceMessage = { @@ -228,7 +229,8 @@ const useSaveResponsePackage = () => { bcgovcode: "", summarydocuments: {} , redactionlayerid: currentLayer.redactionlayerid, - requesttype: requestType + requesttype: requestType, + pdfstitchjobattributes:{"feeoverridereason":""} }; getResponsePackagePreSignedUrl( foiministryrequestid, @@ -238,6 +240,7 @@ const useSaveResponsePackage = () => { zipServiceMessage.requestnumber = res.requestnumber; zipServiceMessage.bcgovcode = res.bcgovcode; zipServiceMessage.summarydocuments= prepareresponseredlinesummarylist(documentList,zipServiceMessage.bcgovcode, requestType) + zipServiceMessage.pdfstitchjobattributes= {"feeoverridereason":feeOverrideReason} let annotList = annotationManager.getAnnotationsList(); annotationManager.ungroupAnnotations(annotList); /** remove duplicate and not responsive pages */ diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 69f4d11cf..45c93d64f 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -224,7 +224,8 @@ const Redlining = React.forwardRef( handleRedlineForSignOffClick(updateModalData, setRedlineModalOpen); }; finalPackageBtn.onclick = () => { - handleFinalPackageClick(updateModalData, setRedlineModalOpen); + handleFinalPackageClick(updateModalData, setRedlineModalOpen, outstandingBalance, + isBalanceFeeOverrode,setOutstandingBalanceModal,setIsOverride); }; menu.appendChild(redlineForOipcBtn); menu.appendChild(redlineForSignOffBtn); @@ -2283,6 +2284,10 @@ const Redlining = React.forwardRef( const cancelSaveRedlineDoc = () => { disableNRDuplicate(); + setRedlineModalOpen(false); + setSelectedPublicBodyIDs([]); + setConsultApplyRedactions(false); + setConsultApplyRedlines(false); if(outstandingBalance > 0 && !isBalanceFeeOverrode){ setOutstandingBalanceModal(false) setIsOverride(false) From df4b9228f21955968bdb72e93ca1eece8d3e7ffc Mon Sep 17 00:00:00 2001 From: Aparna Date: Wed, 12 Jun 2024 15:31:11 -0700 Subject: [PATCH 62/89] Issue fixed in migration script --- api/migrations/versions/9d45ce57481e_.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/migrations/versions/9d45ce57481e_.py b/api/migrations/versions/9d45ce57481e_.py index 25bda2114..03e94fea5 100644 --- a/api/migrations/versions/9d45ce57481e_.py +++ b/api/migrations/versions/9d45ce57481e_.py @@ -19,7 +19,7 @@ def upgrade(): op.create_table('PDFStitchJobAttributes', sa.Column('attributesid', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('pdfstitchjobid', sa.Integer(), primary_key=True, autoincrement=True, nullable=False), + sa.Column('pdfstitchjobid', sa.Integer(), nullable=False), sa.Column('version', sa.Integer(), nullable=False), sa.Column('ministryrequestid', sa.Integer(), nullable=False), sa.Column('attributes', postgresql.JSON(astext_type=sa.Text()), nullable=False), From 27ca3c7f5356493232b2e02c6737ca31d02a8b44 Mon Sep 17 00:00:00 2001 From: Aparna <71481254+aparna-aot@users.noreply.github.com> Date: Wed, 12 Jun 2024 15:37:04 -0700 Subject: [PATCH 63/89] Merge pull request #1017 from bcgov/dev-AS-FOIMOD-3073 Issue fixed in migration script From 253677b17ac91b115f3da6b7209389dd0c078455 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 13:52:16 -0700 Subject: [PATCH 64/89] refactored feeoverride modal to its own component --- .../components/FOI/Home/FeeOverrideModal.jsx | 94 +++++++++++++++++++ web/src/components/FOI/Home/Redlining.js | 12 +++ 2 files changed, 106 insertions(+) create mode 100644 web/src/components/FOI/Home/FeeOverrideModal.jsx diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx new file mode 100644 index 000000000..db1341bbd --- /dev/null +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -0,0 +1,94 @@ +import ReactModal from "react-modal-resizable-draggable"; +import DialogActions from "@mui/material/DialogActions"; +import DialogContent from "@mui/material/DialogContent"; +import DialogContentText from "@mui/material/DialogContentText"; +import DialogTitle from "@mui/material/DialogTitle"; +import CloseIcon from "@mui/icons-material/Close"; +import IconButton from "@mui/material/IconButton"; + +const FeeOverrideModal = ({ + modalData, + cancelRedaction, + outstandingBalanceModal, + cancelSaveRedlineDoc, + isOverride, + feeOverrideReason, + handleOverrideReasonChange, + saveDoc, + overrideOutstandingBalance, +}) => { + return ( + <> + + +

{modalData?.modalTitle}

+ + Close + + +
+ + + + {modalData?.modalMessage} + {isOverride && ( + <> +
+
+ + + + )} +
+
+
+ + {!isOverride && ( + + )} + {isOverride && ( + + )} + + +
+ + ); +}; + +export default FeeOverrideModal; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 45c93d64f..ca92ac940 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -65,6 +65,7 @@ import useSaveResponsePackage from "./CreateResponsePDF/useSaveResponsePackage"; import {ConfirmationModal} from "./ConfirmationModal"; import { FOIPPASectionsModal } from "./FOIPPASectionsModal"; import { NRWarningModal } from "./NRWarningModal"; +import FeeOverrideModal from "./FeeOverrideModal"; const Redlining = React.forwardRef( ( @@ -2434,6 +2435,17 @@ const Redlining = React.forwardRef( modalData={modalData} /> } +
); } From e4a2efce2ba36c399494757512e5238e4d31d75b Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 12 Aug 2024 14:12:20 -0700 Subject: [PATCH 65/89] Small code clean --- .../components/FOI/Home/FeeOverrideModal.jsx | 130 +++++++++--------- 1 file changed, 63 insertions(+), 67 deletions(-) diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx index db1341bbd..a64862710 100644 --- a/web/src/components/FOI/Home/FeeOverrideModal.jsx +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -18,76 +18,72 @@ const FeeOverrideModal = ({ overrideOutstandingBalance, }) => { return ( - <> - - -

{modalData?.modalTitle}

- - Close - - -
- - - - {modalData?.modalMessage} - {isOverride && ( - <> -
-
- - - - )} -
-
-
- - {!isOverride && ( - - )} - {isOverride && ( - - )} + + +

{modalData?.modalTitle}

+ + Close + + +
+ + + + {modalData?.modalMessage} + {isOverride && ( + <> +
+
+ + + + )} +
+
+
+ + {!isOverride && ( + )} + {isOverride && ( + - -
- + )} + +
+
); }; From fe4b4293eefc981735a9e729253aee90790193c6 Mon Sep 17 00:00:00 2001 From: Milos Despotovic Date: Wed, 18 Sep 2024 09:53:44 -0700 Subject: [PATCH 66/89] Disable button if there is no text --- web/src/components/FOI/Home/FeeOverrideModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/FeeOverrideModal.jsx b/web/src/components/FOI/Home/FeeOverrideModal.jsx index a64862710..379a78a3d 100644 --- a/web/src/components/FOI/Home/FeeOverrideModal.jsx +++ b/web/src/components/FOI/Home/FeeOverrideModal.jsx @@ -72,7 +72,7 @@ const FeeOverrideModal = ({ )} {isOverride && ( - )} From a78239ed66883f907d38f948d502a38905d3e912 Mon Sep 17 00:00:00 2001 From: Aparna Date: Fri, 4 Oct 2024 15:09:47 -0700 Subject: [PATCH 67/89] Adding More commits which are missed in between --- api/reviewer_api/resources/document.py | 3 ++- api/reviewer_api/schemas/finalpackage.py | 1 + web/src/components/FOI/Home/Home.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index d308cdbac..11abdc4a0 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -127,7 +127,8 @@ def get(requestid): balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) outstandingbalance=0 if 'cfrfee' in jsonobj and 'feedata' in jsonobj['cfrfee'] and "balanceDue" in jsonobj['cfrfee']['feedata']: - outstandingbalance= jsonobj['cfrfee']['feedata']["balanceDue"] + outstandingbalancestr= jsonobj['cfrfee']['feedata']["balanceDue"] + outstandingbalance = float(outstandingbalancestr) requestinfo = { "bcgovcode": jsonobj["bcgovcode"], "requesttype": jsonobj["requestType"], diff --git a/api/reviewer_api/schemas/finalpackage.py b/api/reviewer_api/schemas/finalpackage.py index 0ad45bf4d..a946fbd2a 100644 --- a/api/reviewer_api/schemas/finalpackage.py +++ b/api/reviewer_api/schemas/finalpackage.py @@ -33,6 +33,7 @@ class FinalPackageSchema(Schema): summarydocuments = fields.Nested(SummarySchema, allow_none=True) redactionlayerid = fields.Int(data_key="redactionlayerid", allow_none=False) requesttype = fields.Str(data_key="requesttype", allow_none=False) + pdfstitchjobattributes = fields.Nested(FeeOverrideSchema, allow_none=True, many=False) class SummaryRecordSchema(Schema): recordname = fields.Str(data_key="recordname", allow_none=True) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index c9e21eccd..caa095d9e 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -70,7 +70,7 @@ function Home() { parseInt(foiministryrequestid), async (data, documentDivisions, _requestInfo) => { setDivisions(documentDivisions); - setOutstandingBalance(outstandingbalance) + setOutstandingBalance(data.requestinfo.outstandingbalance) setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") From 928e72c731e1a20d0bd52a089fe2e0652afcac2d Mon Sep 17 00:00:00 2001 From: Aparna Date: Fri, 4 Oct 2024 16:35:52 -0700 Subject: [PATCH 68/89] FOIMOD-3073-Fees - Remaining Balance Check - Fixed some more Merge issues Fixed some more Merge issue --- web/src/components/FOI/Home/Home.js | 12 ++++++------ web/src/components/FOI/Home/Redlining.js | 10 +++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/web/src/components/FOI/Home/Home.js b/web/src/components/FOI/Home/Home.js index caa095d9e..b67c7f48d 100644 --- a/web/src/components/FOI/Home/Home.js +++ b/web/src/components/FOI/Home/Home.js @@ -68,19 +68,19 @@ function Home() { fetchDocuments( parseInt(foiministryrequestid), - async (data, documentDivisions, _requestInfo) => { + async (documents, documentDivisions, _requestInfo) => { setDivisions(documentDivisions); - setOutstandingBalance(data.requestinfo.outstandingbalance) - setIsBalanceFeeOverrode(data.requestinfo.balancefeeoverrodforrequest) + setOutstandingBalance(_requestInfo.outstandingbalance) + setIsBalanceFeeOverrode(_requestInfo.balancefeeoverrodforrequest) const getFileExt = (filepath) => { const parts = filepath.split(".") const fileExt = parts.pop() return fileExt } // New code added to get the incompatable files for download redline - // data has all the files including incompatable ones + // documents has all the files including incompatable ones // _files has all files except incompatable ones - const _incompatableFiles = data.documents.filter( + const _incompatableFiles = documents.filter( (d) => { const isPdfFile = getFileExt(d.filepath) === "pdf" if (isPdfFile) { @@ -91,7 +91,7 @@ function Home() { } ); setIncompatibleFiles(_incompatableFiles); - const _files = data.documents.filter((d) => { + const _files = documents.filter((d) => { const isPdfFile = getFileExt(d.filepath) === "pdf" const isCompatible = !d.attributes.incompatible || isPdfFile return isCompatible diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index ca92ac940..bc37838c5 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -2286,9 +2286,6 @@ const Redlining = React.forwardRef( const cancelSaveRedlineDoc = () => { disableNRDuplicate(); setRedlineModalOpen(false); - setSelectedPublicBodyIDs([]); - setConsultApplyRedactions(false); - setConsultApplyRedlines(false); if(outstandingBalance > 0 && !isBalanceFeeOverrode){ setOutstandingBalanceModal(false) setIsOverride(false) @@ -2392,6 +2389,13 @@ const Redlining = React.forwardRef( return isDisabled } + const overrideOutstandingBalance = () => { + setIsOverride(true) + } + const handleOverrideReasonChange = (event) => { + setFeeOverrideReason(event.target.value); + }; + return (
From 43edf54a47d1c8779504a3f4205f96217c707f90 Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Mon, 7 Oct 2024 10:31:52 -0700 Subject: [PATCH 69/89] bug fix - missing page stamps --- .../useSaveRedlineForSignOff.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index b35bcab3d..45d143b7c 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1491,13 +1491,6 @@ const stampPageNumberRedline = async ( let doc = docViewer.getDocument(); await annotationManager.applyRedactions(s14annots); - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1519,7 +1512,14 @@ const stampPageNumberRedline = async ( /**must apply redactions before removing pages*/ if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); docObj.getFileData({ // saves the document with annotations in it From 8b1f7619ac338d36b28d12271f30b09a63142225 Mon Sep 17 00:00:00 2001 From: Aparna Date: Tue, 8 Oct 2024 10:32:20 -0700 Subject: [PATCH 70/89] Removed print statement --- api/reviewer_api/resources/document.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/reviewer_api/resources/document.py b/api/reviewer_api/resources/document.py index 11abdc4a0..f73f626ed 100644 --- a/api/reviewer_api/resources/document.py +++ b/api/reviewer_api/resources/document.py @@ -123,7 +123,6 @@ def get(requestid): response.raise_for_status() # get request status jsonobj = response.json() - print("jsonobj:", jsonobj) balancefeeoverrodforrequest = jobrecordservice().isbalancefeeoverrodforrequest(requestid) outstandingbalance=0 if 'cfrfee' in jsonobj and 'feedata' in jsonobj['cfrfee'] and "balanceDue" in jsonobj['cfrfee']['feedata']: From 2df3cc485ab1731692c867165145e4e20029e336 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Tue, 15 Oct 2024 13:23:56 -0700 Subject: [PATCH 71/89] manual redline chnages for pr 1185 + 1183 --- .../useSaveRedlineForSignOff.js | 266 +++++++++++++----- 1 file changed, 192 insertions(+), 74 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index e98cd1b03..0335b8b39 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -861,7 +861,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }).then(async (docObj) => { // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - // applyRotations(docObj, doc.attributes.rotatedpages) + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; @@ -1771,41 +1771,16 @@ const stampPageNumberRedline = async ( } } }; - const applyRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { let annotationManager = docInstance?.Core.annotationManager; - const rarr = []; - let rects = []; + let annots = []; for (const [key, value] of Object.entries(appliedSectionStamps)) { let sectionAnnotation = annotationManager.getAnnotationById(key); - if (sectionAnnotation.Subject === "Redact") { - rects = rects.concat( - sectionAnnotation.getQuads().map((q) => { - return { - pageno: appliedSectionStamps[key], - recto: q.toRect(), - vpageno: sectionAnnotation.getPageNumber() - }; - }) - ); - } - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = stitchObject?.getPageRotation(rect.pageno); - let pageWidth = docViewer.getPageWidth(rect.vpageno); - /**Fix for oipc redline displaying s.14 marked page content partially */ - let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); - //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); + if (sectionAnnotation.Subject === "Redact") { + annots.push(sectionAnnotation); + } } + await annotationManager.applyRedactions(annots); } //useEffects to keep docInstance and docViewer state up to date with Redlining.js @@ -1846,7 +1821,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1872,6 +1847,8 @@ const stampPageNumberRedline = async ( } let string = await stitchObject.extractXFDF(); + + // for redline - formatted annots let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1880,35 +1857,202 @@ const stampPageNumberRedline = async ( } else { xmlObj.children.push(annots); } - let xfdfString = parser.toString(xmlObj); + + // for oipc review + consults - re-apply annots after redaction - annots only no widgets/form fields + let xmlObj1 = parser.parseFromString(string.xfdfString); + xmlObj1.children = []; + xmlObj1.children.push(annots); + let xfdfString1 = parser.toString(xmlObj1); //Apply Redactions (if any) //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(s14_sectionStamps, PDFNet, stitchObject); - await stampPageNumberRedline( - stitchObject, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); + let doc = docViewer.getDocument(); + await applyRedactionsToRedlinesBySection(s14_sectionStamps); + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Redline PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); + }); + }); } //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(redlineCategory === "consult") { if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { return annot.name !== "freetext" && annot.name !== 'redact' }); - xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString = parser.toString(xmlObj); + xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + let doc = docViewer.getDocument(); + await applyRedactionsToRedlinesBySection(nr_sectionStamps); + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Consult PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); + }); + }); } } //Consults - Redlines + Redactions (Redact S.NR) Block : End @@ -1922,6 +2066,7 @@ const stampPageNumberRedline = async ( // } // } + else { stitchObject .getFileData({ // saves the document with annotations in it @@ -1941,7 +2086,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, + render: `Redline PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -1976,6 +2121,7 @@ const stampPageNumberRedline = async ( } ); }); + } } } }; @@ -1999,34 +2145,6 @@ const stampPageNumberRedline = async ( // } // } // } - - const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { - let x1 = recto.x1; - let y1 = recto.y1; - let x2 = recto.x2; - let y2 = recto.y2; - // Adjust Y-coordinates to account for the flipped Y-axis in PDF - y1 = pageHeight - y1; - y2 = pageHeight - y2; - // Adjust for page rotation (90, 180, 270 degrees) - switch (pageRotation) { - case 90: - [x1, y1] = [y1, x1]; - [x2, y2] = [y2, x2]; - break; - case 180: - x1 = pageWidth - x1; - y1 = pageHeight - y1; - x2 = pageWidth - x2; - y2 = pageHeight - y2; - break; - case 270: - [x1, y1] = [pageHeight - y1, x1]; - [x2, y2] = [pageHeight - y2, x2]; - break; - } - return await PDFNet.Rect.init(x1, y1, x2, y2); - } useEffect(() => { if ( From 4186ccf53b118f8053d6383be3d38cb944b0c4e7 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 16 Oct 2024 10:30:03 -0700 Subject: [PATCH 72/89] adjustments to consults --- .../services/docReviewerService.tsx | 2 +- .../useSaveRedlineForSignOff.js | 169 +++++++++--------- 2 files changed, 88 insertions(+), 83 deletions(-) diff --git a/web/src/apiManager/services/docReviewerService.tsx b/web/src/apiManager/services/docReviewerService.tsx index 1e309edb3..7c1813378 100644 --- a/web/src/apiManager/services/docReviewerService.tsx +++ b/web/src/apiManager/services/docReviewerService.tsx @@ -36,7 +36,7 @@ export const fetchDocuments = ( store.dispatch(setRequestNumber(res.data.requestnumber) as any); store.dispatch(setRequestStatus(res.data.requeststatuslabel) as any); store.dispatch(setRequestInfo(res.data.requestinfo) as any); - callback(res.data); + callback(res.data.documents, res.data.documentdivisions, res.data.requestinfo); } else { throw new Error(); } diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 3dc642153..353a2933f 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1838,7 +1838,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline" || redlineCategory === "consult") { + if (redlineCategory === "redline") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1957,6 +1957,7 @@ const stampPageNumberRedline = async ( //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start if(redlineCategory === "consult") { + let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { @@ -1967,92 +1968,96 @@ const stampPageNumberRedline = async ( } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - let doc = docViewer.getDocument(); await applyRedactionsToRedlinesBySection(nr_sectionStamps); - /** apply redaction and save to s3 - newXfdfString is needed to display - * the freetext(section name) on downloaded file.*/ - doc - .getFileData({ - // export the document to arraybuffer - // xfdfString: xfdfString, - downloadType: downloadType, - flatten: true, - }) - .then(async (_data) => { - const _arr = new Uint8Array(_data); - const _blob = new Blob([_arr], { type: "application/pdf" }); - - await docInstance?.Core.createDocument(_data, { - loadAsPDF: true, - useDownloader: false, // Added to fix BLANK page issue - }).then( async (docObj) => { - - /**must apply redactions before removing pages*/ - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } + } + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); - await stampPageNumberRedline( - docObj, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { - docObj.getFileData({ - // saves the document with annotations in it - xfdfString: xfdfString1, - downloadType: downloadType, - flatten: true, - }) - .then(async (__data) => { - const __arr = new Uint8Array(__data); - const __blob = new Blob([__arr], { type: "application/pdf" }); - - saveFilesinS3( - { filepath: redlineStitchInfo[divisionid]["s3path"] }, - __blob, - (_res) => { - // ######### call another process for zipping and generate download here ########## - toast.update(toastId.current, { - render: `Consult PDF saved to Object Storage`, - type: "success", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - triggerRedlineZipper( - redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], - divisionCountForToast, - isSingleRedlinePackage - ); - }, - (_err) => { - console.log(_err); - toast.update(toastId.current, { - render: "Failed to save redline pdf to Object Storage", - type: "error", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - } - ); - }); + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + await addWatermarkToRedline( + docObj, + redlineWatermarkPageMapping, + key + ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Consult PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); }); }); - } + }); } //Consults - Redlines + Redactions (Redact S.NR) Block : End From 1c04c01daf6ccf3456c7bf6ba603f325129ca15a Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 16 Oct 2024 13:53:24 -0700 Subject: [PATCH 73/89] adjusted consults logic back to test-marshal / original code --- .../useSaveRedlineForSignOff.js | 216 ++++++++---------- 1 file changed, 95 insertions(+), 121 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 353a2933f..5960a7621 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -861,7 +861,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }).then(async (docObj) => { // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - applyRotations(docObj, doc.attributes.rotatedpages) + // applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; @@ -1771,7 +1771,7 @@ const stampPageNumberRedline = async ( } } }; - const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { + const applyS14RedactionsToRedlinesBySection = async (appliedSectionStamps) => { let annotationManager = docInstance?.Core.annotationManager; let annots = []; for (const [key, value] of Object.entries(appliedSectionStamps)) { @@ -1782,6 +1782,42 @@ const stampPageNumberRedline = async ( } await annotationManager.applyRedactions(annots); } + const applyNRRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { + let annotationManager = docInstance?.Core.annotationManager; + const rarr = []; + let rects = []; + for (const [key, value] of Object.entries(appliedSectionStamps)) { + let sectionAnnotation = annotationManager.getAnnotationById(key); + if (sectionAnnotation.Subject === "Redact") { + rects = rects.concat( + sectionAnnotation.getQuads().map((q) => { + return { + pageno: appliedSectionStamps[key], + recto: q.toRect(), + vpageno: sectionAnnotation.getPageNumber() + }; + }) + ); + } + } + for (const rect of rects) { + let height = docViewer.getPageHeight(rect.vpageno); + let pageRotation = stitchObject?.getPageRotation(rect.pageno); + let pageWidth = docViewer.getPageWidth(rect.vpageno); + /**Fix for consults redline displaying NR marked page content partially */ + let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); + //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); + rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); + } + if (rarr.length > 0) { + const app = {}; + app.redaction_overlay = true; + app.border = false; + app.show_redacted_content_regions = false; + const doc = await stitchObject.getPDFDoc(); + await PDFNet.Redactor.redact(doc, rarr, app); + } + } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1821,7 +1857,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1838,7 +1874,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline") { + if (redlineCategory === "redline" || redlineCategory === "consult") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1848,7 +1884,7 @@ const stampPageNumberRedline = async ( let string = await stitchObject.extractXFDF(); - // for redline - formatted annots + // for redline + consults - formatted annots let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1870,7 +1906,7 @@ const stampPageNumberRedline = async ( if(redlineCategory === "oipcreview") { let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); - await applyRedactionsToRedlinesBySection(s14_sectionStamps); + await applyS14RedactionsToRedlinesBySection(s14_sectionStamps); /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1955,122 +1991,32 @@ const stampPageNumberRedline = async ( }); } //OIPC - Special Block : End - //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { - let doc = docViewer.getDocument(); - if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; - const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { - return annot.name !== "freetext" && annot.name !== 'redact' - }); - xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString1 = parser.toString(xmlObj1); - } - if (consultApplyRedactions) { - let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps); - } - /** apply redaction and save to s3 - newXfdfString is needed to display - * the freetext(section name) on downloaded file.*/ - doc - .getFileData({ - // export the document to arraybuffer - // xfdfString: xfdfString, - downloadType: downloadType, - flatten: true, - }) - .then(async (_data) => { - const _arr = new Uint8Array(_data); - const _blob = new Blob([_arr], { type: "application/pdf" }); - - await docInstance?.Core.createDocument(_data, { - loadAsPDF: true, - useDownloader: false, // Added to fix BLANK page issue - }).then( async (docObj) => { - - /**must apply redactions before removing pages*/ - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } - - await stampPageNumberRedline( - docObj, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - await addWatermarkToRedline( - docObj, - redlineWatermarkPageMapping, - key - ); - - docObj.getFileData({ - // saves the document with annotations in it - xfdfString: xfdfString1, - downloadType: downloadType, - flatten: true, - }) - .then(async (__data) => { - const __arr = new Uint8Array(__data); - const __blob = new Blob([__arr], { type: "application/pdf" }); - - saveFilesinS3( - { filepath: redlineStitchInfo[divisionid]["s3path"] }, - __blob, - (_res) => { - // ######### call another process for zipping and generate download here ########## - toast.update(toastId.current, { - render: `Consult PDF saved to Object Storage`, - type: "success", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - triggerRedlineZipper( - redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], - divisionCountForToast, - isSingleRedlinePackage - ); - }, - (_err) => { - console.log(_err); - toast.update(toastId.current, { - render: "Failed to save redline pdf to Object Storage", - type: "error", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - } - ); - }); - }); + else { + //Consults - Redlines + Redactions (Redact S.NR) Block : Start + if(redlineCategory === "consult") { + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' }); + xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString = parser.toString(xmlObj); } - //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // for (const doc of totalStitchList[divisionid]) { - // let documentlist = totalStitchList[divisionid]; - // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - // if(documentlist.length > 0) { - // applyRotations(stitchObject, doc, divDocPageMappings); - // } - // } - - else { + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + await applyNRRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); + } + } + //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. + // for (const doc of totalStitchList[divisionid]) { + // let documentlist = totalStitchList[divisionid]; + // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + // if(documentlist.length > 0) { + // applyRotations(stitchObject, doc, divDocPageMappings); + // } + // } stitchObject .getFileData({ // saves the document with annotations in it @@ -2090,7 +2036,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, + render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -2149,6 +2095,34 @@ const stampPageNumberRedline = async ( // } // } // } + + const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { + let x1 = recto.x1; + let y1 = recto.y1; + let x2 = recto.x2; + let y2 = recto.y2; + // Adjust Y-coordinates to account for the flipped Y-axis in PDF + y1 = pageHeight - y1; + y2 = pageHeight - y2; + // Adjust for page rotation (90, 180, 270 degrees) + switch (pageRotation) { + case 90: + [x1, y1] = [y1, x1]; + [x2, y2] = [y2, x2]; + break; + case 180: + x1 = pageWidth - x1; + y1 = pageHeight - y1; + x2 = pageWidth - x2; + y2 = pageHeight - y2; + break; + case 270: + [x1, y1] = [pageHeight - y1, x1]; + [x2, y2] = [pageHeight - y2, x2]; + break; + } + return await PDFNet.Rect.init(x1, y1, x2, y2); + } useEffect(() => { if ( From 4076e86d18d8c4c96d800cd77c1e35c790ac6fec Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 16 Oct 2024 14:49:52 -0700 Subject: [PATCH 74/89] re-added new oipc logic to consults --- .../useSaveRedlineForSignOff.js | 227 ++++++++++-------- 1 file changed, 131 insertions(+), 96 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 5960a7621..37979dddb 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -861,7 +861,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }).then(async (docObj) => { // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - // applyRotations(docObj, doc.attributes.rotatedpages) + applyRotations(docObj, doc.attributes.rotatedpages) //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; @@ -1385,7 +1385,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - window.location.reload(); + // window.location.reload(); }); } return zipServiceMessage; @@ -1771,7 +1771,7 @@ const stampPageNumberRedline = async ( } } }; - const applyS14RedactionsToRedlinesBySection = async (appliedSectionStamps) => { + const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { let annotationManager = docInstance?.Core.annotationManager; let annots = []; for (const [key, value] of Object.entries(appliedSectionStamps)) { @@ -1782,42 +1782,6 @@ const stampPageNumberRedline = async ( } await annotationManager.applyRedactions(annots); } - const applyNRRedactionsToRedlinesBySection = async (appliedSectionStamps, PDFNet, stitchObject) => { - let annotationManager = docInstance?.Core.annotationManager; - const rarr = []; - let rects = []; - for (const [key, value] of Object.entries(appliedSectionStamps)) { - let sectionAnnotation = annotationManager.getAnnotationById(key); - if (sectionAnnotation.Subject === "Redact") { - rects = rects.concat( - sectionAnnotation.getQuads().map((q) => { - return { - pageno: appliedSectionStamps[key], - recto: q.toRect(), - vpageno: sectionAnnotation.getPageNumber() - }; - }) - ); - } - } - for (const rect of rects) { - let height = docViewer.getPageHeight(rect.vpageno); - let pageRotation = stitchObject?.getPageRotation(rect.pageno); - let pageWidth = docViewer.getPageWidth(rect.vpageno); - /**Fix for consults redline displaying NR marked page content partially */ - let adjustedRect = await getAdjustedRedactionCoordinates(pageRotation, rect.recto, PDFNet,pageWidth, height); - //rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, (await PDFNet.Rect.init(rect.recto.x1,height-rect.recto.y1,rect.recto.x2,height-rect.recto.y2)), false, '')); - rarr.push(await PDFNet.Redactor.redactionCreate(rect.pageno, adjustedRect, false, '')); - } - if (rarr.length > 0) { - const app = {}; - app.redaction_overlay = true; - app.border = false; - app.show_redacted_content_regions = false; - const doc = await stitchObject.getPDFDoc(); - await PDFNet.Redactor.redact(doc, rarr, app); - } - } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1857,7 +1821,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory === "consult") { + if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1870,11 +1834,12 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid].length > 0 && stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length ) { + console.log("REDLINE REMOVE", redlinepageMappings["pagestoremove"][divisionid]) await stitchObject.removePages( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline" || redlineCategory === "consult") { + if (redlineCategory === "redline") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1884,7 +1849,7 @@ const stampPageNumberRedline = async ( let string = await stitchObject.extractXFDF(); - // for redline + consults - formatted annots + // for redline - formatted annots let xmlObj = parser.parseFromString(string.xfdfString); let annots = parser.parseFromString('' + formattedAnnotationXML + ''); let annotsObj = xmlObj.getElementsByTagName('annots'); @@ -1906,7 +1871,8 @@ const stampPageNumberRedline = async ( if(redlineCategory === "oipcreview") { let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); - await applyS14RedactionsToRedlinesBySection(s14_sectionStamps); + await applyRedactionsToRedlinesBySection(s14_sectionStamps); + console.log("s14_sectionStamps", s14_sectionStamps) /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1991,32 +1957,129 @@ const stampPageNumberRedline = async ( }); } //OIPC - Special Block : End - else { - //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { - if (!consultApplyRedlines) { - const publicbodyAnnotList = xmlObj.getElementsByTagName('annots')[0]['children']; - const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { - return annot.name !== "freetext" && annot.name !== 'redact' + //Consults - Redlines + Redactions (Redact S.NR) Block : Start + if(redlineCategory === "consult") { + let doc = docViewer.getDocument(); + if (!consultApplyRedlines) { + const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; + console.log("publicbodyAnnotList", publicbodyAnnotList) + const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { + return annot.name !== "freetext" && annot.name !== 'redact' + }); + console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) + xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; + xfdfString1 = parser.toString(xmlObj1); + } + if (consultApplyRedactions) { + let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + console.log("nr_sectionStamps", nr_sectionStamps) + await applyRedactionsToRedlinesBySection(nr_sectionStamps); + } + /** apply redaction and save to s3 - newXfdfString is needed to display + * the freetext(section name) on downloaded file.*/ + doc + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + //LOOP HERE + // loop through each of the divisons/consults that exist, in the loop remove the pages that belong to other divisions find those pages to remove. which pages belong to other divisons + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + console.log("CONSULT REMOVE", redlinepageMappings["pagestoremove"][divisionid]) + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage + ); + // await addWatermarkToRedline( + // docObj, + // redlineWatermarkPageMapping, + // key + // ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Consult PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); + }); }); - xmlObj.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; - xfdfString = parser.toString(xmlObj); - } - if (consultApplyRedactions) { - let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyNRRedactionsToRedlinesBySection(nr_sectionStamps, PDFNet, stitchObject); } - } - //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // for (const doc of totalStitchList[divisionid]) { - // let documentlist = totalStitchList[divisionid]; - // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - // if(documentlist.length > 0) { - // applyRotations(stitchObject, doc, divDocPageMappings); - // } - // } + //Consults - Redlines + Redactions (Redact S.NR) Block : End + + // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. + // for (const doc of totalStitchList[divisionid]) { + // let documentlist = totalStitchList[divisionid]; + // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; + // if(documentlist.length > 0) { + // applyRotations(stitchObject, doc, divDocPageMappings); + // } + // } + + else { stitchObject .getFileData({ // saves the document with annotations in it @@ -2036,7 +2099,7 @@ const stampPageNumberRedline = async ( (_res) => { // ######### call another process for zipping and generate download here ########## toast.update(toastId.current, { - render: `${redlineCategory === "consult" ? "Consult" : "Redline"} PDF saved to Object Storage`, + render: `Redline PDF saved to Object Storage`, type: "success", className: "file-upload-toast", isLoading: false, @@ -2095,34 +2158,6 @@ const stampPageNumberRedline = async ( // } // } // } - - const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { - let x1 = recto.x1; - let y1 = recto.y1; - let x2 = recto.x2; - let y2 = recto.y2; - // Adjust Y-coordinates to account for the flipped Y-axis in PDF - y1 = pageHeight - y1; - y2 = pageHeight - y2; - // Adjust for page rotation (90, 180, 270 degrees) - switch (pageRotation) { - case 90: - [x1, y1] = [y1, x1]; - [x2, y2] = [y2, x2]; - break; - case 180: - x1 = pageWidth - x1; - y1 = pageHeight - y1; - x2 = pageWidth - x2; - y2 = pageHeight - y2; - break; - case 270: - [x1, y1] = [pageHeight - y1, x1]; - [x2, y2] = [pageHeight - y2, x2]; - break; - } - return await PDFNet.Rect.init(x1, y1, x2, y2); - } useEffect(() => { if ( From 99d932a842f4c36f33b8e00da0ec5cec32f7d396 Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Thu, 17 Oct 2024 14:07:06 -0700 Subject: [PATCH 75/89] remove pages from other division --- .../useSaveRedlineForSignOff.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 37979dddb..82b3ff638 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1796,6 +1796,30 @@ const stampPageNumberRedline = async ( const downloadType = "pdf"; let currentDivisionCount = 0; const divisionCountForToast = Object.keys(redlineStitchObject).length; + + let pagesOfEachDivisions = {}; + let pagesOfOtherDivisions = {}; + //get page numbers of each division + Object.keys(redlineStitchInfo).forEach((_div) => { + pagesOfEachDivisions[_div] = []; + redlineStitchInfo[_div]["stitchpages"].forEach((pageinfo) => { + pagesOfEachDivisions[_div].push(pageinfo["stitchedPageNo"]); + }); + }); + + //get page numbers that not belongs to the division + for (const [key, value] of Object.entries(pagesOfEachDivisions)) { + pagesOfOtherDivisions[key] = []; + for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { + if(_div !== key) { + pagesOfOtherDivisions[key] = [...new Set([...pagesOfOtherDivisions[key], ..._pageNumbers])]; + } + } + } + for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { + pagesOfOtherDivisions[_div] = pagesOfOtherDivisions[_div].filter((_pageNum) => {return !_pageNumbers.includes(_pageNum)}) + } + for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; toast.update(toastId.current, { @@ -1995,6 +2019,9 @@ const stampPageNumberRedline = async ( loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { + if (pagesOfOtherDivisions[key].length > 0) { + await docObj.removePages(pagesOfOtherDivisions[key]); + } /**must apply redactions before removing pages*/ console.log("CONSULT REMOVE", redlinepageMappings["pagestoremove"][divisionid]) From bb7528fdf7b52ca8f4e60d92c36d13b4ab7e70f1 Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Thu, 17 Oct 2024 15:17:12 -0700 Subject: [PATCH 76/89] bug fix --- .../useSaveRedlineForSignOff.js | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 82b3ff638..3aea348ed 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1798,7 +1798,7 @@ const stampPageNumberRedline = async ( const divisionCountForToast = Object.keys(redlineStitchObject).length; let pagesOfEachDivisions = {}; - let pagesOfOtherDivisions = {}; + // let pagesOfOtherDivisions = {}; //get page numbers of each division Object.keys(redlineStitchInfo).forEach((_div) => { pagesOfEachDivisions[_div] = []; @@ -1806,19 +1806,7 @@ const stampPageNumberRedline = async ( pagesOfEachDivisions[_div].push(pageinfo["stitchedPageNo"]); }); }); - - //get page numbers that not belongs to the division - for (const [key, value] of Object.entries(pagesOfEachDivisions)) { - pagesOfOtherDivisions[key] = []; - for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { - if(_div !== key) { - pagesOfOtherDivisions[key] = [...new Set([...pagesOfOtherDivisions[key], ..._pageNumbers])]; - } - } - } - for(const [_div, _pageNumbers] of Object.entries(pagesOfEachDivisions)) { - pagesOfOtherDivisions[_div] = pagesOfOtherDivisions[_div].filter((_pageNum) => {return !_pageNumbers.includes(_pageNum)}) - } + console.log("pagesOfEachDivisions: ", pagesOfEachDivisions); for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; @@ -2019,8 +2007,15 @@ const stampPageNumberRedline = async ( loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { - if (pagesOfOtherDivisions[key].length > 0) { - await docObj.removePages(pagesOfOtherDivisions[key]); + + let pagesNotBelongsToThisDivision = []; + for(let i=1; i <= docObj.getPageCount(); i++) { + if(!pagesOfEachDivisions[key].includes(i)) + pagesNotBelongsToThisDivision.push(i); + } + + if(pagesNotBelongsToThisDivision.length > 0) { + await docObj.removePages(pagesNotBelongsToThisDivision); } /**must apply redactions before removing pages*/ From 11007c246c9f7aaa27dec098e318fd8d9b813c46 Mon Sep 17 00:00:00 2001 From: Richard Qi Date: Thu, 17 Oct 2024 16:04:33 -0700 Subject: [PATCH 77/89] fix page stamp issue --- .../useSaveRedlineForSignOff.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 3aea348ed..dae1b431b 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1846,7 +1846,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid].length > 0 && stitchObject?.getPageCount() > redlinepageMappings["pagestoremove"][divisionid].length ) { - console.log("REDLINE REMOVE", redlinepageMappings["pagestoremove"][divisionid]) await stitchObject.removePages( redlinepageMappings["pagestoremove"][divisionid] ); @@ -1884,7 +1883,7 @@ const stampPageNumberRedline = async ( let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); await applyRedactionsToRedlinesBySection(s14_sectionStamps); - console.log("s14_sectionStamps", s14_sectionStamps) + // console.log("s14_sectionStamps", s14_sectionStamps) /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1974,17 +1973,17 @@ const stampPageNumberRedline = async ( let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; - console.log("publicbodyAnnotList", publicbodyAnnotList) + // console.log("publicbodyAnnotList", publicbodyAnnotList) const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { return annot.name !== "freetext" && annot.name !== 'redact' }); - console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) + // console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - console.log("nr_sectionStamps", nr_sectionStamps) + // console.log("nr_sectionStamps", nr_sectionStamps) await applyRedactionsToRedlinesBySection(nr_sectionStamps); } /** apply redaction and save to s3 - newXfdfString is needed to display @@ -2018,18 +2017,18 @@ const stampPageNumberRedline = async ( await docObj.removePages(pagesNotBelongsToThisDivision); } - /**must apply redactions before removing pages*/ - console.log("CONSULT REMOVE", redlinepageMappings["pagestoremove"][divisionid]) - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } - await stampPageNumberRedline( docObj, PDFNet, redlineStitchInfo[divisionid]["stitchpages"], isSingleRedlinePackage ); + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + // await addWatermarkToRedline( // docObj, // redlineWatermarkPageMapping, From b9bb65ced5b527c07dd21454375dcec6b825c4d1 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 18 Oct 2024 11:29:55 -0700 Subject: [PATCH 78/89] code clean --- .../useSaveRedlineForSignOff.js | 87 ++++++++----------- 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index dae1b431b..aec22a58b 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -90,7 +90,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else { for (let doc of divObj.documentlist) { - //page to pageFlag mappings logic for consults + //page to pageFlag mappings logic used for consults const pagePageFlagMappings = {}; for (let pageFlag of doc.pageFlag) { if (pageFlag.page in pagePageFlagMappings) { @@ -822,7 +822,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let divCount = 0; const noofdivision = Object.keys(stitchlist).length; let stitchedDocObj = null; - // setTotalStitchList(stitchlist); //if you want to apply the solution to applyrotations at end of redline process uncomment this for (const [key, value] of Object.entries(stitchlist)) { divCount++; let docCount = 0; @@ -859,10 +858,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then(async (docObj) => { - - // NOTE: applying rotations to records/documents for redlines is turned off per biz. If uncommented, bugs related to redline redactions (s14, NR etc) not being applied and in turn data breachs can occur - applyRotations(docObj, doc.attributes.rotatedpages) - + applyRotations(docObj, doc.attributes.rotatedpages); //if (isIgnoredDocument(doc, docObj.getPageCount(), divisionDocuments) == false) { docCountCopy++; docCount++; @@ -1385,7 +1381,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (divisionCountForToast === zipServiceMessage.attributes.length) { triggerDownloadRedlines(zipServiceMessage, (error) => { console.log(error); - // window.location.reload(); + window.location.reload(); }); } return zipServiceMessage; @@ -1797,8 +1793,8 @@ const stampPageNumberRedline = async ( let currentDivisionCount = 0; const divisionCountForToast = Object.keys(redlineStitchObject).length; + //Consult Package page removal logic let pagesOfEachDivisions = {}; - // let pagesOfOtherDivisions = {}; //get page numbers of each division Object.keys(redlineStitchInfo).forEach((_div) => { pagesOfEachDivisions[_div] = []; @@ -1806,7 +1802,6 @@ const stampPageNumberRedline = async ( pagesOfEachDivisions[_div].push(pageinfo["stitchedPageNo"]); }); }); - console.log("pagesOfEachDivisions: ", pagesOfEachDivisions); for (const [key, value] of Object.entries(redlineStitchObject)) { currentDivisionCount++; @@ -1850,7 +1845,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory === "redline") { + if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1883,7 +1878,6 @@ const stampPageNumberRedline = async ( let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); let doc = docViewer.getDocument(); await applyRedactionsToRedlinesBySection(s14_sectionStamps); - // console.log("s14_sectionStamps", s14_sectionStamps) /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc @@ -1973,17 +1967,14 @@ const stampPageNumberRedline = async ( let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; - // console.log("publicbodyAnnotList", publicbodyAnnotList) const filteredPublicbodyAnnotList = publicbodyAnnotList.filter((annot) => { return annot.name !== "freetext" && annot.name !== 'redact' }); - // console.log("filteredPublicbodyAnnotList", filteredPublicbodyAnnotList) xmlObj1.getElementsByTagName('annots')[0].children = filteredPublicbodyAnnotList; xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - // console.log("nr_sectionStamps", nr_sectionStamps) await applyRedactionsToRedlinesBySection(nr_sectionStamps); } /** apply redaction and save to s3 - newXfdfString is needed to display @@ -1999,14 +1990,12 @@ const stampPageNumberRedline = async ( const _arr = new Uint8Array(_data); const _blob = new Blob([_arr], { type: "application/pdf" }); - //LOOP HERE - // loop through each of the divisons/consults that exist, in the loop remove the pages that belong to other divisions find those pages to remove. which pages belong to other divisons - await docInstance?.Core.createDocument(_data, { loadAsPDF: true, useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { + // Consult Pacakge page removal of pages that are not in this division let pagesNotBelongsToThisDivision = []; for(let i=1; i <= docObj.getPageCount(); i++) { if(!pagesOfEachDivisions[key].includes(i)) @@ -2024,17 +2013,12 @@ const stampPageNumberRedline = async ( isSingleRedlinePackage ); + //Consult Pacakge page removal of NR and DUPE /**must apply redactions before removing pages*/ if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); } - // await addWatermarkToRedline( - // docObj, - // redlineWatermarkPageMapping, - // key - // ); - docObj.getFileData({ // saves the document with annotations in it xfdfString: xfdfString1, @@ -2090,16 +2074,6 @@ const stampPageNumberRedline = async ( }); } //Consults - Redlines + Redactions (Redact S.NR) Block : End - - // Rotate pages - applyrotations after all redline processes (redline applying, stamping, removing pages etc) are completed. This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // for (const doc of totalStitchList[divisionid]) { - // let documentlist = totalStitchList[divisionid]; - // let divDocPageMappings = redlinepageMappings["divpagemappings"][divisionid]; - // if(documentlist.length > 0) { - // applyRotations(stitchObject, doc, divDocPageMappings); - // } - // } - else { stitchObject .getFileData({ @@ -2160,25 +2134,33 @@ const stampPageNumberRedline = async ( } }; - // This is a solution/option to apply the rotation of pages to redline pacakges (consults, oipc etc) without losing redactions and causing data breach of data that should be redacted. - // const applyRotations = (document, doc, divDocPageMappings) => { - // const docPageMappings = divDocPageMappings[doc.documentid]; // {origPage: stitchedPage, origPage: stitchedPage} -> {2: 1, 3:2, 4:3} - // const rotatedpages = doc.attributes.rotatedpages; // {origPage: rotation. origPage: rotations} -> {4: 180} - // const rotatedStitchedPages = {}; - // if (rotatedpages) { - // for (let [originalPage, stitchedPage] of Object.entries(docPageMappings)) { - // let rotation = rotatedpages[originalPage]; - // if (rotation) { - // rotatedStitchedPages[stitchedPage] = rotation; - // } - // } - // for (let page in rotatedStitchedPages) { - // let existingrotation = document.getPageRotation(page); - // let rotation = (rotatedStitchedPages[page] - existingrotation + 360) / 90; - // document.rotatePages([page], rotation); - // } - // } - // } + const getAdjustedRedactionCoordinates = async(pageRotation, recto, PDFNet,pageWidth,pageHeight) => { + let x1 = recto.x1; + let y1 = recto.y1; + let x2 = recto.x2; + let y2 = recto.y2; + // Adjust Y-coordinates to account for the flipped Y-axis in PDF + y1 = pageHeight - y1; + y2 = pageHeight - y2; + // Adjust for page rotation (90, 180, 270 degrees) + switch (pageRotation) { + case 90: + [x1, y1] = [y1, x1]; + [x2, y2] = [y2, x2]; + break; + case 180: + x1 = pageWidth - x1; + y1 = pageHeight - y1; + x2 = pageWidth - x2; + y2 = pageHeight - y2; + break; + case 270: + [x1, y1] = [pageHeight - y1, x1]; + [x2, y2] = [pageHeight - y2, x2]; + break; + } + return await PDFNet.Rect.init(x1, y1, x2, y2); + } useEffect(() => { if ( @@ -2191,7 +2173,6 @@ const stampPageNumberRedline = async ( } }, [redlineDocumentAnnotations, redlineStitchObject, redlineStitchInfo]); - useEffect(() => { if ( pdftronDocObjectsForRedline?.length > 0 && From d125a46bd202edb38fa5a4f2a39f3be7ba58d525 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Fri, 18 Oct 2024 14:45:48 -0700 Subject: [PATCH 79/89] Consults + NR/DUPE client watermark fix --- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 1 - web/src/components/FOI/Home/Redlining.js | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index aec22a58b..0e045b243 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -74,7 +74,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { const [consultApplyRedactions, setConsultApplyRedactions] = useState(false); const [consultApplyRedlines, setConsultApplyRedlines] = useState(false); - const requestInfo = useAppSelector((state) => state.documents?.requestinfo); const requestType = requestInfo?.requesttype ? requestInfo.requesttype : "public"; diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 5cb7a3384..311b43eff 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -1374,8 +1374,9 @@ const Redlining = React.forwardRef( // Hence being able to leverage those properties let originalPage = pageMappedDocs['stitchedPageLookup'][pageNumber] let doc = pageFlags.find(d => d.documentid === originalPage.docid); - let pageFlag = doc?.pageflag?.find(f => f.page === originalPage.page); - if (pageFlag?.flagid === pageFlagTypes["Duplicate"]) { + let pageFlagsOnPage = doc?.pageflag?.filter(f => f.page === originalPage.page); + let NrOrDupeFlag = pageFlagsOnPage.find(pageFlagItem => pageFlagItem.flagid === pageFlagTypes["Duplicate"] || pageFlagItem.flagid === pageFlagTypes["Not Responsive"]); + if (NrOrDupeFlag?.flagid === pageFlagTypes["Duplicate"]) { ctx.fillStyle = "#ff0000"; ctx.font = "20pt Arial"; ctx.globalAlpha = 0.4; @@ -1387,7 +1388,7 @@ const Redlining = React.forwardRef( ctx.restore(); } - if (pageFlag?.flagid === pageFlagTypes["Not Responsive"]) { + if (NrOrDupeFlag?.flagid === pageFlagTypes["Not Responsive"]) { ctx.fillStyle = "#ff0000"; ctx.font = "20pt Arial"; ctx.globalAlpha = 0.4; From 9a65eed85cfdc064621d8c8050de539a3fea4c8e Mon Sep 17 00:00:00 2001 From: nkan-aot2 <156717133+nkan-aot2@users.noreply.github.com> Date: Mon, 21 Oct 2024 09:20:57 -0700 Subject: [PATCH 80/89] fix in progress flag changing to partial disclosure on adding non redaction annotation --- web/src/components/FOI/Home/utils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/utils.js b/web/src/components/FOI/Home/utils.js index ef736a94f..5f7e7dda0 100644 --- a/web/src/components/FOI/Home/utils.js +++ b/web/src/components/FOI/Home/utils.js @@ -517,6 +517,9 @@ const constructPageFlagsForAddOrEdit = ( pageFlags ) => { let pagesToUpdate = {}; + if (annotationsInfo.section === undefined) { + return getValidObject(pagesToUpdate); // non redaction annotations do not need page flags automatically applied + } const foundBlank = ["", " "].includes(annotationsInfo.section); const foundNR = annotationsInfo.section == "NR"; // section with a valid number found @@ -791,4 +794,4 @@ export const findNROrDuplicatePageFlag = (pageFlags, docObj, pageFlagTypes) => { return pageFlag; } } -} \ No newline at end of file +} From 758d02bb47baabdd1414aeb2a63b09be28a0ff2e Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 21 Oct 2024 13:03:08 -0700 Subject: [PATCH 81/89] final consult changes --- .../useSaveRedlineForSignOff.js | 27 +++---------------- web/src/components/FOI/Home/utils.js | 3 +++ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 0e045b243..59506f118 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -508,10 +508,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { let pagesToRemove = []; let totalPageCount = 0; let totalPageCountIncludeRemoved = 0; - let duplicateWatermarkPages = {}; - let duplicateWatermarkPagesEachDiv = []; - let NRWatermarksPages = {}; - let NRWatermarksPagesEachDiv = []; for (let divObj of divisionDocuments) { // sort based on sortorder as the sortorder added based on the LastModified for (let doc of sortBySortOrder(divObj.documentlist)) { @@ -591,8 +587,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if(includeDuplicatePages) { for (let consult of doc.consult) { if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { - duplicateWatermarkPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = pageIndex + totalPageCount - @@ -612,8 +606,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if(includeNRPages) { for (let consult of doc.consult) { if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = pageIndex + totalPageCount - @@ -631,8 +623,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } else if (flagInfo.flagid == pageFlagTypes["In Progress"]) { for (let consult of doc.consult) { if ((consult.page === flagInfo.page && consult.programareaid.includes(divObj.divisionid)) || (consult.page === flagInfo.page && consult.other.includes(divObj.divisionname))) { - NRWatermarksPagesEachDiv.push(pageIndex + totalPageCountIncludeRemoved - pagesToRemove.length); - pageMappings[doc.documentid][flagInfo.page] = pageIndex + totalPageCount - @@ -682,11 +672,7 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } divPageMappings[divObj.divisionid] = pageMappings; removepages[divObj.divisionid] = pagesToRemove; - duplicateWatermarkPages[divObj.divisionid] = duplicateWatermarkPagesEachDiv; - NRWatermarksPages[divObj.divisionid] = NRWatermarksPagesEachDiv; pagesToRemove = []; - duplicateWatermarkPagesEachDiv = []; - NRWatermarksPagesEachDiv = []; totalPageCount = 0; totalPageCountIncludeRemoved = 0; pageMappings = {} @@ -697,10 +683,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { 'pagemapping': pageMappings, 'pagestoremove': removepages }); - setRedlineWatermarkPageMapping({ - 'duplicatewatermark': duplicateWatermarkPages, - 'NRwatermark': NRWatermarksPages - }); } const prepareRedlineIncompatibleMapping = (redlineAPIResponse) => { @@ -1194,9 +1176,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { ); } } - // if (docCount == div.documentlist.length) { - - // } } } if ( @@ -1827,7 +1806,7 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if(redlineCategory !== "oipcreview" || redlineCategory !== "consult") { + if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await stampPageNumberRedline( stitchObject, PDFNet, @@ -1994,7 +1973,7 @@ const stampPageNumberRedline = async ( useDownloader: false, // Added to fix BLANK page issue }).then( async (docObj) => { - // Consult Pacakge page removal of pages that are not in this division + // Consult Pacakge page removal of pages that are not in this division (will leave consult/division specific pages in docObj to be removed by redlinepagemappings pagestoremove below) let pagesNotBelongsToThisDivision = []; for(let i=1; i <= docObj.getPageCount(); i++) { if(!pagesOfEachDivisions[key].includes(i)) @@ -2012,7 +1991,7 @@ const stampPageNumberRedline = async ( isSingleRedlinePackage ); - //Consult Pacakge page removal of NR and DUPE + //Consult Pacakge page removal of pages/documents associated with divison/consult /**must apply redactions before removing pages*/ if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); diff --git a/web/src/components/FOI/Home/utils.js b/web/src/components/FOI/Home/utils.js index ef736a94f..fa910f68f 100644 --- a/web/src/components/FOI/Home/utils.js +++ b/web/src/components/FOI/Home/utils.js @@ -517,6 +517,9 @@ const constructPageFlagsForAddOrEdit = ( pageFlags ) => { let pagesToUpdate = {}; + if (annotationsInfo.section === undefined) { + return getValidObject(pagesToUpdate); // non redaction annotations do not need page flags automatically applied + } const foundBlank = ["", " "].includes(annotationsInfo.section); const foundNR = annotationsInfo.section == "NR"; // section with a valid number found From 2043295e762e4ba7cfef3ef73900f903a684027a Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 21 Oct 2024 15:10:52 -0700 Subject: [PATCH 82/89] final redline changes for consults with new oipc logic --- .../useSaveRedlineForSignOff.js | 192 +++++++++--------- 1 file changed, 99 insertions(+), 93 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index 59506f118..fbd52e3e9 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -1745,17 +1745,6 @@ const stampPageNumberRedline = async ( } } }; - const applyRedactionsToRedlinesBySection = async (appliedSectionStamps) => { - let annotationManager = docInstance?.Core.annotationManager; - let annots = []; - for (const [key, value] of Object.entries(appliedSectionStamps)) { - let sectionAnnotation = annotationManager.getAnnotationById(key); - if (sectionAnnotation.Subject === "Redact") { - annots.push(sectionAnnotation); - } - } - await annotationManager.applyRedactions(annots); - } //useEffects to keep docInstance and docViewer state up to date with Redlining.js useEffect(() => { @@ -1806,14 +1795,13 @@ const stampPageNumberRedline = async ( redlinepageMappings["divpagemappings"][divisionid], redlineStitchInfo[divisionid]["documentids"] ); - if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { + if (redlineCategory === "redline") { await stampPageNumberRedline( stitchObject, PDFNet, redlineStitchInfo[divisionid]["stitchpages"], isSingleRedlinePackage ); - } if ( redlinepageMappings["pagestoremove"][divisionid] && redlinepageMappings["pagestoremove"][divisionid].length > 0 && @@ -1823,7 +1811,6 @@ const stampPageNumberRedline = async ( redlinepageMappings["pagestoremove"][divisionid] ); } - if (redlineCategory !== "oipcreview" || redlineCategory !== "consult") { await addWatermarkToRedline( stitchObject, redlineWatermarkPageMapping, @@ -1853,95 +1840,106 @@ const stampPageNumberRedline = async ( //Apply Redactions (if any) //OIPC - Special Block (Redact S.14) : Begin if(redlineCategory === "oipcreview") { + let annotationManager = docInstance?.Core.annotationManager; let s14_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); + let s14annots = []; + for (const [key, value] of Object.entries(s14_sectionStamps)) { + let s14annoation = annotationManager.getAnnotationById(key); + if ( s14annoation.Subject === "Redact") { + s14annots.push(s14annoation); + } + } + let doc = docViewer.getDocument(); - await applyRedactionsToRedlinesBySection(s14_sectionStamps); + await annotationManager.applyRedactions(s14annots); + /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ doc - .getFileData({ - // export the document to arraybuffer - // xfdfString: xfdfString, - downloadType: downloadType, - flatten: true, - }) - .then(async (_data) => { - const _arr = new Uint8Array(_data); - const _blob = new Blob([_arr], { type: "application/pdf" }); - - await docInstance?.Core.createDocument(_data, { - loadAsPDF: true, - useDownloader: false, // Added to fix BLANK page issue - }).then( async (docObj) => { - - /**must apply redactions before removing pages*/ - if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { - await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); - } - await stampPageNumberRedline( - docObj, - PDFNet, - redlineStitchInfo[divisionid]["stitchpages"], - isSingleRedlinePackage - ); - - docObj.getFileData({ - // saves the document with annotations in it - xfdfString: xfdfString1, - downloadType: downloadType, - flatten: true, - }) - .then(async (__data) => { - const __arr = new Uint8Array(__data); - const __blob = new Blob([__arr], { type: "application/pdf" }); - - saveFilesinS3( - { filepath: redlineStitchInfo[divisionid]["s3path"] }, - __blob, - (_res) => { - // ######### call another process for zipping and generate download here ########## - toast.update(toastId.current, { - render: `Redline PDF saved to Object Storage`, - type: "success", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - triggerRedlineZipper( - redlineIncompatabileMappings[divisionid], - redlineStitchInfo[divisionid]["s3path"], - divisionCountForToast, - isSingleRedlinePackage - ); - }, - (_err) => { - console.log(_err); - toast.update(toastId.current, { - render: "Failed to save redline pdf to Object Storage", - type: "error", - className: "file-upload-toast", - isLoading: false, - autoClose: 3000, - hideProgressBar: true, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - closeButton: true, - }); - } + .getFileData({ + // export the document to arraybuffer + // xfdfString: xfdfString, + downloadType: downloadType, + flatten: true, + }) + .then(async (_data) => { + const _arr = new Uint8Array(_data); + const _blob = new Blob([_arr], { type: "application/pdf" }); + + await docInstance?.Core.createDocument(_data, { + loadAsPDF: true, + useDownloader: false, // Added to fix BLANK page issue + }).then( async (docObj) => { + + /**must apply redactions before removing pages*/ + if (redlinepageMappings["pagestoremove"][divisionid].length > 0) { + await docObj.removePages(redlinepageMappings["pagestoremove"][divisionid]); + } + + await stampPageNumberRedline( + docObj, + PDFNet, + redlineStitchInfo[divisionid]["stitchpages"], + isSingleRedlinePackage ); + + docObj.getFileData({ + // saves the document with annotations in it + xfdfString: xfdfString1, + downloadType: downloadType, + flatten: true, + }) + .then(async (__data) => { + const __arr = new Uint8Array(__data); + const __blob = new Blob([__arr], { type: "application/pdf" }); + + saveFilesinS3( + { filepath: redlineStitchInfo[divisionid]["s3path"] }, + __blob, + (_res) => { + // ######### call another process for zipping and generate download here ########## + toast.update(toastId.current, { + render: `Redline PDF saved to Object Storage`, + type: "success", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + triggerRedlineZipper( + redlineIncompatabileMappings[divisionid], + redlineStitchInfo[divisionid]["s3path"], + divisionCountForToast, + isSingleRedlinePackage + ); + }, + (_err) => { + console.log(_err); + toast.update(toastId.current, { + render: "Failed to save redline pdf to Object Storage", + type: "error", + className: "file-upload-toast", + isLoading: false, + autoClose: 3000, + hideProgressBar: true, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + closeButton: true, + }); + } + ); + }); }); }); - }); } //OIPC - Special Block : End //Consults - Redlines + Redactions (Redact S.NR) Block : Start - if(redlineCategory === "consult") { + else if (redlineCategory === "consult") { let doc = docViewer.getDocument(); if (!consultApplyRedlines) { const publicbodyAnnotList = xmlObj1.getElementsByTagName('annots')[0]['children']; @@ -1952,8 +1950,16 @@ const stampPageNumberRedline = async ( xfdfString1 = parser.toString(xmlObj1); } if (consultApplyRedactions) { + let annotationManager = docInstance?.Core.annotationManager; let nr_sectionStamps = await annotationSectionsMapping(xfdfString, formattedAnnotationXML); - await applyRedactionsToRedlinesBySection(nr_sectionStamps); + let nrAnnots = []; + for (const [key, value] of Object.entries(nr_sectionStamps)) { + let nrAnnotation = annotationManager.getAnnotationById(key); + if (nrAnnotation.Subject === "Redact") { + nrAnnots.push(nrAnnotation); + } + } + await annotationManager.applyRedactions(nrAnnots); } /** apply redaction and save to s3 - newXfdfString is needed to display * the freetext(section name) on downloaded file.*/ From a6112ed346496391e5634e2da808d320ee686de7 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 21 Oct 2024 15:55:20 -0700 Subject: [PATCH 83/89] small code clean (spaces) --- .../CreateResponsePDF/useSaveRedlineForSignOff.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js index fbd52e3e9..65f90de2c 100644 --- a/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js +++ b/web/src/components/FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js @@ -383,7 +383,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { }); }; - const prepareRedlinePageMappingByDivision = (divisionDocuments) => { let removepages = {}; let pageMappings = {}; @@ -763,7 +762,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { return "redline"; }; - const prepareredlinesummarylist = (stitchDocuments) => { let summarylist = []; let alldocuments = []; @@ -871,7 +869,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { if (docCount == documentlist.length && redlineSinglePkg == "N" ) { requestStitchObject[division] = stitchedDocObj; } - } } else { if (incompatableList[division]["incompatibleFiles"].length > 0) { @@ -890,12 +887,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { } }; - - - - - - const stitchSingleDivisionRedlineExport = async ( _instance, divisionDocuments, @@ -1058,7 +1049,6 @@ const useSaveRedlineForSignoff = (initDocInstance, initDocViewer) => { return publicBodies; } - const saveRedlineDocument = async ( _instance, layertype, @@ -2242,4 +2232,4 @@ const stampPageNumberRedline = async ( }; }; -export default useSaveRedlineForSignoff; +export default useSaveRedlineForSignoff; \ No newline at end of file From a48d2c85a594dd05c0c648eb2f9a4338031ff294 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Wed, 23 Oct 2024 16:10:08 -0700 Subject: [PATCH 84/89] bug fix test-marshal for consults merge made on oct 21 --- web/src/components/FOI/Home/Redlining.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 311b43eff..8b4d80b3e 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -1375,7 +1375,7 @@ const Redlining = React.forwardRef( let originalPage = pageMappedDocs['stitchedPageLookup'][pageNumber] let doc = pageFlags.find(d => d.documentid === originalPage.docid); let pageFlagsOnPage = doc?.pageflag?.filter(f => f.page === originalPage.page); - let NrOrDupeFlag = pageFlagsOnPage.find(pageFlagItem => pageFlagItem.flagid === pageFlagTypes["Duplicate"] || pageFlagItem.flagid === pageFlagTypes["Not Responsive"]); + let NrOrDupeFlag = pageFlagsOnPage?.find(pageFlagItem => pageFlagItem.flagid === pageFlagTypes["Duplicate"] || pageFlagItem.flagid === pageFlagTypes["Not Responsive"]); if (NrOrDupeFlag?.flagid === pageFlagTypes["Duplicate"]) { ctx.fillStyle = "#ff0000"; ctx.font = "20pt Arial"; From 2eaecbfc8d8264057d0e1ed54e7c3992d6152019 Mon Sep 17 00:00:00 2001 From: Aman-Hundal Date: Mon, 28 Oct 2024 14:48:18 -0700 Subject: [PATCH 85/89] small wording/messaging changes realted to consults + addedd missed fee-overriding changes(ticket 3073) when main was merged to test-marshal --- .../models/redlineresponsenotificationmessage.py | 2 +- .../ZippingServices/models/zipperproducermessage.py | 2 +- web/src/components/FOI/Home/ConfirmationModal.js | 2 +- .../FOI/Home/CreateResponsePDF/useSaveRedlineForSignOff.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py b/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py index ccb851933..cc562164f 100644 --- a/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py +++ b/computingservices/ZippingServices/models/redlineresponsenotificationmessage.py @@ -1,5 +1,5 @@ class redlineresponsenotificationmessage(object): - def __init__(self, ministryrequestid, serviceid, errorflag, createdby,feeoverridereason) -> None: + def __init__(self, ministryrequestid, serviceid, errorflag, createdby,feeoverridereason="") -> None: self.ministryrequestid = ministryrequestid self.serviceid = serviceid self.errorflag = errorflag diff --git a/computingservices/ZippingServices/models/zipperproducermessage.py b/computingservices/ZippingServices/models/zipperproducermessage.py index 73b4b795c..41b175753 100644 --- a/computingservices/ZippingServices/models/zipperproducermessage.py +++ b/computingservices/ZippingServices/models/zipperproducermessage.py @@ -1,5 +1,5 @@ class zipperproducermessage(object): - def __init__(self,jobid,requestid,category,requestnumber,bcgovcode,createdby,ministryrequestid,filestozip,finaloutput,attributes,feeoverridereason,summarydocuments=None,redactionlayerid=None,foldername=None) -> None: + def __init__(self,jobid,requestid,category,requestnumber,bcgovcode,createdby,ministryrequestid,filestozip,finaloutput,attributes,feeoverridereason=None,summarydocuments=None,redactionlayerid=None,foldername=None) -> None: self.jobid = jobid self.requestid = requestid self.category=category diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index ab49df08a..b44a05762 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -133,7 +133,7 @@ export const ConfirmationModal= ({ checked={consultApplyRedlines} onChange={handleApplyRedlines} /> - +
Date: Tue, 29 Oct 2024 11:13:23 -0700 Subject: [PATCH 86/89] observation fixes for 11.0 (adjusted LSB in docreivewer enums + added disabled option or create consult button --- api/reviewer_api/utils/enums.py | 3 ++- web/src/components/FOI/Home/ConfirmationModal.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/reviewer_api/utils/enums.py b/api/reviewer_api/utils/enums.py index 23e99fb1a..00f5682b1 100644 --- a/api/reviewer_api/utils/enums.py +++ b/api/reviewer_api/utils/enums.py @@ -74,7 +74,8 @@ class MinistryTeamWithKeycloackGroup(Enum): ECC = "ECC Ministry Team" JED = "JED Ministry Team" COR = "COR Ministry Team" - HSG = "HSG Ministry Team" + HSG = "HSG Ministry Team", + LSB = "LSB Ministry Team" @staticmethod def list(): diff --git a/web/src/components/FOI/Home/ConfirmationModal.js b/web/src/components/FOI/Home/ConfirmationModal.js index b44a05762..89280c3dc 100644 --- a/web/src/components/FOI/Home/ConfirmationModal.js +++ b/web/src/components/FOI/Home/ConfirmationModal.js @@ -150,7 +150,7 @@ export const ConfirmationModal= ({ -