diff --git a/forms-flow-web/src/components/FOI/Dashboard/IAO/AdvancedSearch/SearchComponent.js b/forms-flow-web/src/components/FOI/Dashboard/IAO/AdvancedSearch/SearchComponent.js index 56c04bd31..25c7e352b 100644 --- a/forms-flow-web/src/components/FOI/Dashboard/IAO/AdvancedSearch/SearchComponent.js +++ b/forms-flow-web/src/components/FOI/Dashboard/IAO/AdvancedSearch/SearchComponent.js @@ -128,15 +128,14 @@ const AdvancedSearch = ({ userDetail }) => { }); const intitialRequestState = { - [StateEnum.unopened.id]: false, - [StateEnum.open.id]: false, - [StateEnum.callforrecords.id]: false, - [StateEnum.review.id]: false, - [StateEnum.signoff.id]: false, - [StateEnum.closed.id]: false, - [StateEnum.callforrecordsoverdue.id]: false + [StateEnum.unopened.label]: false, + [StateEnum.open.label]: false, + [StateEnum.callforrecords.label]: false, + [StateEnum.review.label]: false, + [StateEnum.signoff.label]: false, + [StateEnum.closed.label]: false, + [StateEnum.callforrecordsoverdue.label]: false }; - const [requestState, setRequestState] = useState(() => { if (Object.keys(advancedSearchParams).length > 0 && advancedSearchParams.requestState.length > 0) { let savedRequestState = {...intitialRequestState} @@ -579,9 +578,9 @@ const AdvancedSearch = ({ userDetail }) => { } @@ -593,9 +592,9 @@ const AdvancedSearch = ({ userDetail }) => { } @@ -607,9 +606,9 @@ const AdvancedSearch = ({ userDetail }) => { } @@ -621,9 +620,9 @@ const AdvancedSearch = ({ userDetail }) => { } @@ -635,9 +634,9 @@ const AdvancedSearch = ({ userDetail }) => { } diff --git a/forms-flow-web/src/components/FOI/Dashboard/Ministry/AdvancedSearch/SearchComponent.js b/forms-flow-web/src/components/FOI/Dashboard/Ministry/AdvancedSearch/SearchComponent.js index 68f82525b..83325ebde 100644 --- a/forms-flow-web/src/components/FOI/Dashboard/Ministry/AdvancedSearch/SearchComponent.js +++ b/forms-flow-web/src/components/FOI/Dashboard/Ministry/AdvancedSearch/SearchComponent.js @@ -127,13 +127,12 @@ const AdvancedSearch = ({ userDetail }) => { }); const intitialRequestState = { - [StateEnum.callforrecords.id]: false, - [StateEnum.review.id]: false, - [StateEnum.signoff.id]: false, - [StateEnum.closed.id]: false, - [StateEnum.callforrecordsoverdue.id]: false + [StateEnum.callforrecords.label]: false, + [StateEnum.review.label]: false, + [StateEnum.signoff.label]: false, + [StateEnum.closed.label]: false, + [StateEnum.callforrecordsoverdue.label]: false }; - const [requestState, setRequestState] = useState(() => { if (Object.keys(advancedSearchParams).length > 0 && advancedSearchParams.requestState.length > 0) { let savedRequestState = {...intitialRequestState} @@ -592,9 +591,9 @@ const AdvancedSearch = ({ userDetail }) => { } @@ -606,9 +605,9 @@ const AdvancedSearch = ({ userDetail }) => { } @@ -620,9 +619,9 @@ const AdvancedSearch = ({ userDetail }) => { } @@ -634,9 +633,9 @@ const AdvancedSearch = ({ userDetail }) => { } diff --git a/forms-flow-web/src/components/FOI/FOIRequest/AxisDetails/AxisSyncModal.js b/forms-flow-web/src/components/FOI/FOIRequest/AxisDetails/AxisSyncModal.js index 57b1ef567..df288a2a5 100644 --- a/forms-flow-web/src/components/FOI/FOIRequest/AxisDetails/AxisSyncModal.js +++ b/forms-flow-web/src/components/FOI/FOIRequest/AxisDetails/AxisSyncModal.js @@ -298,8 +298,9 @@ const AxisSyncModal = ({ axisSyncModalOpen, setAxisSyncModalOpen, saveRequestObj const saveAxisData = async () => { - if (urlIndexCreateRequest > -1) - updatedSaveReqObj.requeststatusid = StateEnum.intakeinprogress.id; + if (urlIndexCreateRequest > -1) { + updatedSaveReqObj.requeststatuslabel = StateEnum.intakeinprogress.label; + } dispatch(saveRequestDetails(updatedSaveReqObj, urlIndexCreateRequest,requestId,ministryId, (err, res) => { if (!err) { diff --git a/forms-flow-web/src/components/FOI/FOIRequest/BottomButtonGroup/index.js b/forms-flow-web/src/components/FOI/FOIRequest/BottomButtonGroup/index.js index 5c301c061..e7bb8b0b5 100644 --- a/forms-flow-web/src/components/FOI/FOIRequest/BottomButtonGroup/index.js +++ b/forms-flow-web/src/components/FOI/FOIRequest/BottomButtonGroup/index.js @@ -115,7 +115,7 @@ const BottomButtonGroup = React.memo( const saveRequest = async (setLoader = false) => { if (urlIndexCreateRequest > -1) { - saveRequestObject.requeststatusid = StateEnum.intakeinprogress.id; + saveRequestObject.requeststatuslabel = StateEnum.intakeinprogress.label; setIsAddRequest(false); } dispatch(setFOILoader(setLoader)) @@ -176,7 +176,7 @@ const BottomButtonGroup = React.memo( if ( currentSelectedStatus && currentSelectedStatus !== StateEnum.open.name && - saveRequestObject.requeststatusid && + saveRequestObject.requeststatuslabel && saveRequestObject.currentState ) { //scanning team - MSD/CFD personal @@ -200,7 +200,7 @@ const BottomButtonGroup = React.memo( } saveRequestModal(); } else { - saveRequestObject.requeststatusid = StateEnum.open.id; + saveRequestObject.requeststatuslabel = StateEnum.open.label; if (currentSelectedStatus === StateEnum.open.name && ministryId) { saveRequestModal(); } @@ -231,7 +231,7 @@ const BottomButtonGroup = React.memo( saveRequestObject.id = saveRequestObject.id ? saveRequestObject.id : requestId; - saveRequestObject.requeststatusid = 1; + saveRequestObject.requeststatuslabel = StateEnum.open.label; setOpenModal(true); }; @@ -292,14 +292,14 @@ const BottomButtonGroup = React.memo( if (currentSelectedStatus) { switch (currentSelectedStatus) { case StateEnum.closed.name: - saveRequestObject.requeststatusid = StateEnum.closed.id; + saveRequestObject.requeststatuslabel = StateEnum.closed.label; saveRequestObject.closedate = closingDate; saveRequestObject.closereasonid = closingReasonId; break; case StateEnum.callforrecords.name: saveRequestObject.paymentExpiryDate = "" - saveRequestObject.requeststatusid = StateEnum.callforrecords.id; + saveRequestObject.requeststatuslabel = StateEnum.callforrecords.label; if ( !("cfrDueDate" in saveRequestObject) || saveRequestObject.cfrDueDate === "" @@ -354,7 +354,7 @@ const BottomButtonGroup = React.memo( const status = Object.values(StateEnum).find( (statusValue) => statusValue.name === currentSelectedStatus ); - saveRequestObject.requeststatusid = status.id; + saveRequestObject.requeststatuslabel = status.label; if (currentSelectedStatus === StateEnum.onhold.name && !saveRequestObject.paymentExpiryDate) { saveRequestObject.paymentExpiryDate = dueDateCalculation(new Date(), PAYMENT_EXPIRY_DAYS); } diff --git a/forms-flow-web/src/components/FOI/FOIRequest/FOIRequest.js b/forms-flow-web/src/components/FOI/FOIRequest/FOIRequest.js index d754731d2..1da3db7ab 100644 --- a/forms-flow-web/src/components/FOI/FOIRequest/FOIRequest.js +++ b/forms-flow-web/src/components/FOI/FOIRequest/FOIRequest.js @@ -301,8 +301,8 @@ const FOIRequest = React.memo(({ userDetail }) => { const assignedTo = getAssignedTo(requestDetails); setAssignedToValue(assignedTo); if (Object.entries(requestDetails)?.length !== 0) { - let requestStateFromId = findRequestState(requestDetails.requeststatusid) - ? findRequestState(requestDetails.requeststatusid) + let requestStateFromId = findRequestState(requestDetails.requeststatuslabel) + ? findRequestState(requestDetails.requeststatuslabel) : StateEnum.unopened.name; setRequestState(requestStateFromId); settabStatus(requestStateFromId); diff --git a/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/BottomButtonGroup.js b/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/BottomButtonGroup.js index 1d2ef577e..14fd9def1 100644 --- a/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/BottomButtonGroup.js +++ b/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/BottomButtonGroup.js @@ -186,34 +186,34 @@ const BottomButtonGroup = React.memo( const [successCount, setSuccessCount] = useState(0); const [fileCount, setFileCount] = useState(0); const [documents, setDocuments] = useState([]); - + const saveStatusId = () => { if (currentSelectedStatus) { switch (currentSelectedStatus.toLowerCase()) { case StateEnum.review.name.toLowerCase(): - saveMinistryRequestObject.requeststatusid = StateEnum.review.id; + saveMinistryRequestObject.requeststatuslabel = StateEnum.review.label; break; case StateEnum.feeassessed.name.toLowerCase(): - saveMinistryRequestObject.requeststatusid = - StateEnum.feeassessed.id; + saveMinistryRequestObject.requeststatuslabel = + StateEnum.feeassessed.label; break; case StateEnum.deduplication.name.toLowerCase(): - saveMinistryRequestObject.requeststatusid = - StateEnum.deduplication.id; + saveMinistryRequestObject.requeststatuslabel = + StateEnum.deduplication.label; break; case StateEnum.harms.name.toLowerCase(): - saveMinistryRequestObject.requeststatusid = StateEnum.harms.id; + saveMinistryRequestObject.requeststatuslabel = StateEnum.harms.label; break; case StateEnum.signoff.name.toLowerCase(): - saveMinistryRequestObject.requeststatusid = StateEnum.signoff.id; + saveMinistryRequestObject.requeststatuslabel = StateEnum.signoff.label; break; case StateEnum.response.name.toLowerCase(): saveMinistryRequestObject.ministrysignoffapproval = ministryApprovalState; - saveMinistryRequestObject.requeststatusid = StateEnum.response.id; + saveMinistryRequestObject.requeststatuslabel = StateEnum.response.label; break; case StateEnum.callforrecords.name.toLowerCase(): - saveMinistryRequestObject.requeststatusid = - StateEnum.callforrecords.id; + saveMinistryRequestObject.requeststatuslabel = + StateEnum.callforrecords.label; break; } } diff --git a/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/MinistryReview.js b/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/MinistryReview.js index 6b779db48..c6032e05e 100644 --- a/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/MinistryReview.js +++ b/forms-flow-web/src/components/FOI/FOIRequest/MinistryReview/MinistryReview.js @@ -436,10 +436,10 @@ const MinistryReview = React.memo(({ userDetail }) => { break; case StateEnum.tagging.name: foitabheaderBG = "foitabheadercollection foitabheaderTaggingBG"; - break; + break; case StateEnum.readytoscan.name: foitabheaderBG = "foitabheadercollection foitabheaderReadytoScanBG"; - break; + break; default: foitabheaderBG = "foitabheadercollection foitabheaderdefaultBG"; break; diff --git a/forms-flow-web/src/components/FOI/FOIRequest/RequestDetails.js b/forms-flow-web/src/components/FOI/FOIRequest/RequestDetails.js index 03f3005ef..43e4b4ae1 100644 --- a/forms-flow-web/src/components/FOI/FOIRequest/RequestDetails.js +++ b/forms-flow-web/src/components/FOI/FOIRequest/RequestDetails.js @@ -126,7 +126,7 @@ const RequestDetails = React.memo( receivedDate: !!receivedDate ? formatDate(receivedDate): "", requestStartDate: startDate ? formatDate(startDate): "", dueDate: validateFields(requestDetails, FOI_COMPONENT_CONSTANTS.DUE_DATE, startDate ? formatDate(startDate): ""), - requestState: findRequestState(requestDetails?.requeststatusid) + requestState: findRequestState(requestDetails?.requeststatuslabel) } //event bubble up - sets the initial value to validate the required fields handleRequestDetailsInitialValue(requestDetailsObject); diff --git a/forms-flow-web/src/components/FOI/FOIRequest/utils.js b/forms-flow-web/src/components/FOI/FOIRequest/utils.js index f4aa33500..1ed724913 100644 --- a/forms-flow-web/src/components/FOI/FOIRequest/utils.js +++ b/forms-flow-web/src/components/FOI/FOIRequest/utils.js @@ -359,10 +359,10 @@ export const alertUser = (e) => { e.returnValue = ""; }; -export const findRequestState = (requestStatusId) => { - if (requestStatusId != undefined) { +export const findRequestState = (requestStatusLabel) => { + if (requestStatusLabel != undefined) { let stateArray = Object.entries(StateEnum).find( - (value) => value[1].id === requestStatusId + (value) => value[1].label === requestStatusLabel ); return stateArray[1].name; } diff --git a/forms-flow-web/src/components/FOI/Header/NotificationPopup/NotificationPopup.js b/forms-flow-web/src/components/FOI/Header/NotificationPopup/NotificationPopup.js index 13d0e0084..400703d11 100644 --- a/forms-flow-web/src/components/FOI/Header/NotificationPopup/NotificationPopup.js +++ b/forms-flow-web/src/components/FOI/Header/NotificationPopup/NotificationPopup.js @@ -23,14 +23,14 @@ const NotificationPopup = ({notifications, isMinistry, ministryCode}) => { },[notifications]); const tabTitle = () =>{ - let myRequestList = notifications?.filter(x => (x.notificationusertype === 'Assignee' || x.notificationusertype === 'Comment User')); + let myRequestList = notifications?.filter(x => (x.notificationusertype === 'Assignee' || x.notificationusertype === 'Comment User' || x.notificationusertype === 'Triggered User')); let watchingRequestList = notifications?.filter(x => x.notificationusertype === 'Watcher'); setMyRequestTitle(myRequestList?.length > 0 ? "My Notifications ("+myRequestList.length+")": "My Notifications"); setWatchingRequestTitle(watchingRequestList?.length > 0 ? "Watching Notifications ("+watchingRequestList.length+")": "Watching Notifications"); } const assigmentNotifications = notifications?.map((notification,index) => - {return (notification.notificationusertype === 'Assignee' || notification.notificationusertype === "Comment User") && + {return (notification.notificationusertype === 'Assignee' || notification.notificationusertype === "Comment User" || notification.notificationusertype === "Triggered User") && } @@ -45,7 +45,7 @@ const NotificationPopup = ({notifications, isMinistry, ministryCode}) => { const checkIfNotificationExists = (type) => { if(type ==='assignee' && notifications.find(notification => - (notification.notificationusertype === 'Assignee'|| notification.notificationusertype === "Comment User"))){ + (notification.notificationusertype === 'Assignee'|| notification.notificationusertype === "Comment User" || notification.notificationusertype === "Triggered User"))){ return true; } if(type ==='watcher' && notifications.find(notification => diff --git a/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/index.js b/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/index.js index a0ffb50ff..e727e9b4d 100644 --- a/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/index.js +++ b/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/index.js @@ -133,8 +133,8 @@ export default function ConfirmationModal({requestId, openModal, handleModal, st ( state.toLowerCase() === StateEnum.onhold.name.toLowerCase() && ( - saveRequestObject.requeststatusid === StateEnum.feeassessed.id - || saveRequestObject.requeststatusid === StateEnum.response.id + saveRequestObject.requeststatuslabel === StateEnum.feeassessed.label + || saveRequestObject.requeststatuslabel === StateEnum.response.label ) && saveRequestObject.email) ) @@ -150,22 +150,22 @@ export default function ConfirmationModal({requestId, openModal, handleModal, st let fileStatusTransition = ""; if (state.toLowerCase() === StateEnum.response.name.toLowerCase()) fileStatusTransition = StateTransitionCategories.signoffresponse.name; - else if (saveRequestObject.requeststatusid === StateEnum.callforrecords.id + else if (saveRequestObject.requeststatuslabel === StateEnum.callforrecords.label && state.toLowerCase() === StateEnum.review.name.toLowerCase()) fileStatusTransition = StateTransitionCategories.cfrreview.name; - else if (saveRequestObject.requeststatusid === StateEnum.harms.id + else if (saveRequestObject.requeststatuslabel === StateEnum.harms.label && state.toLowerCase() === StateEnum.review.name.toLowerCase()) fileStatusTransition = StateTransitionCategories.harmsreview.name; - else if (saveRequestObject.requeststatusid === StateEnum.feeassessed.id + else if (saveRequestObject.requeststatuslabel === StateEnum.feeassessed.label && state.toLowerCase() === StateEnum.onhold.name.toLowerCase()) fileStatusTransition = StateTransitionCategories.feeonhold.name; - else if (saveRequestObject.requeststatusid === StateEnum.response.id + else if (saveRequestObject.requeststatuslabel === StateEnum.response.label && state.toLowerCase() === StateEnum.onhold.name.toLowerCase()) fileStatusTransition = StateTransitionCategories.responseonhold.name; - else if (saveRequestObject.requeststatusid === StateEnum.response.id + else if (saveRequestObject.requeststatuslabel === StateEnum.response.label && state.toLowerCase() === StateEnum.review.name.toLowerCase()) fileStatusTransition = StateTransitionCategories.responsereview.name; - else if (saveRequestObject.requeststatusid === StateEnum.signoff.id + else if (saveRequestObject.requeststatuslabel === StateEnum.signoff.label && state.toLowerCase() === StateEnum.review.name.toLowerCase()) fileStatusTransition = StateTransitionCategories.signoffreview.name; @@ -206,7 +206,7 @@ export default function ConfirmationModal({requestId, openModal, handleModal, st (state.toLowerCase() === StateEnum.review.name.toLowerCase() && (!isAnyAmountPaid || !isMinistry)) || (state.toLowerCase() === StateEnum.onhold.name.toLowerCase() - && (saveRequestObject.requeststatusid === StateEnum.feeassessed.id || saveRequestObject.requeststatusid === StateEnum.response.id) + && (saveRequestObject.requeststatuslabel === StateEnum.feeassessed.label || saveRequestObject.requeststatuslabel === StateEnum.response.label) && saveRequestObject.email && cfrStatus == 'approved' && amountDue !== 0) @@ -226,7 +226,7 @@ export default function ConfirmationModal({requestId, openModal, handleModal, st ); } - else if (currentState?.toLowerCase() === StateEnum.signoff.name.toLowerCase() && state.toLowerCase() === StateEnum.response.name.toLowerCase() && saveRequestObject.requeststatusid === StateEnum.signoff.id) { + else if (currentState?.toLowerCase() === StateEnum.signoff.name.toLowerCase() && state.toLowerCase() === StateEnum.response.name.toLowerCase() && saveRequestObject.requeststatuslabel === StateEnum.signoff.label) { return (
@@ -312,7 +312,7 @@ export default function ConfirmationModal({requestId, openModal, handleModal, st
@@ -331,7 +331,7 @@ export default function ConfirmationModal({requestId, openModal, handleModal, st
diff --git a/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/util.js b/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/util.js index c24c79a58..5cd9c4e31 100644 --- a/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/util.js +++ b/forms-flow-web/src/components/FOI/customComponents/ConfirmationModal/util.js @@ -67,9 +67,9 @@ import { getFullnameList } from "../../../../helper/FOI/helper"; case StateEnum.review.name.toLowerCase(): if(!allowStateChange) return {title: "Changing the state", body: `Unable to change state until fee estimate actuals have been completed.`}; - else if (!isAnyAmountPaid && _saveRequestObject.requeststatusid === StateEnum.callforrecords.id) + else if (!isAnyAmountPaid && _saveRequestObject.requeststatuslabel === StateEnum.callforrecords.label) return {title: "Review Request", body: `Upload completed Call for Records form (if required) to change the state.`}; - else if (_saveRequestObject.requeststatusid === StateEnum.harms.id) + else if (_saveRequestObject.requeststatuslabel === StateEnum.harms.label) return {title: "Review Request", body: `Upload completed Call for Records form (if required) to change the state.`}; else return {title: "Changing the state", body: `Are you sure you want to change Request #${_requestNumber} to ${StateEnum.review.name}?`}; @@ -122,7 +122,7 @@ import { getFullnameList } from "../../../../helper/FOI/helper"; body: <>Are you sure you want to change Request #{_requestNumber} to on hold?
This will stop the clock and automatically email the applicant the fee estimate. }; } case StateEnum.response.name.toLowerCase(): - if (_saveRequestObject.requeststatusid === StateEnum.signoff.id) + if (_saveRequestObject.requeststatuslabel === StateEnum.signoff.label) return {title: "Ministry Sign Off", body: `Upload eApproval Logs, and enter in required approval fields to verify Ministry Approval and then change the state.`}; else return {title: "Changing the state", body: `Are you sure you want to change Request #${_requestNumber} to ${StateEnum.response.name}?`}; diff --git a/forms-flow-web/src/constants/FOI/statusEnum.js b/forms-flow-web/src/constants/FOI/statusEnum.js index aae8ef2ae..6f226fa09 100644 --- a/forms-flow-web/src/constants/FOI/statusEnum.js +++ b/forms-flow-web/src/constants/FOI/statusEnum.js @@ -188,27 +188,27 @@ const MinistryStateList = Object.freeze({ // This corresponds to rows in the FOIRequestStatuses table on the backend const StateEnum = Object.freeze({ - open: { name: "Open", id: 1 }, - callforrecords: { name: "Call For Records", id: 2 }, - callforrecordsoverdue: { name: "Call For Records Overdue", id: -100 }, - closed: { name: "Closed", id: 3 }, - redirect: { name: "Redirect", id: 4 }, - unopened: { name: "Unopened", id: 5 }, - intakeinprogress: { name: "Intake in Progress", id: 6 }, - review: { name: "Records Review", id: 7 }, - feeassessed: { name: "Fee Estimate", id: 8 }, - consult: { name: "Consult", id: 9 }, - signoff: { name: "Ministry Sign Off", id: 10 }, - onhold: { name: "On Hold", id: 11 }, - deduplication: { name: "Deduplication", id: 12 }, - harms: { name: "Harms Assessment", id: 13 }, - response: { name: "Response", id: 14 }, - archived: { name: "Archived", id: 15 }, - peerreview: { name: "Peer Review", id: 16 }, - tagging: { name: "Tagging", id: 17 }, - readytoscan: { name: "Ready to Scan", id: 18 }, - appfeeowing: { name: "App Fee Owing", id: 19 }, - section5pending: { name: "Section 5 Pending", id: 20 }, + open: { name: "Open", label: "open" }, + callforrecords: { name: "Call For Records", label: "callforrecords" }, + callforrecordsoverdue: { name: "Call For Records Overdue", label: "callforrecordsoverdue" }, + closed: { name: "Closed", label: "closed" }, + redirect: { name: "Redirect", label: "redirect" }, + unopened: { name: "Unopened", label: "unopened" }, + intakeinprogress: { name: "Intake in Progress", label: "intakeinprogress" }, + review: { name: "Records Review", label: "recordsreview" }, + feeassessed: { name: "Fee Estimate", label: "feeestimate" }, + consult: { name: "Consult", label: "consult" }, + signoff: { name: "Ministry Sign Off", label: "ministrysignoff" }, + onhold: { name: "On Hold", label: "onhold" }, + deduplication: { name: "Deduplication", label: "deduplication" }, + harms: { name: "Harms Assessment", label: "harmsassessment" }, + response: { name: "Response", label: "response" }, + archived: { name: "Archived", label: "archived" }, + peerreview: { name: "Peer Review", label: "peerreview" }, + tagging: { name: "Tagging", label: "tagging" }, + readytoscan: { name: "Ready to Scan", label: "readytoscan" }, + appfeeowing: { name: "App Fee Owing", label: "appfeeowing" }, + section5pending: { name: "Section 5 Pending", label: "section5pending" }, }); const StateTransitionCategories = Object.freeze({ diff --git a/notification-manager/common/notificationtypes.json b/notification-manager/common/notificationtypes.json new file mode 100644 index 000000000..5c04ecec7 --- /dev/null +++ b/notification-manager/common/notificationtypes.json @@ -0,0 +1,142 @@ +{ + "state": { + "notificationtypeid": 1, + "name": "State", + "description": "State", + "active": true, + "notificationtypelabel": "state" + }, + "division": { + "notificationtypeid": 2, + "name": "Division", + "description": "Division", + "active": true, + "notificationtypelabel": "division" + }, + "newusercomments": { + "notificationtypeid": 3, + "name": "New User Comments", + "description": "New User Comments", + "active": true, + "notificationtypelabel": "newusercomments" + }, + "extension": { + "notificationtypeid": 4, + "name": "Extension", + "description": "Extension", + "active": true, + "notificationtypelabel": "extension" + }, + "iaoassignment": { + "notificationtypeid": 5, + "name": "IAO Assignment", + "description": "IAO Assignment", + "active": true, + "notificationtypelabel": "iaoassignment" + }, + "ministryassignment": { + "notificationtypeid": 6, + "name": "Ministry Assignment", + "description": "Ministry Assignment", + "active": true, + "notificationtypelabel": "ministryassignment" + }, + "cfrduereminder": { + "notificationtypeid": 7, + "name": "CFR Due Reminder", + "description": "CFR Due Reminder", + "active": true, + "notificationtypelabel": "cfrduereminder" + }, + "legislativeduereminder": { + "notificationtypeid": 8, + "name": "Legislative Due Reminder", + "description": "Legislative Due Reminder", + "active": true, + "notificationtypelabel": "legislativeduereminder" + }, + "replyusercomments": { + "notificationtypeid": 9, + "name": "Reply User Comments", + "description": "Reply User Comments", + "active": true, + "notificationtypelabel": "replyusercomments" + }, + "taggedusercomments": { + "notificationtypeid": 10, + "name": "Tagged User Comments", + "description": "Tagged User Comments", + "active": true, + "notificationtypelabel": "taggedusercomments" + }, + "cfrfeeform": { + "notificationtypeid": 11, + "name": "CFR Fee Form", + "description": "CFR Fee Form", + "active": true, + "notificationtypelabel": "cfrfeeform" + }, + "groupmembers": { + "notificationtypeid": 12, + "name": "Group Members", + "description": "Group Members", + "active": true, + "notificationtypelabel": "groupmembers" + }, + "divisionduereminder": { + "notificationtypeid": 13, + "name": "Division Due Reminder", + "description": "Division Due Reminder", + "active": true, + "notificationtypelabel": "divisionduereminder" + }, + "watcher": { + "notificationtypeid": 14, + "name": "Watcher", + "description": "Watcher", + "active": true, + "notificationtypelabel": "watcher" + }, + "userassignmentremoval": { + "notificationtypeid": 15, + "name": "User Assignment Removal", + "description": "User Assignment Removal", + "active": true, + "notificationtypelabel": "userassignmentremoval" + }, + "emailfailure": { + "notificationtypeid": 16, + "name": "Email Failure", + "description": "Email Failure", + "active": true, + "notificationtypelabel": "emailfailure" + }, + "payment": { + "notificationtypeid": 17, + "name": "Payment", + "description": "Payment", + "active": true, + "notificationtypelabel": "payment" + }, + "records": { + "notificationtypeid": 18, + "name": "Records", + "description": "Records", + "active": true, + "notificationtypelabel": "records" + }, + "pdfstitch": { + "notificationtypeid": 19, + "name": "PDFStitch", + "description": "PDFStitch", + "active": true, + "notificationtypelabel": "pdfstitch" + }, + "section5pendingreminder": { + "notificationtypeid": 20, + "name": "Section 5 Pending Reminder", + "description": "Section 5 Pending Reminder", + "active": true, + "notificationtypelabel": "section5pendingreminder" + } +} diff --git a/notification-manager/common/notificationusertypes.json b/notification-manager/common/notificationusertypes.json new file mode 100644 index 000000000..0ea835c44 --- /dev/null +++ b/notification-manager/common/notificationusertypes.json @@ -0,0 +1,30 @@ +{ + "watcher": { + "notificationusertypeid": 1, + "name": "Watcher", + "description": "Watcher", + "isactive": true, + "notificationusertypelabel": "watcher" + }, + "assignee": { + "notificationusertypeid": 2, + "name": "Assignee", + "description": "Assignee", + "isactive": true, + "notificationusertypelabel": "assignee" + }, + "commentuser": { + "notificationusertypeid": 3, + "name": "Comment User", + "description": "Comment User", + "isactive": true, + "notificationusertypelabel": "commentuser" + }, + "triggereduser": { + "notificationusertypeid": 4, + "name": "Triggered User", + "description": "Triggered User", + "isactive": true, + "notificationusertypelabel": "triggereduser" + } +} diff --git a/notification-manager/notification_api/dao/models/FOIRequestNotificationUsers.py b/notification-manager/notification_api/dao/models/FOIRequestNotificationUsers.py index df9bd1737..ecf341c6f 100644 --- a/notification-manager/notification_api/dao/models/FOIRequestNotificationUsers.py +++ b/notification-manager/notification_api/dao/models/FOIRequestNotificationUsers.py @@ -11,7 +11,8 @@ class Meta: # pylint: disable=too-few-public-methods unknown = EXCLUDE notificationid = fields.Int(data_key="notificationid") userid = fields.Str(data_key="userid") - notificationusertypeid = fields.Int(data_key="notificationusertypeid") + notificationusertypelabel = fields.Str(data_key="notificationusertypelabel") + notificationusertypeid = fields.Int(data_key="notificationusertypeid") createdby = fields.Str(data_key="createdby") created_at = fields.Str(data_key="created_at") isdeleted = fields.Boolean(data_key="isdeleted") @@ -21,9 +22,9 @@ def savenotificationuser(self, notificationuser): try: conn = getconnection() cursor = conn.cursor() - cursor.execute('INSERT INTO public."FOIRequestNotificationUsers" (notificationid, userid, notificationusertypeid, createdby, created_at, isdeleted) \ - VALUES(%s::integer, %s, %s::integer, %s, %s, %s::boolean)', - (int(notificationuser.notificationid), str(notificationuser.userid), int(notificationuser.notificationusertypeid), str(notificationuser.createdby), datetime.now(), int(notificationuser.isdeleted))) + cursor.execute('INSERT INTO public."FOIRequestNotificationUsers" (notificationid, userid, notificationusertypeid, notificationusertypelabel, createdby, created_at, isdeleted) \ + VALUES(%s::integer, %s, %s::integer, %s, %s, %s, %s::boolean)', + (int(notificationuser.notificationid), str(notificationuser.userid), int(notificationuser.notificationusertypeid), str(notificationuser.notificationusertypelabel), str(notificationuser.createdby), datetime.now(), int(notificationuser.isdeleted))) conn.commit() cursor.close() except(Exception) as error: diff --git a/notification-manager/notification_api/dao/models/FOIRequestNotifications.py b/notification-manager/notification_api/dao/models/FOIRequestNotifications.py index 7cfa7b643..524d4d8ed 100644 --- a/notification-manager/notification_api/dao/models/FOIRequestNotifications.py +++ b/notification-manager/notification_api/dao/models/FOIRequestNotifications.py @@ -13,6 +13,7 @@ class Meta: # pylint: disable=too-few-public-methods requestid = fields.Int(data_key="requestid") idnumber = fields.Str(data_key="idnumber") foirequestid = fields.Int(data_key="foirequestid") + notificationtypelabel = fields.Str(data_key="notificationtypelabel") notificationtypeid = fields.Int(data_key="notificationtypeid") axisnumber = fields.Str(data_key="axisnumber") version = fields.Int(data_key="version") @@ -26,9 +27,9 @@ def savenotification(self, notificationschema): id_of_new_row = None conn = getconnection() cursor = conn.cursor() - cursor.execute('INSERT INTO public."FOIRequestNotifications" (notification, notificationtypeid, requestid, "version", idnumber, axisnumber, foirequestid, createdby, created_at) \ - VALUES(%s::json,%s::integer, %s::integer, %s::integer,%s,%s,%s::integer,%s,%s) RETURNING notificationid', - (json.dumps(notificationschema.notification), int(notificationschema.notificationtypeid), int(notificationschema.requestid), int(notificationschema.version), + cursor.execute('INSERT INTO public."FOIRequestNotifications" (notification, notificationtypeid, notificationtypelabel, requestid, "version", idnumber, axisnumber, foirequestid, createdby, created_at) \ + VALUES(%s::json,%s::integer, %s, %s::integer, %s::integer,%s,%s,%s::integer,%s,%s) RETURNING notificationid', + (json.dumps(notificationschema.notification), int(notificationschema.notificationtypeid), str(notificationschema.notificationtypelabel), int(notificationschema.requestid), int(notificationschema.version), str(notificationschema.idnumber), str(notificationschema.axisnumber), int(notificationschema.foirequestid), str(notificationschema.createdby), datetime.now())) conn.commit() diff --git a/notification-manager/notification_api/dao/models/NotificationTypes.py b/notification-manager/notification_api/dao/models/NotificationTypes.py index 7fdc577b3..458c9d69f 100644 --- a/notification-manager/notification_api/dao/models/NotificationTypes.py +++ b/notification-manager/notification_api/dao/models/NotificationTypes.py @@ -11,10 +11,11 @@ def getid(self, name): _notificationtypes = [] conn = getconnection() cursor = conn.cursor() - cursor.execute("""select notificationtypeid from "NotificationTypes" nt where isactive = true and name = '{0}'""".format(name)) + cursor.execute("""select notificationtypelabel, notificationtypeid from "NotificationTypes" nt where isactive = true and name = '{0}'""".format(name)) data = cursor.fetchone() if data is not None: - return data[0] + data = {"notificationtypelabel": data[0], "notificationtypeid": data[1]} + return data cursor.close() return _notificationtypes diff --git a/notification-manager/notification_api/dao/models/NotificationUserTypes.py b/notification-manager/notification_api/dao/models/NotificationUserTypes.py new file mode 100644 index 000000000..ae06e67f6 --- /dev/null +++ b/notification-manager/notification_api/dao/models/NotificationUserTypes.py @@ -0,0 +1,28 @@ +''' +This file is used in the notification manager container +to fetch the data models for the NotificationUserTypes table +''' +from datetime import datetime +from notification_api.dao.db import getconnection +import logging + +class NotificationUserType(object): + def getid(self, name): + conn = None + try: + _notificationusertypes = [] + conn = getconnection() + cursor = conn.cursor() + cursor.execute("""select notificationusertypelabel, notificationusertypeid from "NotificationUserTypes" nt where isactive = true and name = '{0}'""".format(name)) + data = cursor.fetchone() + if data is not None: + data = {"notificationusertypelabel": data[0], "notificationusertypeid": data[1]} + return data + + cursor.close() + return _notificationusertypes + except(Exception) as error: + logging.error(error) + finally: + if conn: + conn.close() diff --git a/notification-manager/notification_api/services/notifications/notificationconfig.py b/notification-manager/notification_api/services/notifications/notificationconfig.py index 42cc40736..6b18da016 100644 --- a/notification-manager/notification_api/services/notifications/notificationconfig.py +++ b/notification-manager/notification_api/services/notifications/notificationconfig.py @@ -4,6 +4,7 @@ import json import os from notification_api.dao.models.NotificationTypes import NotificationType +from notification_api.dao.models.NotificationUserTypes import NotificationUserType class notificationconfig: """ Notfication config @@ -11,27 +12,24 @@ class notificationconfig: """ def getnotificationtypeid(self, notificationtype): - - if "IAO Assignment" in notificationtype: - return 5 - elif "Ministry Assignment" in notificationtype: - return 6 - else: - notificationid = NotificationType().getid(notificationtype) - if notificationid is not None: - return notificationid - return 0 + notificationid = NotificationType().getid(notificationtype) + if notificationid is not None: + return notificationid + + def getnotificationtype(self, notificationtype): + notificationid = NotificationType().getid(notificationtype) + if notificationid is not None: + return notificationid def getnotificationusertypeid(self, notificationusertype): - if notificationusertype.lower() == "watcher": - return 1 - elif notificationusertype.lower() == "assignee" or "comment" or "group members" in notificationusertype.lower(): - return 2 - elif notificationusertype.lower() == "comment user": - return 3 - elif notificationusertype.lower() == "triggered user": - return 4 - return 0 + notificationuserid = NotificationUserType().getid(notificationusertype) + if notificationuserid is not None: + return notificationuserid + + def getnotificationusertype(self, notificationusertype): + notificationuserid = NotificationUserType().getid(notificationusertype) + if notificationuserid is not None: + return notificationuserid def getnotificationdays(self): if 'FOI_NOTIFICATION_DAYS' in os.environ and os.getenv('FOI_NOTIFICATION_DAYS') != '': diff --git a/notification-manager/notification_api/services/notifications/notificationuser.py b/notification-manager/notification_api/services/notifications/notificationuser.py index 4618dc4d3..35341738f 100644 --- a/notification-manager/notification_api/services/notifications/notificationuser.py +++ b/notification-manager/notification_api/services/notifications/notificationuser.py @@ -8,7 +8,7 @@ from notification_api.services.external.keycloakadminservice import KeycloakAdminService class notificationuser: - """ Notfication user service + """ notification user service """ @@ -54,33 +54,33 @@ def __istaggeduser(self, notificationuser, foicomment, notificationtype): def __gettriggereduser(self, userid, notificationtype): notificationusers = [] if notificationtype in ["Records", "PDFStitch"]: - notificationusers.append({"userid":userid, "usertype":notificationconfig().getnotificationusertypeid("triggered user")}) + notificationusers.append({"userid":userid, "usertype":notificationconfig().getnotificationusertype("Triggered User")['notificationusertypelabel']}) return notificationusers def __getwatchers(self, notificationtype, foirequest, requesttype, requestjson=None): notificationusers = [] if notificationtype == "Watcher": - notificationusers.append({"userid": requestjson['watchedby'], "usertype":notificationconfig().getnotificationusertypeid("Watcher")}) + notificationusers.append({"userid": requestjson['watchedby'], "usertype":notificationconfig().getnotificationusertype("Watcher")['notificationusertypelabel']}) else: if requesttype == "ministryrequest": watchers = FOIMinistryRequest().getwatchers(foirequest["foiministryrequestid"]) else: watchers = FOIRawRequest().getwatchers(foirequest['requestid']) for watcher in watchers: - notificationusers.append({"userid":watcher["watchedby"], "usertype":notificationconfig().getnotificationusertypeid("Watcher")}) + notificationusers.append({"userid":watcher["watchedby"], "usertype":notificationconfig().getnotificationusertype("Watcher")['notificationusertypelabel']}) return notificationusers def __getassignees(self, foirequest, requesttype, notificationtype, requestjson=None): notificationusers = [] - notificationtypeid = notificationconfig().getnotificationusertypeid("Assignee") + notificationtypelabel = "assignee" #notificationconfig().getnotificationusertypelabel("assignee") if notificationtype == 'User Assignment Removal': - notificationusers.append({"userid": requestjson['userid'], "usertype":notificationtypeid}) + notificationusers.append({"userid": requestjson['userid'], "usertype":notificationtypelabel}) else: if requesttype == "ministryrequest" and foirequest["assignedministryperson"] is not None and (notificationtype == 'Ministry Assignment' or 'Assignment' not in notificationtype): - notificationusers.append({"userid":foirequest["assignedministryperson"], "usertype":notificationtypeid}) + notificationusers.append({"userid":foirequest["assignedministryperson"], "usertype":notificationtypelabel}) if foirequest["assignedto"] is not None and foirequest["assignedto"] != '' and (notificationtype == 'IAO Assignment' or 'Assignment' not in notificationtype): - notificationusers.append({"userid":foirequest["assignedto"], "usertype":notificationtypeid}) + notificationusers.append({"userid":foirequest["assignedto"], "usertype":notificationtypelabel}) return notificationusers def __getcommentusers(self, foirequest, comment, requesttype): @@ -105,7 +105,7 @@ def __getcommentusertype(self, userid, requestusers): for requestuser in requestusers: if requestuser["userid"] == userid: return requestuser["usertype"] - return notificationconfig().getnotificationusertypeid("comment user") + return notificationconfig().getnotificationusertypelabel("comment user") def __getrelatedusers(self, comment, requesttype): if requesttype == "ministryrequest": @@ -121,14 +121,14 @@ def __gettaggedusers(self, comment): def __preparetaggeduser(self, data): taggedusers = [] for entry in data: - taggedusers.append({"userid":entry["username"], "usertype":notificationconfig().getnotificationusertypeid("comment tagged user")}) + taggedusers.append({"userid":entry["username"], "usertype":notificationconfig().getnotificationusertypelabel("comment tagged user")}) return taggedusers def __getgroupmembers(self,groupid): notificationusers = [] - notificationtypeid = notificationconfig().getnotificationusertypeid("Group Members") + notificationtypelabel = notificationconfig().getnotificationusertypelabel("Group Members") usergroupfromkeycloak= KeycloakAdminService().getmembersbygroupname(groupid) for user in usergroupfromkeycloak[0].get("members"): - notificationusers.append({"userid":user["username"], "usertype":notificationtypeid}) + notificationusers.append({"userid":user["username"], "usertype":notificationtypelabel}) return notificationusers \ No newline at end of file diff --git a/notification-manager/notification_api/services/notificationservice.py b/notification-manager/notification_api/services/notificationservice.py index 8c46a8fff..3a9df645d 100644 --- a/notification-manager/notification_api/services/notificationservice.py +++ b/notification-manager/notification_api/services/notificationservice.py @@ -14,6 +14,9 @@ from dateutil.parser import parse from pytz import timezone import logging +import json +f = open('common/notificationusertypes.json', encoding="utf8") +notificationusertypes_cache = json.load(f) class notificationservice: """ FOI notification management service @@ -65,7 +68,9 @@ def __preparenotification(self, message, requesttype, notificationtype, userid, notification.requestid = foirequest["foiministryrequestid"] notification.idnumber = foirequest["filenumber"] notification.foirequestid = foirequest["foirequest_id"] - notification.notificationtypeid = notificationconfig().getnotificationtypeid(notificationtype) + notificationtypes = notificationconfig().getnotificationtype(notificationtype) + notification.notificationtypelabel = notificationtypes['notificationtypelabel'] + notification.notificationtypeid = notificationtypes['notificationtypeid'] notification.axisnumber = foirequest["axisrequestid"] notification.version = foirequest["version"] notification.createdby = userid @@ -79,7 +84,13 @@ def __preparenotificationuser(self, notificationid, notificationuser, userid, mu user.isdeleted = mute else: user.isdeleted = False - user.notificationusertypeid = notificationuser["usertype"] + usertype = notificationusertypes_cache[notificationuser["usertype"]] + if usertype is None: + print('User type not found', notificationuser["usertype"]) + return None + notificationtypes = notificationconfig().getnotificationusertype(usertype['name']) + user.notificationusertypelabel = notificationtypes['notificationusertypelabel'] + user.notificationusertypeid = notificationtypes['notificationusertypeid'] user.notificationid = notificationid user.userid = notificationuser["userid"] user.createdby = userid @@ -102,4 +113,4 @@ def __mutenotification(self, requesttype, notificationtype, request): return False return True - return False \ No newline at end of file + return False diff --git a/notification-manager/notification_api/util/enums.py b/notification-manager/notification_api/util/enums.py index 6d67df5a3..3eb507072 100644 --- a/notification-manager/notification_api/util/enums.py +++ b/notification-manager/notification_api/util/enums.py @@ -5,6 +5,6 @@ class ServiceKey(Enum): """Authorization header types.""" - pdfstitchforhamrs = "pdfstitchforhamrs" + pdfstitchforhamrs = "pdfstitchforharms" pdfstitchforredline = "pdfstitchforredline" pdfstitchforresponsepackage = "pdfstitchforresponsepackage" diff --git a/notification-manager/sample.env b/notification-manager/sample.env index 8898ee81e..ec3d90c8a 100644 --- a/notification-manager/sample.env +++ b/notification-manager/sample.env @@ -19,4 +19,4 @@ NOTIFICATION_REDIS_PORT= NOTIFICATION_REDIS_PASSWORD= NOTIFICATION_REDIS_HEALTHCHECK_INT=10 NOTIFICATION_STREAM_KEY=FOINOTIFICATION -MUTE_NOTIFICATION={"MCF": {"request_types": ["Personal"], "state_exceptions": ["Call For Records", "Ministry Sign Off"], "type_exceptions":["Reply User Comments", "Tagged User Comments"]}} \ No newline at end of file +MUTE_NOTIFICATION={"MCF": {"request_types": ["Personal"], "state_exceptions": ["Call For Records", "Ministry Sign Off"], "type_exceptions":["Reply User Comments", "Tagged User Comments"]}} diff --git a/request-management-api/common/notificationtypes.json b/request-management-api/common/notificationtypes.json new file mode 100644 index 000000000..5c04ecec7 --- /dev/null +++ b/request-management-api/common/notificationtypes.json @@ -0,0 +1,142 @@ +{ + "state": { + "notificationtypeid": 1, + "name": "State", + "description": "State", + "active": true, + "notificationtypelabel": "state" + }, + "division": { + "notificationtypeid": 2, + "name": "Division", + "description": "Division", + "active": true, + "notificationtypelabel": "division" + }, + "newusercomments": { + "notificationtypeid": 3, + "name": "New User Comments", + "description": "New User Comments", + "active": true, + "notificationtypelabel": "newusercomments" + }, + "extension": { + "notificationtypeid": 4, + "name": "Extension", + "description": "Extension", + "active": true, + "notificationtypelabel": "extension" + }, + "iaoassignment": { + "notificationtypeid": 5, + "name": "IAO Assignment", + "description": "IAO Assignment", + "active": true, + "notificationtypelabel": "iaoassignment" + }, + "ministryassignment": { + "notificationtypeid": 6, + "name": "Ministry Assignment", + "description": "Ministry Assignment", + "active": true, + "notificationtypelabel": "ministryassignment" + }, + "cfrduereminder": { + "notificationtypeid": 7, + "name": "CFR Due Reminder", + "description": "CFR Due Reminder", + "active": true, + "notificationtypelabel": "cfrduereminder" + }, + "legislativeduereminder": { + "notificationtypeid": 8, + "name": "Legislative Due Reminder", + "description": "Legislative Due Reminder", + "active": true, + "notificationtypelabel": "legislativeduereminder" + }, + "replyusercomments": { + "notificationtypeid": 9, + "name": "Reply User Comments", + "description": "Reply User Comments", + "active": true, + "notificationtypelabel": "replyusercomments" + }, + "taggedusercomments": { + "notificationtypeid": 10, + "name": "Tagged User Comments", + "description": "Tagged User Comments", + "active": true, + "notificationtypelabel": "taggedusercomments" + }, + "cfrfeeform": { + "notificationtypeid": 11, + "name": "CFR Fee Form", + "description": "CFR Fee Form", + "active": true, + "notificationtypelabel": "cfrfeeform" + }, + "groupmembers": { + "notificationtypeid": 12, + "name": "Group Members", + "description": "Group Members", + "active": true, + "notificationtypelabel": "groupmembers" + }, + "divisionduereminder": { + "notificationtypeid": 13, + "name": "Division Due Reminder", + "description": "Division Due Reminder", + "active": true, + "notificationtypelabel": "divisionduereminder" + }, + "watcher": { + "notificationtypeid": 14, + "name": "Watcher", + "description": "Watcher", + "active": true, + "notificationtypelabel": "watcher" + }, + "userassignmentremoval": { + "notificationtypeid": 15, + "name": "User Assignment Removal", + "description": "User Assignment Removal", + "active": true, + "notificationtypelabel": "userassignmentremoval" + }, + "emailfailure": { + "notificationtypeid": 16, + "name": "Email Failure", + "description": "Email Failure", + "active": true, + "notificationtypelabel": "emailfailure" + }, + "payment": { + "notificationtypeid": 17, + "name": "Payment", + "description": "Payment", + "active": true, + "notificationtypelabel": "payment" + }, + "records": { + "notificationtypeid": 18, + "name": "Records", + "description": "Records", + "active": true, + "notificationtypelabel": "records" + }, + "pdfstitch": { + "notificationtypeid": 19, + "name": "PDFStitch", + "description": "PDFStitch", + "active": true, + "notificationtypelabel": "pdfstitch" + }, + "section5pendingreminder": { + "notificationtypeid": 20, + "name": "Section 5 Pending Reminder", + "description": "Section 5 Pending Reminder", + "active": true, + "notificationtypelabel": "section5pendingreminder" + } +} diff --git a/request-management-api/common/notificationusertypes.json b/request-management-api/common/notificationusertypes.json new file mode 100644 index 000000000..1048cc990 --- /dev/null +++ b/request-management-api/common/notificationusertypes.json @@ -0,0 +1,58 @@ +{ + "watcher": { + "notificationusertypeid": 1, + "name": "Watcher", + "description": "Watcher", + "isactive": true, + "notificationusertypelabel": "watcher" + }, + "assignee": { + "notificationusertypeid": 2, + "name": "Assignee", + "description": "Assignee", + "isactive": true, + "notificationusertypelabel": "assignee" + }, + "groupmembers": { + "notificationusertypeid": 2, + "name": "Group Members", + "description": "Assignee", + "isactive": true, + "notificationusertypelabel": "assignee" + }, + "groupmember": { + "notificationusertypeid": 2, + "name": "groupmembers", + "description": "Assignee", + "isactive": true, + "notificationusertypelabel": "assignee" + }, + "comment": { + "notificationusertypeid": 2, + "name": "Comment", + "description": "Assignee", + "isactive": true, + "notificationusertypelabel": "assignee" + }, + "commentuser": { + "notificationusertypeid": 3, + "name": "Comment User", + "description": "Comment User", + "isactive": true, + "notificationusertypelabel": "commentuser" + }, + "comment tagged user": { + "notificationusertypeid": 3, + "name": "comment tagged user", + "description": "Comment User", + "isactive": true, + "notificationusertypelabel": "commentuser" + }, + "triggereduser": { + "notificationusertypeid": 4, + "name": "Triggered User", + "description": "Triggered User", + "isactive": true, + "notificationusertypelabel": "triggereduser" + } +} diff --git a/request-management-api/migrations/versions/29b44e8dc305_.py b/request-management-api/migrations/versions/29b44e8dc305_.py new file mode 100644 index 000000000..eaf2adf40 --- /dev/null +++ b/request-management-api/migrations/versions/29b44e8dc305_.py @@ -0,0 +1,186 @@ +"""empty message + +Revision ID: 29b44e8dc305 +Revises: +Create Date: 2021-07-08 10:08:53.028617 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '29b44e8dc305' +down_revision = 'd185518c3661' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute('ALTER TABLE public."NotificationTypes" ADD COLUMN notificationtypelabel VARCHAR(50);') + op.execute('UPDATE public."NotificationTypes" SET notificationtypelabel = REPLACE(LOWER(name), \' \', \'\');') + op.execute('ALTER TABLE public."NotificationTypes" ALTER COLUMN notificationtypelabel SET NOT NULL;') + op.execute('ALTER TABLE public."NotificationTypes" ADD CONSTRAINT unique_notificationtypelabel UNIQUE (notificationtypelabel);') + + op.execute('ALTER TABLE public."NotificationUserTypes" ADD COLUMN notificationusertypelabel VARCHAR(50);') + op.execute('UPDATE public."NotificationUserTypes" SET notificationusertypelabel = REPLACE(LOWER(name), \' \', \'\');') + op.execute('ALTER TABLE public."NotificationUserTypes" ALTER COLUMN notificationusertypelabel SET NOT NULL;') + op.execute('ALTER TABLE public."NotificationUserTypes" ADD CONSTRAINT unique_notificationusertypelabel UNIQUE (notificationusertypelabel);') + + op.execute('ALTER TABLE public."FOIRequestNotifications" ADD COLUMN notificationtypelabel VARCHAR(50);') + op.execute('UPDATE public."FOIRequestNotifications" AS mr SET notificationtypelabel = st.notificationtypelabel FROM public."NotificationTypes" AS st WHERE mr.notificationtypeid = st.notificationtypeid;') + op.execute('ALTER TABLE public."FOIRequestNotifications" ALTER COLUMN notificationtypelabel SET NOT NULL;') + op.execute('ALTER TABLE public."FOIRequestNotifications" ALTER COLUMN notificationtypeid DROP NOT NULL;') + + op.execute('ALTER TABLE public."FOIRawRequestNotifications" ADD COLUMN notificationtypelabel VARCHAR(50);') + op.execute('UPDATE public."FOIRawRequestNotifications" AS mr SET notificationtypelabel = st.notificationtypelabel FROM public."NotificationTypes" AS st WHERE mr.notificationtypeid = st.notificationtypeid;') + op.execute('ALTER TABLE public."FOIRawRequestNotifications" ALTER COLUMN notificationtypelabel SET NOT NULL;') + op.execute('ALTER TABLE public."FOIRawRequestNotifications" ALTER COLUMN notificationtypeid DROP NOT NULL;') + + op.execute('ALTER TABLE public."FOIRequestNotificationUsers" ADD COLUMN notificationusertypelabel VARCHAR(50);') + op.execute('UPDATE public."FOIRequestNotificationUsers" AS mr SET notificationusertypelabel = st.notificationusertypelabel FROM public."NotificationUserTypes" AS st WHERE mr.notificationusertypeid = st.notificationusertypeid;') + op.execute('ALTER TABLE public."FOIRequestNotificationUsers" ALTER COLUMN notificationusertypelabel SET NOT NULL;') + op.execute('ALTER TABLE public."FOIRequestNotificationUsers" ALTER COLUMN notificationusertypelabel DROP NOT NULL;') + + op.execute('ALTER TABLE public."FOIRawRequestNotificationUsers" ADD COLUMN notificationusertypelabel VARCHAR(50);') + op.execute('UPDATE public."FOIRawRequestNotificationUsers" AS mr SET notificationusertypelabel = st.notificationusertypelabel FROM public."NotificationUserTypes" AS st WHERE mr.notificationusertypeid = st.notificationusertypeid;') + op.execute('ALTER TABLE public."FOIRawRequestNotificationUsers" ALTER COLUMN notificationusertypelabel SET NOT NULL;') + op.execute('ALTER TABLE public."FOIRawRequestNotificationUsers" ALTER COLUMN notificationusertypelabel DROP NOT NULL;') + + op.execute('drop view public."v_FOINotifications";') + op.execute(""" +CREATE OR REPLACE VIEW public."v_FOINotifications" +AS select fn.idnumber::text || to_char(fnu.created_at,'YYYYMMDDHH24MMSSMSUS') || fn.axisnumber::text||fnu.userid||fnu.createdby AS id, + fn.idnumber, + fn.axisnumber, + fn.notification ->> 'message'::text AS notification, + fn.notificationtypeid, + fn.notificationtypelabel, + fnu.userid, + fnu.createdby, + fnu.created_at, + CASE + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NOT NULL THEN ((usr.lastname || ', '::text) || usr.firstname)::character varying + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NULL THEN usr.lastname::character varying + WHEN usr.lastname IS NULL AND usr.firstname IS NOT NULL THEN usr.firstname::character varying + ELSE fnu.userid + END AS userformatted, + CASE + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NOT NULL THEN ((ctr.lastname || ', '::text) || ctr.firstname)::character varying + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NULL THEN ctr.lastname::character varying + WHEN ctr.lastname IS NULL AND ctr.firstname IS NOT NULL THEN ctr.firstname::character varying + ELSE fnu.createdby + END AS creatorformatted, + nt.name AS notificationtype, + to_char(fnu.created_at at time zone 'utc' at time zone 'pdt', 'YYYY Mon DD | HH12:MI AM') as createdatformatted + FROM "FOIRequestNotifications" fn + JOIN "FOIRequestNotificationUsers" fnu ON fn.notificationid = fnu.notificationid + LEFT JOIN "FOIUsers" usr ON fnu.userid::text = usr.preferred_username + LEFT JOIN "FOIUsers" ctr ON fnu.createdby::text = ctr.preferred_username + JOIN "NotificationTypes" nt ON fn.notificationtypeid = nt.notificationtypeid +UNION ALL + SELECT fn.idnumber::text || to_char(fnu.created_at,'YYYYMMDDHH24MMSSMSUS') || fn.axisnumber::text||fnu.userid||fnu.createdby AS id, + fn.idnumber, + fn.axisnumber, + fn.notification ->> 'message'::text AS notification, + fn.notificationtypeid, + fn.notificationtypelabel , + fnu.userid, + fnu.createdby, + fnu.created_at, + CASE + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NOT NULL THEN ((usr.lastname || ', '::text) || usr.firstname)::character varying + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NULL THEN usr.lastname::character varying + WHEN usr.lastname IS NULL AND usr.firstname IS NOT NULL THEN usr.firstname::character varying + ELSE fnu.userid + END AS userformatted, + CASE + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NOT NULL THEN ((ctr.lastname || ', '::text) || ctr.firstname)::character varying + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NULL THEN ctr.lastname::character varying + WHEN ctr.lastname IS NULL AND ctr.firstname IS NOT NULL THEN ctr.firstname::character varying + ELSE fnu.createdby + END AS creatorformatted, + nt.name AS notificationtype, + to_char(fnu.created_at at time zone 'utc' at time zone 'pdt', 'YYYY Mon DD | HH12:MI AM') as createdatformatted + FROM "FOIRawRequestNotifications" fn + JOIN "FOIRawRequestNotificationUsers" fnu ON fn.notificationid = fnu.notificationid + LEFT JOIN "FOIUsers" usr ON fnu.userid::text = usr.preferred_username + LEFT JOIN "FOIUsers" ctr ON fnu.createdby::text = ctr.preferred_username + JOIN "NotificationTypes" nt ON fn.notificationtypeid = nt.notificationtypeid; +""") + + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute('drop view public."v_FOINotifications";') + op.execute(""" +CREATE OR REPLACE VIEW public."v_FOINotifications" +AS select fn.idnumber::text || to_char(fnu.created_at,'YYYYMMDDHH24MMSSMSUS') || fn.axisnumber::text||fnu.userid||fnu.createdby AS id, + fn.idnumber, + fn.axisnumber, + fn.notification ->> 'message'::text AS notification, + fn.notificationtypeid, + fnu.userid, + fnu.createdby, + fnu.created_at, + CASE + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NOT NULL THEN ((usr.lastname || ', '::text) || usr.firstname)::character varying + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NULL THEN usr.lastname::character varying + WHEN usr.lastname IS NULL AND usr.firstname IS NOT NULL THEN usr.firstname::character varying + ELSE fnu.userid + END AS userformatted, + CASE + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NOT NULL THEN ((ctr.lastname || ', '::text) || ctr.firstname)::character varying + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NULL THEN ctr.lastname::character varying + WHEN ctr.lastname IS NULL AND ctr.firstname IS NOT NULL THEN ctr.firstname::character varying + ELSE fnu.createdby + END AS creatorformatted, + nt.name AS notificationtype, + to_char(fnu.created_at at time zone 'utc' at time zone 'pdt', 'YYYY Mon DD | HH12:MI AM') as createdatformatted + FROM "FOIRequestNotifications" fn + JOIN "FOIRequestNotificationUsers" fnu ON fn.notificationid = fnu.notificationid + LEFT JOIN "FOIUsers" usr ON fnu.userid::text = usr.preferred_username + LEFT JOIN "FOIUsers" ctr ON fnu.createdby::text = ctr.preferred_username + JOIN "NotificationTypes" nt ON fn.notificationtypeid = nt.notificationtypeid +UNION ALL + SELECT fn.idnumber::text || to_char(fnu.created_at,'YYYYMMDDHH24MMSSMSUS') || fn.axisnumber::text||fnu.userid||fnu.createdby AS id, + fn.idnumber, + fn.axisnumber, + fn.notification ->> 'message'::text AS notification, + fn.notificationtypeid, + fnu.userid, + fnu.createdby, + fnu.created_at, + CASE + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NOT NULL THEN ((usr.lastname || ', '::text) || usr.firstname)::character varying + WHEN usr.lastname IS NOT NULL AND usr.firstname IS NULL THEN usr.lastname::character varying + WHEN usr.lastname IS NULL AND usr.firstname IS NOT NULL THEN usr.firstname::character varying + ELSE fnu.userid + END AS userformatted, + CASE + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NOT NULL THEN ((ctr.lastname || ', '::text) || ctr.firstname)::character varying + WHEN ctr.lastname IS NOT NULL AND ctr.firstname IS NULL THEN ctr.lastname::character varying + WHEN ctr.lastname IS NULL AND ctr.firstname IS NOT NULL THEN ctr.firstname::character varying + ELSE fnu.createdby + END AS creatorformatted, + nt.name AS notificationtype, + to_char(fnu.created_at at time zone 'utc' at time zone 'pdt', 'YYYY Mon DD | HH12:MI AM') as createdatformatted + FROM "FOIRawRequestNotifications" fn + JOIN "FOIRawRequestNotificationUsers" fnu ON fn.notificationid = fnu.notificationid + LEFT JOIN "FOIUsers" usr ON fnu.userid::text = usr.preferred_username + LEFT JOIN "FOIUsers" ctr ON fnu.createdby::text = ctr.preferred_username + JOIN "NotificationTypes" nt ON fn.notificationtypeid = nt.notificationtypeid; +""") + + op.execute('ALTER TABLE public."FOIRequestNotifications" drop column notificationtypelabel;') + op.execute('ALTER TABLE public."FOIRequestNotificationUsers" drop column notificationusertypelabel;') + op.execute('ALTER TABLE public."FOIRawRequestNotifications" drop column notificationtypelabel;') + op.execute('ALTER TABLE public."FOIRawRequestNotificationUsers" drop column notificationusertypelabel;') + op.execute('ALTER TABLE public."NotificationTypes" drop column notificationtypelabel;') + op.execute('ALTER TABLE public."NotificationUserTypes" drop column notificationusertypelabel;') + # ### end Alembic commands ### + diff --git a/request-management-api/migrations/versions/d185518c3661_ state_label.py b/request-management-api/migrations/versions/d185518c3661_ state_label.py new file mode 100644 index 000000000..205948f0d --- /dev/null +++ b/request-management-api/migrations/versions/d185518c3661_ state_label.py @@ -0,0 +1,228 @@ +"""empty message + +Revision ID: d185518c3661 +Revises: 7fa7236d06fb +Create Date: 2023-06-01 22:31:24.595281 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'd185518c3661' +down_revision = '7fa7236d06fb' + +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute('ALTER TABLE public."FOIRequestStatuses" ADD COLUMN statuslabel VARCHAR(50);') + op.execute('UPDATE public."FOIRequestStatuses" SET statuslabel = REPLACE(LOWER(name), \' \', \'\');') + op.execute('ALTER TABLE public."FOIRequestStatuses" ALTER COLUMN statuslabel SET NOT NULL;') + op.execute('ALTER TABLE public."FOIRequestStatuses" ADD CONSTRAINT unique_statuslabel UNIQUE (statuslabel);') + + op.execute('ALTER TABLE public."FOIMinistryRequests" ADD COLUMN requeststatuslabel VARCHAR(50);') + op.execute('UPDATE public."FOIMinistryRequests" AS mr SET requeststatuslabel = st.statuslabel FROM public."FOIRequestStatuses" AS st WHERE mr.requeststatusid = st.requeststatusid;') + op.execute('ALTER TABLE public."FOIMinistryRequests" ALTER COLUMN requeststatuslabel SET NOT NULL;') + op.execute('DROP INDEX "FOIMinistryRequests_event";') + op.execute('CREATE INDEX "FOIMinistryRequests_event" ON "FOIMinistryRequests"(axisrequestid, assignedto, assignedgroup, assignedministryperson, assignedministrygroup, requeststatusid, requeststatuslabel);') + + op.execute('ALTER TABLE public."FOIRawRequests" ADD COLUMN requeststatuslabel VARCHAR(50);') + op.execute('UPDATE public."FOIRawRequests" SET requeststatuslabel = REPLACE(LOWER(status), \' \', \'\');') + op.execute('ALTER TABLE public."FOIRawRequests" ALTER COLUMN requeststatuslabel SET NOT NULL;') + op.execute('DROP INDEX "FOIRawRequests_event";') + op.execute('CREATE INDEX "FOIRawRequests_event" ON "FOIRawRequests" (axisrequestid, assignedto, assignedgroup, status, requeststatuslabel);') + + op.execute('ALTER TABLE public."FOIRequestTeams" ADD COLUMN requeststatuslabel VARCHAR(50);') + op.execute('UPDATE public."FOIRequestTeams" AS rt SET requeststatuslabel = st.statuslabel FROM public."FOIRequestStatuses" AS st WHERE rt.requeststatusid = st.requeststatusid;') + op.execute('ALTER TABLE public."FOIRequestTeams" ALTER COLUMN requeststatuslabel SET NOT NULL;') + + + op.execute(""" +CREATE OR REPLACE VIEW public."v_FOIRequests" +AS SELECT DISTINCT ON (fr.foiministryrequestid) fr.foiministryrequestid, + fr.version, + fr.axisrequestid, + fr.foirequest_id, + NULL::text AS rawrequestid, + fr.assignedto, + fr.assignedgroup, + fr.assignedministryperson, + fr.assignedministrygroup, + CASE + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NOT NULL THEN ((asg.lastname::text || ', '::text) || asg.firstname::text)::character varying + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NULL THEN asg.lastname + WHEN asg.lastname IS NULL AND asg.firstname IS NOT NULL THEN asg.firstname + ELSE coalesce(fr.assignedto, fr.assignedgroup) + END AS assignedtoformatted, + CASE + WHEN msg.lastname IS NOT NULL AND msg.firstname IS NOT NULL THEN ((msg.lastname::text || ', '::text) || msg.firstname::text)::character varying + WHEN msg.lastname IS NOT NULL AND msg.firstname IS NULL THEN msg.lastname + WHEN msg.lastname IS NULL AND msg.firstname IS NOT NULL THEN msg.firstname + ELSE coalesce(fr.assignedministryperson, fr.assignedministrygroup) + END AS ministryassignedtoformatted, + fr.requeststatusid, + fs2.name AS status, + fr.description, to_char(fr.created_at,'YYYYMMDDHH24MMSSMSUS') crtid, + fr.requeststatuslabel AS requeststatuslabel + FROM "FOIMinistryRequests" fr + JOIN "FOIRequestStatuses" fs2 ON fr.requeststatusid = fs2.requeststatusid + LEFT JOIN "FOIAssignees" asg ON fr.assignedto::text = asg.username::text + LEFT JOIN "FOIAssignees" msg ON fr.assignedministryperson::text = msg.username::text + ORDER BY fr.foiministryrequestid, fr.version DESC, fr.axisrequestid; +""") + op.execute(""" +CREATE OR REPLACE VIEW public."v_FOIRawRequests" +AS SELECT tmp.requestid::text AS rawrequestid, + tmp.axisrequestid, + tmp.foirequest_id, + tmp.ministryrequestid, + tmp.assignedto, + tmp.assignedgroup, + tmp.assignedministryperson, + tmp.assignedministrygroup, + tmp.assignedtoformatted, + tmp.ministryassignedtoformatted, + tmp.status, + tmp.description, + tmp.isiaorestricted, + tmp.crtid + FROM ( SELECT DISTINCT ON (fr.requestid) fr.requestid, + fr.version, + CASE + WHEN fr.axisrequestid IS NULL THEN ('U-00'::text || fr.requestid)::character varying + ELSE fr.axisrequestid + END AS axisrequestid, + NULL::integer AS foirequest_id, + NULL::integer AS ministryrequestid, + fr.assignedto, + fr.assignedgroup, + NULL::text AS assignedministryperson, + NULL::text AS assignedministrygroup, + CASE + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NOT NULL THEN ((asg.lastname::text || ', '::text) || asg.firstname::text)::character varying + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NULL THEN asg.lastname + WHEN asg.lastname IS NULL AND asg.firstname IS NOT NULL THEN asg.firstname + ELSE coalesce(fr.assignedto, fr.assignedgroup) + END AS assignedtoformatted, + NULL::text AS ministryassignedtoformatted, + fr.status, + CASE + WHEN fr.status::text = 'Unopened'::text THEN (fr.requestrawdata -> 'descriptionTimeframe'::text) ->> 'description'::text + ELSE fr.requestrawdata ->> 'description'::text + END AS description, + fr.isiaorestricted, to_char(fr.created_at,'YYYYMMDDHH24MMSSMSUS') crtid + FROM "FOIRawRequests" fr + LEFT JOIN "FOIAssignees" asg ON fr.assignedto::text = asg.username::text + WHERE NOT (fr.axisrequestid::text IN ( SELECT "v_FOIRequests".axisrequestid + FROM "v_FOIRequests" + WHERE "v_FOIRequests".requeststatuslabel = 'closed')) + ORDER BY fr.requestid, fr.version DESC, fr.axisrequestid) tmp + WHERE tmp.status::text <> ALL (ARRAY['Archived'::character varying, 'Unopened'::character varying, 'Closed'::character varying]::text[]); +""") + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute('drop view public."v_FOIRawRequests";') + op.execute('drop view public."v_FOIRequests";') + op.execute(""" +CREATE OR REPLACE VIEW public."v_FOIRequests" +AS SELECT DISTINCT ON (fr.foiministryrequestid) fr.foiministryrequestid, + fr.version, + fr.axisrequestid, + fr.foirequest_id, + NULL::text AS rawrequestid, + fr.assignedto, + fr.assignedgroup, + fr.assignedministryperson, + fr.assignedministrygroup, + CASE + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NOT NULL THEN ((asg.lastname::text || ', '::text) || asg.firstname::text)::character varying + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NULL THEN asg.lastname + WHEN asg.lastname IS NULL AND asg.firstname IS NOT NULL THEN asg.firstname + ELSE coalesce(fr.assignedto, fr.assignedgroup) + END AS assignedtoformatted, + CASE + WHEN msg.lastname IS NOT NULL AND msg.firstname IS NOT NULL THEN ((msg.lastname::text || ', '::text) || msg.firstname::text)::character varying + WHEN msg.lastname IS NOT NULL AND msg.firstname IS NULL THEN msg.lastname + WHEN msg.lastname IS NULL AND msg.firstname IS NOT NULL THEN msg.firstname + ELSE coalesce(fr.assignedministryperson, fr.assignedministrygroup) + END AS ministryassignedtoformatted, + fr.requeststatusid, + fs2.name AS status, + fr.description, to_char(fr.created_at,'YYYYMMDDHH24MMSSMSUS') crtid + FROM "FOIMinistryRequests" fr + JOIN "FOIRequestStatuses" fs2 ON fr.requeststatusid = fs2.requeststatusid + LEFT JOIN "FOIAssignees" asg ON fr.assignedto::text = asg.username::text + LEFT JOIN "FOIAssignees" msg ON fr.assignedministryperson::text = msg.username::text + ORDER BY fr.foiministryrequestid, fr.version DESC, fr.axisrequestid; +""") + op.execute(""" +CREATE OR REPLACE VIEW public."v_FOIRawRequests" +AS SELECT tmp.requestid::text AS rawrequestid, + tmp.axisrequestid, + tmp.foirequest_id, + tmp.ministryrequestid, + tmp.assignedto, + tmp.assignedgroup, + tmp.assignedministryperson, + tmp.assignedministrygroup, + tmp.assignedtoformatted, + tmp.ministryassignedtoformatted, + tmp.status, + tmp.description, + tmp.isiaorestricted, + tmp.crtid + FROM ( SELECT DISTINCT ON (fr.requestid) fr.requestid, + fr.version, + CASE + WHEN fr.axisrequestid IS NULL THEN ('U-00'::text || fr.requestid)::character varying + ELSE fr.axisrequestid + END AS axisrequestid, + NULL::integer AS foirequest_id, + NULL::integer AS ministryrequestid, + fr.assignedto, + fr.assignedgroup, + NULL::text AS assignedministryperson, + NULL::text AS assignedministrygroup, + CASE + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NOT NULL THEN ((asg.lastname::text || ', '::text) || asg.firstname::text)::character varying + WHEN asg.lastname IS NOT NULL AND asg.firstname IS NULL THEN asg.lastname + WHEN asg.lastname IS NULL AND asg.firstname IS NOT NULL THEN asg.firstname + ELSE coalesce(fr.assignedto, fr.assignedgroup) + END AS assignedtoformatted, + NULL::text AS ministryassignedtoformatted, + fr.status, + CASE + WHEN fr.status::text = 'Unopened'::text THEN (fr.requestrawdata -> 'descriptionTimeframe'::text) ->> 'description'::text + ELSE fr.requestrawdata ->> 'description'::text + END AS description, + fr.isiaorestricted, to_char(fr.created_at,'YYYYMMDDHH24MMSSMSUS') crtid + FROM "FOIRawRequests" fr + LEFT JOIN "FOIAssignees" asg ON fr.assignedto::text = asg.username::text + WHERE NOT (fr.axisrequestid::text IN ( SELECT "v_FOIRequests".axisrequestid + FROM "v_FOIRequests" + WHERE "v_FOIRequests".requeststatusid = 3)) + ORDER BY fr.requestid, fr.version DESC, fr.axisrequestid) tmp + WHERE tmp.status::text <> ALL (ARRAY['Archived'::character varying, 'Unopened'::character varying, 'Closed'::character varying]::text[]); +""") + + op.execute('DROP INDEX "FOIMinistryRequests_event";') + op.execute('CREATE INDEX "FOIMinistryRequests_event" ON "FOIMinistryRequests"(axisrequestid, assignedto, assignedgroup, assignedministryperson, assignedministrygroup, requeststatusid);') + + op.execute('DROP INDEX "FOIRawRequests_event";') + op.execute('CREATE INDEX "FOIRawRequests_event" ON "FOIRawRequests" (axisrequestid, assignedto, assignedgroup, status);') + + op.execute('ALTER TABLE public."FOIRequestStatuses" drop column statuslabel;') + op.execute('ALTER TABLE public."FOIMinistryRequests" drop column requeststatuslabel;') + op.execute('ALTER TABLE public."FOIRawRequests" drop column requeststatuslabel;') + op.execute('ALTER TABLE public."FOIRequestTeams" drop column requeststatuslabel;') + + + # ### end Alembic commands ### diff --git a/request-management-api/request_api/models/FOIMinistryRequests.py b/request-management-api/request_api/models/FOIMinistryRequests.py index cd6e2a8e9..4db017a84 100644 --- a/request-management-api/request_api/models/FOIMinistryRequests.py +++ b/request-management-api/request_api/models/FOIMinistryRequests.py @@ -27,6 +27,7 @@ from request_api.utils.enums import StateName from .FOIMinistryRequestSubjectCodes import FOIMinistryRequestSubjectCode from .SubjectCodes import SubjectCode +from request_api.utils.enums import StateName class FOIMinistryRequest(db.Model): # Name of the table in our database @@ -68,7 +69,7 @@ class FOIMinistryRequest(db.Model): linkedrequests = db.Column(JSON, unique=False, nullable=True) identityverified = db.Column(JSON, unique=False, nullable=True) ministrysignoffapproval = db.Column(JSON, unique=False, nullable=True) - + requeststatuslabel = db.Column(db.String(50), nullable=False) #ForeignKey References @@ -106,13 +107,13 @@ def getrequest(cls,ministryrequestid): return request_schema.dump(query) @classmethod - def getLastStatusUpdateDate(cls,foiministryrequestid,requeststatusid): + def getLastStatusUpdateDate(cls,foiministryrequestid,requeststatuslabel): statusdate = None try: sql = """select created_at from "FOIMinistryRequests" - where foiministryrequestid = :foiministryrequestid and requeststatusid = :requeststatusid + where foiministryrequestid = :foiministryrequestid and requeststatuslabel = :requeststatuslabel order by version desc limit 1;""" - rs = db.session.execute(text(sql), {'foiministryrequestid': foiministryrequestid, 'requeststatusid': requeststatusid}) + rs = db.session.execute(text(sql), {'foiministryrequestid': foiministryrequestid, 'requeststatuslabel': requeststatuslabel}) statusdate = [row[0] for row in rs][0] except Exception as ex: logging.error(ex) @@ -163,11 +164,11 @@ def getrequests(cls, group = None): if group is None: _ministryrequestids = _session.query(distinct(FOIMinistryRequest.foiministryrequestid)).filter(FOIMinistryRequest.isactive == True).all() elif (group == IAOTeamWithKeycloackGroup.flex.value): - _ministryrequestids = _session.query(distinct(FOIMinistryRequest.foiministryrequestid)).filter(and_(FOIMinistryRequest.isactive == True), and_(and_(FOIMinistryRequest.assignedgroup == group),and_(FOIMinistryRequest.requeststatusid.in_([1,2,3,12,13,7,8,9,10,11,14,16,17,18])))).all() + _ministryrequestids = _session.query(distinct(FOIMinistryRequest.foiministryrequestid)).filter(and_(FOIMinistryRequest.isactive == True), and_(and_(FOIMinistryRequest.assignedgroup == group),and_(FOIMinistryRequest.requeststatuslabel.in_([StateName.open.name,StateName.callforrecords.name,StateName.closed.name,StateName.recordsreview.name,StateName.feeestimate.name,StateName.consult.name,StateName.ministrysignoff.value,StateName.onhold.name,StateName.deduplication.name,StateName.harmsassessment.name,StateName.response.name,StateName.peerreview.name,StateName.tagging.name,StateName.readytoscan.name])))).all() elif (group in ProcessingTeamWithKeycloackGroup.list()): - _ministryrequestids = _session.query(distinct(FOIMinistryRequest.foiministryrequestid)).filter(and_(FOIMinistryRequest.isactive == True), and_(and_(FOIMinistryRequest.assignedgroup == group),and_(FOIMinistryRequest.requeststatusid.in_([1,2,3,7,8,9,10,11,14,16,17,18])))).all() + _ministryrequestids = _session.query(distinct(FOIMinistryRequest.foiministryrequestid)).filter(and_(FOIMinistryRequest.isactive == True), and_(and_(FOIMinistryRequest.assignedgroup == group),and_(FOIMinistryRequest.requeststatuslabel.in_([StateName.open.name,StateName.callforrecords.name,StateName.closed.name,StateName.recordsreview.name,StateName.feeestimate.name,StateName.consult.name,StateName.ministrysignoff.value,StateName.onhold.name,StateName.response.name,StateName.peerreview.name,StateName.tagging.name,StateName.readytoscan.name])))).all() else: - _ministryrequestids = _session.query(distinct(FOIMinistryRequest.foiministryrequestid)).filter(and_(FOIMinistryRequest.isactive == True), or_(and_(FOIMinistryRequest.assignedgroup == group),and_(FOIMinistryRequest.assignedministrygroup == group,or_(FOIMinistryRequest.requeststatusid.in_([2,7,9,8,10,11,12,13,14,16,17,18]))))).all() + _ministryrequestids = _session.query(distinct(FOIMinistryRequest.foiministryrequestid)).filter(and_(FOIMinistryRequest.isactive == True), or_(and_(FOIMinistryRequest.assignedgroup == group),and_(FOIMinistryRequest.assignedministrygroup == group,or_(FOIMinistryRequest.requeststatuslabel.in_([StateName.callforrecords.name,StateName.recordsreview.name,StateName.feeestimate.name,StateName.consult.name,StateName.ministrysignoff.name,StateName.onhold.name,StateName.deduplication.name,StateName.harmsassessment.name,StateName.response.name,StateName.peerreview.name,StateName.tagging.name,StateName.readytoscan.name]))))).all() _requests = [] ministryrequest_schema = FOIMinistryRequestSchema() @@ -226,10 +227,11 @@ def getrequestById(cls,ministryrequestid): def getrequeststatusById(cls,ministryrequestid): summary = [] try: - sql = 'select foirequest_id, version, requeststatusid, created_at from "FOIMinistryRequests" fr where foiministryrequestid = :ministryrequestid and requeststatusid != 3 order by version desc;' - rs = db.session.execute(text(sql), {'ministryrequestid': ministryrequestid}) + sql = 'select foirequest_id, version, requeststatusid, requeststatuslabel, created_at from "FOIMinistryRequests" fr where foiministryrequestid = :ministryrequestid and requeststatuslabel != :requeststatuslabel order by version desc;' + + rs = db.session.execute(text(sql), {'ministryrequestid': ministryrequestid, 'requeststatuslabel': StateName.closed.name}) for row in rs: - summary.append({"requeststatusid": row["requeststatusid"], "created_at": row["created_at"], "foirequest_id": row["foirequest_id"]}) + summary.append({"requeststatusid": row["requeststatusid"], "requeststatuslabel": row["requeststatuslabel"], "created_at": row["created_at"], "foirequest_id": row["foirequest_id"]}) except Exception as ex: logging.error(ex) raise ex @@ -406,13 +408,13 @@ def getrequestssubquery(cls, groups, filterfields, keyword, additionalfilter, us else_ = FOIMinistryRequest.assignedministrygroup).label('ministryAssignedToFormatted') duedate = case([ - (FOIMinistryRequest.requeststatusid == 11, # On Hold + (FOIMinistryRequest.requeststatuslabel == StateName.onhold.name, # On Hold literal(None)), ], else_ = cast(FOIMinistryRequest.duedate, String)).label('duedate') cfrduedate = case([ - (FOIMinistryRequest.requeststatusid == 11, # On Hold + (FOIMinistryRequest.requeststatuslabel == StateName.onhold.name, # On Hold literal(None)), ], else_ = cast(FOIMinistryRequest.cfrduedate, String)).label('cfrduedate') @@ -553,7 +555,7 @@ def getrequestssubquery(cls, groups, filterfields, keyword, additionalfilter, us SubjectCode, SubjectCode.subjectcodeid == FOIMinistryRequestSubjectCode.subjectcodeid, isouter=True - ).filter(FOIMinistryRequest.requeststatusid != 3) + ).filter(FOIMinistryRequest.requeststatuslabel != StateName.closed.name) if(additionalfilter == 'watchingRequests'): #watchby @@ -682,7 +684,7 @@ def getgroupfilters(cls, groups): FOIMinistryRequest.assignedgroup == group, and_( FOIMinistryRequest.assignedgroup == IAOTeamWithKeycloackGroup.flex.value, - FOIMinistryRequest.requeststatusid.in_([1]) + FOIMinistryRequest.requeststatuslabel.in_([StateName.open.name]) ) ) ) @@ -692,7 +694,7 @@ def getgroupfilters(cls, groups): FOIMinistryRequest.assignedgroup == group, and_( FOIMinistryRequest.assignedministrygroup == group, - FOIMinistryRequest.requeststatusid.in_([2,7,9,8,10,11,12,13,14,16,17,18]) + FOIMinistryRequest.requeststatuslabel.in_([StateName.callforrecords.name,StateName.recordsreview.name,StateName.feeestimate.name,StateName.consult.name,StateName.ministrysignoff.name,StateName.onhold.name,StateName.deduplication.name,StateName.harmsassessment.name,StateName.response.name,StateName.peerreview.name,StateName.tagging.name,StateName.readytoscan.name]) ) ) ) @@ -707,7 +709,7 @@ def getgroupfilters(cls, groups): @classmethod def getrequestoriginalduedate(cls,ministryrequestid): - return db.session.query(FOIMinistryRequest.duedate).filter(FOIMinistryRequest.foiministryrequestid == ministryrequestid, FOIMinistryRequest.requeststatusid == 1).order_by(FOIMinistryRequest.version).first()[0] + return db.session.query(FOIMinistryRequest.duedate).filter(FOIMinistryRequest.foiministryrequestid == ministryrequestid, FOIMinistryRequest.requeststatuslabel == StateName.open.name).order_by(FOIMinistryRequest.version).first()[0] @classmethod def getduedate(cls,ministryrequestid): @@ -719,10 +721,10 @@ def getupcomingcfrduerecords(cls): upcomingduerecords = [] try: sql = """select distinct on (filenumber) filenumber, to_char(cfrduedate, 'YYYY-MM-DD') as cfrduedate, foiministryrequestid, version, foirequest_id, created_at, createdby from "FOIMinistryRequests" fpa - where isactive = true and cfrduedate is not null and requeststatusid = 2 + where isactive = true and cfrduedate is not null and requeststatuslabel = :requeststatuslabel and cfrduedate between NOW() - INTERVAL '7 DAY' AND NOW() + INTERVAL '7 DAY' order by filenumber , version desc;""" - rs = db.session.execute(text(sql)) + rs = db.session.execute(text(sql), {'requeststatuslabel': StateName.callforrecords.name}) for row in rs: upcomingduerecords.append({"filenumber": row["filenumber"], "cfrduedate": row["cfrduedate"],"foiministryrequestid": row["foiministryrequestid"], "version": row["version"], "foirequest_id": row["foirequest_id"], "created_at": row["created_at"], "createdby": row["createdby"]}) except Exception as ex: @@ -737,10 +739,11 @@ def getupcominglegislativeduerecords(cls): upcomingduerecords = [] try: sql = """select distinct on (filenumber) filenumber, to_char(duedate, 'YYYY-MM-DD') as duedate, foiministryrequestid, version, foirequest_id, created_at, createdby from "FOIMinistryRequests" fpa - where isactive = true and duedate is not null and requeststatusid not in (5,6,4,11,3,15) + where isactive = true and duedate is not null and requeststatuslabel not in :requeststatuslabel and duedate between NOW() - INTERVAL '7 DAY' AND NOW() + INTERVAL '7 DAY' order by filenumber , version desc;""" - rs = db.session.execute(text(sql)) + requeststatuslabel = tuple([StateName.closed.name,StateName.redirect.name,StateName.unopened.name,StateName.intakeinprogress.name,StateName.onhold.name,StateName.archived.name]) + rs = db.session.execute(text(sql), {'requeststatuslabel': requeststatuslabel}) for row in rs: upcomingduerecords.append({"filenumber": row["filenumber"], "duedate": row["duedate"],"foiministryrequestid": row["foiministryrequestid"], "version": row["version"], "foirequest_id": row["foirequest_id"], "created_at": row["created_at"], "createdby": row["createdby"]}) except Exception as ex: @@ -758,14 +761,16 @@ def getupcomingdivisionduerecords(cls): frd.divisionid, frd.stageid, pad2."name" divisionname, pads."name" stagename, to_char(divisionduedate, 'YYYY-MM-DD') as duedate, frd.created_at, frd.createdby from "FOIMinistryRequestDivisions" frd - inner join (select distinct on (fpa.foiministryrequestid) foiministryrequestid, version as foiministryrequestversion, axisrequestid, filenumber, foirequest_id, requeststatusid + inner join (select distinct on (fpa.foiministryrequestid) foiministryrequestid, version as foiministryrequestversion, axisrequestid, filenumber, foirequest_id, requeststatusid, requeststatuslabel from "FOIMinistryRequests" fpa - order by fpa.foiministryrequestid , fpa.version desc) fma on frd.foiministryrequest_id = fma.foiministryrequestid and frd.foiministryrequestversion_id = fma.foiministryrequestversion and fma.requeststatusid not in (5,6,4,11,3,15) + order by fpa.foiministryrequestid , fpa.version desc) fma on frd.foiministryrequest_id = fma.foiministryrequestid and frd.foiministryrequestversion_id = fma.foiministryrequestversion and fma.requeststatuslabel not in :requeststatuslabel inner join "ProgramAreaDivisions" pad2 on frd.divisionid = pad2.divisionid inner join "ProgramAreaDivisionStages" pads on frd.stageid = pads.stageid and frd.stageid in (5, 7, 9) and frd.divisionduedate between NOW() - INTERVAL '7 DAY' AND NOW() + INTERVAL '7 DAY' order by frd.foiministryrequest_id , frd.foiministryrequestversion_id desc;""" - rs = db.session.execute(text(sql)) + requeststatuslabel = tuple([StateName.closed.name,StateName.redirect.name,StateName.unopened.name,StateName.intakeinprogress.name,StateName.onhold.name,StateName.archived.name]) + rs = db.session.execute(text(sql), {'requeststatuslabel': requeststatuslabel}) + for row in rs: upcomingduerecords.append({"axisrequestid": row["axisrequestid"], "filenumber": row["filenumber"], "foiministryrequestid": row["foiministryrequestid"], "version": row["foiministryrequestversion"], @@ -849,9 +854,9 @@ def getclosedaxisids(cls): try: sql = """ select distinct on (foiministryrequestid) foiministryrequestid, version, axisrequestid from "FOIMinistryRequests" fr - where requeststatusid = 3 + where requeststatuslabel = :requeststatuslabel order by foiministryrequestid , version desc, axisrequestid""" - rs = db.session.execute(text(sql)) + rs = db.session.execute(text(sql), {'requeststatuslabel': StateName.closed.name}) for row in rs: axisids.append(row["axisrequestid"]) except Exception as ex: @@ -926,13 +931,13 @@ def getbasequery(cls, iaoassignee, ministryassignee, userid=None, requestby='IAO else_ = FOIMinistryRequest.assignedministrygroup).label('ministryAssignedToFormatted') duedate = case([ - (FOIMinistryRequest.requeststatusid == 11, # On Hold + (FOIMinistryRequest.requeststatuslabel == StateName.onhold.name, # On Hold literal(None)), ], else_ = cast(FOIMinistryRequest.duedate, String)).label('duedate') cfrduedate = case([ - (FOIMinistryRequest.requeststatusid == 11, # On Hold + (FOIMinistryRequest.requeststatuslabel == StateName.onhold.name, # On Hold literal(None)), ], else_ = cast(FOIMinistryRequest.cfrduedate, String)).label('cfrduedate') @@ -1116,7 +1121,7 @@ def advancedsearch(cls, params, userid, isministryrestrictedfilemanager = False) groupfilter.append(FOIMinistryRequest.assignedministrygroup == group) #ministry advanced search show cfr onwards - statefilter = FOIMinistryRequest.requeststatusid.in_([2,3,7,9,8,10,11,12,13,14,16,17,18]) + statefilter = FOIMinistryRequest.requeststatuslabel.in_([StateName.callforrecords.name,StateName.closed.name,StateName.recordsreview.name,StateName.feeestimate.name,StateName.consult.name,StateName.ministrysignoff.name,StateName.onhold.name,StateName.deduplication.name,StateName.harmsassessment.name,StateName.response.name,StateName.peerreview.name,StateName.tagging.name,StateName.readytoscan.name]) ministry_queue = FOIMinistryRequest.advancedsearchsubquery(params, iaoassignee, ministryassignee, userid, 'Ministry', False, isministryrestrictedfilemanager).filter(and_(or_(*groupfilter), statefilter)) @@ -1153,10 +1158,10 @@ def getfilterforadvancedsearch(cls, params, iaoassignee, ministryassignee): # return all except closed if(includeclosed == False): - filtercondition.append(FOIMinistryRequest.requeststatusid != 3) + filtercondition.append(FOIMinistryRequest.requeststatuslabel != StateName.closed.name) elif(len(params['requeststatus']) > 1 and includeclosed == False): # return all except closed - filtercondition.append(FOIMinistryRequest.requeststatusid != 3) + filtercondition.append(FOIMinistryRequest.requeststatuslabel != StateName.closed.name) #request type: personal, general if(len(params['requesttype']) > 0): @@ -1185,9 +1190,9 @@ def getfilterforadvancedsearch(cls, params, iaoassignee, ministryassignee): def getfilterforrequeststate(cls, params, includeclosed): #request state: unopened, call for records, etc. requeststatecondition = [] - for stateid in params['requeststate']: - requeststatecondition.append(FOIMinistryRequest.requeststatusid == stateid) - if(stateid == 3): + for statelabel in params['requeststate']: + requeststatecondition.append(FOIMinistryRequest.requeststatuslabel == statelabel) + if(statelabel == StateName.closed.name): includeclosed = True return {'condition': or_(*requeststatecondition), 'includeclosed': includeclosed} @@ -1196,8 +1201,8 @@ def getfilterforrequeststatus(cls, params, iaoassignee, ministryassignee): #request status: overdue || on time if(params['requeststatus'][0] == 'overdue'): #exclude "on hold" for overdue - stateid = 11 - return and_(FOIMinistryRequest.findfield('duedate', iaoassignee, ministryassignee) < datetime.now().date(), FOIMinistryRequest.requeststatusid != stateid) + statelabel = StateName.onhold.name + return and_(FOIMinistryRequest.findfield('duedate', iaoassignee, ministryassignee) < datetime.now().date(), FOIMinistryRequest.requeststatuslabel != statelabel) else: return FOIMinistryRequest.findfield('duedate', iaoassignee, ministryassignee) >= datetime.now().date() @@ -1302,9 +1307,9 @@ def getofflinepaymentflag(cls,ministryrequestid): class FOIMinistryRequestSchema(ma.Schema): class Meta: fields = ('foiministryrequestid','version','filenumber','description','recordsearchfromdate','recordsearchtodate', - 'startdate','duedate','assignedgroup','assignedto','programarea.programareaid','requeststatus.requeststatusid', + 'startdate','duedate','assignedgroup','assignedto','programarea.programareaid', 'foirequest.foirequestid','foirequest.requesttype','foirequest.receiveddate','foirequest.deliverymodeid', - 'foirequest.receivedmodeid','requeststatus.requeststatusid','requeststatus.name','programarea.bcgovcode', + 'foirequest.receivedmodeid','requeststatus.requeststatusid','requeststatuslabel','requeststatus.name','programarea.bcgovcode', 'programarea.name','foirequest_id','foirequestversion_id','created_at','updated_at','createdby','assignedministryperson', 'assignedministrygroup','cfrduedate','closedate','closereasonid','closereason.name', 'assignee.firstname','assignee.lastname','ministryassignee.firstname','ministryassignee.lastname', 'axisrequestid', 'axissyncdate', 'requestpagecount', 'linkedrequests', 'ministrysignoffapproval', 'identityverified','originalldd') diff --git a/request-management-api/request_api/models/FOIRawRequestNotificationUsers.py b/request-management-api/request_api/models/FOIRawRequestNotificationUsers.py index 619bdfd9a..2f114310d 100644 --- a/request-management-api/request_api/models/FOIRawRequestNotificationUsers.py +++ b/request-management-api/request_api/models/FOIRawRequestNotificationUsers.py @@ -17,7 +17,11 @@ from request_api.utils.enums import ProcessingTeamWithKeycloackGroup, IAOTeamWithKeycloackGroup from request_api.models.views.FOINotifications import FOINotifications from request_api.models.views.FOIRawRequests import FOIRawRequests +f = open('common/notificationusertypes.json', encoding="utf8") +notificationusertypes_cache = json.load(f) +file = open('common/notificationtypes.json', encoding="utf8") +notificationtypes_cache = json.load(file) class FOIRawRequestNotificationUser(db.Model): # Name of the table in our database @@ -31,8 +35,8 @@ class FOIRawRequestNotificationUser(db.Model): createdby = db.Column(db.String(120), unique=False, nullable=True) updated_at = db.Column(db.DateTime, nullable=True) updatedby = db.Column(db.String(120), unique=False, nullable=True) - notificationusertypeid = db.Column(db.Integer,nullable=False) + notificationusertypelabel = db.Column(db.String(120),nullable=False) @classmethod @@ -53,8 +57,8 @@ def dismissnotificationbyuser(cls, userid): return DefaultMethodResult(True,'Notifications deleted for user',userid) @classmethod - def dismissnotificationbyuserandtype(cls, userid, notificationusertypeid): - db.session.query(FOIRawRequestNotificationUser).filter(FOIRawRequestNotificationUser.userid == userid, FOIRawRequestNotificationUser.notificationusertypeid == notificationusertypeid).update({FOIRawRequestNotificationUser.isdeleted: True, FOIRawRequestNotificationUser.updatedby: userid, + def dismissnotificationbyuserandtype(cls, userid, notificationusertypelabel): + db.session.query(FOIRawRequestNotificationUser).filter(FOIRawRequestNotificationUser.userid == userid, FOIRawRequestNotificationUser.notificationusertypelabel == notificationusertypelabel).update({FOIRawRequestNotificationUser.isdeleted: True, FOIRawRequestNotificationUser.updatedby: userid, FOIRawRequestNotificationUser.updated_at: datetime2.now()}) db.session.commit() return DefaultMethodResult(True,'Notifications deleted for user',userid) @@ -92,12 +96,15 @@ def getnotificationsbyuser(cls, userid): return notifications @classmethod - def getnotificationsbyuserandtype(cls, userid, notificationusertypeid): + def getnotificationsbyuserandtype(cls, userid, typeid): + for key in notificationusertypes_cache: + if (notificationusertypes_cache[key].notificationusertypeid == typeid) or (notificationusertypes_cache[key].notificationusertypelabel == typeid): + notificationusertypelabel = notificationusertypes_cache[key].notificationusertypelabel notifications = [] try: sql = """select notificationid, count(1) as relcount from "FOIRawRequestNotificationUsers" frnu - where notificationid in (select notificationid from "FOIRawRequestNotificationUsers" frnu where userid = :userid and notificationusertypeid = :notificationusertypeid) group by notificationid """ - rs = db.session.execute(text(sql), {'userid': userid, 'notificationusertypeid': notificationusertypeid}) + where notificationid in (select notificationid from "FOIRawRequestNotificationUsers" frnu where userid = :userid and notificationusertypelabel = :notificationusertypelabel) group by notificationid """ + rs = db.session.execute(text(sql), {'userid': userid, 'notificationusertypelabel': notificationusertypelabel}) for row in rs: notifications.append({"notificationid": row["notificationid"], "count" : row["relcount"]}) except Exception as ex: @@ -109,7 +116,7 @@ def getnotificationsbyuserandtype(cls, userid, notificationusertypeid): @classmethod def dismissbynotificationid(cls, notificationids, userid='system'): - db.session.query(FOIRawRequestNotificationUser).filter(FOIRawRequestNotificationUser.notificationid.in_(notificationids)).update({FOIRawRequestNotificationUser.isdeleted: True, FOIRawRequestNotificationUser.updatedby: userid, + db.session.query(FOIRawRequestNotificationUser).filter(FOIRawRequestNotificationUser.notificationid.in_(notificationids), FOIRawRequestNotificationUser.isdeleted == False).update({FOIRawRequestNotificationUser.isdeleted: True, FOIRawRequestNotificationUser.updatedby: userid, FOIRawRequestNotificationUser.updated_at: datetime2.now()}, synchronize_session=False) db.session.commit() return DefaultMethodResult(True,'Notifications deleted for id',notificationids) @@ -168,7 +175,7 @@ def getbasequery(cls, groups, additionalfilter=None, userid=None, isiaorestricte return basequery.join(subquery_watchby, subquery_watchby.c.requestid == cast(FOIRawRequests.rawrequestid, Integer)) elif(additionalfilter == 'myRequests'): #myrequest - return basequery.filter(or_(FOIRawRequests.assignedto == userid, and_(FOINotifications.userid == userid, FOINotifications.notificationtypeid == 10))) + return basequery.filter(or_(FOIRawRequests.assignedto == userid, and_(FOINotifications.userid == userid, FOINotifications.notificationtypelabel == notificationtypes_cache['taggedusercomments']['notificationtypelabel']))) else: if(isiaorestrictedfilemanager == True): return basequery.filter(FOIRawRequests.assignedgroup.in_(groups)) @@ -263,4 +270,4 @@ def validatefield(cls, x): class FOIRawRequestNotificationUserSchema(ma.Schema): class Meta: - fields = ('notificationid', 'userid','notificationusertypeid','created_at','createdby','updated_at','updatedby') \ No newline at end of file + fields = ('notificationid', 'userid', 'notificationusertypeid' , 'notificationusertypelabel','created_at','createdby','updated_at','updatedby') \ No newline at end of file diff --git a/request-management-api/request_api/models/FOIRawRequestNotifications.py b/request-management-api/request_api/models/FOIRawRequestNotifications.py index e0351e90d..cb21f0769 100644 --- a/request-management-api/request_api/models/FOIRawRequestNotifications.py +++ b/request-management-api/request_api/models/FOIRawRequestNotifications.py @@ -28,6 +28,7 @@ class FOIRawRequestNotification(db.Model): updatedby = db.Column(db.String(120), unique=False, nullable=True) notificationtypeid = db.Column(db.Integer, nullable=False) + notificationtypelabel = db.Column(db.Integer, nullable=False) notificationusers = db.relationship('FOIRawRequestNotificationUser', backref='FOIRawRequestNotifications', lazy='dynamic') @@ -45,7 +46,7 @@ def savenotification(cls,foinotification)->DefaultMethodResult: @classmethod def dismissnotification(cls, notificationids, userid='system'): try: - db.session.query(FOIRawRequestNotification).filter(FOIRawRequestNotification.notificationid.in_(notificationids)).update({FOIRawRequestNotification.isdeleted: True, FOIRawRequestNotification.updatedby: userid, + db.session.query(FOIRawRequestNotification).filter(FOIRawRequestNotification.notificationid.in_(notificationids), FOIRawRequestNotification.isdeleted == False).update({FOIRawRequestNotification.isdeleted: True, FOIRawRequestNotification.updatedby: userid, FOIRawRequestNotification.updated_at: datetime2.now()}, synchronize_session=False) db.session.commit() return DefaultMethodResult(True,'Notifications deleted ', notificationids) @@ -69,11 +70,11 @@ def updatenotification(cls, foinotification, userid): return DefaultMethodResult(True,'No notification found',foinotification['notificationid']) @classmethod - def getnotificationidsbynumberandtype(cls, idnumber, notificationtypeid): + def getnotificationidsbynumberandtype(cls, idnumber, notificationtypelabel): notificationids = [] try: - sql = """select notificationid from "FOIRawRequestNotifications" where idnumber = :idnumber and notificationtypeid= :notificationtypeid """ - rs = db.session.execute(text(sql), {'idnumber': idnumber, 'notificationtypeid': notificationtypeid}) + sql = """select notificationid from "FOIRawRequestNotifications" where idnumber = :idnumber and notificationtypelabel= :notificationtypelabel """ + rs = db.session.execute(text(sql), {'idnumber': idnumber, 'notificationtypelabel': notificationtypelabel}) for row in rs: notificationids.append(row["notificationid"]) except Exception as ex: @@ -99,11 +100,11 @@ def getnotificationidsbynumber(cls, idnumber): return notificationids @classmethod - def getnotificationidsbytype(cls, notificationtypeid): + def getnotificationidsbytype(cls, notificationtypelabel): notificationids = [] try: - sql = """select notificationid from "FOIRawRequestNotifications" where notificationtypeid= :notificationtypeid """ - rs = db.session.execute(text(sql), {'notificationtypeid': notificationtypeid}) + sql = """select notificationid from "FOIRawRequestNotifications" where notificationtypelabel= :notificationtypelabel and isdeleted = false """ + rs = db.session.execute(text(sql), {'notificationtypelabel': notificationtypelabel}) for row in rs: notificationids.append(row["notificationid"]) except Exception as ex: @@ -115,4 +116,4 @@ def getnotificationidsbytype(cls, notificationtypeid): class FOIRawRequestNotificationSchema(ma.Schema): class Meta: - fields = ('notificationid', 'requestid', 'idnumber','notification', 'notificationtypeid','created_at','createdby','updated_at','updatedby','notificationusers') \ No newline at end of file + fields = ('notificationid', 'requestid', 'idnumber','notification', 'notificationtypeid', 'notificationtypelabel','created_at','createdby','updated_at','updatedby','notificationusers') \ No newline at end of file diff --git a/request-management-api/request_api/models/FOIRawRequests.py b/request-management-api/request_api/models/FOIRawRequests.py index b25a9b916..7a244d0c8 100644 --- a/request-management-api/request_api/models/FOIRawRequests.py +++ b/request-management-api/request_api/models/FOIRawRequests.py @@ -18,6 +18,7 @@ import logging from dateutil import parser import json +from request_api.utils.enums import StateName from request_api.utils.enums import ProcessingTeamWithKeycloackGroup, IAOTeamWithKeycloackGroup class FOIRawRequest(db.Model): @@ -28,6 +29,7 @@ class FOIRawRequest(db.Model): version = db.Column(db.Integer, primary_key=True,nullable=False) requestrawdata = db.Column(JSON, unique=False, nullable=True) status = db.Column(db.String(25), unique=False, nullable=True) + requeststatuslabel = db.Column(db.String(50), unique=False, nullable=False) notes = db.Column(db.String(120), unique=False, nullable=True) wfinstanceid = db.Column(UUID(as_uuid=True), unique=False, nullable=True) assignedgroup = db.Column(db.String(250), unique=False, nullable=True) @@ -56,7 +58,7 @@ class FOIRawRequest(db.Model): @classmethod def saverawrequest(cls, _requestrawdata, sourceofsubmission, ispiiredacted, userid, notes, requirespayment, axisrequestid, axissyncdate, linkedrequests, assigneegroup=None, assignee=None, assigneefirstname=None, assigneemiddlename=None, assigneelastname=None)->DefaultMethodResult: version = 1 - newrawrequest = FOIRawRequest(requestrawdata=_requestrawdata, status = 'Unopened' if sourceofsubmission != "intake" else 'Intake in Progress', createdby=userid, version=version, sourceofsubmission=sourceofsubmission, assignedgroup=assigneegroup, assignedto=assignee, ispiiredacted=ispiiredacted, notes=notes, requirespayment=requirespayment, axisrequestid=axisrequestid, axissyncdate=axissyncdate, linkedrequests=linkedrequests) + newrawrequest = FOIRawRequest(requestrawdata=_requestrawdata, status = StateName.unopened.value if sourceofsubmission != "intake" else StateName.intakeinprogress.value, requeststatuslabel = StateName.unopened.name if sourceofsubmission != "intake" else StateName.intakeinprogress.name, createdby=userid, version=version, sourceofsubmission=sourceofsubmission, assignedgroup=assigneegroup, assignedto=assignee, ispiiredacted=ispiiredacted, notes=notes, requirespayment=requirespayment, axisrequestid=axisrequestid, axissyncdate=axissyncdate, linkedrequests=linkedrequests) if assignee is not None: FOIAssignee.saveassignee(assignee, assigneefirstname, assigneemiddlename, assigneelastname) @@ -67,13 +69,13 @@ def saverawrequest(cls, _requestrawdata, sourceofsubmission, ispiiredacted, user @classmethod def saverawrequest_foipayment(cls,_requestrawdata,notes, requirespayment, ispiiredacted)->DefaultMethodResult: version = 1 - newrawrequest = FOIRawRequest(requestrawdata=_requestrawdata, status='Unopened',createdby=None,version=version,sourceofsubmission="onlineform",assignedgroup=None,assignedto=None,ispiiredacted=ispiiredacted,notes=notes, requirespayment= requirespayment) + newrawrequest = FOIRawRequest(requestrawdata=_requestrawdata, status=StateName.unopened.value, requeststatuslabel = StateName.unopened.name ,createdby=None,version=version,sourceofsubmission="onlineform",assignedgroup=None,assignedto=None,ispiiredacted=ispiiredacted,notes=notes, requirespayment= requirespayment) db.session.add(newrawrequest) db.session.commit() return DefaultMethodResult(True,'Request added',newrawrequest.requestid) @classmethod - def saverawrequestversion(cls,_requestrawdata,requestid,assigneegroup,assignee,status,ispiiredacted,userid,assigneefirstname=None,assigneemiddlename=None,assigneelastname=None)->DefaultMethodResult: + def saverawrequestversion(cls,_requestrawdata,requestid,assigneegroup,assignee,status,ispiiredacted,userid,statuslabel,assigneefirstname=None,assigneemiddlename=None,assigneelastname=None)->DefaultMethodResult: request = db.session.query(FOIRawRequest).filter_by(requestid=requestid).order_by(FOIRawRequest.version.desc()).first() if request is not None: _assginee = assignee if assignee not in (None,'') else None @@ -95,6 +97,7 @@ def saverawrequestversion(cls,_requestrawdata,requestid,assigneegroup,assignee,s updatedby=None, updated_at=datetime.now(), status=status, + requeststatuslabel=statuslabel, assignedgroup=assigneegroup, assignedto=_assginee, wfinstanceid=request.wfinstanceid, @@ -146,6 +149,7 @@ def saveiaorestrictedrawrequest(cls,requestid,_isiaorestricted=False, _updatedby requirespayment = request.requirespayment, isiaorestricted =_isiaorestricted, notes = request.notes, + requeststatuslabel = request.requeststatuslabel, ) ) @@ -192,8 +196,8 @@ def saverawrequestassigneeversion(cls,requestid,assigneegroup,assignee,userid,as axisrequestid= axisrequestid, axissyncdate=axissyncdate, linkedrequests=linkedrequests, - isiaorestricted = request.isiaorestricted - + isiaorestricted = request.isiaorestricted, + requeststatuslabel = request.requeststatuslabel ) ) db.session.execute(insertstmt) @@ -298,7 +302,7 @@ def getDescriptionSummaryById(cls, requestid): requests = [] try: sql = """select * , - CASE WHEN description = (select requestrawdata -> 'descriptionTimeframe' ->> 'description' from "FOIRawRequests" where requestid = :requestid and status = 'Unopened' and version = 1) + CASE WHEN description = (select requestrawdata -> 'descriptionTimeframe' ->> 'description' from "FOIRawRequests" where requestid = :requestid and status = :requeststatus and version = 1) then 'Online Form' else savedby END as createdby from (select CASE WHEN lower(status) <> 'unopened' @@ -313,7 +317,7 @@ def getDescriptionSummaryById(cls, requestid): to_char(created_at, 'YYYY-MM-DD HH24:MI:SS') as createdat, status, ispiiredacted, createdby as savedby from "FOIRawRequests" fr where requestid = :requestid order by version ) as sq;""" - rs = db.session.execute(text(sql), {'requestid': requestid}) + rs = db.session.execute(text(sql), {'requestid': requestid, 'requeststatus': StateName.unopened.value}) for row in rs: requests.append(dict(row)) except Exception as ex: @@ -369,10 +373,10 @@ def getappfeeowingrequests(cls): # with the reminder date sql = ''' SELECT * FROM (SELECT DISTINCT ON (requestid) requestid, updated_at, status FROM public."FOIRawRequests" ORDER BY requestid ASC, version DESC) r - WHERE r.status = 'App Fee Owing' + WHERE r.status = :requeststaus order by r.updated_at asc ''' - rs = db.session.execute(text(sql)) + rs = db.session.execute(text(sql), {'requeststaus': StateName.appfeeowing.value}) appfeeowingrequests = rs except Exception as ex: logging.error(ex) @@ -442,47 +446,47 @@ def getbasequery(cls, additionalfilter=None, userid=None, isiaorestrictedfileman ] requesttype = case([ - (FOIRawRequest.status == 'Unopened', + (FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['requestType']['requestType'].astext), ], else_ = FOIRawRequest.requestrawdata['requestType'].astext).label('requestType') firstname = case([ - (FOIRawRequest.status == 'Unopened', + (FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['contactInfo']['firstName'].astext), ], else_ = FOIRawRequest.requestrawdata['firstName'].astext).label('firstName') lastname = case([ - (FOIRawRequest.status == 'Unopened', + (FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['contactInfo']['lastName'].astext), ], else_ = FOIRawRequest.requestrawdata['lastName'].astext).label('lastName') description = case([ - (FOIRawRequest.status == 'Unopened', + (FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['descriptionTimeframe']['description'].astext), ], else_ = FOIRawRequest.requestrawdata['description'].astext).label('description') recordsearchfromdate = case([ - (FOIRawRequest.status == 'Unopened', + (FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['descriptionTimeframe']['fromDate'].astext), ], else_ = FOIRawRequest.requestrawdata['fromDate'].astext).label('recordsearchfromdate') recordsearchtodate = case([ - (FOIRawRequest.status == 'Unopened', + (FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['descriptionTimeframe']['toDate'].astext), ], else_ = FOIRawRequest.requestrawdata['toDate'].astext).label('recordsearchtodate') duedate = case([ - (FOIRawRequest.status == 'Unopened', + (FOIRawRequest.status == StateName.unopened.value, literal(None)), ], else_ = FOIRawRequest.requestrawdata['dueDate'].astext).label('duedate') receiveddate = case([ - (and_(FOIRawRequest.status == 'Unopened', FOIRawRequest.requestrawdata['receivedDate'].is_(None)), + (and_(FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['receivedDate'].is_(None)), func.to_char(FOIRawRequest.created_at, 'YYYY-mm-DD')), ], else_ = FOIRawRequest.requestrawdata['receivedDate'].astext).label('receivedDate') receiveddateuf = case([ - (and_(FOIRawRequest.status == 'Unopened', FOIRawRequest.requestrawdata['receivedDateUF'].is_(None)), + (and_(FOIRawRequest.status == StateName.unopened.value, FOIRawRequest.requestrawdata['receivedDateUF'].is_(None)), func.to_char(FOIRawRequest.created_at, 'YYYY-mm-DD HH:MM:SS')), ], else_ = FOIRawRequest.requestrawdata['receivedDateUF'].astext).label('receivedDateUF') @@ -804,7 +808,7 @@ def getfilterforadvancedsearch(cls, params): filtercondition.append(requeststatecondition['condition']) includeclosed = requeststatecondition['includeclosed'] else: - filtercondition.append(FOIRawRequest.status != 'Unopened') #not return Unopened by default + filtercondition.append(FOIRawRequest.status != StateName.unopened.value) #not return Unopened by default #request status: overdue, on time - no due date for unopen & intake in progress, so return all except closed if(len(params['requeststatus']) > 0 and includeclosed == False): @@ -812,7 +816,7 @@ def getfilterforadvancedsearch(cls, params): #no rawrequest returned for this case filtercondition.append(FOIRawRequest.status == 'ReturnNothing') else: - filtercondition.append(FOIRawRequest.status != 'Closed') + filtercondition.append(FOIRawRequest.status != StateName.closed.value) #request type: personal, general if(len(params['requesttype']) > 0): @@ -873,15 +877,15 @@ def getfilterforrequeststate(cls, params, includeclosed): #request state: unopened, call for records, etc. requeststatecondition = [] for state in params['requeststate']: - if(state == '3'): - requeststatecondition.append(FOIRawRequest.status == 'Closed') + if(state == StateName.closed.name): + requeststatecondition.append(FOIRawRequest.status == StateName.closed.value) includeclosed = True - elif(state == '4'): - requeststatecondition.append(FOIRawRequest.status == 'Redirect') - elif(state == '5'): - requeststatecondition.append(FOIRawRequest.status == 'Unopened') - elif(state == '6'): - requeststatecondition.append(FOIRawRequest.status == 'Intake in Progress') + elif(state == StateName.redirect.name): + requeststatecondition.append(FOIRawRequest.status == StateName.redirect.value) + elif(state == StateName.unopened.name): + requeststatecondition.append(FOIRawRequest.status == StateName.unopened.value) + elif(state == StateName.intakeinprogress.name): + requeststatecondition.append(FOIRawRequest.status == StateName.intakeinprogress.value) if(len(requeststatecondition) == 0): requeststatecondition.append(FOIRawRequest.status == 'Not Applicable') #searched state does not apply to rawrequests @@ -1038,8 +1042,8 @@ def getlatestsection5pendings(cls): (SELECT DISTINCT ON (requestid) requestid, created_at, version, status, axisrequestid FROM public."FOIRawRequests" ORDER BY requestid ASC, version DESC) foireqs - WHERE foireqs.status = 'Section 5 Pending';""" - rs = db.session.execute(text(sql)) + WHERE foireqs.status = :requeststatus;""" + rs = db.session.execute(text(sql), {'requeststatus': StateName.section5pending.value}) for row in rs: section5pendings.append({"requestid": row["requestid"], "version": row["version"], "statusname": row["status"], "created_at": row["created_at"], "axisrequestid": ["axisrequestid"]}) except Exception as ex: @@ -1051,4 +1055,4 @@ def getlatestsection5pendings(cls): class FOIRawRequestSchema(ma.Schema): class Meta: - fields = ('requestid', 'requestrawdata', 'status','notes','created_at','wfinstanceid','version','updated_at','assignedgroup','assignedto','updatedby','createdby','sourceofsubmission','ispiiredacted','assignee.firstname','assignee.lastname', 'axisrequestid', 'axissyncdate', 'linkedrequests', 'closedate','isiaorestricted') \ No newline at end of file + fields = ('requestid', 'requestrawdata', 'status', 'requeststatuslabel', 'notes','created_at','wfinstanceid','version','updated_at','assignedgroup','assignedto','updatedby','createdby','sourceofsubmission','ispiiredacted','assignee.firstname','assignee.lastname', 'axisrequestid', 'axissyncdate', 'linkedrequests', 'closedate','isiaorestricted') \ No newline at end of file diff --git a/request-management-api/request_api/models/FOIRequestNotificationUsers.py b/request-management-api/request_api/models/FOIRequestNotificationUsers.py index e35dbda75..9e80691ca 100644 --- a/request-management-api/request_api/models/FOIRequestNotificationUsers.py +++ b/request-management-api/request_api/models/FOIRequestNotificationUsers.py @@ -12,6 +12,8 @@ from sqlalchemy import text import logging import json +f = open('common/notificationtypes.json', encoding="utf8") +notificationtypes_cache = json.load(f) from .FOIRequestApplicantMappings import FOIRequestApplicantMapping @@ -49,7 +51,7 @@ class FOIRequestNotificationUser(db.Model): createdby = db.Column(db.String(120), unique=False, nullable=True) updated_at = db.Column(db.DateTime, nullable=True) updatedby = db.Column(db.String(120), unique=False, nullable=True) - + notificationusertypelabel = db.Column(db.String(100),nullable=False) notificationusertypeid = db.Column(db.Integer,nullable=False) @@ -71,8 +73,8 @@ def dismissnotificationbyuser(cls, userid): return DefaultMethodResult(True,'Notifications deleted for user',userid) @classmethod - def dismissnotificationbyuserandtype(cls, userid, notificationusertypeid): - db.session.query(FOIRequestNotificationUser).filter(FOIRequestNotificationUser.userid == userid, FOIRequestNotificationUser.notificationusertypeid == notificationusertypeid).update({FOIRequestNotificationUser.isdeleted: True, FOIRequestNotificationUser.updatedby: userid, + def dismissnotificationbyuserandtype(cls, userid, notificationusertypelabel): + db.session.query(FOIRequestNotificationUser).filter(FOIRequestNotificationUser.userid == userid, FOIRequestNotificationUser.notificationusertypelabel == notificationusertypelabel).update({FOIRequestNotificationUser.isdeleted: True, FOIRequestNotificationUser.updatedby: userid, FOIRequestNotificationUser.updated_at: datetime2.now()}) db.session.commit() return DefaultMethodResult(True,'Notifications deleted for user',userid) @@ -118,12 +120,12 @@ def getnotificationsbyuser(cls, userid): return notifications @classmethod - def getnotificationsbyuserandtype(cls, userid, notificationusertypeid): + def getnotificationsbyuserandtype(cls, userid, notificationusertypelabel): notifications = [] try: sql = """select notificationid, count(1) as relcount from "FOIRequestNotificationUsers" frnu - where notificationid in (select notificationid from "FOIRequestNotificationUsers" frnu where userid = :userid and notificationusertypeid = :notificationusertypeid) group by notificationid """ - rs = db.session.execute(text(sql), {'userid': userid, 'notificationusertypeid':notificationusertypeid}) + where notificationid in (select notificationid from "FOIRequestNotificationUsers" frnu where userid = :userid and notificationusertypelabel = :notificationusertypelabel) group by notificationid """ + rs = db.session.execute(text(sql), {'userid': userid, 'notificationusertypelabel':notificationusertypelabel}) for row in rs: notifications.append({"notificationid": row["notificationid"], "count" : row["relcount"]}) except Exception as ex: @@ -212,7 +214,7 @@ def geteventsubquery(cls, groups, filterfields, keyword, additionalfilter, useri ).join( FOINotifications, and_(FOINotifications.axisnumber == FOIRequests.axisrequestid), - ).filter(FOIRequests.requeststatusid != 3) + ).filter(FOIRequests.requeststatuslabel != StateName.closed.name) if(additionalfilter == 'watchingRequests'): #watchby @@ -223,9 +225,9 @@ def geteventsubquery(cls, groups, filterfields, keyword, additionalfilter, useri elif(additionalfilter == 'myRequests'): #myrequest if(requestby == 'IAO'): - dbquery = basequery.filter(or_(and_(FOIRequests.assignedto == userid, ministryfilter),and_(FOINotifications.userid == userid, FOINotifications.notificationtypeid == 10))) + dbquery = basequery.filter(or_(and_(FOIRequests.assignedto == userid, ministryfilter),and_(FOINotifications.userid == userid, FOINotifications.notificationtypelabel == notificationtypes_cache['taggedusercomments']['notificationtypelabel']))) else: - dbquery = basequery.filter(or_(and_(FOIRequests.assignedministryperson == userid, ministryfilter),and_(FOINotifications.userid == userid, FOINotifications.notificationtypeid == 10))) + dbquery = basequery.filter(or_(and_(FOIRequests.assignedministryperson == userid, ministryfilter),and_(FOINotifications.userid == userid, FOINotifications.notificationtypelabel == notificationtypes_cache['taggedusercomments']['notificationtypelabel']))) else: if(isiaorestrictedfilemanager == True or isministryrestrictedfilemanager == True): dbquery = basequery @@ -262,7 +264,7 @@ def getgroupfilters(cls, groups): FOIRequests.assignedgroup == group, and_( FOIRequests.assignedgroup == IAOTeamWithKeycloackGroup.flex.value, - FOIRequests.requeststatusid.in_([1]) + FOIRequests.requeststatuslabel.in_([StateName.open.name]) ) ) ) @@ -272,7 +274,7 @@ def getgroupfilters(cls, groups): FOIRequests.assignedgroup == group, and_( FOIRequests.assignedministrygroup == group, - FOIRequests.requeststatusid.in_([2,7,9,8,10,11,12,13,14,17,18]) + FOIRequests.requeststatuslabel.in_([StateName.callforrecords.name,StateName.recordsreview.name,StateName.feeestimate.name,StateName.consult.name,StateName.ministrysignoff.name,StateName.onhold.name,StateName.deduplication.name,StateName.harmsassessment.name,StateName.response.name,StateName.tagging.name,StateName.readytoscan.name]) ) ) ) @@ -333,4 +335,4 @@ def findfield(cls, x): class FOIRequestNotificationUserSchema(ma.Schema): class Meta: - fields = ('notificationid', 'userid','notificationusertypeid','created_at','createdby','updated_at','updatedby') \ No newline at end of file + fields = ('notificationid', 'userid','notificationusertypeid', 'notificationusertypelabel','created_at','createdby','updated_at','updatedby') \ No newline at end of file diff --git a/request-management-api/request_api/models/FOIRequestNotifications.py b/request-management-api/request_api/models/FOIRequestNotifications.py index f9b53425a..fc8728878 100644 --- a/request-management-api/request_api/models/FOIRequestNotifications.py +++ b/request-management-api/request_api/models/FOIRequestNotifications.py @@ -11,8 +11,10 @@ from sqlalchemy.sql.expression import distinct from sqlalchemy import text import maya - import json +f = open('common/notificationtypes.json', encoding="utf8") +notificationtypes_cache = json.load(f) + class FOIRequestNotification(db.Model): # Name of the table in our database __tablename__ = 'FOIRequestNotifications' @@ -29,8 +31,8 @@ class FOIRequestNotification(db.Model): createdby = db.Column(db.String(120), unique=False, nullable=True) updated_at = db.Column(db.DateTime, nullable=True) updatedby = db.Column(db.String(120), unique=False, nullable=True) - notificationtypeid = db.Column(db.Integer, nullable=False) + notificationtypelabel = db.Column(db.String(50), nullable=False) notificationusers = db.relationship('FOIRequestNotificationUser', backref='FOIRequestNotifications', lazy='dynamic') @@ -66,9 +68,9 @@ def getconsolidatednotifications(cls, userid, days): notifications = [] try: sql = """select idnumber, axisnumber, notificationid, notification , notificationtype, userid, notificationusertype, created_at, createdby, requesttype, requestid, foirequestid from ( - select frn.idnumber, frn.axisnumber, frn.requestid, frns.notificationuserid as notificationid, frn.notification -> 'message' as notification , nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'ministryrequest' requesttype, frn.foirequestid from "FOIRequestNotifications" frn inner join "FOIRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypeid = nty.notificationtypeid inner join "NotificationUserTypes" ntu on frns.notificationusertypeid = ntu.notificationusertypeid where frns.userid=:userid and frn.created_at >= current_date - interval :days day + select frn.idnumber, frn.axisnumber, frn.requestid, frns.notificationuserid as notificationid, frn.notification -> 'message' as notification , nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'ministryrequest' requesttype, frn.foirequestid from "FOIRequestNotifications" frn inner join "FOIRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypelabel = nty.notificationtypelabel inner join "NotificationUserTypes" ntu on frns.notificationusertypelabel = ntu.notificationusertypelabel where frns.userid=:userid and frn.created_at >= current_date - interval :days day union all - select frn.idnumber, frn.axisnumber, frn.requestid, frns.notificationuserid as notificationid, frn.notification -> 'message' as notification, nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'rawrequest' requesttype, 0 foirequestid from "FOIRawRequestNotifications" frn inner join "FOIRawRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypeid = nty.notificationtypeid inner join "NotificationUserTypes" ntu on frns.notificationusertypeid = ntu.notificationusertypeid where frns.userid=:userid and frn.created_at >= current_date - interval :days day + select frn.idnumber, frn.axisnumber, frn.requestid, frns.notificationuserid as notificationid, frn.notification -> 'message' as notification, nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'rawrequest' requesttype, 0 foirequestid from "FOIRawRequestNotifications" frn inner join "FOIRawRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypelabel = nty.notificationtypelabel inner join "NotificationUserTypes" ntu on frns.notificationusertypelabel = ntu.notificationusertypelabel where frns.userid=:userid and frn.created_at >= current_date - interval :days day ) as notf order by created_at desc""" rs = db.session.execute(text(sql), {'userid': userid, 'days': days}) for row in rs: @@ -87,11 +89,16 @@ def getcommentnotifications(cls, commentid): notifications = [] try: sql = """select idnumber, axisnumber, notificationid, notificationuserid, notification , notificationtype, userid, notificationusertype, created_at, createdby, requesttype, requestid, foirequestid from ( - select frn.idnumber, frn.axisnumber, frn.requestid, frn.notificationid, frns.notificationuserid, frn.notification -> 'message' as notification , nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'ministryrequest' requesttype, frn.foirequestid from "FOIRequestNotifications" frn inner join "FOIRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypeid = nty.notificationtypeid inner join "NotificationUserTypes" ntu on frns.notificationusertypeid = ntu.notificationusertypeid where frn.notificationtypeid in (3,9,10) and (frn.notification ->> 'commentid')::int = :commentid + select frn.idnumber, frn.axisnumber, frn.requestid, frn.notificationid, frns.notificationuserid, frn.notification -> 'message' as notification , nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'ministryrequest' requesttype, frn.foirequestid from "FOIRequestNotifications" frn inner join "FOIRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypelabel = nty.notificationtypelabel inner join "NotificationUserTypes" ntu on frns.notificationusertypelabel = ntu.notificationusertypelabel where frn.notificationtypelabel in :notificationtypelabel and (frn.notification ->> 'commentid')::int = :commentid union all - select frn.idnumber, frn.axisnumber, frn.requestid, frn.notificationid, frns.notificationuserid, frn.notification -> 'message' as notification, nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'rawrequest' requesttype, 0 foirequestid from "FOIRawRequestNotifications" frn inner join "FOIRawRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypeid = nty.notificationtypeid inner join "NotificationUserTypes" ntu on frns.notificationusertypeid = ntu.notificationusertypeid where frn.notificationtypeid in (3,9,10) and (frn.notification ->> 'commentid')::int = :commentid + select frn.idnumber, frn.axisnumber, frn.requestid, frn.notificationid, frns.notificationuserid, frn.notification -> 'message' as notification, nty.name as notificationtype, frn.created_at , frns.createdby, frns.userid, ntu.name as notificationusertype, 'rawrequest' requesttype, 0 foirequestid from "FOIRawRequestNotifications" frn inner join "FOIRawRequestNotificationUsers" frns on frn.notificationid = frns.notificationid and frns.isdeleted = false inner join "NotificationTypes" nty on frn.notificationtypelabel = nty.notificationtypelabel inner join "NotificationUserTypes" ntu on frns.notificationusertypelabel = ntu.notificationusertypelabel where frn.notificationtypelabel in :notificationtypelabel and (frn.notification ->> 'commentid')::int = :commentid ) as notf order by created_at desc""" - rs = db.session.execute(text(sql), {'commentid': commentid}) + notificationtypelabel = tuple([notificationtypes_cache['newusercomments']['notificationtypelabel'], + notificationtypes_cache['replyusercomments']['notificationtypelabel'], + notificationtypes_cache['taggedusercomments']['notificationtypelabel'], + ]) # 3,9,10 + # notificationtypelabel = ','.join(str(e) for e in notificationtypelabel) + rs = db.session.execute(text(sql), {'commentid': commentid, 'notificationtypelabel': notificationtypelabel}) for row in rs: dt = maya.parse(row["created_at"]).datetime(to_timezone='America/Vancouver', naive=False) _createddate = dt @@ -107,10 +114,10 @@ def getcommentnotifications(cls, commentid): def getextensionnotifications(cls, extensionid): notifications = [] try: - sql = sql = """select idnumber, axisnumber, notificationid, notification , notificationtypeid from "FOIRequestNotifications" where notification->>'extensionid' = :extensionid """ + sql = sql = """select idnumber, axisnumber, notificationid, notification , notificationtypelabel from "FOIRequestNotifications" where isdeleted = false and notification->>'extensionid' = :extensionid """ rs = db.session.execute(text(sql), {'extensionid': str(extensionid)}) for row in rs: - notifications.append({"idnumber": row["idnumber"], "axisnumber": row["axisnumber"], "notificationid": row["notificationid"], "notification": row["notification"], "notificationtypeid": row["notificationtypeid"]}) + notifications.append({"idnumber": row["idnumber"], "axisnumber": row["axisnumber"], "notificationid": row["notificationid"], "notification": row["notification"], "notificationtypelabel": row["notificationtypelabel"]}) except Exception as ex: logging.error(ex) raise ex @@ -130,11 +137,11 @@ def dismissnotification(cls, notificationids, userid='system'): raise @classmethod - def getnotificationidsbynumberandtype(cls, idnumber, notificationtypeids): + def getnotificationidsbynumberandtype(cls, idnumber, notificationtypelabels): notificationids = [] try: - sql = """select notificationid from "FOIRequestNotifications" where idnumber = :idnumber and notificationtypeid = ANY(:notificationtypeids) """ - rs = db.session.execute(text(sql), {'idnumber': idnumber, 'notificationtypeids': notificationtypeids}) + sql = """select notificationid from "FOIRequestNotifications" where idnumber = :idnumber and notificationtypelabel = ANY(:notificationtypelabels) and isdeleted = false """ + rs = db.session.execute(text(sql), {'idnumber': idnumber, 'notificationtypelabels': notificationtypelabels}) for row in rs: notificationids.append(row["notificationid"]) except Exception as ex: @@ -148,7 +155,7 @@ def getnotificationidsbynumberandtype(cls, idnumber, notificationtypeids): def getnotificationidsbynumber(cls, idnumber): notificationids = [] try: - sql = """select notificationid from "FOIRequestNotifications" where idnumber = :idnumber """ + sql = """select notificationid from "FOIRequestNotifications" where idnumber = :idnumber and isdeleted = false """ rs = db.session.execute(text(sql), {'idnumber': idnumber}) for row in rs: notificationids.append(row["notificationid"]) @@ -160,9 +167,9 @@ def getnotificationidsbynumber(cls, idnumber): return notificationids @classmethod - def getnotificationidsbytype(cls, notificationtypeid): - sql = """select notificationid from "FOIRequestNotifications" where notificationtypeid= :notificationtypeid """ - rs = db.session.execute(text(sql), {'notificationtypeid': notificationtypeid}) + def getnotificationidsbytype(cls, notificationtypelabel): + sql = """select notificationid from "FOIRequestNotifications" where notificationtypelabel= :notificationtypelabel and isdeleted = false """ + rs = db.session.execute(text(sql), {'notificationtypelabel': notificationtypelabel}) notificationids = [] for row in rs: notificationids.append(row["notificationid"]) @@ -170,7 +177,7 @@ def getnotificationidsbytype(cls, notificationtypeid): @classmethod def getextensionnotificationidsbyministry(cls, ministryid): - sql = """select notificationid from "FOIRequestNotifications" where requestid = :requestid and notificationtypeid = 4 """ + sql = """select notificationid from "FOIRequestNotifications" where requestid = :requestid and notificationtypelabel = 4 and isdeleted = false """ rs = db.session.execute(text(sql), {'requestid': ministryid}) notificationids = [] for row in rs: @@ -179,4 +186,4 @@ def getextensionnotificationidsbyministry(cls, ministryid): class FOIRequestNotificationSchema(ma.Schema): class Meta: - fields = ('notificationid', 'ministryrequestid', 'notification', 'notificationtypeid','created_at','createdby','updated_at','updatedby') \ No newline at end of file + fields = ('notificationid', 'ministryrequestid', 'notification', 'notificationtypeid', 'notificationtypelabel','created_at','createdby','updated_at','updatedby') \ No newline at end of file diff --git a/request-management-api/request_api/models/FOIRequestStatus.py b/request-management-api/request_api/models/FOIRequestStatus.py index fa751e971..439c9f6ed 100644 --- a/request-management-api/request_api/models/FOIRequestStatus.py +++ b/request-management-api/request_api/models/FOIRequestStatus.py @@ -9,6 +9,7 @@ class FOIRequestStatus(db.Model): name = db.Column(db.String(100), unique=False, nullable=False) description = db.Column(db.String(255), unique=False, nullable=True) isactive = db.Column(db.Boolean, unique=False, nullable=False) + statuslabel = db.Column(db.String(50), unique=True, nullable=False) @classmethod def getrequeststatuses(cls): @@ -17,17 +18,17 @@ def getrequeststatuses(cls): return requeststatus_schema.dump(query) @classmethod - def getrequeststatusid(cls,status): + def getrequeststatus(cls,status): requeststatus_schema = RequestStatusSchema() query = db.session.query(FOIRequestStatus).filter_by(name=status).first() return requeststatus_schema.dump(query) @classmethod - def getrequeststatusname(cls,statusid): + def getrequeststatusbylabel(cls,statuslabel): requeststatus_schema = RequestStatusSchema() - query = db.session.query(FOIRequestStatus).filter_by(requeststatusid=statusid, isactive=True).first() + query = db.session.query(FOIRequestStatus).filter_by(statuslabel=statuslabel, isactive=True).first() return requeststatus_schema.dump(query) class RequestStatusSchema(ma.Schema): class Meta: - fields = ('requeststatusid', 'name', 'description','isactive') \ No newline at end of file + fields = ('requeststatusid', 'name', 'description','isactive','statuslabel') \ No newline at end of file diff --git a/request-management-api/request_api/models/FOIRequestTeams.py b/request-management-api/request_api/models/FOIRequestTeams.py index 02d02714b..e6ddbe50f 100644 --- a/request-management-api/request_api/models/FOIRequestTeams.py +++ b/request-management-api/request_api/models/FOIRequestTeams.py @@ -4,12 +4,15 @@ from sqlalchemy.sql.schema import ForeignKey from sqlalchemy import text import logging +from request_api.utils.enums import StateName + class FOIRequestTeam(db.Model): __tablename__ = 'FOIRequestTeams' # Defining the columns requestteamid = db.Column(db.Integer, primary_key=True,autoincrement=True) requesttype = db.Column(db.String(100), unique=False, nullable=True) requeststatusid = db.Column(db.Integer,ForeignKey('FOIRequestStatuses.requeststatusid')) + requeststatuslabel = db.Column(db.String(50), unique=False, nullable=False) teamid = db.Column(db.Integer,ForeignKey('OperatingTeams.teamid')) programareaid = db.Column(db.Integer,ForeignKey('ProgramAreas.programareaid')) isactive = db.Column(db.Boolean, unique=False, nullable=False) @@ -23,14 +26,15 @@ def getrequestteams(cls): @classmethod def getteamsbystatusandprogramarea(cls, requesttype, status, bcgovcode): teams = [] - try: + try: + # and replace(lower(fs2."name"),' ','') = :status sql = """ with mappedteams as ( select ot."name" as name, ot."type" as type, ft.requestteamid as orderby from "FOIRequestTeams" ft inner join "FOIRequestStatuses" fs2 on ft.requeststatusid = fs2.requeststatusid inner join "OperatingTeams" ot on ft.teamid = ot.teamid left join "ProgramAreas" pa on ft.programareaid = pa.programareaid - where ft.isactive = true and lower(ft.requesttype) = :requesttype - and replace(lower(fs2."name"),' ','') = :status + where ft.isactive = true and lower(ft.requesttype) = :requesttype + and ft.requeststatuslabel = :status and (lower(pa.bcgovcode) = :bcgovcode or ft.programareaid is null) ) -- remove the with statement and below query go back to mapped teams only in assignee drop down @@ -57,8 +61,8 @@ def getprocessingteamsbytype(cls, requesttype): inner join "ProgramAreas" pa on ft.programareaid = pa.programareaid where lower(ft.requesttype) = :requesttype and ft.programareaid is not null and ot."type" = 'iao' - and ft.requeststatusid = 8""" - rs = db.session.execute(text(sql), {'requesttype': requesttype}) + and ft.requeststatuslabel = :requeststatuslabel""" + rs = db.session.execute(text(sql), {'requesttype': requesttype, 'requeststatuslabel': StateName.feeestimate.name}) for row in rs: teams.append({"team":row["team"], "ministry":row["ministry"], "bcgovcode":row["bcgovcode"], "iaocode":row["iaocode"]}) except Exception as ex: @@ -91,4 +95,4 @@ def getdefaultprocessingteamforpersonal(cls, bcgovcode): class FOIRequestTeamSchema(ma.Schema): class Meta: - fields = ('requestteamid', 'requesttype', 'requeststatusid','teamid','programareaid','isactive') \ No newline at end of file + fields = ('requestteamid', 'requesttype', 'requeststatusid','teamid','programareaid','isactive', 'requeststatuslabel') \ No newline at end of file diff --git a/request-management-api/request_api/models/NotificationTypes.py b/request-management-api/request_api/models/NotificationTypes.py index a3743612a..71be7a7d3 100644 --- a/request-management-api/request_api/models/NotificationTypes.py +++ b/request-management-api/request_api/models/NotificationTypes.py @@ -11,14 +11,23 @@ class NotificationType(db.Model): name = db.Column(db.String(100), unique=False, nullable=False) description = db.Column(db.String(255), unique=False, nullable=False) isactive = db.Column(db.Boolean, unique=False, nullable=False) + notificationtypelabel = db.Column(db.String(100), unique=True, nullable=False) @classmethod def getnotificationtypes(cls): type_schema = NotificationTypeSchema(many=True) query = db.session.query(NotificationType).filter_by(isactive=True).all() return type_schema.dump(query) + + # create a class method that returns the notification type id + @classmethod + def getnotificationtypeid(cls, notificationtype): + type_schema = NotificationTypeSchema(many=False) + query = db.session.query(NotificationType).filter_by(name=notificationtype, isactive=True).first() + return type_schema.dump(query) if query is not None else None class NotificationTypeSchema(ma.Schema): class Meta: - fields = ('notificationtypeid', 'name', 'description','isactive') \ No newline at end of file + fields = ('notificationtypeid', 'name', 'description','isactive', 'notificationtypelabel') + diff --git a/request-management-api/request_api/models/NotificationUserTypes.py b/request-management-api/request_api/models/NotificationUserTypes.py index 054b4c213..c358ffbea 100644 --- a/request-management-api/request_api/models/NotificationUserTypes.py +++ b/request-management-api/request_api/models/NotificationUserTypes.py @@ -3,6 +3,10 @@ from sqlalchemy.orm import relationship,backref from datetime import datetime from sqlalchemy import text +import json +f = open('common/notificationusertypes.json', encoding="utf8") +notificationusertypes_cache = json.load(f) + class NotificationUserType(db.Model): __tablename__ = 'NotificationUserTypes' @@ -11,14 +15,28 @@ class NotificationUserType(db.Model): name = db.Column(db.String(100), unique=False, nullable=False) description = db.Column(db.String(255), unique=False, nullable=False) isactive = db.Column(db.Boolean, unique=False, nullable=False) + notificationusertypelabel = db.Column(db.String(100), unique=True, nullable=False) @classmethod def getnotificationusertypes(cls): usertype_schema = NotificationUserTypeSchema(many=True) query = db.session.query(NotificationUserType).filter_by(isactive=True).all() return usertype_schema.dump(query) + + # create a class method that returns the notification type id + @classmethod + def getnotificationusertypesid(cls, notificationusertype): + notificationusertypelabel = None + for usertype in notificationusertypes_cache: + if (notificationusertypes_cache[usertype]['name'] == notificationusertype) or (notificationusertypes_cache[usertype]['notificationusertypelabel'] == notificationusertype): + notificationusertypelabel = notificationusertypes_cache[usertype]['notificationusertypelabel'] + if notificationusertypelabel is None: + return None + type_schema = NotificationUserTypeSchema(many=False) + query = db.session.query(NotificationUserType).filter_by(notificationusertypelabel=notificationusertypelabel, isactive=True).first() + return type_schema.dump(query) if query is not None else None class NotificationUserTypeSchema(ma.Schema): class Meta: - fields = ('notificationusertypeid', 'name', 'description','isactive') \ No newline at end of file + fields = ('notificationusertypeid', 'notificationusertypelabel', 'name', 'description','isactive') \ No newline at end of file diff --git a/request-management-api/request_api/models/views/FOINotifications.py b/request-management-api/request_api/models/views/FOINotifications.py index ab6b9e214..dc14ffe7b 100644 --- a/request-management-api/request_api/models/views/FOINotifications.py +++ b/request-management-api/request_api/models/views/FOINotifications.py @@ -17,4 +17,5 @@ class FOINotifications(db.Model): userformatted = db.Column(db.Text) creatorformatted = db.Column(db.Text) notificationtype = db.Column(db.String(500)) + notificationtypelabel = db.Column(db.String(500)) diff --git a/request-management-api/request_api/models/views/FOIRequests.py b/request-management-api/request_api/models/views/FOIRequests.py index b4a85ddc8..baa3395f3 100644 --- a/request-management-api/request_api/models/views/FOIRequests.py +++ b/request-management-api/request_api/models/views/FOIRequests.py @@ -20,4 +20,5 @@ class FOIRequests(db.Model): ministryassignedtoformatted = db.Column(db.String(500)) description = db.Column(db.Text) crtid = db.Column(db.Text) + requeststatuslabel = db.Column(db.String(50)) diff --git a/request-management-api/request_api/resources/foirequest.py b/request-management-api/request_api/resources/foirequest.py index 290cd2ccc..58cf30376 100644 --- a/request-management-api/request_api/resources/foirequest.py +++ b/request-management-api/request_api/resources/foirequest.py @@ -28,6 +28,7 @@ from request_api.services.eventservice import eventservice from request_api.schemas.foirequestwrapper import FOIRequestWrapperSchema, EditableFOIRequestWrapperSchema, FOIRequestMinistrySchema, FOIRequestStatusSchema from request_api.schemas.foiassignee import FOIRequestAssigneeSchema +from request_api.utils.enums import StateName from marshmallow import Schema, fields, validate, ValidationError from request_api.utils.enums import MinistryTeamWithKeycloackGroup import json @@ -99,7 +100,7 @@ def post(): assignedtofirstname = request_json["assignedToFirstName"] if request_json.get("assignedToFirstName") != None else None assignedtomiddlename = request_json["assignedToMiddleName"] if request_json.get("assignedToMiddleName") != None else None assignedtolastname = request_json["assignedToLastName"] if request_json.get("assignedToLastName") != None else None - rawresult = rawrequestservice().saverawrequestversion(request_json,request_json['id'],assignedgroup,assignedto,"Archived",AuthHelper.getuserid(), assignedtofirstname,assignedtomiddlename,assignedtolastname) + rawresult = rawrequestservice().saverawrequestversion(request_json,request_json['id'],assignedgroup,assignedto,"Archived",AuthHelper.getuserid(), assignedtofirstname,assignedtomiddlename,assignedtolastname,StateName.archived.name) diff --git a/request-management-api/request_api/resources/request.py b/request-management-api/request_api/resources/request.py index cfc9fc012..fcec8a2e5 100644 --- a/request-management-api/request_api/resources/request.py +++ b/request-management-api/request_api/resources/request.py @@ -25,6 +25,7 @@ from request_api.services.rawrequestservice import rawrequestservice from request_api.services.documentservice import documentservice from request_api.services.eventservice import eventservice +from request_api.utils.enums import StateName import json import asyncio from jose import jwt as josejwt @@ -92,12 +93,12 @@ def post(requestid=None, actiontype=None): assigneefirstname = requestdata['assigneefirstname'] assigneemiddlename = requestdata['assigneemiddlename'] assigneelastname = requestdata['assigneelastname'] - + statuslabel = requestdata['requeststatuslabel'] if int(requestid) and str(requestid) != "-1" : - status = rawrequestservice().getstatus(updaterequest) - if status not in ['Intake in Progress', 'Closed', 'Redirect', 'Peer Review', 'Section 5 Pending', 'App Fee Owing']: + status, statuslabel = rawrequestservice().getstatus(updaterequest) + if status not in [StateName.intakeinprogress.value, StateName.closed.value, StateName.redirect.value, StateName.peerreview.value, StateName.section5pending.value, StateName.appfeeowing.value]: raise ValueError('Invalid request state.') - result = rawrequestservice().saverawrequestversion(updaterequest,requestid,assigneegroup,assignee,status,AuthHelper.getuserid(),assigneefirstname,assigneemiddlename,assigneelastname, actiontype) + result = rawrequestservice().saverawrequestversion(updaterequest,requestid,assigneegroup,assignee,status,AuthHelper.getuserid(),assigneefirstname,assigneemiddlename,assigneelastname, statuslabel, actiontype) assignee = '' if(actiontype == 'assignee'): assignee = getassignee(assigneefirstname,assigneelastname,assigneegroup) @@ -128,7 +129,8 @@ def getparams(updaterequest): 'assignee': updaterequest["assignedTo"] if 'assignedTo' in updaterequest else None, 'assigneefirstname': updaterequest["assignedToFirstName"] if updaterequest.get("assignedToFirstName") != None else None, 'assigneemiddlename': updaterequest["assignedToMiddleName"] if updaterequest.get("assignedToMiddleName") != None else None, - 'assigneelastname': updaterequest["assignedToLastName"] if updaterequest.get("assignedToLastName") != None else None + 'assigneelastname': updaterequest["assignedToLastName"] if updaterequest.get("assignedToLastName") != None else None, + 'requeststatuslabel': updaterequest["requeststatuslabel"] if updaterequest.get("requeststatuslabel") != None else None } @cors_preflight('GET,OPTIONS') diff --git a/request-management-api/request_api/schemas/foirequestwrapper.py b/request-management-api/request_api/schemas/foirequestwrapper.py index efdb027ac..ce3ef32f6 100644 --- a/request-management-api/request_api/schemas/foirequestwrapper.py +++ b/request-management-api/request_api/schemas/foirequestwrapper.py @@ -105,6 +105,7 @@ class Meta: # pylint: disable=too-few-public-methods postal = fields.Str(data_key="postal",allow_none=True, validate=[validate.Length(max=10, error=MAX_EXCEPTION_MESSAGE)]) country = fields.Str(data_key="country",allow_none=True) requeststatusid = fields.Int(data_key="requeststatusid",allow_none=True) + requeststatuslabel = fields.Str(data_key="requeststatuslabel",allow_none=False) closedate = fields.Date(data_key="closedate", required=False,allow_none=True) closereasonid = fields.Int(data_key="closereasonid",allow_none=True) correctionalServiceNumber = fields.Str(data_key="correctionalServiceNumber",allow_none=True, validate=[validate.Length(max=50, error=MAX_EXCEPTION_MESSAGE)]) @@ -168,6 +169,7 @@ class Meta: # pylint: disable=too-few-public-methods assignedgroup = fields.Str(data_key="assignedGroup",allow_none=True, validate=[validate.Length(max=250, error=MAX_EXCEPTION_MESSAGE)]) assignedto = fields.Str(data_key="assignedTo",allow_none=True, validate=[validate.Length(max=120, error=MAX_EXCEPTION_MESSAGE)]) requeststatusid = fields.Int(data_key="requeststatusid",allow_none=True) + requeststatuslabel = fields.Str(data_key="requeststatuslabel",allow_none=False) divisions = fields.Nested(FOIMinistryRequestDivisionSchema, many=True,allow_none=True) documents = fields.Nested(FOIMinistryRequestDocumentSchema, many=True,allow_none=True) assignedToFirstName = fields.Str(data_key="assignedToFirstName",allow_none=True, validate=[validate.Length(max=50, error=MAX_EXCEPTION_MESSAGE)]) diff --git a/request-management-api/request_api/services/events/assignment.py b/request-management-api/request_api/services/events/assignment.py index b8f74dea1..538317aba 100644 --- a/request-management-api/request_api/services/events/assignment.py +++ b/request-management-api/request_api/services/events/assignment.py @@ -7,6 +7,7 @@ from request_api.models.FOIRawRequests import FOIRawRequest from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRequestStatus import FOIRequestStatus +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult from request_api.utils.enums import CommentType @@ -38,7 +39,8 @@ def createassignmentevent(self, requestid, requesttype, userid, isministryuser,a def __createnotification(self, requestid, requesttype, userid, isministryuser): notification = self.__preparenotification() - return notificationservice().createnotification({"message" : notification}, requestid, requesttype, self.__assignmenttype(isministryuser), userid) + notificationtype = NotificationType().getnotificationtypeid(self.__assignmenttype(isministryuser)) + return notificationservice().createnotification({"message" : notification}, requestid, requesttype, notificationtype, userid) def __createnotificationforremoval(self, requestid, requesttype, userid, username, previousassignee): notification = self.__preparenotification(username, True) diff --git a/request-management-api/request_api/services/events/cfrdate.py b/request-management-api/request_api/services/events/cfrdate.py index 7f353b710..6d742234a 100644 --- a/request-management-api/request_api/services/events/cfrdate.py +++ b/request-management-api/request_api/services/events/cfrdate.py @@ -6,6 +6,7 @@ from request_api.services.commentservice import commentservice from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRequestComments import FOIRequestComment +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult from enum import Enum @@ -16,6 +17,7 @@ import os from flask import current_app from dateutil.parser import parse +import time as t class cfrdateevent(duecalculator): """ FOI Event management service @@ -24,26 +26,28 @@ class cfrdateevent(duecalculator): def createdueevent(self): try: _today = self.gettoday() - notificationservice().dismissremindernotification("ministryrequest", self.__notificationtype()) + notificationservice().dismissremindernotification("ministryrequest", self.__notificationtype()) + ca_holidays = self.getholidays() _upcomingdues = FOIMinistryRequest.getupcomingcfrduerecords() + notificationtype = NotificationType().getnotificationtypeid(self.__notificationtype()) for entry in _upcomingdues: _duedate = self.formatduedate(entry['cfrduedate']) message = None if _duedate == _today: message = self.__todayduemessage() elif self.getpreviousbusinessday(entry['cfrduedate'],ca_holidays) == _today: - message = self.__upcomingduemessage(_duedate) - self.__createnotification(message,entry['foiministryrequestid']) + message = self.__upcomingduemessage(_duedate) + self.__createnotification(message,entry['foiministryrequestid'], notificationtype) self.__createcomment(entry, message) return DefaultMethodResult(True,'CFR reminder notifications created',_today) except BusinessException as exception: current_app.logger.error("%s,%s" % ('CFR reminder Notification Error', exception.message)) return DefaultMethodResult(False,'CFR reminder notifications failed',_today) - def __createnotification(self, message, requestid): + def __createnotification(self, message, requestid, notificationtype): if message is not None: - return notificationservice().createremindernotification({"message" : message}, requestid, "ministryrequest", self.__notificationtype(), self.__defaultuserid()) + return notificationservice().createremindernotification({"message" : message}, requestid, "ministryrequest", notificationtype, self.__defaultuserid()) def __createcomment(self, entry, message): if message is not None: diff --git a/request-management-api/request_api/services/events/cfrfeeform.py b/request-management-api/request_api/services/events/cfrfeeform.py index d82e57806..e98711244 100644 --- a/request-management-api/request_api/services/events/cfrfeeform.py +++ b/request-management-api/request_api/services/events/cfrfeeform.py @@ -6,6 +6,7 @@ from request_api.services.commentservice import commentservice from request_api.services.cfrfeeservice import cfrfeeservice from request_api.services.notificationservice import notificationservice +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult from enum import Enum @@ -60,7 +61,8 @@ def __createcomment(self, requestid, state, userid, username, updatedamounts=Non def __createnotification(self, requestid, state, userid): notification = self.__preparenotification(state) - return notificationservice().createnotification({"message" : notification}, requestid, "ministryrequest", "CFR Fee Form", userid) + notificationtype = NotificationType().getnotificationtypeid("CFR Fee Form") + return notificationservice().createnotification({"message" : notification}, requestid, "ministryrequest", notificationtype, userid) def __preparecomment(self, requestid, state, username, updatedamounts): comment = {"comment": self.__commentmessage(state, username, updatedamounts)} diff --git a/request-management-api/request_api/services/events/divisiondate.py b/request-management-api/request_api/services/events/divisiondate.py index ceab3a561..c208581dd 100644 --- a/request-management-api/request_api/services/events/divisiondate.py +++ b/request-management-api/request_api/services/events/divisiondate.py @@ -5,6 +5,7 @@ from request_api.services.commentservice import commentservice from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRequestComments import FOIRequestComment +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult from enum import Enum @@ -26,6 +27,7 @@ def createdueevent(self): notificationservice().dismissremindernotification("ministryrequest", self.__notificationtype()) ca_holidays = self.getholidays() _upcomingdues = FOIMinistryRequest.getupcomingdivisionduerecords() + notificationtype = NotificationType().getnotificationtypeid(self.__notificationtype()) for entry in _upcomingdues: _duedate = self.formatduedate(entry['duedate']) message = None @@ -33,16 +35,16 @@ def createdueevent(self): message = self.__todayduemessage(entry) elif self.getpreviousbusinessday(entry['duedate'],ca_holidays) == _today: message = self.__upcomingduemessage(entry) - self.__createnotification(message,entry['foiministryrequestid']) + self.__createnotification(message,entry['foiministryrequestid'], notificationtype) self.__createcomment(entry, message) return DefaultMethodResult(True,'Division reminder notifications created',_today) except BusinessException as exception: current_app.logger.error("%s,%s" % ('Legislative reminder Notification Error', exception.message)) return DefaultMethodResult(False,'Division reminder notifications failed',_today) - def __createnotification(self, message, requestid): + def __createnotification(self, message, requestid, notificationtype): if message is not None: - return notificationservice().createnotification({"message" : message}, requestid, "ministryrequest", self.__notificationtype(), self.__defaultuserid(), False) + return notificationservice().createnotification({"message" : message}, requestid, "ministryrequest", notificationtype, self.__defaultuserid(), False) def __createcomment(self, entry, message): if message is not None: diff --git a/request-management-api/request_api/services/events/email.py b/request-management-api/request_api/services/events/email.py index 395d84fb8..8011ad324 100644 --- a/request-management-api/request_api/services/events/email.py +++ b/request-management-api/request_api/services/events/email.py @@ -7,6 +7,7 @@ from request_api.models.FOIRawRequests import FOIRawRequest from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRequestStatus import FOIRequestStatus +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult import logging @@ -35,7 +36,8 @@ def __createcomment(self, requestid, requesttype, stage, reason, userid): def __createnotification(self, requestid, requesttype, stage): notification = self.__preparenotification(stage) - return notificationservice().createnotification({"message" : notification}, requestid, requesttype, "Email Failure", self.__defaultuserid()) + notificationtype = NotificationType().getnotificationtypeid("Email Failure") + return notificationservice().createnotification({"message" : notification}, requestid, requesttype, notificationtype, self.__defaultuserid()) def __preparenotification(self, stage): return self.__notificationmessage(stage) diff --git a/request-management-api/request_api/services/events/extension.py b/request-management-api/request_api/services/events/extension.py index 497ad2bcb..dec4a8447 100644 --- a/request-management-api/request_api/services/events/extension.py +++ b/request-management-api/request_api/services/events/extension.py @@ -8,6 +8,7 @@ from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRequestComments import FOIRequestComment from request_api.models.FOIRequestNotifications import FOIRequestNotification +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult from enum import Enum @@ -72,7 +73,8 @@ def createnotification(self, ministryrequestid, extensionid, curextension, preve notification = self.__preparenotification(extensionsummary) if notificationandcleanup == True: self.__deleteextensionnotification(extensionid) - return notificationservice().createnotification({"extensionid": extensionid, "message": notification}, ministryrequestid, "ministryrequest", "Extension", userid, False) + notificationtype = NotificationType().getnotificationtypeid("Extension") + return notificationservice().createnotification({"extensionid": extensionid, "message": notification}, ministryrequestid, "ministryrequest", notificationtype, userid, False) def __deleteaxisextensionnotifications(self, notificationids): notificationservice().dismissnotificationbyid("ministryrequest", notificationids) diff --git a/request-management-api/request_api/services/events/legislativedate.py b/request-management-api/request_api/services/events/legislativedate.py index 41ab4669f..56885014c 100644 --- a/request-management-api/request_api/services/events/legislativedate.py +++ b/request-management-api/request_api/services/events/legislativedate.py @@ -6,6 +6,7 @@ from request_api.services.commentservice import commentservice from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRequestComments import FOIRequestComment +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult from enum import Enum @@ -16,6 +17,7 @@ import os from flask import current_app from dateutil.parser import parse +import time as t class legislativedateevent(duecalculator): """ FOI Event management service @@ -28,6 +30,7 @@ def createdueevent(self): notificationservice().dismissremindernotification("ministryrequest", self.__notificationtype()) ca_holidays = self.getholidays() _upcomingdues = FOIMinistryRequest.getupcominglegislativeduerecords() + notificationtype = NotificationType().getnotificationtypeid(self.__notificationtype()) for entry in _upcomingdues: _duedate = self.formatduedate(entry['duedate']) message = None @@ -35,16 +38,17 @@ def createdueevent(self): message = self.__todayduemessage() elif self.getpreviousbusinessday(entry['duedate'],ca_holidays) == _today or self.getbusinessdaysbetween(entry['duedate'],_today) == 5: message = self.__upcomingduemessage(_duedate) - self.__createnotification(message,entry['foiministryrequestid']) + + self.__createnotification(message,entry['foiministryrequestid'], notificationtype) self.__createcomment(entry, message) return DefaultMethodResult(True,'Legislative reminder notifications created',_today) except BusinessException as exception: current_app.logger.error("%s,%s" % ('Legislative reminder Notification Error', exception.message)) return DefaultMethodResult(False,'Legislative reminder notifications failed',_today) - def __createnotification(self, message, requestid): + def __createnotification(self, message, requestid, notificationtype): if message is not None: - return notificationservice().createnotification({"message" : message}, requestid, "ministryrequest", self.__notificationtype(), self.__defaultuserid(), False) + return notificationservice().createnotification({"message" : message}, requestid, "ministryrequest", notificationtype, self.__defaultuserid(), False) def __createcomment(self, entry, message): if message is not None: diff --git a/request-management-api/request_api/services/events/payment.py b/request-management-api/request_api/services/events/payment.py index 6263e5a8a..f22cbb83b 100644 --- a/request-management-api/request_api/services/events/payment.py +++ b/request-management-api/request_api/services/events/payment.py @@ -6,6 +6,7 @@ from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRawRequests import FOIRawRequest from request_api.models.FOIRequestStatus import FOIRequestStatus +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult from enum import Enum @@ -46,6 +47,7 @@ def createpaymentreminderevent(self): notificationservice().dismissremindernotification("rawrequest", self.__notificationtype()) eventtype = PaymentEventType.reminder.value _onholdrequests = FOIRawRequest.getappfeeowingrequests() + notificationtype = NotificationType().getnotificationtypeid(self.__notificationtype()) for entry in _onholdrequests: _dateofstatechange = datetimehandler().formatdate(entry['updated_at']) businessdayselapsed = duecalculator().getbusinessdaysbetween(_dateofstatechange) @@ -57,7 +59,7 @@ def createpaymentreminderevent(self): commentexists = True if not commentexists: self.__createcommentforrawrequest(entry['requestid'], eventtype) - self.__createnotificationforrawrequest(entry['requestid'], eventtype) + self.__createnotificationforrawrequest(entry['requestid'], eventtype, notificationtype) return DefaultMethodResult(True,'Payment reminder notifications created',_today) except BusinessException as exception: current_app.logger.error("%s,%s" % ('Payment reminder Notification Error', exception.message)) @@ -67,17 +69,18 @@ def __createcommentforrawrequest(self, requestid, eventtype): comment = self.__preparecomment(requestid, eventtype) return commentservice().createrawrequestcomment(comment, "system", 2) - def __createnotificationforrawrequest(self, requestid, eventtype): + def __createnotificationforrawrequest(self, requestid, eventtype, notificationtype): notification = self.__preparenotification(requestid, eventtype) - return notificationservice().createnotification({"message" : notification}, requestid, "rawrequest", self.__notificationtype(), "system") + return notificationservice().createnotification({"message" : notification}, requestid, "rawrequest", notificationtype, "system") def __createcomment(self, requestid, eventtype): comment = self.__preparecomment(requestid, eventtype) return commentservice().createministryrequestcomment(comment, self.__defaultuserid(), 2) def __createnotification(self, requestid, eventtype): + notificationtype = NotificationType().getnotificationtypeid(self.__notificationtype()) notification = self.__preparenotification(requestid, eventtype) - return notificationservice().createnotification({"message" : notification}, requestid, "ministryrequest", "Payment", self.__defaultuserid()) + return notificationservice().createnotification({"message" : notification}, requestid, "ministryrequest", notificationtype, self.__defaultuserid()) def __preparenotification(self, requestid, eventtype): return self.__notificationmessage(requestid, eventtype) diff --git a/request-management-api/request_api/services/events/section5pending.py b/request-management-api/request_api/services/events/section5pending.py index 20450500e..84e6897f5 100644 --- a/request-management-api/request_api/services/events/section5pending.py +++ b/request-management-api/request_api/services/events/section5pending.py @@ -4,6 +4,7 @@ from request_api.services.notificationservice import notificationservice from request_api.services.commentservice import commentservice from request_api.models.FOIRawRequests import FOIRawRequest +from request_api.models.NotificationTypes import NotificationType from request_api.models.default_method_result import DefaultMethodResult from enum import Enum from request_api.exceptions import BusinessException @@ -20,6 +21,7 @@ def createdueevent(self): _today = self.gettoday() notificationservice().dismissremindernotification("rawrequest", self.__notificationtype()) section5pendings = FOIRawRequest.getlatestsection5pendings() + notificationtype = NotificationType().getnotificationtypeid(self.__notificationtype()) for entry in section5pendings: _dateofstatechange = datetimehandler().formatdate(entry['created_at']) businessdayselapsed = self.getbusinessdaysbetween(_dateofstatechange) @@ -32,15 +34,15 @@ def createdueevent(self): commentexists = True if not commentexists: self.__createcomment(entry, message) - self.__createnotification(message, entry['requestid']) + self.__createnotification(message, entry['requestid'], notificationtype) return DefaultMethodResult(True,'Section 5 Pending passed due notification created',_today) except BusinessException as exception: current_app.logger.error("%s,%s" % ('Section 5 Pending passed due notification Error', exception.message)) return DefaultMethodResult(False,'Section 5 Pending passed due notification failed',_today) - def __createnotification(self, message, requestid): + def __createnotification(self, message, requestid, notificationtype): if message is not None: - return notificationservice().createremindernotification({"message" : message}, requestid, "rawrequest", self.__notificationtype(), self.__defaultuserid()) + return notificationservice().createremindernotification({"message" : message}, requestid, "rawrequest", notificationtype, self.__defaultuserid()) def __createcomment(self, entry, message): if message is not None: diff --git a/request-management-api/request_api/services/events/state.py b/request-management-api/request_api/services/events/state.py index 789c72ca9..877009889 100644 --- a/request-management-api/request_api/services/events/state.py +++ b/request-management-api/request_api/services/events/state.py @@ -7,8 +7,10 @@ from request_api.models.FOIRawRequests import FOIRawRequest from request_api.models.FOIMinistryRequests import FOIMinistryRequest from request_api.models.FOIRequestStatus import FOIRequestStatus +from request_api.models.NotificationTypes import NotificationType import json from request_api.models.default_method_result import DefaultMethodResult +from request_api.utils.enums import StateName class stateevent: """ FOI Event management service @@ -34,12 +36,12 @@ def __haschanged(self, requestid, requesttype): if len(states) == 2: newstate = states[0] oldstate = states[1] - if newstate != oldstate and newstate != 'Intake in Progress': + if newstate != oldstate and newstate != StateName.intakeinprogress.value: return newstate return None def __createcommentwrapper(self, requestid, state, requesttype, userid, username): - if state == 'Archived': + if state == StateName.archived.value: _openedministries = FOIMinistryRequest.getministriesopenedbyuid(requestid) for ministry in _openedministries: response=self.__createcomment(ministry["ministryrequestid"], state, 'ministryrequest', userid, username) @@ -58,24 +60,26 @@ def __createcomment(self, requestid, state, requesttype, userid, username): def __createnotification(self, requestid, state, requesttype, userid): _notificationtype = "State" - if state == 'Call For Records' and requesttype == "ministryrequest": + if state == StateName.callforrecords.value and requesttype == "ministryrequest": foirequest = notificationservice().getrequest(requestid, requesttype) _notificationtype = "Group Members" if foirequest['assignedministryperson'] is None else "State" + notificationtype = NotificationType().getnotificationtypeid(_notificationtype) notification = self.__preparenotification(state) - if state == "Response" and requesttype == "ministryrequest": + if state == StateName.response.value and requesttype == "ministryrequest": signgoffapproval = FOIMinistryRequest().getrequest(requestid)['ministrysignoffapproval'] - notification = notification + f". Approved by {signgoffapproval['approvername']}, {signgoffapproval['approvertitle']} on {signgoffapproval['approveddate']}" - if state == 'Closed' or state == 'Archived' : + if signgoffapproval: + notification = notification + f". Approved by {signgoffapproval['approvername']}, {signgoffapproval['approvertitle']} on {signgoffapproval['approveddate']}" + if state == StateName.closed.value or state == StateName.archived.value: notificationservice().dismissnotificationsbyrequestid(requestid, requesttype) - if state == 'Archived': + if state == StateName.archived.value: _openedministries = FOIMinistryRequest.getministriesopenedbyuid(requestid) for ministry in _openedministries: - response = notificationservice().createnotification({"message" : notification}, ministry["ministryrequestid"], 'ministryrequest', "State", userid) + response = notificationservice().createnotification({"message" : notification}, ministry["ministryrequestid"], 'ministryrequest', notificationtype, userid) else: - response = notificationservice().createnotification({"message" : notification}, requestid, requesttype, "State", userid) + response = notificationservice().createnotification({"message" : notification}, requestid, requesttype, notificationtype, userid) if _notificationtype == "Group Members": notification = self.__preparegroupmembernotification(state, requestid) - groupmemberresponse = notificationservice().createnotification({"message" : notification}, requestid, requesttype, _notificationtype, userid) + groupmemberresponse = notificationservice().createnotification({"message" : notification}, requestid, requesttype, notificationtype, userid) if response.success == True and groupmemberresponse.success == True : return DefaultMethodResult(True,'Notification added',requestid) else: @@ -88,7 +92,7 @@ def __preparenotification(self, state): return self.__notificationmessage(state) def __preparegroupmembernotification(self, state, requestid): - if state == 'Call For Records': + if state == StateName.callforrecords.value: return self.__notificationcfrmessage(requestid) return self.__groupmembernotificationmessage(state) @@ -101,11 +105,11 @@ def __preparecomment(self, requestid, state,requesttype, username): return comment def __formatstate(self, state): - return "Open" if state == "Archived" else state + return StateName.open.value if state == StateName.archived.value else state def __commentmessage(self, state, username, requesttype, requestid): comment = username+' changed the state of the request to '+self.__formatstate(state) - if state == "Response" and requesttype == "ministryrequest": + if state == StateName.response.value and requesttype == "ministryrequest": signgoffapproval = FOIMinistryRequest().getrequest(requestid)['ministrysignoffapproval'] if signgoffapproval: comment = comment + f". Approved by {signgoffapproval['approvername']}, {signgoffapproval['approvertitle']} on {signgoffapproval['approveddate']}" @@ -120,7 +124,7 @@ def __notificationcfrmessage(self, requestid): def __createcfrentry(self, state, ministryrequestid, userid): cfrfee = cfrfeeservice().getcfrfee(ministryrequestid) - if (state == "Fee Estimate" and cfrfee['cfrfeestatusid'] in (None, '')): + if (state == StateName.feeestimate.value and cfrfee['cfrfeestatusid'] in (None, '')): return cfrfeeservice().sanctioncfrfee(ministryrequestid, {"status": "review"}, userid) else: return DefaultMethodResult(True,'No action needed',ministryrequestid) diff --git a/request-management-api/request_api/services/eventservice.py b/request-management-api/request_api/services/eventservice.py index 9610cb5a6..013977901 100644 --- a/request-management-api/request_api/services/eventservice.py +++ b/request-management-api/request_api/services/eventservice.py @@ -17,6 +17,7 @@ from request_api.models.default_method_result import DefaultMethodResult from request_api.exceptions import BusinessException from request_api.utils.enums import PaymentEventType +import time as timer import json from flask import current_app @@ -57,9 +58,9 @@ def posteventforaxisextension(self, ministryrequestid, extensionids, userid, use def postreminderevent(self): try: - cfreventresponse = cfrdateevent().createdueevent() - legislativeeventresponse = legislativedateevent().createdueevent() - divisioneventresponse = divisiondateevent().createdueevent() + cfreventresponse = cfrdateevent().createdueevent() + legislativeeventresponse = legislativedateevent().createdueevent() + divisioneventresponse = divisiondateevent().createdueevent() paymentremindereventresponse = paymentevent().createpaymentreminderevent() section5pendingresponse = section5pendingevent().createdueevent() if cfreventresponse.success == False or legislativeeventresponse.success == False or divisioneventresponse.success == False or paymentremindereventresponse.success == False or section5pendingresponse == False: diff --git a/request-management-api/request_api/services/foirequest/requestservicebuilder.py b/request-management-api/request_api/services/foirequest/requestservicebuilder.py index 4f6db7aa5..d3f5a4d8b 100644 --- a/request-management-api/request_api/services/foirequest/requestservicebuilder.py +++ b/request-management-api/request_api/services/foirequest/requestservicebuilder.py @@ -8,8 +8,9 @@ from request_api.models.FOIRequestApplicants import FOIRequestApplicant from request_api.models.FOIRequestApplicantMappings import FOIRequestApplicantMapping from request_api.models.FOIRequestTeams import FOIRequestTeam +from request_api.models.FOIRequestStatus import FOIRequestStatus from datetime import datetime as datetime2 -from request_api.utils.enums import MinistryTeamWithKeycloackGroup +from request_api.utils.enums import MinistryTeamWithKeycloackGroup, StateName from request_api.services.foirequest.requestserviceconfigurator import requestserviceconfigurator from request_api.services.foirequest.requestserviceministrybuilder import requestserviceministrybuilder @@ -22,7 +23,8 @@ class requestservicebuilder(requestserviceconfigurator): def createministry(self, requestschema, ministry, activeversion, userid, filenumber=None, ministryid=None): foiministryrequest = FOIMinistryRequest() foiministryrequest.__dict__.update(ministry) - foiministryrequest.requeststatusid = requestschema.get("requeststatusid") + foiministryrequest.requeststatusid = self.__getrequeststatusid(requestschema.get("requeststatuslabel")) + foiministryrequest.requeststatuslabel = requestschema.get("requeststatuslabel") foiministryrequest.isactive = True foiministryrequest.axisrequestid = requestschema.get("axisRequestId") foiministryrequest.axissyncdate = requestschema.get("axisSyncDate") @@ -43,9 +45,9 @@ def createministry(self, requestschema, ministry, activeversion, userid, filenum startdate = requestschema.get("requestProcessStart") foiministryrequest.startdate = startdate foiministryrequest.createdby = userid - requeststatusid = self.getpropertyvaluefromschema(requestschema, 'requeststatusid') - if requeststatusid is not None: - status = self.getstatusname(requeststatusid) + requeststatuslabel = self.getpropertyvaluefromschema(requestschema, 'requeststatuslabel') + if requeststatuslabel is not None: + status = self.getstatusname(requeststatuslabel) if self.isNotBlankorNone(requestschema,"fromDate","main") == True: foiministryrequest.recordsearchfromdate = requestschema.get("fromDate") if self.isNotBlankorNone(requestschema,"toDate","main") == True: @@ -89,7 +91,7 @@ def __updateassignedtoandgroup(self, foiministryrequest, requestschema, ministry foiministryrequest.assignedto = None def __isgrouprequired(self,status): - if status == "Call For Records" or status == "Review" or status == "Consult" or status == "Fee Assessed" or status == "Ministry Sign Off" or status == "Response": + if status == StateName.callforrecords.value or status == StateName.recordsreview.value or status == StateName.consult.value or status == StateName.feeestimate.value or status == StateName.ministrysignoff.value or status == StateName.response.value: return True else: return False @@ -97,6 +99,17 @@ def __isgrouprequired(self,status): def __getgroupname(self, requesttype, bcgovcode): return 'Flex Team' if requesttype == "general" else FOIRequestTeam.getdefaultprocessingteamforpersonal(bcgovcode) + def __getrequeststatusid(self, requeststatuslabel): + state = FOIRequestStatus.getrequeststatusbylabel( + requeststatuslabel + ) + stateid = ( + state.get("requeststatusid") + if isinstance(state, dict) and state.get("requeststatusid") not in (None, "") + else "" + ) + return stateid + def createcontactinformation(self,dataformat, name, value, contacttypes, userid): contactinformation = FOIRequestContactInformation() contactinformation.contactinformation = value diff --git a/request-management-api/request_api/services/foirequest/requestserviceconfigurator.py b/request-management-api/request_api/services/foirequest/requestserviceconfigurator.py index a2a87909f..2c31f1674 100644 --- a/request-management-api/request_api/services/foirequest/requestserviceconfigurator.py +++ b/request-management-api/request_api/services/foirequest/requestserviceconfigurator.py @@ -15,10 +15,10 @@ class requestserviceconfigurator: """This class consolidates helper fiunctions and constants """ - def getstatusname(self,requeststatusid): + def getstatusname(self,requeststatuslabel): allstatus = FOIRequestStatus().getrequeststatuses() for status in allstatus: - if status["requeststatusid"] == requeststatusid: + if status["statuslabel"] == requeststatuslabel: return status["name"] return None; diff --git a/request-management-api/request_api/services/foirequest/requestservicecreate.py b/request-management-api/request_api/services/foirequest/requestservicecreate.py index 6d4b2142f..ac6f24275 100644 --- a/request-management-api/request_api/services/foirequest/requestservicecreate.py +++ b/request-management-api/request_api/services/foirequest/requestservicecreate.py @@ -12,6 +12,7 @@ from request_api.models.FOIRequestContactInformation import FOIRequestContactInformation from request_api.models.FOIRequestPersonalAttributes import FOIRequestPersonalAttribute from request_api.models.FOIRequestApplicantMappings import FOIRequestApplicantMapping +from request_api.utils.enums import StateName import json class requestservicecreate: @@ -169,10 +170,10 @@ def __prepareapplicants(self, foirequestschema, userid): return requestapplicantarr def __disablewatchers(self, ministryid, requestschema, userid): - requeststatusid = requestschema.get("requeststatusid") if 'requeststatusid' in requestschema else None - if requeststatusid is not None: - status = requestserviceconfigurator().getstatusname(requeststatusid) - if status == "Open": + requeststatuslabel = requestschema.get("requeststatuslabel") if 'requeststatuslabel' in requestschema else None + if requeststatuslabel is not None: + status = requestserviceconfigurator().getstatusname(requeststatuslabel) + if status == StateName.open.value: watchers = watcherservice().getministryrequestwatchers(int(ministryid), True) for watcher in watchers: watcherschema = {"ministryrequestid":ministryid,"watchedbygroup":watcher["watchedbygroup"],"watchedby":watcher["watchedby"],"isactive":False} diff --git a/request-management-api/request_api/services/foirequest/requestservicegetter.py b/request-management-api/request_api/services/foirequest/requestservicegetter.py index 6e49d44c5..5e8e95818 100644 --- a/request-management-api/request_api/services/foirequest/requestservicegetter.py +++ b/request-management-api/request_api/services/foirequest/requestservicegetter.py @@ -15,6 +15,7 @@ from request_api.services.programareaservice import programareaservice from request_api.utils.commons.datetimehandler import datetimehandler from request_api.services.external.keycloakadminservice import KeycloakAdminService +from request_api.utils.enums import StateName class requestservicegetter: """ This class consolidates retrival of FOI request for actors: iao and ministry. @@ -29,7 +30,7 @@ def getrequest(self,foirequestid,foiministryrequestid): iaorestrictrequestdetails = FOIRestrictedMinistryRequest.getrestricteddetails(ministryrequestid=foiministryrequestid,type='iao') baserequestinfo = self.__preparebaseinfo(request,foiministryrequestid,requestministry,requestministrydivisions) - baserequestinfo['lastStatusUpdateDate'] = FOIMinistryRequest.getLastStatusUpdateDate(foiministryrequestid, requestministry['requeststatus.requeststatusid']).strftime(self.__genericdateformat()), + baserequestinfo['lastStatusUpdateDate'] = FOIMinistryRequest.getLastStatusUpdateDate(foiministryrequestid, requestministry['requeststatuslabel']).strftime(self.__genericdateformat()), for contactinfo in requestcontactinformation: if contactinfo['contacttype.name'] == 'Email': baserequestinfo.update({'email':contactinfo['contactinformation']}) @@ -152,8 +153,8 @@ def __preparebaseinfo(self,request,foiministryrequestid,requestministry,requestm 'description': requestministry['description'], 'fromDate': parse(requestministry['recordsearchfromdate']).strftime(self.__genericdateformat()) if requestministry['recordsearchfromdate'] is not None else '', 'toDate': parse(requestministry['recordsearchtodate']).strftime(self.__genericdateformat()) if requestministry['recordsearchtodate'] is not None else '', - 'currentState':requestministry['requeststatus.name'], - 'requeststatusid':requestministry['requeststatus.requeststatusid'], + 'currentState':requestministry['requeststatus.name'], + 'requeststatuslabel':requestministry['requeststatuslabel'], 'requestProcessStart': parse(requestministry['startdate']).strftime(self.__genericdateformat()) if requestministry['startdate'] is not None else '', 'dueDate':parse(requestministry['duedate']).strftime(self.__genericdateformat()), 'originalDueDate': parse(requestministry['originalldd']).strftime(self.__genericdateformat()) if requestministry['originalldd'] is not None else parse(requestministry['duedate']).strftime(self.__genericdateformat()), @@ -213,7 +214,7 @@ def getonholdtransition(self, foiministryrequestid): onholddate = None transitions = FOIMinistryRequest.getrequeststatusById(foiministryrequestid) for entry in transitions: - if entry['requeststatusid'] == 11: + if entry['requeststatuslabel'] == StateName.onhold.name: onholddate = datetimehandler().convert_to_pst(entry['created_at'],'%Y-%m-%d') else: if onholddate is not None: diff --git a/request-management-api/request_api/services/foirequest/requestserviceministrybuilder.py b/request-management-api/request_api/services/foirequest/requestserviceministrybuilder.py index f35af8e74..56db80d2d 100644 --- a/request-management-api/request_api/services/foirequest/requestserviceministrybuilder.py +++ b/request-management-api/request_api/services/foirequest/requestserviceministrybuilder.py @@ -11,6 +11,7 @@ from request_api.models.FOIRequestExtensionDocumentMappings import FOIRequestExtensionDocumentMapping from request_api.models.FOIAssignees import FOIAssignee from request_api.models.FOIMinistryRequestSubjectCodes import FOIMinistryRequestSubjectCode +from request_api.models.FOIRequestStatus import FOIRequestStatus from request_api.services.foirequest.requestserviceconfigurator import requestserviceconfigurator from datetime import datetime as datetime2 @@ -76,7 +77,8 @@ def createfoiministryrequestfromobject(self, ministryschema, requestschema, user foiministryrequest.assignedto = None if usertype == "iao" and 'assignedto' in requestschema and requestschema['assignedto'] in (None, '') else ministryschema["assignedto"] foiministryrequest.ministrysignoffapproval = requestdict["ministrysignoffapproval"] - foiministryrequest.requeststatusid = requestdict['requeststatusid'] + foiministryrequest.requeststatusid = self.__getrequeststatusid(requestdict['requeststatuslabel']) + foiministryrequest.requeststatuslabel = requestdict['requeststatuslabel'] foiministryrequest.programareaid = requestdict['programareaid'] foiministryrequest.createdby = userid @@ -88,6 +90,16 @@ def createfoiministryrequestfromobject(self, ministryschema, requestschema, user foiministryrequest.closereasonid = requestdict['closereasonid'] return foiministryrequest + def __getrequeststatusid(self, requeststatuslabel): + state = FOIRequestStatus.getrequeststatusbylabel( + requeststatuslabel + ) + stateid = ( + state.get("requeststatusid") + if isinstance(state, dict) and state.get("requeststatusid") not in (None, "") + else "" + ) + return stateid def __createministrydivisions(self, requestschema, foiministryrequestid, foiministryrequestversion, userid): if 'divisions' in requestschema: return self.createfoirequestdivision(requestschema,foiministryrequestid ,foiministryrequestversion + 1, userid) @@ -111,7 +123,7 @@ def createfoiministryrequestfromobject1(self, ministryschema, requestschema): 'duedate': requestschema['duedate'] if 'duedate' in requestschema else ministryschema["duedate"], #and isextension':= True 'assignedministrygroup': requestschema['assignedministrygroup'] if 'assignedministrygroup' in requestschema else ministryschema["assignedministrygroup"], 'assignedgroup': requestschema['assignedgroup'] if 'assignedgroup' in requestschema else ministryschema["assignedgroup"], - 'requeststatusid': requestschema['requeststatusid'] if 'requeststatusid' in requestschema else ministryschema["requeststatus.requeststatusid"], + 'requeststatuslabel': requestschema['requeststatuslabel'] if 'requeststatuslabel' in requestschema else ministryschema["requeststatuslabel"], 'programareaid': ministryschema["programarea.programareaid"] if 'programarea.programareaid' in ministryschema else None, 'closedate': requestschema['closedate'] if 'closedate' in requestschema else None, 'closereasonid': requestschema['closereasonid'] if 'closereasonid' in requestschema else None, diff --git a/request-management-api/request_api/services/foirequest/requestserviceupdate.py b/request-management-api/request_api/services/foirequest/requestserviceupdate.py index c800ae387..a85ca38e9 100644 --- a/request-management-api/request_api/services/foirequest/requestserviceupdate.py +++ b/request-management-api/request_api/services/foirequest/requestserviceupdate.py @@ -19,7 +19,7 @@ def updaterequest(self,foirequestschema,foirequestid,userid): for ministry in foirequestschema.get("selectedMinistries"): for status in allstatus: if ministry["status"] == status["name"]: - updatedministries.append({"filenumber" : ministry["filenumber"], "requeststatusid": status["requeststatusid"]}) + updatedministries.append({"filenumber" : ministry["filenumber"], "requeststatuslabel": status["statuslabel"]}) return FOIRequest.updateStatus(foirequestid, updatedministries, userid) def updateministryrequestduedate(self, ministryrequestid, duedate, userid): diff --git a/request-management-api/request_api/services/notifications/notificationconfig.py b/request-management-api/request_api/services/notifications/notificationconfig.py index 44175ed20..b6b771206 100644 --- a/request-management-api/request_api/services/notifications/notificationconfig.py +++ b/request-management-api/request_api/services/notifications/notificationconfig.py @@ -3,55 +3,58 @@ from re import VERBOSE import json import os +from request_api.models.NotificationTypes import NotificationType +from request_api.models.NotificationUserTypes import NotificationUserType +notificationuserfile = open('common/notificationusertypes.json', encoding="utf8") +notificationusertypes_cache = json.load(notificationuserfile) + +notificationfile = open('common/notificationtypes.json', encoding="utf8") +notificationtypes_cache = json.load(notificationfile) class notificationconfig: """ Notfication config """ + + # This method is used to get the notification user type label + # It first tries to get the notification user type label from the cache + # If it is not found in the cache, it fetches it from the DB + def getnotificationtypelabel(self, notificationtype): + notificationtype_format = notificationtype.replace(" ", "").lower() + if notificationtype_format in notificationtypes_cache: + return notificationtypes_cache[notificationtype_format]['notificationtypelabel'] + else: + print("Notification type not found in json. Fetching from DB", notificationtype) + id = NotificationType().getnotificationtypeid(notificationtype) + if id is not None: + return id['notificationtypelabel'] + return None def getnotificationtypeid(self, notificationtype): - if notificationtype == "State": - return 1 - elif notificationtype == "Extension": - return 4 - elif "IAO Assignment" in notificationtype: - return 5 - elif "Ministry Assignment" in notificationtype: - return 6 - elif notificationtype == "CFR Due Reminder": - return 7 - elif notificationtype == "Legislative Due Reminder": - return 8 - elif notificationtype == "New User Comments": - return 3 - elif notificationtype == "Reply User Comments": - return 9 - elif notificationtype == "Tagged User Comments": - return 10 - elif notificationtype == "CFR Fee Form": - return 11 - elif notificationtype == "Group Members": - return 12 - elif notificationtype == "Division Due Reminder": - return 13 - elif notificationtype == "Watcher": - return 14 - elif notificationtype == "User Assignment Removal": - return 15 - elif notificationtype == "Email Failure": - return 16 - elif notificationtype == "Payment": - return 17 - elif notificationtype == "Section 5 Pending Reminder": - return 20 - return 0 + id = NotificationType().getnotificationtypeid(notificationtype) + if id is not None: + return id['notificationtypeid'] + return None + + # This method is used to get the notification user type label + # It first tries to get the notification user type label from the cache + # If it is not found in the cache, it fetches it from the DB + def getnotificationusertypelabel(self, notificationusertype): + notificationusertype_format = notificationusertype.replace(" ", "").lower() + if notificationusertype_format in notificationusertypes_cache: + return notificationusertypes_cache[notificationusertype_format]['notificationusertypelabel'] + else: + print("Notification user type not found in json. Fetching from DB", notificationusertype) + id = NotificationUserType().getnotificationusertypesid(notificationusertype) + if id is not None: + return id['notificationusertypelabel'] + return None def getnotificationusertypeid(self, notificationusertype): - if notificationusertype.lower() == "watcher": - return 1 - elif notificationusertype.lower() == "assignee" or "comment" or "group members" in notificationusertype.lower(): - return 2 - return 0 + id = NotificationUserType().getnotificationusertypesid(notificationusertype) + if id is not None: + return id['notificationusertypeid'] + return None def getnotificationdays(self): if 'FOI_NOTIFICATION_DAYS' in os.environ and os.getenv('FOI_NOTIFICATION_DAYS') != '': diff --git a/request-management-api/request_api/services/notifications/notificationuser.py b/request-management-api/request_api/services/notifications/notificationuser.py index 2b5a104cf..5f810690a 100644 --- a/request-management-api/request_api/services/notifications/notificationuser.py +++ b/request-management-api/request_api/services/notifications/notificationuser.py @@ -9,7 +9,7 @@ from request_api.services.external.keycloakadminservice import KeycloakAdminService class notificationuser: - """ Notfication user service + """ notification user service """ @@ -55,26 +55,26 @@ def __istaggeduser(self, notificationuser, foicomment, notificationtype): def __getwatchers(self, notificationtype, foirequest, requesttype, requestjson=None): notificationusers = [] if notificationtype == "Watcher": - notificationusers.append({"userid": requestjson['watchedby'], "usertype":notificationconfig().getnotificationusertypeid("Watcher")}) + notificationusers.append({"userid": requestjson['watchedby'], "usertype":notificationconfig().getnotificationusertypelabel("Watcher")}) else: if requesttype == "ministryrequest": watchers = watcherservice().getallministryrequestwatchers(foirequest["foiministryrequestid"], self.__isministryonly(notificationtype)) else: watchers = watcherservice().getrawrequestwatchers(foirequest['requestid']) for watcher in watchers: - notificationusers.append({"userid":watcher["watchedby"], "usertype":notificationconfig().getnotificationusertypeid("Watcher")}) + notificationusers.append({"userid":watcher["watchedby"], "usertype":notificationconfig().getnotificationusertypelabel("Watcher")}) return notificationusers def __getassignees(self, foirequest, requesttype, notificationtype, requestjson=None): notificationusers = [] - notificationtypeid = notificationconfig().getnotificationusertypeid("Assignee") + notificationusertypelabel = notificationconfig().getnotificationusertypelabel("Assignee") if notificationtype == 'User Assignment Removal': - notificationusers.append({"userid": requestjson['userid'], "usertype":notificationtypeid}) + notificationusers.append({"userid": requestjson['userid'], "usertype":notificationusertypelabel}) else: if requesttype == "ministryrequest" and foirequest["assignedministryperson"] is not None and (notificationtype == 'Ministry Assignment' or 'Assignment' not in notificationtype): - notificationusers.append({"userid":foirequest["assignedministryperson"], "usertype":notificationtypeid}) + notificationusers.append({"userid":foirequest["assignedministryperson"], "usertype":notificationusertypelabel}) if self.__isministryonly(notificationtype) == False and foirequest["assignedto"] is not None and foirequest["assignedto"] != '' and (notificationtype == 'IAO Assignment' or 'Assignment' not in notificationtype): - notificationusers.append({"userid":foirequest["assignedto"], "usertype":notificationtypeid}) + notificationusers.append({"userid":foirequest["assignedto"], "usertype":notificationusertypelabel}) return notificationusers def __isministryonly(self, notificationtype): @@ -102,7 +102,7 @@ def __getcommentusertype(self, userid, requestusers): for requestuser in requestusers: if requestuser["userid"] == userid: return requestuser["usertype"] - return notificationconfig().getnotificationusertypeid("comment user") + return notificationconfig().getnotificationusertypelabel("comment user") def __getrelatedusers(self, comment, requesttype): if requesttype == "ministryrequest": @@ -118,16 +118,16 @@ def __gettaggedusers(self, comment): def __preparetaggeduser(self, data): taggedusers = [] for entry in data: - taggedusers.append({"userid":entry["username"], "usertype":notificationconfig().getnotificationusertypeid("comment tagged user")}) + taggedusers.append({"userid":entry["username"], "usertype":notificationconfig().getnotificationusertypelabel("comment tagged user")}) return taggedusers def __getgroupmembers(self,groupid): notificationusers = [] - notificationtypeid = notificationconfig().getnotificationusertypeid("Group Members") + notificationusertypelabel = notificationconfig().getnotificationusertypelabel("Group Members") usergroupfromkeycloak= KeycloakAdminService().getmembersbygroupname(groupid) if usergroupfromkeycloak is not None and len(usergroupfromkeycloak) > 0: for user in usergroupfromkeycloak[0].get("members"): - notificationusers.append({"userid":user["username"], "usertype":notificationtypeid}) + notificationusers.append({"userid":user["username"], "usertype":notificationusertypelabel}) return notificationusers return [] \ No newline at end of file diff --git a/request-management-api/request_api/services/notificationservice.py b/request-management-api/request_api/services/notificationservice.py index 036a4ae60..1e2c91a13 100644 --- a/request-management-api/request_api/services/notificationservice.py +++ b/request-management-api/request_api/services/notificationservice.py @@ -15,6 +15,7 @@ from request_api.models.FOIRawRequestNotificationUsers import FOIRawRequestNotificationUser from request_api.models.FOIRawRequestComments import FOIRawRequestComment from request_api.models.FOIRequestComments import FOIRequestComment +from request_api.models.NotificationTypes import NotificationType from request_api.models.default_method_result import DefaultMethodResult from datetime import datetime as datetime2 import os @@ -25,6 +26,9 @@ from request_api.services.external.keycloakadminservice import KeycloakAdminService from request_api.models.OperatingTeams import OperatingTeam import logging +file = open('common/notificationtypes.json', encoding="utf8") +notificationtypes_cache = json.load(file) + class notificationservice: """ FOI notification management service @@ -33,11 +37,12 @@ class notificationservice: def createnotification(self, message, requestid, requesttype, notificationtype, userid, iscleanup=True): foirequest = self.getrequest(requestid, requesttype) if iscleanup == True: - self.__cleanupnotifications(requesttype, notificationtype, foirequest) + self.__cleanupnotifications(requesttype, notificationtype['name'], foirequest) return self.__createnotification(message, requestid, requesttype, notificationtype, userid, foirequest) - def createusernotification(self, message, requestid, requesttype, notificationtype, notificationuser, userid): + def createusernotification(self, message, requestid, requesttype, notificationtypename, notificationuser, userid): foirequest = self.getrequest(requestid, requesttype) + notificationtype = NotificationType().getnotificationtypeid(notificationtypename) return self.__createnotification(message, requestid, requesttype, notificationtype, userid, foirequest, {"userid": notificationuser}) def createremindernotification(self, message, requestid, requesttype, notificationtype, userid): @@ -46,13 +51,15 @@ def createremindernotification(self, message, requestid, requesttype, notificati def createcommentnotification(self, message, comment, commenttype, requesttype, userid): requestid = comment["ministryrequestid"] if requesttype == "ministryrequest" else comment["requestid"] - foirequest = self.getrequest(requestid, requesttype) - return self.__createnotification(message, requestid, requesttype, commenttype, userid, foirequest, comment) + foirequest = self.getrequest(requestid, requesttype) + notificationtype = NotificationType().getnotificationtypeid(commenttype) + return self.__createnotification(message, requestid, requesttype, notificationtype, userid, foirequest, comment) def createwatchernotification(self, message, requesttype, watcher, userid): requestid = watcher["ministryrequestid"] if requesttype == "ministryrequest" else watcher["requestid"] - foirequest = self.getrequest(requestid, requesttype) - return self.__createnotification(message, requestid, requesttype, 'Watcher', userid, foirequest, watcher) + foirequest = self.getrequest(requestid, requesttype) + notificationtype = NotificationType().getnotificationtypeid('Watcher') + return self.__createnotification(message, requestid, requesttype, notificationtype, userid, foirequest, watcher) def editcommentnotification(self, message, comment, userid): notificationsusers = FOIRequestNotification.getcommentnotifications(comment['commentid']) @@ -93,21 +100,21 @@ def dismissnotificationbyid(self, requesttype, notificationids): return self.__deletenotificationids(requesttype, notificationids) def dismissremindernotification(self, requesttype, notificationtype): - notificationid = notificationconfig().getnotificationtypeid(notificationtype) + notificationlabel = notificationconfig().getnotificationtypelabel(notificationtype) if requesttype == "ministryrequest": - _ids = FOIRequestNotification.getnotificationidsbytype(notificationid) + _ids = FOIRequestNotification.getnotificationidsbytype(notificationlabel) else: - _ids = FOIRawRequestNotification.getnotificationidsbytype(notificationid) + _ids = FOIRawRequestNotification.getnotificationidsbytype(notificationlabel) self.__deletenotificationids(requesttype, _ids) def dismissnotifications_by_requestid_type_userid(self, requestid, requesttype, notificationtype, userid): - notificationtypeids = self.__getcleanupnotificationids(notificationtype) + notificationtypelabels = self.__getcleanupnotificationids(notificationtype) foirequest = self.getrequest(requestid, requesttype) if requesttype == "ministryrequest": idnumber = foirequest["filenumber"] - _ids = FOIRequestNotification.getnotificationidsbynumberandtype(idnumber, notificationtypeids) + _ids = FOIRequestNotification.getnotificationidsbynumberandtype(idnumber, notificationtypelabels) else: - _ids = FOIRawRequestNotification.getnotificationidsbynumberandtype('U-00' + str(foirequest['requestid']), notificationtypeids[0]) + _ids = FOIRawRequestNotification.getnotificationidsbynumberandtype('U-00' + str(foirequest['requestid']), notificationtypelabels[0]) self.__deletenotificationbyuserandid(requesttype, _ids, userid) def __createnotification(self, message, requestid, requesttype, notificationtype, userid, foirequest, requestjson=None): @@ -134,22 +141,22 @@ def dismissnotificationsbyrequestid(self,requestid, requesttype): FOIRawRequestNotification.dismissnotification(_ids) def __cleanupnotifications(self, requesttype, notificationtype, foirequest): - notificationtypeids = self.__getcleanupnotificationids(notificationtype) + notificationtypelabels = self.__getcleanupnotificationids(notificationtype) if requesttype == "ministryrequest": idnumber = foirequest["filenumber"] - _ids = FOIRequestNotification.getnotificationidsbynumberandtype(idnumber, notificationtypeids) + _ids = FOIRequestNotification.getnotificationidsbynumberandtype(idnumber, notificationtypelabels) else: - _ids = FOIRawRequestNotification.getnotificationidsbynumberandtype('U-00' + str(foirequest['requestid']), notificationtypeids[0]) + _ids = FOIRawRequestNotification.getnotificationidsbynumberandtype('U-00' + str(foirequest['requestid']), notificationtypelabels[0]) self.__deletenotificationids(requesttype, _ids) def __getcleanupnotificationids(self, notificationtype): - notificationtypeids = [] - notificationid = notificationconfig().getnotificationtypeid(notificationtype) - notificationtypeids.append(notificationid) + notificationtypelabels = [] + notificationlabel = notificationconfig().getnotificationtypelabel(notificationtype) + notificationtypelabels.append(notificationlabel) if notificationtype == "State" or notificationtype.endswith("Assignment"): - notificationtypeids.append(notificationconfig().getnotificationtypeid("Group Members")) - return notificationtypeids + notificationtypelabels.append(notificationconfig().getnotificationtypelabel("Group Members")) + return notificationtypelabels def __deletenotificationids(self, requesttype, notificationids): @@ -191,11 +198,11 @@ def __dismissnotificationbyuser(self, userid): return DefaultMethodResult(False,'Unable to delete the notifications',userid) def __dismissnotificationbytype(self, userid, type): - typeid = notificationconfig().getnotificationusertypeid(type) - requestnotificationids = self.__getdismissparentidsbyuserandtype("ministryrequest", userid, typeid) - requestnotification = FOIRequestNotificationUser.dismissnotificationbyuserandtype(userid, typeid) - rawnotificationids = self.__getdismissparentidsbyuserandtype("rawrequest", userid, typeid) - rawnotification = FOIRawRequestNotificationUser.dismissnotificationbyuserandtype(userid, typeid) + notificationusertypelabel = notificationconfig().getnotificationusertypelabel(type) + requestnotificationids = self.__getdismissparentidsbyuserandtype("ministryrequest", userid, notificationusertypelabel) + requestnotification = FOIRequestNotificationUser.dismissnotificationbyuserandtype(userid, notificationusertypelabel) + rawnotificationids = self.__getdismissparentidsbyuserandtype("rawrequest", userid, notificationusertypelabel) + rawnotification = FOIRawRequestNotificationUser.dismissnotificationbyuserandtype(userid, notificationusertypelabel) prequestnotification = FOIRequestNotification.dismissnotification(requestnotificationids) prawnotification = FOIRawRequestNotification.dismissnotification(rawnotificationids) if requestnotification.success == True and rawnotification.success == True and prequestnotification.success == True and prawnotification.success == True: @@ -236,11 +243,11 @@ def __getdismissparentidsbyuser(self, requesttype, userid): _notficationids = FOIRawRequestNotificationUser.getnotificationsbyuser(userid) return self.__filterdismissparentids(_notficationids) - def __getdismissparentidsbyuserandtype(self, requesttype, userid, typeid): + def __getdismissparentidsbyuserandtype(self, requesttype, userid, notificationusertypelabel): if requesttype == "ministryrequest": - _notficationids = FOIRequestNotificationUser.getnotificationsbyuserandtype(userid, typeid) + _notficationids = FOIRequestNotificationUser.getnotificationsbyuserandtype(userid, notificationusertypelabel) else: - _notficationids = FOIRawRequestNotificationUser.getnotificationsbyuserandtype(userid, typeid) + _notficationids = FOIRawRequestNotificationUser.getnotificationsbyuserandtype(userid, notificationusertypelabel) return self.__filterdismissparentids(_notficationids) def __filterdismissparentids(self,_notficationids): @@ -262,7 +269,7 @@ def __preparenotification(self, message, requesttype, notificationtype, userid, notification.foirequestid = foirequest["foirequest_id"] #mute notifications for ministry users - mutenotification = self.__mutenotification(requesttype, notificationtype, foirequest) + mutenotification = self.__mutenotification(requesttype, notificationtype['name'], foirequest) usergroupfromkeycloak = KeycloakAdminService().getmembersbygroupname(foirequest["assignedministrygroup"]) if usergroupfromkeycloak is not None and len(usergroupfromkeycloak) > 0: for user in usergroupfromkeycloak[0].get("members"): @@ -273,14 +280,15 @@ def __preparenotification(self, message, requesttype, notificationtype, userid, notification.idnumber ='U-00' + str(foirequest['requestid']) mutenotification = False - notification.notificationtypeid = notificationconfig().getnotificationtypeid(notificationtype) + notification.notificationtypelabel = notificationtype['notificationtypelabel'] + notification.notificationtypeid = notificationtype['notificationtypeid'] notification.axisnumber = foirequest["axisrequestid"] notification.version = foirequest["version"] notification.createdby = userid notification.notification = message notification.isdeleted = False - notificationusers = notificationuser().getnotificationusers(notificationtype, requesttype, userid, foirequest, requestjson) + notificationusers = notificationuser().getnotificationusers(notificationtype['name'], requesttype, userid, foirequest, requestjson) users = [] for _notificationuser in notificationusers: users.append(self.__preparenotificationuser(requesttype, _notificationuser, userid, mutenotification, ministryusers)) @@ -297,7 +305,8 @@ def __preparenotificationuser(self, requesttype, notificationuser, userid, mute= else: user = FOIRawRequestNotificationUser() user.isdeleted = False - user.notificationusertypeid = notificationuser["usertype"] + user.notificationusertypelabel = notificationuser["usertype"] + user.notificationusertypeid = notificationconfig().getnotificationusertypeid( notificationuser["usertype"]) user.userid = notificationuser["userid"] user.createdby = userid return user diff --git a/request-management-api/request_api/services/rawrequest/rawrequestservicegetter.py b/request-management-api/request_api/services/rawrequest/rawrequestservicegetter.py index bb56f9317..b8b1cf870 100644 --- a/request-management-api/request_api/services/rawrequest/rawrequestservicegetter.py +++ b/request-management-api/request_api/services/rawrequest/rawrequestservicegetter.py @@ -7,6 +7,7 @@ from dateutil.parser import parse import maya from request_api.models.FOIAssignees import FOIAssignee +from request_api.utils.enums import StateName class rawrequestservicegetter: """ This class consolidates retrival of FOI raw request for actors: iao. @@ -52,7 +53,7 @@ def getallrawrequests(self): def getrawrequestforid(self, requestid): request = FOIRawRequest.get_request(requestid) request = self.__attachministriesinfo(request) - if request != {} and (request['version'] == 1 or request['status'] == 'Unopened') and request['sourceofsubmission'] != "intake": + if request != {} and (request['version'] == 1 or request['status'] == StateName.unopened.value) and request['sourceofsubmission'] != "intake": requestrawdata = request['requestrawdata'] requesttype = requestrawdata['requestType']['requestType'] baserequestinfo = self.__preparebaserequestinfo(requestid, request, requesttype, requestrawdata) @@ -60,16 +61,15 @@ def getrawrequestforid(self, requestid): baserequestinfo['additionalPersonalInfo'] = self.__prepareadditionalpersonalinfo(requestrawdata) return baserequestinfo elif request != {} and request['version'] != 1 and request['sourceofsubmission'] != "intake": - request['requestrawdata']['currentState'] = request['status'] - requeststatus = FOIRequestStatus().getrequeststatusid(request['status']) - request['requestrawdata']['requeststatusid'] = requeststatus['requeststatusid'] + request['requestrawdata']['currentState'] = request['status'] + request['requestrawdata']['requeststatuslabel'] = request['requeststatuslabel'] request['requestrawdata']['lastStatusUpdateDate'] = FOIRawRequest.getLastStatusUpdateDate(requestid, request['status']).strftime(self.__generaldateformat()) - if request['status'] == 'Closed': + if request['requeststatuslabel'] == StateName.closed.name: request['requestrawdata']['stateTransition']= FOIRawRequest.getstatesummary(requestid) request['requestrawdata']['wfinstanceid'] = request['wfinstanceid'] request['requestrawdata']['closedate']= self.__getclosedate(request['closedate']) request['requestrawdata']['isiaorestricted']= request['isiaorestricted'] if request['isiaorestricted'] is not None else False - return request['requestrawdata'] + return request['requestrawdata'] elif request != {} and request['sourceofsubmission'] == "intake": requestrawdata = request['requestrawdata'] requesttype = requestrawdata['requestType'] @@ -81,8 +81,8 @@ def getrawrequestforid(self, requestid): request['requestrawdata']['wfinstanceid'] = request['wfinstanceid'] request['requestrawdata']['currentState'] = request['status'] - requeststatus = FOIRequestStatus().getrequeststatusid(request['status']) - request['requestrawdata']['requeststatusid'] = requeststatus['requeststatusid'] + requeststatus = FOIRequestStatus().getrequeststatus(request['status']) + request['requestrawdata']['requeststatuslabel'] = requeststatus['statuslabel'] request['requestrawdata']['lastStatusUpdateDate'] = FOIRawRequest.getLastStatusUpdateDate(requestid, request['status']).strftime(self.__generaldateformat()) request['requestrawdata']['stateTransition']= FOIRawRequest.getstatesummary(requestid) request['requestrawdata']['closedate']= self.__getclosedate(request['closedate']) diff --git a/request-management-api/request_api/services/rawrequestservice.py b/request-management-api/request_api/services/rawrequestservice.py index 6abaf1ff1..c39c67b85 100644 --- a/request-management-api/request_api/services/rawrequestservice.py +++ b/request-management-api/request_api/services/rawrequestservice.py @@ -15,7 +15,8 @@ from request_api.exceptions import BusinessException, Error from request_api.models.default_method_result import DefaultMethodResult from request_api.models.FOIRawRequestWatchers import FOIRawRequestWatcher -from request_api.services.foirequest.requestserviceconfigurator import requestserviceconfigurator +from request_api.services.foirequest.requestserviceconfigurator import requestserviceconfigurator +from request_api.utils.enums import StateName import logging class rawrequestservice: @@ -91,13 +92,13 @@ def doesrequirepayment(requestdatajson): return requestdatajson['requiresPayment'] raise BusinessException(Error.DATA_NOT_FOUND) - def saverawrequestversion(self, _requestdatajson, _requestid, _assigneegroup, _assignee, status, userid, assigneefirstname, assigneemiddlename, assigneelastname, actiontype=None): + def saverawrequestversion(self, _requestdatajson, _requestid, _assigneegroup, _assignee, status, userid, assigneefirstname, assigneemiddlename, assigneelastname, statuslabel, actiontype=None): ispiiredacted = _requestdatajson["ispiiredacted"] if 'ispiiredacted' in _requestdatajson else False #Get documents if actiontype == "assignee": result = FOIRawRequest.saverawrequestassigneeversion(_requestid, _assigneegroup, _assignee, userid, assigneefirstname, assigneemiddlename, assigneelastname) else: - result = FOIRawRequest.saverawrequestversion(_requestdatajson, _requestid, _assigneegroup, _assignee, status,ispiiredacted, userid, assigneefirstname, assigneemiddlename, assigneelastname) + result = FOIRawRequest.saverawrequestversion(_requestdatajson, _requestid, _assigneegroup, _assignee, status,ispiiredacted, userid, statuslabel, assigneefirstname, assigneemiddlename, assigneelastname) documentservice().createrawrequestdocumentversion(_requestid) return result @@ -125,10 +126,10 @@ def getrawrequestfields(self, requestid, fields): return rawrequestservicegetter().getrawrequestfieldsforid(requestid, fields) def getstatus(self, foirequest): - statusid = foirequest["requeststatusid"] if "requeststatusid" in foirequest else None - if statusid is not None: + statuslabel = foirequest["requeststatuslabel"] if "requeststatuslabel" in foirequest else None + if statuslabel is not None: try: - return requestserviceconfigurator().getstatusname(statusid) + return requestserviceconfigurator().getstatusname(statuslabel), statuslabel # if statusid== 4: # return 'Redirect' # if statusid == 3: @@ -137,7 +138,7 @@ def getstatus(self, foirequest): # return 'Peer Review' except KeyError: print("Key Error on requeststatusid, ignore will be intake in Progress") - return 'Intake in Progress' + return StateName.intakeinprogress.value, StateName.intakeinprogress.name def getaxisequestids(self): return rawrequestservicegetter().getaxisequestids() diff --git a/request-management-api/request_api/services/recordservice.py b/request-management-api/request_api/services/recordservice.py index eda12999a..45a11662a 100644 --- a/request-management-api/request_api/services/recordservice.py +++ b/request-management-api/request_api/services/recordservice.py @@ -218,12 +218,9 @@ def __triggerpdfstitchservice(self, requestid, ministryrequestid, message, useri "attributes": json.JSONEncoder().encode(message["attributes"]), "totalfilesize": message["totalfilesize"] } - print("final message >>>>>> ", streamobject) if message["totalfilesize"] > int(self.stitchinglargefilesizelimit) and self.pdfstitchstreamkey_largefiles: - print("pdfstitchstreamkey_largefiles = ", self.pdfstitchstreamkey_largefiles) return eventqueueservice().add(self.pdfstitchstreamkey_largefiles, streamobject) elif self.pdfstitchstreamkey: - print("pdfstitchstreamkey = ", self.pdfstitchstreamkey) return eventqueueservice().add(self.pdfstitchstreamkey, streamobject) else: print("pdfstitch stream key is missing. Message is not pushed to the stream.") @@ -249,8 +246,7 @@ def __bulkcreate(self, requestid, ministryrequestid, records, userid): if (dbresponse.success): #processingrecords = [{**record, **{"recordid": dbresponse.args[0][record['s3uripath']]['recordid']}} for record in records if not record['attributes'].get('incompatible', False)] processingrecords = [{**record, **{"recordid": dbresponse.args[0][record['s3uripath']]['recordid']}} for record in records] - - print(processingrecords) + # record all jobs before sending first redis stream message to avoid race condition jobids, err = self.makedocreviewerrequest('POST', '/api/jobstatus', { 'records': processingrecords, diff --git a/request-management-api/request_api/services/requestservice.py b/request-management-api/request_api/services/requestservice.py index d98d24cb3..445ec9914 100644 --- a/request-management-api/request_api/services/requestservice.py +++ b/request-management-api/request_api/services/requestservice.py @@ -62,8 +62,8 @@ def saverequest( ) def saverequestversion(self, foirequestschema, foirequestid, ministryid, userid): - nextstate = FOIRequestStatus.getrequeststatusname( - foirequestschema["requeststatusid"] + nextstate = FOIRequestStatus.getrequeststatusbylabel( + foirequestschema["requeststatuslabel"] ) nextstatename = ( nextstate.get("name") @@ -112,8 +112,8 @@ def postpaymentstatetransition( foirequest = self.updateduedate( requestid, ministryrequestid, paymentdate, _foirequest, nextstatename ) - status = FOIRequestStatus().getrequeststatusid(nextstatename) - foirequest["requeststatusid"] = status["requeststatusid"] + status = FOIRequestStatus().getrequeststatus(nextstatename) + foirequest["requeststatuslabel"] = status["statuslabel"] return requestservicecreate().saverequestversion( foirequest, requestid, ministryrequestid, "Online Payment" ) @@ -204,7 +204,7 @@ def copysubjectcode(self, subjectcode, ministries, userid): def postopeneventtoworkflow(self, id, requestschema, ministries): pid = workflowservice().syncwfinstance("rawrequest", requestschema["id"]) - workflowservice().postunopenedevent(id, pid, requestschema, "Open", ministries) + workflowservice().postunopenedevent(id, pid, requestschema, StateName.open.value, ministries) def postfeeeventtoworkflow( self, requestid, ministryrequestid, paymentstatus, nextstatename=None @@ -215,14 +215,14 @@ def postfeeeventtoworkflow( ) def posteventtoworkflow(self, id, requestschema, data, usertype): - requeststatusid = ( - requestschema.get("requeststatusid") - if "requeststatusid" in requestschema + requeststatuslabel = ( + requestschema.get("requeststatuslabel") + if "requeststatuslabel" in requestschema else None ) status = ( - requestserviceconfigurator().getstatusname(requeststatusid) - if requeststatusid is not None + requestserviceconfigurator().getstatusname(requeststatuslabel) + if requeststatuslabel is not None else None ) pid = workflowservice().syncwfinstance("ministryrequest", id) diff --git a/request-management-api/request_api/services/workflowservice.py b/request-management-api/request_api/services/workflowservice.py index f4b6f81a0..1cbcbb1db 100644 --- a/request-management-api/request_api/services/workflowservice.py +++ b/request-management-api/request_api/services/workflowservice.py @@ -70,7 +70,7 @@ def postopenedevent(self, id, wfinstanceid, requestsschema, data, newstatus, use _variables = bpmservice().getinstancevariables(wfinstanceid) if ministry["status"] == OpenedEvent.callforrecords.value and (("status" not in _variables) or (_variables not in (None, []) and "status" in _variables and _variables["status"]["value"] != OpenedEvent.callforrecords.value)): messagename = MessageType.iaoopencomplete.value - elif _variables not in (None, []) and ("status" in _variables and _variables["status"]["value"] == "Closed"): + elif _variables not in (None, []) and ("status" in _variables and _variables["status"]["value"] == StateName.closed.value): return bpmservice().reopenevent(wfinstanceid, metadata, MessageType.iaoreopen.value) else: return bpmservice().openedcomplete(wfinstanceid, filenumber, metadata, messagename) diff --git a/request-management-api/request_api/utils/enums.py b/request-management-api/request_api/utils/enums.py index f21d807ab..becdb9d9e 100644 --- a/request-management-api/request_api/utils/enums.py +++ b/request-management-api/request_api/utils/enums.py @@ -149,15 +149,20 @@ class StateName(Enum): redirect = "Redirect" unopened = "Unopened" intakeinprogress = "Intake in Progress" - recordsreview = "Records Review" - feeestimate = "Fee Estimate" consult = "Consult" ministrysignoff = "Ministry Sign Off" onhold = "On Hold" deduplication = "Deduplication" harmsassessment = "Harms Assessment" response = "Response" - + feeestimate = "Fee Estimate" + recordsreview = "Records Review" + archived = "Archived" + peerreview = "Peer Review" + tagging = "Tagging" + readytoscan = "Ready to Scan" + appfeeowing = "App Fee Owing" + section5pending = "Section 5 Pending" class CacheUrls(Enum): keycloakusers= "/api/foiassignees" programareas= "/api/foiflow/programareas"