diff --git a/frontend/src/App.js b/frontend/src/App.js index e91fbfd93..7832218df 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -40,6 +40,7 @@ import PrintBarcode from "./components/printBarcode/Index"; import NonConformIndex from "./components/nonconform/index"; import SampleBatchEntrySetup from "./components/batchOrderEntry/SampleBatchEntrySetup.js"; import AuditTrailReportIndex from "./components/reports/auditTrailReport/Index.js"; +import OrganizationAddEdit from "./components/admin/OrganizationManagement/OrganizationAddModify.js"; export default function App() { let i18nConfig = { diff --git a/frontend/src/components/admin/Admin.js b/frontend/src/components/admin/Admin.js index be73362ef..49e5698df 100644 --- a/frontend/src/components/admin/Admin.js +++ b/frontend/src/components/admin/Admin.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import config from "../../config.json"; import { FormattedMessage, useIntl, injectIntl } from "react-intl"; import "../Style.css"; @@ -23,6 +23,7 @@ import { ListDropdown, CicsSystemGroup, QrCode, + ContainerSoftware, } from "@carbon/icons-react"; import PathRoute from "../utils/PathRoute"; import CalculatedValue from "./calculatedValue/CalculatedValueForm"; @@ -35,15 +36,33 @@ import { } from "@carbon/react"; import { CommonProperties } from "./menu/CommonProperties"; import ConfigMenuDisplay from "./formEntry/common/ConfigMenuDisplay"; - import ProviderMenu from "./ProviderMenu/ProviderMenu"; import BarcodeConfiguration from "./barcodeConfiguration/BarcodeConfiguration"; +import OrganizationManagament from "./OrganizationManagement/OrganizationManagement"; +import OrganizationAddModify from "./OrganizationManagement/OrganizationAddModify.js"; function Admin() { const intl = useIntl(); + const [isSmallScreen, setIsSmallScreen] = useState(false); + + useEffect(() => { + const mediaQuery = window.matchMedia("(max-width: 1024px)"); //applicable for medium screen and below for only small screen set max-width: 768px + const handleMediaQueryChange = () => setIsSmallScreen(mediaQuery.matches); + + handleMediaQueryChange(); + mediaQuery.addEventListener("change", handleMediaQueryChange); + + return () => + mediaQuery.removeEventListener("change", handleMediaQueryChange); + }, []); + return ( <> - + + + + + + + + + + diff --git a/frontend/src/components/admin/OrganizationManagement/OrganizationAddModify.js b/frontend/src/components/admin/OrganizationManagement/OrganizationAddModify.js new file mode 100644 index 000000000..3e65664da --- /dev/null +++ b/frontend/src/components/admin/OrganizationManagement/OrganizationAddModify.js @@ -0,0 +1,664 @@ +import React, { useContext, useState, useEffect, useRef } from "react"; +import { useLocation } from "react-router-dom"; +import { + Form, + Heading, + Button, + Loading, + Grid, + Column, + Section, + DataTable, + Table, + TableHead, + TableRow, + TableBody, + TableHeader, + TableCell, + TableSelectRow, + TableSelectAll, + TableContainer, + Pagination, + Search, + TextInput, +} from "@carbon/react"; +import { + getFromOpenElisServer, + postToOpenElisServer, + postToOpenElisServerFormData, + postToOpenElisServerFullResponse, + postToOpenElisServerJsonResponse, +} from "../../utils/Utils.js"; +import { NotificationContext } from "../../layout/Layout.js"; +import { + AlertDialog, + NotificationKinds, +} from "../../common/CustomNotification.js"; +import { Field, Formik } from "formik"; +import { FormattedMessage, injectIntl, useIntl } from "react-intl"; +import PageBreadCrumb from "../../common/PageBreadCrumb.js"; + +let breadcrumbs = [ + { label: "home.label", link: "/" }, + { label: "breadcrums.admin.managment", link: "/MasterListsPage" }, + { + label: "organization.main.title", + link: "/MasterListsPage#organizationManagement", + }, +]; + +function OrganizationAddModify() { + const { notificationVisible, setNotificationVisible, addNotification } = + useContext(NotificationContext); + + const componentMounted = useRef(false); + const intl = useIntl(); + const [loading, setLoading] = useState(true); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(20); + const [selectedRowIds, setSelectedRowIds] = useState([]); + const [orgSelectedTypeOfActivity, setOrgSelectedTypeOfActivity] = useState( + [], + ); + const [orgInfo, setOrgInfo] = useState({}); + const [orgInfoPost, setOrgInfoPost] = useState({}); + const [saveButton, setSaveButton] = useState(true); + const [typeOfActivity, setTypeOfActivity] = useState(); + const [typeOfActivityShow, setTypeOfActivityShow] = useState([]); + const [id, setId] = useState(null); + + //const id = new URLSearchParams(useLocation().search).get("ID"); + + useEffect(() => { + const getIdFromUrl = () => { + // Get the hash part of the URL + const hash = window.location.hash; + + // Check if the hash contains the query parameters + if (hash.includes('?')) { + // Extract the query part from the hash + const queryParams = hash.split('?')[1]; + + // Create a URLSearchParams object to easily access the parameters + const urlParams = new URLSearchParams(queryParams); + + // Get the value of the 'ID' parameter + const id = urlParams.get('ID'); + + return id; + } + return null; + }; + + const extractedId = getIdFromUrl(); + setId(extractedId); + }, []); + + useEffect(() => { + componentMounted.current = true; + setLoading(true); + if (id) { + getFromOpenElisServer( + `/rest/Organization?ID=${id}&startingRecNo=1`, + handleMenuItems, + ); + } + return () => { + componentMounted.current = false; + }; + }, [id]); + + const handleMenuItems = (res) => { + if (!res) { + setLoading(true); + } else { + setTypeOfActivity(res); + } + }; + + useEffect(() => { + if (typeOfActivity) { + const newOrganizationsManagementList = typeOfActivity.orgTypes.map( + (item) => { + return { + id: item.id, + name: item.name, + description: item.description, + }; + }, + ); + const newOrganizationsManagementListArray = Object.values( + newOrganizationsManagementList, + ); + setTypeOfActivityShow(newOrganizationsManagementListArray); + + const organizationsManagementIdInfo = { + id: typeOfActivity.id, + organizationName: typeOfActivity.organizationName, + shortName: typeOfActivity.shortName, + isActive: typeOfActivity.isActive, + internetAddress: typeOfActivity.internetAddress, + selectedTypes: typeOfActivity.selectedTypes, + }; + + const organizationsManagementIdInfoPost = { + departmentList: typeOfActivity.departmentList, + orgTypes: typeOfActivity.orgTypes, + id: typeOfActivity.id, + organizationName: typeOfActivity.organizationName, + shortName: typeOfActivity.shortName, + isActive: typeOfActivity.isActive, + lastupdated: typeOfActivity.lastupdated, + commune: typeOfActivity.commune, + village: typeOfActivity.village, + department: typeOfActivity.department, + formName: typeOfActivity.formName, + formMethod: typeOfActivity.formMethod, + cancelAction: typeOfActivity.cancelAction, + submitOnCancel: typeOfActivity.submitOnCancel, + cancelMethod: typeOfActivity.cancelMethod, + mlsSentinelLabFlag: typeOfActivity.mlsSentinelLabFlag, + parentOrgName: typeOfActivity.parentOrgName, + state: typeOfActivity.state, + internetAddress: typeOfActivity.internetAddress, + selectedTypes: typeOfActivity.selectedTypes, + }; + setOrgInfo(organizationsManagementIdInfo); + setOrgInfoPost(organizationsManagementIdInfoPost); + setSelectedRowIds(typeOfActivity.selectedTypes); + + if (id !== "0") { + const organizationSelectedTypeOfActivity = + typeOfActivity.selectedTypes.map((item) => { + return { + id: item, + }; + }); + const organizationSelectedTypeOfActivityListArray = Object.values( + organizationSelectedTypeOfActivity, + ); + setOrgSelectedTypeOfActivity( + organizationSelectedTypeOfActivityListArray, + ); + } else { + setOrgSelectedTypeOfActivity([]); + } + } + }, [typeOfActivity, id]); + + useEffect(() => { + setOrgInfoPost((prevOrgInfoPost) => ({ + ...prevOrgInfoPost, + selectedTypes: selectedRowIds, + })); + }, [selectedRowIds, orgInfo]); + + // const handlePageChange = ({ page, pageSize }) => { + // setPage(page); + // setPageSize(pageSize); + // setSelectedRowIds([]); + // }; + + function handleOrgNameChange(e) { + setSaveButton(false); + setOrgInfoPost((prevOrgInfoPost) => ({ + ...prevOrgInfoPost, + organizationName: e.target.value, + })); + setOrgInfo((prevOrgInfo) => ({ + ...prevOrgInfo, + organizationName: e.target.value, + })); + } + + function handleOrgPrefixChange(e) { + setSaveButton(false); + setOrgInfoPost((prevOrgInfoPost) => ({ + ...prevOrgInfoPost, + shortName: e.target.value, + })); + setOrgInfo((prevOrgInfo) => ({ + ...prevOrgInfo, + shortName: e.target.value, + })); + } + + function handleIsActiveChange(e) { + setSaveButton(false); + setOrgInfoPost((prevOrgInfoPost) => ({ + ...prevOrgInfoPost, + isActive: e.target.value, + })); + setOrgInfo((prevOrgInfo) => ({ + ...prevOrgInfo, + isActive: e.target.value, + })); + } + + function handleInternetAddressChange(e) { + setSaveButton(false); + setOrgInfoPost((prevOrgInfoPost) => ({ + ...prevOrgInfoPost, + internetAddress: e.target.value, + })); + setOrgInfo((prevOrgInfo) => ({ + ...prevOrgInfo, + internetAddress: e.target.value, + })); + } + + function submitAddUpdatedOrgInfo() { + setLoading(true); + postToOpenElisServerJsonResponse( + `/rest/Organization?ID=${id}&startingRecNo=1`, + JSON.stringify(orgInfoPost), + () => { + submitAddUpdatedOrgInfoCallback(); + }, + ); + } + + const submitAddUpdatedOrgInfoCallback = () => { + setLoading(false); + addNotification({ + title: intl.formatMessage({ + id: "notification.title", + }), + message: intl.formatMessage({ + id: "notification.organization.post.success", + }), + kind: NotificationKinds.success, + }); + setTimeout(() => { + window.location.assign("/MasterListsPage#organizationManagement"); + }, 2000); + setNotificationVisible(true); + }; + + const renderCell = (cell, row) => { + if (cell.info.header === "select") { + return ( + { + setSaveButton(false); + if (selectedRowIds.includes(row.id)) { + setSelectedRowIds(selectedRowIds.filter((id) => id !== row.id)); + } else { + setSelectedRowIds([...selectedRowIds, row.id]); + } + }} + /> + ); + } else if (cell.info.header === "active") { + return {cell.value.toString()}; + } else { + return {cell.value}; + } + }; + + if (!loading) { + return ( + <> + + + ); + } + + return ( + <> + {notificationVisible === true ? : ""} +
+ + + +
+ + {id === "0" ? ( + + ) : ( + + )} + +
+
+
+
+
+ + +
+ + + <> + + * : + + + + handleOrgNameChange(e)} + /> + + + + + <> + : + + + + handleOrgPrefixChange(e)} + /> + + + + + <> + + * : + + + + handleIsActiveChange(e)} + /> + + + + + <> + : + + + + handleInternetAddressChange(e)} + /> + + +
+
+
+
+ + +
+
+
+ + <> + + * + + +
+
+
+
+
+
+ + +
+ + {({ + rows, + headers, + getHeaderProps, + getTableProps, + getSelectionProps, + }) => ( + + + + + + !row.disabled && + selectedRowIds.includes(row.id), + ).length === pageSize + } + indeterminate={ + selectedRowIds.length > 0 && + selectedRowIds.length < + typeOfActivityShow + .slice((page - 1) * pageSize, page * pageSize) + .filter((row) => !row.disabled).length + } + onSelect={() => { + setSaveButton(false); + const currentPageIds = typeOfActivityShow + .slice((page - 1) * pageSize, page * pageSize) + .filter((row) => !row.disabled) + .map((row) => row.id); + if ( + selectedRowIds.length === pageSize && + currentPageIds.every((id) => + selectedRowIds.includes(id), + ) + ) { + setSelectedRowIds([]); + } else { + setSelectedRowIds( + currentPageIds.filter( + (id) => !selectedRowIds.includes(id), + ), + ); + } + }} + /> + {headers.map( + (header) => + header.key !== "select" && ( + + {header.header} + + ), + )} + + + + <> + {rows.map((row) => ( + { + const id = row.id; + const isSelected = selectedRowIds.includes(id); + if (isSelected) { + setSelectedRowIds( + selectedRowIds.filter( + (selectedId) => selectedId !== id, + ), + ); + } else { + setSelectedRowIds([...selectedRowIds, id]); + } + }} + > + {row.cells.map((cell) => renderCell(cell, row))} + + ))} + + +
+
+ )} +
+ {/* + intl.formatMessage( + { id: "pagination.item-range" }, + { min: min, max: max, total: total }, + ) + } + itemsPerPageText={intl.formatMessage({ + id: "pagination.items-per-page", + })} + itemText={(min, max) => + intl.formatMessage( + { id: "pagination.item" }, + { min: min, max: max }, + ) + } + pageNumberText={intl.formatMessage({ + id: "pagination.page-number", + })} + pageRangeText={(_current, total) => + intl.formatMessage( + { id: "pagination.page-range" }, + { total: total }, + ) + } + pageText={(page, pagesUnknown) => + intl.formatMessage( + { id: "pagination.page" }, + { page: pagesUnknown ? "" : page }, + ) + } + /> */} +
+
+
+
+ + + {" "} + + + +
+
+ + ); +} + +export default injectIntl(OrganizationAddModify); diff --git a/frontend/src/components/admin/OrganizationManagement/OrganizationManagement.js b/frontend/src/components/admin/OrganizationManagement/OrganizationManagement.js new file mode 100644 index 000000000..dbab55969 --- /dev/null +++ b/frontend/src/components/admin/OrganizationManagement/OrganizationManagement.js @@ -0,0 +1,837 @@ +import React, { useContext, useState, useEffect, useRef } from "react"; +import { + Form, + Heading, + Button, + Loading, + Grid, + Column, + Section, + DataTable, + Table, + TableHead, + TableRow, + TableBody, + TableHeader, + TableCell, + TableSelectRow, + TableSelectAll, + TableContainer, + Pagination, + Search, +} from "@carbon/react"; +import { + getFromOpenElisServer, + postToOpenElisServer, + postToOpenElisServerFormData, + postToOpenElisServerFullResponse, + postToOpenElisServerJsonResponse, +} from "../../utils/Utils.js"; +import { NotificationContext } from "../../layout/Layout.js"; +import { + AlertDialog, + NotificationKinds, +} from "../../common/CustomNotification.js"; +import { FormattedMessage, injectIntl, useIntl } from "react-intl"; +import PageBreadCrumb from "../../common/PageBreadCrumb.js"; +import { ArrowLeft, ArrowRight } from "@carbon/icons-react"; + +let breadcrumbs = [ + { label: "home.label", link: "/" }, + { label: "breadcrums.admin.managment", link: "/MasterListsPage" }, + { + label: "organization.main.title", + link: "/MasterListsPage#organizationManagement", + }, +]; + +function OrganizationManagament() { + const { notificationVisible, setNotificationVisible, addNotification } = + useContext(NotificationContext); + + const intl = useIntl(); + + const componentMounted = useRef(false); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [deactivateButton, setDeactivateButton] = useState(true); + const [modifyButton, setModifyButton] = useState(true); + const [selectedRowIds, setSelectedRowIds] = useState([]); + const [selectedRowIdsPost, setSelectedRowIdsPost] = useState([]); + const [loading, setLoading] = useState(true); + const [isSearching, setIsSearching] = useState(false); + const [panelSearchTerm, setPanelSearchTerm] = useState(""); + const [totalRecordCount, setTotalRecordCount] = useState(""); + const [startingRecNo, setStartingRecNo] = useState(1); + const [fromRecordCount, setFromRecordCount] = useState(""); + const [toRecordCount, setToRecordCount] = useState(""); + const [paging, setPaging] = useState(1); + const [ + searchedOrganizationManagamentList, + setSearchedOrganizationManagamentList, + ] = useState(); + const [ + searchedOrganizationManagamentListShow, + setSearchedOrganizationManagamentListShow, + ] = useState([]); + const [organizationsManagmentList, setOrganizationsManagmentList] = + useState(); + const [organizationsManagmentListShow, setOrganizationsManagmentListShow] = + useState([]); + + function deleteDeactivateOrganizationManagament(event) { + event.preventDefault(); + setLoading(true); + postToOpenElisServerJsonResponse( + `/rest/DeleteOrganization?ID=${selectedRowIds.join(",")}&startingRecNo=1`, + JSON.stringify(selectedRowIdsPost), + () => { + deleteDeactivateOrganizationManagamentCallback(); + }, + ); + } + + const handleNextPage = () => { + setPaging((pager) => Math.max(pager, 2)); + setStartingRecNo(fromRecordCount); + }; + + const handlePreviousPage = () => { + setPaging((pager) => Math.max(pager - 1, 1)); + setStartingRecNo(Math.max(fromRecordCount, 1)); + }; + + const handlePanelSearchChange = (event) => { + setIsSearching(true); + setPaging(1); + setStartingRecNo(1); + const query = event.target.value; + setPanelSearchTerm(query); + setSelectedRowIds([]); + }; + + const deleteDeactivateOrganizationManagamentCallback = () => { + setLoading(false); + setNotificationVisible(true); + addNotification({ + title: intl.formatMessage({ + id: "notification.title", + }), + message: intl.formatMessage({ + id: "notification.organization.post.delete.success", + }), + kind: NotificationKinds.success, + }); + setTimeout(() => { + window.location.reload(); + }, 2000); + }; + + const handlePageChange = ({ page, pageSize }) => { + setPage(page); + setPageSize(pageSize); + setSelectedRowIds([]); + }; + + const handleMenuItems = (res) => { + if (!res) { + setLoading(true); + } else { + setOrganizationsManagmentList(res); + } + }; + + useEffect(() => { + componentMounted.current = true; + setLoading(true); + getFromOpenElisServer( + `/rest/OrganizationMenu?paging=${paging}&startingRecNo=${startingRecNo}`, + handleMenuItems, + ); + return () => { + componentMounted.current = false; + setLoading(false); + }; + }, [paging, startingRecNo]); + + const handleSearchedProviderMenuList = (res) => { + if (!res) { + setLoading(true); + } else { + setSearchedOrganizationManagamentList(res); + } + }; + + useEffect(() => { + getFromOpenElisServer( + `/rest/SearchOrganizationMenu?search=Y&startingRecNo=${startingRecNo}&searchString=${panelSearchTerm}`, + handleSearchedProviderMenuList, + ); + }, [panelSearchTerm]); + + useEffect(() => { + if (organizationsManagmentList) { + const pagination = { + totalRecordCount: + organizationsManagmentList.modelMap.form.totalRecordCount, + fromRecordCount: + organizationsManagmentList.modelMap.form.fromRecordCount, + toRecordCount: organizationsManagmentList.modelMap.form.toRecordCount, + }; + setFromRecordCount(pagination.fromRecordCount); + setToRecordCount(pagination.toRecordCount); + setTotalRecordCount(pagination.totalRecordCount); + + const newOrganizationsManagementList = + organizationsManagmentList.modelMap.form.menuList.map((item) => { + return { + id: item.id, + orgName: item.organizationName , + parentOrg: item.organization ? item.organization.organizationName :"", + orgPrefix: item.shortName || "", + active: item.isActive || "", + streetAddress: item.internetAddress || "", + city: item.state || "", + cliaNumber: item.cliaNumber || "", + }; + }); + const newOrganizationsManagementListArray = Object.values( + newOrganizationsManagementList, + ); + setOrganizationsManagmentListShow(newOrganizationsManagementListArray); + } + }, [organizationsManagmentList]); + + useEffect(() => { + if (searchedOrganizationManagamentList) { + const newOrganizationsManagementList = + searchedOrganizationManagamentList.modelMap.form.menuList.map( + (item) => { + return { + id: item.id, + orgName: item.organizationName , + parentOrg: item.organization ? item.organization.organizationName :"", + orgPrefix: item.shortName || "", + active: item.isActive || "", + streetAddress: item.internetAddress || "", + city: item.state || "", + cliaNumber: item.cliaNumber || "", + }; + }, + ); + const newOrganizationsManagementListArray = Object.values( + newOrganizationsManagementList, + ); + setSearchedOrganizationManagamentListShow( + newOrganizationsManagementListArray, + ); + } + }, [searchedOrganizationManagamentList]); + + useEffect(() => { + const selectedIDsObject = { + selectedIDs: selectedRowIds, + }; + + setSelectedRowIdsPost(selectedIDsObject); + }, [selectedRowIds, organizationsManagmentListShow]); + + useEffect(() => { + if (selectedRowIds.length === 1) { + setModifyButton(false); + } else { + setModifyButton(true); + } + }, [selectedRowIds]); + + useEffect(() => { + if (isSearching && panelSearchTerm === "") { + setIsSearching(false); + setPaging(1); + setStartingRecNo(1); + } + }, [isSearching, panelSearchTerm]); + + useEffect(() => { + if (selectedRowIds.length === 0) { + setDeactivateButton(true); + } + }, [selectedRowIds]); + + const renderCell = (cell, row) => { + if (cell.info.header === "select") { + return ( + { + setDeactivateButton(false); + if (selectedRowIds.includes(row.id)) { + setSelectedRowIds(selectedRowIds.filter((id) => id !== row.id)); + } else { + setSelectedRowIds([...selectedRowIds, row.id]); + } + }} + /> + ); + } else if (cell.info.header === "active") { + return {cell.value.toString()}; + } else { + return {cell.value}; + } + }; + + if (!loading) { + return ( + <> + + + ); + } + + return ( + <> + {notificationVisible === true ? : ""} +
+ + + +
+ + + +
+
+
+
+ + +
+ {" "} + {" "} + +
+
+
+

+ {fromRecordCount} -{" "} + {toRecordCount} {totalRecordCount}{" "} +

+
+
+
+
+ + +
+ + } + placeholder={intl.formatMessage({ + id: "organization.search.placeHolder", + })} + onChange={handlePanelSearchChange} + value={(() => { + if (panelSearchTerm) { + return panelSearchTerm; + } + return ""; + })()} + > +
+
+
+
+ {isSearching ? ( + <> + + +
+ + {({ + rows, + headers, + getHeaderProps, + getTableProps, + getSelectionProps, + }) => ( + + + + + + !row.disabled && + selectedRowIds.includes(row.id), + ).length === pageSize + } + indeterminate={ + selectedRowIds.length > 0 && + selectedRowIds.length < + searchedOrganizationManagamentListShow + .slice( + (page - 1) * pageSize, + page * pageSize, + ) + .filter((row) => !row.disabled).length + } + onSelect={() => { + setDeactivateButton(false); + const currentPageIds = + searchedOrganizationManagamentListShow + .slice( + (page - 1) * pageSize, + page * pageSize, + ) + .filter((row) => !row.disabled) + .map((row) => row.id); + if ( + selectedRowIds.length === pageSize && + currentPageIds.every((id) => + selectedRowIds.includes(id), + ) + ) { + setSelectedRowIds([]); + } else { + setSelectedRowIds( + currentPageIds.filter( + (id) => !selectedRowIds.includes(id), + ), + ); + } + }} + /> + {headers.map( + (header) => + header.key !== "select" && ( + + {header.header} + + ), + )} + + + + <> + {rows.map((row) => ( + { + const id = row.id; + const isSelected = + selectedRowIds.includes(id); + if (isSelected) { + setSelectedRowIds( + selectedRowIds.filter( + (selectedId) => selectedId !== id, + ), + ); + } else { + setSelectedRowIds([ + ...selectedRowIds, + id, + ]); + } + }} + > + {row.cells.map((cell) => + renderCell(cell, row), + )} + + ))} + + +
+
+ )} +
+ + intl.formatMessage( + { id: "pagination.item-range" }, + { min: min, max: max, total: total }, + ) + } + itemsPerPageText={intl.formatMessage({ + id: "pagination.items-per-page", + })} + itemText={(min, max) => + intl.formatMessage( + { id: "pagination.item" }, + { min: min, max: max }, + ) + } + pageNumberText={intl.formatMessage({ + id: "pagination.page-number", + })} + pageRangeText={(_current, total) => + intl.formatMessage( + { id: "pagination.page-range" }, + { total: total }, + ) + } + pageText={(page, pagesUnknown) => + intl.formatMessage( + { id: "pagination.page" }, + { page: pagesUnknown ? "" : page }, + ) + } + /> +
+
+
+ + ) : ( + <> + + + + {({ + rows, + headers, + getHeaderProps, + getTableProps, + getSelectionProps, + }) => ( + + + + + + !row.disabled && + selectedRowIds.includes(row.id), + ).length === pageSize + } + indeterminate={ + selectedRowIds.length > 0 && + selectedRowIds.length < + organizationsManagmentListShow + .slice( + (page - 1) * pageSize, + page * pageSize, + ) + .filter((row) => !row.disabled).length + } + onSelect={() => { + setDeactivateButton(false); + const currentPageIds = + organizationsManagmentListShow + .slice( + (page - 1) * pageSize, + page * pageSize, + ) + .filter((row) => !row.disabled) + .map((row) => row.id); + if ( + selectedRowIds.length === pageSize && + currentPageIds.every((id) => + selectedRowIds.includes(id), + ) + ) { + setSelectedRowIds([]); + } else { + setSelectedRowIds( + currentPageIds.filter( + (id) => !selectedRowIds.includes(id), + ), + ); + } + }} + /> + {headers.map( + (header) => + header.key !== "select" && ( + + {header.header} + + ), + )} + + + + <> + {rows.map((row) => ( + { + const id = row.id; + const isSelected = + selectedRowIds.includes(id); + if (isSelected) { + setSelectedRowIds( + selectedRowIds.filter( + (selectedId) => selectedId !== id, + ), + ); + } else { + setSelectedRowIds([ + ...selectedRowIds, + id, + ]); + } + }} + > + {row.cells.map((cell) => + renderCell(cell, row), + )} + + ))} + + +
+
+ )} +
+ + intl.formatMessage( + { id: "pagination.item-range" }, + { min: min, max: max, total: total }, + ) + } + itemsPerPageText={intl.formatMessage({ + id: "pagination.items-per-page", + })} + itemText={(min, max) => + intl.formatMessage( + { id: "pagination.item" }, + { min: min, max: max }, + ) + } + pageNumberText={intl.formatMessage({ + id: "pagination.page-number", + })} + pageRangeText={(_current, total) => + intl.formatMessage( + { id: "pagination.page-range" }, + { total: total }, + ) + } + pageText={(page, pagesUnknown) => + intl.formatMessage( + { id: "pagination.page" }, + { page: pagesUnknown ? "" : page }, + ) + } + /> +
+
+ + )} +
+
+ + ); +} + +export default injectIntl(OrganizationManagament); diff --git a/frontend/src/components/admin/ProviderMenu/ProviderMenu.js b/frontend/src/components/admin/ProviderMenu/ProviderMenu.js index e9d1822c1..5470efd4e 100644 --- a/frontend/src/components/admin/ProviderMenu/ProviderMenu.js +++ b/frontend/src/components/admin/ProviderMenu/ProviderMenu.js @@ -19,12 +19,18 @@ import { TableContainer, Pagination, Search, + Modal, + TextInput, + Dropdown, } from "@carbon/react"; import { getFromOpenElisServer, postToOpenElisServerFullResponse, } from "../../utils/Utils.js"; -import { NotificationContext } from "../../layout/Layout.js"; +import { + ConfigurationContext, + NotificationContext, +} from "../../layout/Layout.js"; import { AlertDialog, NotificationKinds, @@ -39,6 +45,7 @@ let breadcrumbs = [ function ProviderMenu() { const { notificationVisible, setNotificationVisible, addNotification } = useContext(NotificationContext); + const { reloadConfiguration } = useContext(ConfigurationContext); const intl = useIntl(); @@ -59,6 +66,39 @@ function ProviderMenu() { const [providerMenuList, setProviderMenuList] = useState([]); const [providerMenuListShow, setProviderMenuListShow] = useState([]); + const [isAddModalOpen, setIsAddModalOpen] = useState(false); + const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); + const [currentProvider, setCurrentProvider] = useState(null); + const [lastName, setLastName] = useState(""); + const [firstName, setFirstName] = useState(""); + const [telephone, setTelephone] = useState(""); + const [fhirUuid, setFhirUuid] = useState(""); + const [fax, setFax] = useState(""); + const [isActive, setIsActive] = useState({ id: "yes", value: "Yes" }); + + const yesOrNo = [ + { id: "yes", value: "Yes" }, + { id: "no", value: "No" }, + ]; + + async function displayStatus(res) { + setNotificationVisible(true); + if (res.status == "201" || res.status == "200") { + addNotification({ + kind: NotificationKinds.success, + title: intl.formatMessage({ id: "notification.title" }), + message: intl.formatMessage({ id: "save.config.success.msg" }), + }); + } else { + addNotification({ + kind: NotificationKinds.error, + title: intl.formatMessage({ id: "notification.title" }), + message: intl.formatMessage({ id: "server.error.msg" }), + }); + } + reloadConfiguration(); + } + function deleteDeactivateProvider(event) { event.preventDefault(); setLoading(true); @@ -114,10 +154,11 @@ function ProviderMenu() { const newProviderMenuList = providerMenuList.map((item) => { return { id: item.id, + fhirUuid: item.fhirUuid, lastName: item.person.lastName, firstName: item.person.firstName, active: item.active, - telephone: item.person.telephone, + telephone: item.person.workPhone, fax: item.person.fax, }; }); @@ -207,6 +248,77 @@ function ProviderMenu() { setPanelSearchTerm(query); }; + const openAddModal = () => { + setLastName(""); + setFirstName(""); + setTelephone(""); + setFax(""); + setIsActive({ id: "yes", value: "Yes" }); + setIsAddModalOpen(true); + }; + + const closeAddModal = () => { + setIsAddModalOpen(false); + }; + + const openUpdateModal = (providerId) => { + const provider = providerMenuListShow.find((p) => p.id === providerId); + setCurrentProvider(provider); + setLastName(provider.lastName); + setFirstName(provider.firstName); + setTelephone(provider.telephone); + setFax(provider.fax); + setIsActive( + provider.active ? { id: "yes", value: "Yes" } : { id: "no", value: "No" }, + ); + setIsUpdateModalOpen(true); + }; + + const closeUpdateModal = () => { + setIsUpdateModalOpen(false); + }; + + const handleAddProvider = () => { + const newProvider = { + person: { + lastName, + firstName, + workPhone: telephone, + fax, + }, + active: isActive.id === "yes", + }; + postToOpenElisServerFullResponse( + "/rest/Provider/FhirUuid?fhirUuid=", + JSON.stringify(newProvider), + displayStatus, + ); + + closeAddModal(); + window.location.reload(); + }; + + const handleUpdateProvider = () => { + const updatedProvider = { + fhirUuid: currentProvider.fhirUuid, + person: { + lastName, + firstName, + workPhone: telephone, + fax, + }, + active: isActive.id === "yes", + }; + postToOpenElisServerFullResponse( + "/rest/Provider/FhirUuid?fhirUuid=", + JSON.stringify(updatedProvider), + displayStatus, + ); + + closeUpdateModal(); + window.location.reload(); + }; + if (!loading) { return ( <> @@ -231,13 +343,18 @@ function ProviderMenu() {
- {" "} {" "} - @@ -245,6 +362,97 @@ function ProviderMenu() {
+ + + setLastName(e.target.value)} + required + /> + setFirstName(e.target.value)} + required + /> + setTelephone(e.target.value)} + /> + setFax(e.target.value)} + /> + (item ? item.value : "")} + selectedItem={isActive} + onChange={({ selectedItem }) => setIsActive(selectedItem)} + /> + + + + setLastName(e.target.value)} + required + /> + setFirstName(e.target.value)} + required + /> + setTelephone(e.target.value)} + /> + setFax(e.target.value)} + /> + (item ? item.value : "")} + selectedItem={isActive} + onChange={({ selectedItem }) => setIsActive(selectedItem)} + /> + +
diff --git a/frontend/src/components/admin/menu/DictionaryManagement.js b/frontend/src/components/admin/menu/DictionaryManagement.js index 6f8c155f0..d15cc89fc 100644 --- a/frontend/src/components/admin/menu/DictionaryManagement.js +++ b/frontend/src/components/admin/menu/DictionaryManagement.js @@ -11,6 +11,7 @@ import { Link, Modal, Pagination, + Search, Section, Table, TableBody, @@ -20,9 +21,6 @@ import { TableHeader, TableRow, TableSelectRow, - TableToolbar, - TableToolbarContent, - TableToolbarSearch, TextInput, } from "@carbon/react"; import { FormattedMessage, useIntl } from "react-intl"; @@ -71,11 +69,14 @@ function DictionaryManagement() { const [paging, setPaging] = useState(null); const [startingRecNo, setStartingRecNo] = useState(1); + const [isSearching, setIsSearching] = useState(false); + const [panelSearchTerm, setPanelSearchTerm] = useState(""); + const [searchedMenuList, setSearchedMenuList] = useState([]); useEffect(() => { componentMounted.current = true; getFromOpenElisServer( - `/rest/dictionary-menu?paging=${paging}&startingRecNo=${startingRecNo}`, + `/rest/DictionaryMenu?paging=${paging}&startingRecNo=${startingRecNo}`, fetchedDictionaryMenu, ); return () => { @@ -149,9 +150,49 @@ function DictionaryManagement() { } }; + useEffect(() => { + if (panelSearchTerm) { + getFromOpenElisServer( + `/rest/SearchDictionaryMenu?search=Y&startingRecNo=1&searchString=${panelSearchTerm}`, + fetchedSearchedDictionaryMenu, + ); + } else { + setSearchedMenuList([]); + } + }, [panelSearchTerm]); + + const fetchedSearchedDictionaryMenu = (res) => { + if (componentMounted.current) { + if (res) { + if ( + res.toRecordCount !== undefined && + res.fromRecordCount !== undefined && + res.totalRecordCount !== undefined + ) { + setToRecordCount(res.toRecordCount); + setFromRecordCount(res.fromRecordCount); + setTotalRecordCount(res.totalRecordCount); + } + if (res.menuList) { + const menuList = res.menuList.map((item) => ({ + id: item.id, + dictEntry: item.dictEntry, + localAbbreviation: item.localAbbreviation, + isActive: item.isActive, + categoryName: item.dictionaryCategory + ? item.dictionaryCategory.categoryName + : "not available", + lastupdated: item.lastupdated, + })); + setSearchedMenuList(menuList); + } + } + } + }; + useEffect(() => { componentMounted.current = true; - getFromOpenElisServer("/rest/dictionary-menu", fetchedDictionaryMenu); + getFromOpenElisServer("/rest/DictionaryMenu", fetchedDictionaryMenu); return () => { componentMounted.current = false; }; @@ -345,6 +386,16 @@ function DictionaryManagement() { } }; + const handlePanelSearchChange = (event) => { + const query = event.target.value; + setPanelSearchTerm(query); + if (query) { + setIsSearching(true); + } else { + setIsSearching(false); + } + }; + return (
{notificationVisible === true ? : ""} @@ -507,14 +558,43 @@ function DictionaryManagement() {
+ + +
+ } + placeholder={intl.formatMessage({ + id: "search.by.dictionary.entry", + })} + onChange={handlePanelSearchChange} + value={(() => { + if (panelSearchTerm) { + return panelSearchTerm; + } + return ""; + })()} + > +
+
+
+
- {({ - rows, - headers, - getHeaderProps, - getTableProps, - getToolbarProps, - getBatchActionProps, - onInputChange, - selectRow, - }) => { - const batchActionProps = { - ...getBatchActionProps({ - onSelectAll: () => { - rows.map((row) => { - if (!row.isSelected) { - selectRow(row.id); - } - }); - }, - }), - }; - + {({ rows, headers, getHeaderProps, getTableProps }) => { return ( - - - - - @@ -619,7 +666,11 @@ function DictionaryManagement() { page={page} pageSize={pageSize} pageSizes={[10, 20]} - totalItems={dictionaryMenuList.length} + totalItems={ + isSearching + ? searchedMenuList.length + : dictionaryMenuList.length + } forwardText={intl.formatMessage({ id: "pagination.forward" })} backwardText={intl.formatMessage({ id: "pagination.backward" })} size="sm" diff --git a/frontend/src/components/utils/PathRoute.js b/frontend/src/components/utils/PathRoute.js index 18af7859f..8acb2076d 100644 --- a/frontend/src/components/utils/PathRoute.js +++ b/frontend/src/components/utils/PathRoute.js @@ -1,5 +1,10 @@ const PathRoute = ({ path, children }) => { - return window.location.href.endsWith(path) ? children : null; + var fullPath = window.location.href + if (window.location.href.includes('?')) { + // Remove Query Params from the path + fullPath = window.location.href.split('?')[0]; + } + return fullPath.endsWith(path) ? children : null; }; export default PathRoute; diff --git a/frontend/src/languages/en.json b/frontend/src/languages/en.json index 678901108..042ea54f8 100644 --- a/frontend/src/languages/en.json +++ b/frontend/src/languages/en.json @@ -1023,5 +1023,32 @@ "labno.alt.prefix.use": "Use the same accession number format and pool of available numbers as Order Entry Generation.", "labno.alt.prefix.instruction": "Prefix for pre-printed barcode labels (4 characters) :", "labno.alt.prefix.note": "NOTE: If this prefix has already been used, the numbering will continue from the last number generated.", - "siteInfo.description.dimensions": "Indicate the dimensions that bar code labels should conform to when printing." + "siteInfo.description.dimensions": "Indicate the dimensions that bar code labels should conform to when printing.", + "organization.main.title": "Organization Management", + "organization.add.title": "Add Organization", + "organization.edit.title": "Edit Organization", + "notification.organization.post.success": "Organization Information Updated Succesfully.", + "notification.organization.post.save.success": "Organization Information Added Succesfully.", + "notification.organization.post.delete.success": "Organization Deactivated Succesfully.", + "organization.select": "Select", + "organization.type.CI": "Type of Activity", + "organization.type.CI.select": "Type of Activity : Select", + "organization.type.CI.name": "Type of Activity : Name", + "organization.type.CI.description": "Type of Activity : Description", + "organization.add.placeholder": "AlphaNumeric Values", + "organization.add.placeholder.active": "Y or N", + "organization.search.byorgname": "Search By Org Name", + "organization.search.placeHolder": "Search By Org Name...", + "organization.organizationName": "Org Name", + "organization.parent": "Parent Org", + "organization.short.CI": "Org prefix", + "organization.isActive": "Is Active", + "organization.streetAddress": "Street Address", + "organization.internetaddress": "Internet Address", + "organization.city": "City", + "organization.clia.number": "CLIA Number", + "organization.previous": "Previous Page", + "organization.next": "Next Page", + "showing": "Showing", + "of": "of" } diff --git a/frontend/src/languages/fr.json b/frontend/src/languages/fr.json index c7d264016..2853823d5 100644 --- a/frontend/src/languages/fr.json +++ b/frontend/src/languages/fr.json @@ -934,5 +934,32 @@ "labno.alt.prefix.use": "Utilisez le même format de numéro d'accès et le même pool de numéros disponibles que la génération de commande.", "labno.alt.prefix.instruction": "Préfixe pour les étiquettes de code-barres pré-imprimées (4 caractères) :", "labno.alt.prefix.note": "REMARQUE : Si ce préfixe a déjà été utilisé, la numérotation continuera à partir du dernier numéro généré.", - "siteInfo.description.dimensions": "Indiquez les dimensions auxquelles les étiquettes de code-barres doivent se conformer lors de l'impression." + "siteInfo.description.dimensions": "Indiquez les dimensions auxquelles les étiquettes de code-barres doivent se conformer lors de l'impression.", + "organization.main.title": "Gestion des organisations", + "organization.add.title": "Ajouter une organisation", + "organization.edit.title": "Modifier l'organisation", + "notification.organization.post.success": "Informations sur l'organisation mises à jour avec succès.", + "notification.organization.post.save.success": "Informations sur l'organisation ajoutées avec succès.", + "notification.organization.post.delete.success": "Organisation désactivée avec succès.", + "organization.select": "Sélectionner", + "organization.type.CI": "Type d'activité", + "organization.type.CI.select": "Type d'activité : Sélectionner", + "organization.type.CI.name": "Type d'activité : Nom", + "organization.type.CI.description": "Type d'activité : Description", + "organization.add.placeholder": "Valeurs alphanumériques", + "organization.add.placeholder.active": "Oui ou Non", + "organization.search.byorgname": "Rechercher par nom d'organisation", + "organization.search.placeHolder": "Rechercher par nom d'organisation...", + "organization.organizationName": "Nom de l'organisation", + "organization.parent": "Organisation parent", + "organization.short.CI": "Préfixe d'org", + "organization.isActive": "Est actif", + "organization.streetAddress": "Adresse", + "organization.internetaddress": "Adresse Internet", + "organization.city": "Ville", + "organization.clia.number": "Numéro de CLIA", + "organization.previous": "Page précédente", + "organization.next": "Page suivante", + "showing": "Affichage", + "of": "de" } diff --git a/src/main/java/org/openelisglobal/common/rest/DisplayListController.java b/src/main/java/org/openelisglobal/common/rest/DisplayListController.java index 60964744f..3f6925043 100644 --- a/src/main/java/org/openelisglobal/common/rest/DisplayListController.java +++ b/src/main/java/org/openelisglobal/common/rest/DisplayListController.java @@ -479,7 +479,7 @@ public List getTestBeansBySample(@RequestParam(required = false List testItems = new ArrayList<>(); List testList = new ArrayList<>(); if (StringUtils.isNotBlank(sampleType)) { - testList = typeOfSampleService.getActiveTestsBySampleTypeId(sampleType, false); + testList = typeOfSampleService.getActiveTestsBySampleTypeId(sampleType, true); } else { return testItems; } diff --git a/src/main/java/org/openelisglobal/dictionary/controller/rest/DictionaryMenuRestController.java b/src/main/java/org/openelisglobal/dictionary/controller/rest/DictionaryMenuRestController.java index 8eabc5d53..f0393816e 100644 --- a/src/main/java/org/openelisglobal/dictionary/controller/rest/DictionaryMenuRestController.java +++ b/src/main/java/org/openelisglobal/dictionary/controller/rest/DictionaryMenuRestController.java @@ -53,7 +53,7 @@ public void initBinder(WebDataBinder binder) { binder.setAllowedFields(ALLOWED_FIELDS); } - @RequestMapping(value = "/dictionary-menu", produces = MediaType.APPLICATION_JSON_VALUE,method = RequestMethod.GET) + @RequestMapping(value = { "/DictionaryMenu", "/SearchDictionaryMenu" }, produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) public ResponseEntity showDictionaryMenu(HttpServletRequest request, RedirectAttributes redirectAttributes) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { DictionaryMenuForm form = new DictionaryMenuForm(); diff --git a/src/main/java/org/openelisglobal/organization/controller/rest/OrganizationMenuRestController.java b/src/main/java/org/openelisglobal/organization/controller/rest/OrganizationMenuRestController.java new file mode 100644 index 000000000..bfb178bc4 --- /dev/null +++ b/src/main/java/org/openelisglobal/organization/controller/rest/OrganizationMenuRestController.java @@ -0,0 +1,232 @@ +package org.openelisglobal.organization.controller.rest; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.constraints.Pattern; + +import org.openelisglobal.common.controller.BaseMenuController; +import org.openelisglobal.common.exception.LIMSRuntimeException; +import org.openelisglobal.common.form.AdminOptionMenuForm; +import org.openelisglobal.common.log.LogEvent; +import org.openelisglobal.common.util.SystemConfiguration; +import org.openelisglobal.common.validator.BaseErrors; +import org.openelisglobal.dataexchange.fhir.exception.FhirTransformationException; +import org.openelisglobal.organization.form.OrganizationMenuForm; +import org.openelisglobal.organization.service.OrganizationExportService; +import org.openelisglobal.organization.service.OrganizationService; +import org.openelisglobal.organization.valueholder.Organization; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/rest") +public class OrganizationMenuRestController extends BaseMenuController { + + private static final String[] ALLOWED_FIELDS = new String[] { "selectedIds*", "searchString" }; + + @Autowired + private OrganizationService organizationService; + @Autowired + private OrganizationExportService organizationExportService; + + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.setAllowedFields(ALLOWED_FIELDS); + } + + @GetMapping(value = { "/OrganizationMenu", "/SearchOrganizationMenu" }) + public ResponseEntity showOrganizationMenu(HttpServletRequest request) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + String forward; + OrganizationMenuForm form = new OrganizationMenuForm(); + + forward = performMenuAction(form, request); + if (FWD_FAIL.equals(forward)) { + Errors errors = new BaseErrors(); + errors.reject("error.generic"); + // redirectAttributes.addFlashAttribute(Constants.REQUEST_ERRORS, errors); + // return findForward(forward, form); + return ResponseEntity.badRequest().body(errors.getAllErrors()); + } else { + request.setAttribute("menuDefinition", "OrganizationMenuDefinition"); + addFlashMsgsToRequest(request); + // return findForward(forward, form); + return ResponseEntity.ok(findForward(forward, form)); + } + } + + @GetMapping(value = "/OrganizationExport", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity exportOrganizations(@RequestParam(name = "active", defaultValue = "true") String active) + throws FhirTransformationException { + // return organizationExportService.exportFhirOrganizationsFromOrganizations(Boolean.valueOf(active)).getBytes(); + try { + byte[] data = organizationExportService.exportFhirOrganizationsFromOrganizations(Boolean.valueOf(active)).getBytes(); + return ResponseEntity.ok().body(data); + } catch (FhirTransformationException e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage().getBytes()); + } + } + + @Override + protected List createMenuList(AdminOptionMenuForm form, HttpServletRequest request) throws LIMSRuntimeException { + + // LogEvent.logInfo(this.getClass().getSimpleName(), "method unkown", "I am in + // OrganizationMenuAction createMenuList()"); + + List organizations = new ArrayList<>(); + + int startingRecNo = this.getCurrentStartingRecNo(request); + + if (YES.equals(request.getParameter("search"))) { + organizations = organizationService.getPagesOfSearchedOrganizations(startingRecNo, + request.getParameter("searchString")); + } else { + organizations = organizationService.getOrderedPage("organizationName", false, startingRecNo); + } + + request.setAttribute("menuDefinition", "OrganizationMenuDefinition"); + + // bugzilla 1411 set pagination variables + // bugzilla 2372 set pagination variables for searched results + if (YES.equals(request.getParameter("search"))) { + request.setAttribute(MENU_TOTAL_RECORDS, String.valueOf( + organizationService.getTotalSearchedOrganizationCount(request.getParameter("searchString")))); + request.setAttribute(SEARCHED_STRING, request.getParameter("searchString")); + } else { + request.setAttribute(MENU_TOTAL_RECORDS, String.valueOf(organizationService.getCount())); + } + + request.setAttribute(MENU_FROM_RECORD, String.valueOf(startingRecNo)); + int numOfRecs = 0; + if (organizations != null) { + if (organizations.size() > SystemConfiguration.getInstance().getDefaultPageSize()) { + numOfRecs = SystemConfiguration.getInstance().getDefaultPageSize(); + } else { + numOfRecs = organizations.size(); + } + numOfRecs--; + } + int endingRecNo = startingRecNo + numOfRecs; + request.setAttribute(MENU_TO_RECORD, String.valueOf(endingRecNo)); + // end bugzilla 1411 + + // bugzilla 2372 + request.setAttribute(MENU_SEARCH_BY_TABLE_COLUMN, "organization.organizationName"); + // bugzilla 2372 set up a seraching mode so the next and previous action will + // know + // what to do + + if (YES.equals(request.getParameter("search"))) { + + request.setAttribute(IN_MENU_SELECT_LIST_HEADER_SEARCH, "true"); + } + // setPaginationVariables(request, organizations); + form.setToRecordCount(String.valueOf(endingRecNo)); + form.setFromRecordCount(String.valueOf(startingRecNo)); + form.setTotalRecordCount(String.valueOf(String.valueOf(organizationService.getCount()))); + + return organizations; + } + + @Override + protected String getDeactivateDisabled() { + return "false"; + } + + @Override + protected int getPageSize() { + return SystemConfiguration.getInstance().getDefaultPageSize(); + } + + // gnr: Deactivate not Delete + @PostMapping(value = "/DeleteOrganization") + public ResponseEntity showDeleteOrganization(HttpServletRequest request, + @RequestParam(value = ID, required = false) @Pattern(regexp = "[a-zA-Z0-9 -]*") String id, + @RequestBody OrganizationMenuForm form, BindingResult result) throws LIMSRuntimeException { + if (result.hasErrors()) { + // redirectAttributes.addFlashAttribute(Constants.REQUEST_ERRORS, result); + // findForward(FWD_FAIL_DELETE, form); + return ResponseEntity.badRequest().body(result.getAllErrors()); + } + + String[] IDs = id.split(","); + List selectedIDs = new ArrayList<>(); + for (int i = 0; i < IDs.length; i++) { + selectedIDs.add(IDs[i]); + } + // List selectedIDs = form.getSelectedIDs; + List organizations = new ArrayList<>(); + for (int i = 0; i < selectedIDs.size(); i++) { + Organization organization = new Organization(); + organization.setId(selectedIDs.get(i)); + organization.setSysUserId(getSysUserId(request)); + organizations.add(organization); + } + + try { + // LogEvent.logInfo(this.getClass().getSimpleName(), "method unkown", "Going to delete + // Organization"); + organizationService.deactivateOrganizations(organizations); + return ResponseEntity.ok(form); + // LogEvent.logInfo(this.getClass().getSimpleName(), "method unkown", "Just deleted + // Organization"); + } catch (LIMSRuntimeException e) { + // bugzilla 2154 + LogEvent.logError(e); + + String errorMsg; + if (e.getCause() instanceof org.hibernate.StaleObjectStateException) { + errorMsg = "errors.OptimisticLockException"; + } else { + errorMsg = "errors.DeleteException"; + } + result.reject(errorMsg); + // redirectAttributes.addFlashAttribute(Constants.REQUEST_ERRORS, result); + // return findForward(FWD_FAIL_DELETE, form); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result.getAllErrors()); + } + // redirectAttributes.addAttribute(FWD_SUCCESS, true); + // return findForward(FWD_SUCCESS_DELETE, form); + } + + @Override + protected String findLocalForward(String forward) { + if (FWD_SUCCESS.equals(forward)) { + return "orgMasterListsPageDefinition"; + } else if (FWD_FAIL.equals(forward)) { + return "redirect:/MasterListsPage"; + } else if (FWD_SUCCESS_DELETE.equals(forward)) { + return "redirect:/OrganizationMenu"; + } else if (FWD_FAIL_DELETE.equals(forward)) { + return "redirect:/OrganizationMenu"; + } else { + return "PageNotFound"; + } + } + + @Override + protected String getPageTitleKey() { + return "organization.browse.title"; + } + + @Override + protected String getPageSubtitleKey() { + return "organization.browse.title"; + } + +} diff --git a/src/main/java/org/openelisglobal/organization/controller/rest/OrganizationRestController.java b/src/main/java/org/openelisglobal/organization/controller/rest/OrganizationRestController.java new file mode 100644 index 000000000..f37a55ca5 --- /dev/null +++ b/src/main/java/org/openelisglobal/organization/controller/rest/OrganizationRestController.java @@ -0,0 +1,548 @@ +package org.openelisglobal.organization.controller.rest; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.lang.StringUtils; +import org.openelisglobal.address.service.AddressPartService; +import org.openelisglobal.address.service.OrganizationAddressService; +import org.openelisglobal.address.valueholder.AddressPart; +import org.openelisglobal.address.valueholder.OrganizationAddress; +import org.openelisglobal.citystatezip.service.CityStateZipService; +import org.openelisglobal.common.controller.BaseController; +import org.openelisglobal.common.exception.LIMSDuplicateRecordException; +import org.openelisglobal.common.exception.LIMSRuntimeException; +import org.openelisglobal.common.formfields.FormFields; +import org.openelisglobal.common.formfields.FormFields.Field; +import org.openelisglobal.common.log.LogEvent; +import org.openelisglobal.common.services.DisplayListService; +import org.openelisglobal.common.util.StringUtil; +import org.openelisglobal.common.validator.ValidationHelper; +import org.openelisglobal.dictionary.service.DictionaryService; +import org.openelisglobal.dictionary.valueholder.Dictionary; +import org.openelisglobal.internationalization.MessageUtil; +import org.openelisglobal.organization.form.OrganizationForm; +import org.openelisglobal.organization.service.OrganizationService; +import org.openelisglobal.organization.service.OrganizationTypeService; +import org.openelisglobal.organization.valueholder.Organization; +import org.openelisglobal.organization.valueholder.OrganizationType; +import org.owasp.encoder.Encode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.support.SessionStatus; + +@RestController +@RequestMapping("/rest") +public class OrganizationRestController extends BaseController { + + private static final String[] ALLOWED_FIELDS = new String[] { "id", "parentOrgName", + "organizationLocalAbbreviation", "organizationName", "shortName", "isActive", "multipleUnit", + "streetAddress", "city", "department", "commune", "village", "state", "zipCode", "internetAddress", + "mlsSentinelLabFlag", "cliaNum", "mlsLabFlag", "selectedTypes*" }; + + @Autowired + private OrganizationService organizationService; + @Autowired + private OrganizationAddressService organizationAddressService; + @Autowired + private CityStateZipService cityStateZipService; + @Autowired + private OrganizationTypeService organizationTypeService; + @Autowired + private DictionaryService dictionaryService; + + // @ModelAttribute("form") + // public OrganizationForm form() { + // return new OrganizationForm(); + // } + + // private static boolean useZip = + // FormFields.getInstance().useField(FormFields.Field.ZipCode); + private static boolean useState = FormFields.getInstance().useField(FormFields.Field.OrgState); + private static boolean useDepartment = FormFields.getInstance().useField(Field.ADDRESS_DEPARTMENT); + private static boolean useCommune = FormFields.getInstance().useField(Field.ADDRESS_COMMUNE); + private static boolean useVillage = FormFields.getInstance().useField(Field.ADDRESS_VILLAGE); + + private final String DEPARTMENT_ID; + private final String COMMUNE_ID; + private final String VILLAGE_ID; + + private static final String DEPARTMENT_ADDRESS_KEY = "department"; + private static final String COMMUNE_ADDRESS_KEY = "commune"; + private static final String VILLAGE_ADDRESS_KEY = "village"; + + private static boolean useParentOrganization = FormFields.getInstance().useField(Field.OrganizationParent); + private static boolean useOrganizationState = FormFields.getInstance().useField(Field.OrgState); + private static boolean useOrganizationTypeList = FormFields.getInstance().useField(Field.InlineOrganizationTypes); + + public OrganizationRestController(AddressPartService addressPartService) { + String departmentId = null; + String communeId = null; + String villageId = null; + + List partList = addressPartService.getAll(); + for (AddressPart addressPart : partList) { + if ("department".equals(addressPart.getPartName())) { + departmentId = addressPart.getId(); + } else if ("commune".equals(addressPart.getPartName())) { + communeId = addressPart.getId(); + } else if ("village".equals(addressPart.getPartName())) { + villageId = addressPart.getId(); + } + } + DEPARTMENT_ID = departmentId; + COMMUNE_ID = communeId; + VILLAGE_ID = villageId; + + if (useDepartment && departmentId == null) { + throw new IllegalStateException("can't use department without department Id"); + } + if (useCommune && communeId == null) { + throw new IllegalStateException("can't use commune without commune Id"); + } + if (useVillage && villageId == null) { + throw new IllegalStateException("can't use village without village Id"); + } + } + + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.setAllowedFields(ALLOWED_FIELDS); + } + + @GetMapping(value = { "/Organization", "/NextPreviousOrganization" }) + public ResponseEntity showOrganization( HttpServletRequest request ) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + + OrganizationForm newForm = new OrganizationForm(); + // OrganizationForm newForm = resetSessionFormToType(oldForm, OrganizationForm.class); + + newForm.setCancelAction("CancelOrganization"); + + // The first job is to determine if we are coming to this action with an + // ID parameter in the request. If there is no parameter, we are + // creating a new Organization. + // If there is a parameter present, we should bring up an existing + // Organization to edit. + String id = ""; + String start = ""; + // validate start + if (StringUtils.isNumericSpace(request.getParameter("startingRecNo"))) { + start = request.getParameter("startingRecNo"); + } + // validate id + if (request.getParameter(ID) != null && request.getParameter(ID).matches(ValidationHelper.ID_REGEX)) { + id = request.getParameter(ID); + } + + // request.setAttribute(ALLOW_EDITS_KEY, "true"); + // request.setAttribute(PREVIOUS_DISABLED, "true"); + // request.setAttribute(NEXT_DISABLED, "true"); + + List departmentList = getDepartmentList(); + newForm.setDepartmentList(departmentList); + + Organization organization; + + // redirect to get organization for next or previous entry + if (FWD_NEXT.equals(request.getParameter("direction"))) { + organization = organizationService.getNext(id); + String newId = organization.getId(); + + // return new ModelAndView("redirect:/Organization?ID=" + Encode.forUriComponent(newId) + "&startingRecNo=" + // + Encode.forUriComponent(start)); + return ResponseEntity.status(HttpStatus.FOUND).header("Location", "/Organization?ID=" + Encode.forUriComponent(newId) + "&startingRecNo=" + + Encode.forUriComponent(start)).build(); + } else if (FWD_PREVIOUS.equals(request.getParameter("direction"))) { + organization = organizationService.getPrevious(id); + String newId = organization.getId(); + // return new ModelAndView("redirect:/Organization?ID=" + Encode.forUriComponent(newId) + "&startingRecNo=" + // + Encode.forUriComponent(start)); + return ResponseEntity.status(HttpStatus.FOUND).header("Location", "/Organization?ID=" + Encode.forUriComponent(newId) + "&startingRecNo=" + + Encode.forUriComponent(start)).build(); + } + + boolean isNew = (id == null) || "0".equals(id); + if (isNew) { + request.setAttribute("key", "organization.add.title"); + organization = new Organization(); + + // default isActive to 'Y' + organization.setIsActive(YES); + organization.setMlsSentinelLabFlag(NO); + organization.setMlsLabFlag("N"); + } else { + request.setAttribute("key", "organization.edit.title"); + + organization = organizationService.get(id); + if (organization.getOrganization() != null) { + organization.setSelectedOrgId(organization.getOrganization().getId()); + } + + if (organizationService.hasNext(id)) { + request.setAttribute(NEXT_DISABLED, "false"); + } + if (organizationService.hasPrevious(id)) { + request.setAttribute(PREVIOUS_DISABLED, "false"); + } + + if (useCommune || useDepartment || useVillage) { + List orgAddressList = organizationAddressService + .getAddressPartsByOrganizationId(id); + + for (OrganizationAddress orgAddress : orgAddressList) { + if (useCommune && COMMUNE_ID.equals(orgAddress.getAddressPartId())) { + newForm.setCommune(orgAddress.getValue()); + } else if (useVillage && VILLAGE_ID.equals(orgAddress.getAddressPartId())) { + newForm.setVillage(orgAddress.getValue()); + } else if (useDepartment && DEPARTMENT_ID.equals(orgAddress.getAddressPartId())) { + newForm.setDepartment(orgAddress.getValue()); + } + } + } + + } + + // initialize state to MN + if (organization.getState() == null) { + organization.setState("MN"); + } + + if (organization.getId() != null && !organization.getId().equals("0")) { + request.setAttribute(ID, organization.getId()); + } + + PropertyUtils.copyProperties(newForm, organization); + + if (useParentOrganization) { + setParentOrganiztionName(newForm, organization); + } + + if (useOrganizationState) { + setCityStateZipList(newForm); + } + + if (useOrganizationTypeList) { + List orgTypeList = getOrganizationTypeList(); + List selectedList = new ArrayList<>(); + newForm.setOrgTypes(orgTypeList); + + if (organization.getId() != null && orgTypeList != null) { + if (orgTypeList.size() > 0) { + List selectedOrgTypeList = organizationService + .getTypeIdsForOrganizationId(organization.getId()); + for (String orgTypeId : selectedOrgTypeList) { + selectedList.add(orgTypeId); + } + } + } + newForm.setSelectedTypes(selectedList); + } + + // return findForward(FWD_SUCCESS, newForm); + return ResponseEntity.ok(newForm); + } + + private void setParentOrganiztionName(OrganizationForm form, Organization organization) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + Organization parentOrg = new Organization(); + String parentOrgName = null; + + if (!StringUtil.isNullorNill(organization.getSelectedOrgId())) { + parentOrg = organizationService.get(organization.getSelectedOrgId()); + parentOrgName = parentOrg.getOrganizationName(); + } + + form.setParentOrgName(parentOrgName); + } + + private void setCityStateZipList(OrganizationForm form) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + if (FormFields.getInstance().useField(FormFields.Field.OrgState)) { + // bugzilla 1545 + List states = cityStateZipService.getAllStateCodes(); + form.setStates(states); + } + } + + // private void setCityStateZipList(OrganizationForm form) + // throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + // List cityStateZipList = cityStateZipService.getAll(); + // form.setCityStateZipList(cityStateZipList); + // } + + private List getOrganizationTypeList() { + + List orgTypeList = organizationTypeService.getAll(); + if (orgTypeList == null) { + orgTypeList = new ArrayList<>(); + } + + return orgTypeList; + } + + private List getDepartmentList() { + return dictionaryService.getDictionaryEntrysByCategoryAbbreviation("description", "haitiDepartment", true); + } + + @GetMapping("/organization/{id}") + public ResponseEntity getOrganization(@PathVariable("id") String id) { + Organization organization = organizationService.get(id); + if (organization != null) { + return ResponseEntity.ok(organization); + } else { + return ResponseEntity.notFound().build(); + } + } + + @PostMapping(value = "/Organization") + public ResponseEntity showUpdateOrganization(@RequestBody @Valid OrganizationForm form, BindingResult result)throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + + // setDefaultButtonAttributes(request); + if (result.hasErrors()) { + saveErrors(result); + // return findForward(FWD_FAIL_INSERT, form); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Failed to save or update organization. Validation errors exist."); + + } + + Organization organization; + boolean isNew = (StringUtil.isNullorNill(form.getId()) || "0".equals(form.getId())); + if (isNew) { + organization = new Organization(); + // request.setAttribute("key", "organization.add.title"); + } else { + organization = organizationService.get(form.getId()); + // request.setAttribute("key", "organization.edit.title"); + if (organization == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Organization not found."); + } + } + List selectedOrgTypes = form.getSelectedTypes(); + + organization.setSysUserId(getSysUserId(request)); + + // List states = getPossibleStates(form); + + PropertyUtils.copyProperties(organization, form); + + if (FormFields.getInstance().useField(FormFields.Field.OrganizationParent)) { + String parentOrgName = form.getParentOrgName(); + Organization o = new Organization(); + o.setOrganizationName(parentOrgName); + Organization parentOrg = organizationService.getActiveOrganizationByName(o, false); + organization.setOrganization(parentOrg); + } + Map addressParts = createAddressParts(form, isNew); + + try { + if (!isNew) { + organizationService.update(organization); + } else { + organizationService.insert(organization); + } + + persistAddressParts(organization, addressParts); + + linkOrgWithOrgType(organization, selectedOrgTypes); + + } catch (LIMSRuntimeException e) { + // bugzilla 2154 + LogEvent.logError(e); + if (e.getCause() instanceof org.hibernate.StaleObjectStateException) { + result.reject("errors.OptimisticLockException"); + return ResponseEntity.status(HttpStatus.CONFLICT).body("Another transaction has updated the organization. Please refresh and try again."); + } else if + // bugzilla 1482 + (e.getCause() instanceof LIMSDuplicateRecordException) { + String messageKey = "organization.organization"; + String msg = MessageUtil.getMessage(messageKey); + result.reject("errors.DuplicateRecord.activeonly", new String[] { msg },"errors.DuplicateRecord.activeonly"); + return ResponseEntity.status(HttpStatus.CONFLICT).body("Duplicate record error."); + } else { + result.reject("errors.UpdateException"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to save or update organization. Error: " + e.getMessage()); + } + // saveErrors(result); + // request.setAttribute(PREVIOUS_DISABLED, "true"); + // request.setAttribute(NEXT_DISABLED, "true"); + // return findForward(FWD_FAIL_INSERT, form); + // return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to save or update organization. Error: " + e.getMessage()); + + } + // finally { + // HibernateUtil.closeSession(); + // } + // PropertyUtils.copyProperties(form, organization); + + // if (states != null) { + // form.setStates(states); + // } + + if (organization.getId() != null && !organization.getId().equals("0")) { + request.setAttribute(ID, organization.getId()); + } + + DisplayListService.getInstance().refreshList(DisplayListService.ListType.REFERRAL_ORGANIZATIONS); + DisplayListService.getInstance().refreshLists(); + + // redirectAttributes.addFlashAttribute(FWD_SUCCESS, true); + // status.setComplete(); + // return findForward(FWD_SUCCESS_INSERT, form); + return ResponseEntity.ok("Organization saved or updated successfully."); + } + + // private void setDefaultButtonAttributes(HttpServletRequest request) { + // request.setAttribute(ALLOW_EDITS_KEY, "true"); + // request.setAttribute(PREVIOUS_DISABLED, "false"); + // request.setAttribute(NEXT_DISABLED, "false"); + // } + + private void persistAddressParts(Organization organization, Map addressParts) { + OrganizationAddress departmentAddress = addressParts.get(DEPARTMENT_ADDRESS_KEY); + if (departmentAddress != null) { + organizationAddressService.save(departmentAddress); + } + + OrganizationAddress communeAddress = addressParts.get(COMMUNE_ADDRESS_KEY); + if (communeAddress != null) { + organizationAddressService.save(communeAddress); + } + OrganizationAddress villageAddress = addressParts.get(VILLAGE_ADDRESS_KEY); + if (villageAddress != null) { + organizationAddressService.save(villageAddress); + } + } + + private Map createAddressParts(OrganizationForm form, boolean isNew) { + Map addressParts = new HashMap<>(); + OrganizationAddress departmentAddress = null; + OrganizationAddress communeAddress = null; + OrganizationAddress villageAddress = null; + if (useDepartment || useCommune || useVillage) { + if (!isNew) { + List orgAddressList = organizationAddressService + .getAddressPartsByOrganizationId(form.getId()); + + for (OrganizationAddress orgAddress : orgAddressList) { + if (DEPARTMENT_ID.equals(orgAddress.getAddressPartId())) { + departmentAddress = orgAddress; + } else if (COMMUNE_ID.equals(orgAddress.getAddressPartId())) { + communeAddress = orgAddress; + } else if (VILLAGE_ID.equals(orgAddress.getAddressPartId())) { + villageAddress = orgAddress; + } + } + } + + if (useDepartment) { + if (departmentAddress == null) { + departmentAddress = new OrganizationAddress(); + departmentAddress.setAddressPartId(DEPARTMENT_ID); + departmentAddress.setType("D"); + departmentAddress.setOrganizationId(form.getId()); + } + + departmentAddress.setValue(form.getDepartment()); + departmentAddress.setSysUserId(getSysUserId(request)); + addressParts.put(DEPARTMENT_ADDRESS_KEY, departmentAddress); + } + + if (useCommune) { + if (communeAddress == null) { + communeAddress = new OrganizationAddress(); + communeAddress.setAddressPartId(COMMUNE_ID); + communeAddress.setType("T"); + communeAddress.setOrganizationId(form.getId()); + } + + communeAddress.setValue(form.getCommune()); + communeAddress.setSysUserId(getSysUserId(request)); + } + + if (useVillage) { + if (villageAddress == null) { + villageAddress = new OrganizationAddress(); + villageAddress.setAddressPartId(VILLAGE_ID); + villageAddress.setType("T"); + villageAddress.setOrganizationId(form.getId()); + } + + villageAddress.setValue(form.getVillage()); + villageAddress.setSysUserId(getSysUserId(request)); + } + } + return addressParts; + } + + private void linkOrgWithOrgType(Organization organization, List selectedOrgTypes) { + organizationService.deleteAllLinksForOrganization(organization.getId()); + + for (String typeId : selectedOrgTypes) { + organizationService.linkOrganizationAndType(organization, typeId); + } + } + + private List getPossibleStates(OrganizationForm form) { + List states = null; + if (useState) { + if (form.getStates() != null) { + states = (List) form.getStates(); + } else { + states = cityStateZipService.getAllStateCodes(); + } + } + return states; + } + + @GetMapping(value = "/CancelOrganization") + public ResponseEntity cancelOrganization(HttpServletRequest request, SessionStatus status) { + status.setComplete(); + // return findForward(FWD_CANCEL, new OrganizationForm()); + return ResponseEntity.ok("Cancellation successful"); + } + + @Override + protected String findLocalForward(String forward) { + if (FWD_SUCCESS.equals(forward)) { + return "organizationDefinition"; + } else if (FWD_FAIL.equals(forward)) { + return "redirect:/MasterListsPage"; + } else if (FWD_SUCCESS_INSERT.equals(forward)) { + return "redirect:/OrganizationMenu"; + } else if (FWD_FAIL_INSERT.equals(forward)) { + return "organizationDefinition"; + } else if (FWD_CANCEL.equals(forward)) { + return "redirect:/OrganizationMenu"; + } else { + return "PageNotFound"; + } + } + + @Override + protected String getPageTitleKey() { + return (String) request.getAttribute("key"); + } + + @Override + protected String getPageSubtitleKey() { + return (String) request.getAttribute("key"); + } +} diff --git a/src/main/java/org/openelisglobal/organization/valueholder/Organization.java b/src/main/java/org/openelisglobal/organization/valueholder/Organization.java index 1695390d4..9ddfa7127 100644 --- a/src/main/java/org/openelisglobal/organization/valueholder/Organization.java +++ b/src/main/java/org/openelisglobal/organization/valueholder/Organization.java @@ -28,6 +28,7 @@ import org.openelisglobal.common.valueholder.ValueHolder; import org.openelisglobal.common.valueholder.ValueHolderInterface; import org.openelisglobal.validation.annotations.SafeHtml; +import com.fasterxml.jackson.annotation.JsonIgnore; public class Organization extends EnumValueItemImpl implements SimpleBaseEntity { private static final long serialVersionUID = 1L; @@ -90,6 +91,7 @@ public String getId() { return id; } + @JsonIgnore public String getConcatOrganizationLocalAbbreviationName() { return organizationLocalAbbreviation + "-" + organizationName; } @@ -239,6 +241,7 @@ public void setOrganizationLocalAbbreviation(String organizationLocalAbbreviatio this.organizationLocalAbbreviation = organizationLocalAbbreviation; } + @JsonIgnore public String getDoubleName() { return shortName + " = " + organizationName; } @@ -273,6 +276,7 @@ public void setFhirUuid(UUID fhirUuid) { this.fhirUuid = fhirUuid; } + @JsonIgnore public String getFhirUuidAsString() { return fhirUuid == null ? "" : fhirUuid.toString(); } diff --git a/src/main/java/org/openelisglobal/provider/controller/rest/ProviderRestController.java b/src/main/java/org/openelisglobal/provider/controller/rest/ProviderRestController.java index 96703802d..8d468c0ba 100644 --- a/src/main/java/org/openelisglobal/provider/controller/rest/ProviderRestController.java +++ b/src/main/java/org/openelisglobal/provider/controller/rest/ProviderRestController.java @@ -1,14 +1,21 @@ package org.openelisglobal.provider.controller.rest; +import java.util.UUID; + import org.openelisglobal.person.service.PersonService; import org.openelisglobal.person.valueholder.Person; import org.openelisglobal.provider.service.ProviderService; import org.openelisglobal.provider.valueholder.Provider; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; @RestController @@ -33,4 +40,20 @@ public Person getPerson(@PathVariable String id) { Person person = personService.get(id); return person; } + + @PostMapping(value = "/Provider/FhirUuid") + @ResponseBody + public ResponseEntity insertOrUpdateProviderByFhirUuid(@RequestParam(required = false) UUID fhirUuid, + @RequestBody Provider provider) { + try { + if (fhirUuid == null) { + fhirUuid = UUID.randomUUID(); + } + Provider updatedProvider = providerService.insertOrUpdateProviderByFhirUuid(fhirUuid, provider); + return ResponseEntity.ok(updatedProvider); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error processing request."); + } + } + } diff --git a/src/main/java/org/openelisglobal/provider/service/ProviderImportServiceImpl.java b/src/main/java/org/openelisglobal/provider/service/ProviderImportServiceImpl.java index 45d8f349e..4ec4fca5a 100644 --- a/src/main/java/org/openelisglobal/provider/service/ProviderImportServiceImpl.java +++ b/src/main/java/org/openelisglobal/provider/service/ProviderImportServiceImpl.java @@ -66,7 +66,7 @@ public void importPractitionerList() throws FhirLocalPersistingException, FhirGe responseBundle = client.loadPage().next(responseBundle).execute(); responseBundles.add(responseBundle); } -// providerService.deactivateAllProviders(); + // providerService.deactivateAllProviders(); importProvidersFromBundle(client, responseBundles); } @@ -86,8 +86,7 @@ private void importProvidersFromBundle(IGenericClient client, List respo Provider provider = fhirTransformService.transformToProvider(fhirPractitioner); if (providerService.getProviderByFhirId(provider.getFhirUuid()) == null || !providerService.getProviderByFhirId(provider.getFhirUuid()).isDesynchronized()) { - providerService.insertOrUpdateProviderByFhirUuid( - fhirTransformService.transformToProvider(fhirPractitioner)); + providerService.insertOrUpdateProviderByFhirUuid(provider.getFhirUuid(), provider); remoteFhirProviders.put(fhirPractitioner.getIdElement().getIdPart(), fhirPractitioner); } @@ -102,5 +101,4 @@ private void importProvidersFromBundle(IGenericClient client, List respo fhirPersistanceService.updateFhirResourcesInFhirStore(remoteFhirProviders); } - } diff --git a/src/main/java/org/openelisglobal/provider/service/ProviderService.java b/src/main/java/org/openelisglobal/provider/service/ProviderService.java index 2777d19e1..b0b651452 100644 --- a/src/main/java/org/openelisglobal/provider/service/ProviderService.java +++ b/src/main/java/org/openelisglobal/provider/service/ProviderService.java @@ -30,5 +30,5 @@ public interface ProviderService extends BaseObjectService { void deactivateProviders(List providers); - Provider insertOrUpdateProviderByFhirUuid(Provider provider); + Provider insertOrUpdateProviderByFhirUuid(UUID fhirUuid, Provider provider); } diff --git a/src/main/java/org/openelisglobal/provider/service/ProviderServiceImpl.java b/src/main/java/org/openelisglobal/provider/service/ProviderServiceImpl.java index e770af048..0e2915ed9 100644 --- a/src/main/java/org/openelisglobal/provider/service/ProviderServiceImpl.java +++ b/src/main/java/org/openelisglobal/provider/service/ProviderServiceImpl.java @@ -122,20 +122,25 @@ public void deactivateProviders(List providers) { @Override @Transactional - public Provider insertOrUpdateProviderByFhirUuid(Provider provider) { - Provider dbProvider = getProviderByFhirId(provider.getFhirUuid()); + public Provider insertOrUpdateProviderByFhirUuid(UUID fhirUuid, Provider provider) { + Provider dbProvider = getProviderByFhirId(fhirUuid); + if (dbProvider != null) { dbProvider.setActive(provider.getActive()); dbProvider.getPerson().setLastName(provider.getPerson().getLastName()); dbProvider.getPerson().setMiddleName(provider.getPerson().getMiddleName()); dbProvider.getPerson().setFirstName(provider.getPerson().getFirstName()); - dbProvider.getPerson().setEmail(provider.getPerson().getEmail()); dbProvider.getPerson().setPrimaryPhone(provider.getPerson().getPrimaryPhone()); dbProvider.getPerson().setWorkPhone(provider.getPerson().getWorkPhone()); dbProvider.getPerson().setFax(provider.getPerson().getFax()); dbProvider.getPerson().setCellPhone(provider.getPerson().getCellPhone()); + dbProvider = save(dbProvider); } else { + if (fhirUuid == null) { + fhirUuid = UUID.randomUUID(); + } + provider.setFhirUuid(fhirUuid); provider.getPerson().setSysUserId("1"); provider.setPerson(personService.save(provider.getPerson())); provider.setSysUserId("1"); @@ -143,4 +148,5 @@ public Provider insertOrUpdateProviderByFhirUuid(Provider provider) { } return dbProvider; } + } diff --git a/src/main/java/org/openelisglobal/provider/valueholder/Provider.java b/src/main/java/org/openelisglobal/provider/valueholder/Provider.java index 4a0d43490..eaf3c1bd5 100644 --- a/src/main/java/org/openelisglobal/provider/valueholder/Provider.java +++ b/src/main/java/org/openelisglobal/provider/valueholder/Provider.java @@ -23,6 +23,8 @@ import org.openelisglobal.common.valueholder.ValueHolderInterface; import org.openelisglobal.person.valueholder.Person; +import com.fasterxml.jackson.annotation.JsonIgnore; + public class Provider extends BaseObject implements DesynchronousCapable { private String id; diff --git a/src/main/java/org/openelisglobal/result/action/util/ResultUtil.java b/src/main/java/org/openelisglobal/result/action/util/ResultUtil.java index e787dcc35..a1d8a9541 100644 --- a/src/main/java/org/openelisglobal/result/action/util/ResultUtil.java +++ b/src/main/java/org/openelisglobal/result/action/util/ResultUtil.java @@ -16,10 +16,14 @@ */ package org.openelisglobal.result.action.util; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.commons.validator.GenericValidator; import org.openelisglobal.analysis.valueholder.Analysis; +import org.openelisglobal.analyte.valueholder.Analyte; import org.openelisglobal.dictionary.service.DictionaryService; import org.openelisglobal.result.valueholder.Result; import org.openelisglobal.spring.util.SpringContext; @@ -77,6 +81,50 @@ public static TestAnalyte getTestAnalyteForResult(Result result) { return null; } + /* + * The logic behind this code is that there are some other matching analytes for a specific result other than + * the Analyte fetched by getTestAnalyteForResult which is set to a Result + */ + @SuppressWarnings("unchecked") + public static List getOtherAnalyteForResult(Result result) { + List otherAnalyte = new ArrayList<>(); + if (result.getTestResult() != null) { + List testAnalyteList = testAnalyteService + .getAllTestAnalytesPerTest(result.getTestResult().getTest()); + if (testAnalyteList == null) { + return otherAnalyte; // or handle the null case appropriately + } + + Set othertestAnalyteList = new HashSet<>(); + Analyte defaultAnalyte = result.getAnalyte(); + if (defaultAnalyte == null) { + return otherAnalyte; + } + if (testAnalyteList.size() == 1) { + return otherAnalyte; + } + + if (testAnalyteList.size() > 1) { + + Analysis parentAnalysis = result.getAnalysis().getParentAnalysis(); + + if (parentAnalysis == null) { + testAnalyteList.forEach(ta -> { + if (!ta.getAnalyte().getId().equals(defaultAnalyte.getId())) { + othertestAnalyteList.add(ta); + } + }); + } + othertestAnalyteList.forEach(a -> { + otherAnalyte.add(a.getAnalyte()); + }); + + return otherAnalyte; + } + } + return otherAnalyte; + } + public static boolean areNotes(TestResultItem item) { return !GenericValidator.isBlankOrNull(item.getNote()); } diff --git a/src/main/java/org/openelisglobal/result/controller/rest/LogbookResultsRestController.java b/src/main/java/org/openelisglobal/result/controller/rest/LogbookResultsRestController.java index d91d32e74..b03d1aecc 100644 --- a/src/main/java/org/openelisglobal/result/controller/rest/LogbookResultsRestController.java +++ b/src/main/java/org/openelisglobal/result/controller/rest/LogbookResultsRestController.java @@ -310,6 +310,9 @@ private LogbookResultsForm getLogbookResults(HttpServletRequest request, Logbook patient = getPatient(sample); tests = resultsLoadUtility.getGroupedTestsForSample(sample, patient); + patientName = patientService.getLastFirstName(patient); + patientInfo = patient.getNationalId() + ", " + patient.getGender() + ", " + + patient.getBirthDateForDisplay(); } } diff --git a/src/main/java/org/openelisglobal/result/service/LogbookPersistServiceImpl.java b/src/main/java/org/openelisglobal/result/service/LogbookPersistServiceImpl.java index ceb49f25f..982e4317b 100644 --- a/src/main/java/org/openelisglobal/result/service/LogbookPersistServiceImpl.java +++ b/src/main/java/org/openelisglobal/result/service/LogbookPersistServiceImpl.java @@ -167,14 +167,14 @@ private void saveReferralsWithRequiredObjects(ReferralSet referralSet, String sy protected List setTestReflexes(ResultsUpdateDataSet actionDataSet, String sysUserId) { TestReflexUtil testReflexUtil = new TestReflexUtil(); - TestCalculatedUtil testCallatedUtil = new TestCalculatedUtil(); + TestCalculatedUtil testCaliculatedUtil = new TestCalculatedUtil(); List allResults = actionDataSet.getNewResults(); allResults.addAll(actionDataSet.getModifiedResults()); List reflexAnalysises = testReflexUtil .addNewTestsToDBForReflexTests(convertToTestReflexBeanList(allResults), sysUserId); testReflexUtil.updateModifiedReflexes(convertToTestReflexBeanList(actionDataSet.getModifiedResults()), sysUserId); - List caclculatedAnalyses = testCallatedUtil.addNewTestsToDBForCalculatedTests(allResults, sysUserId) ; + List caclculatedAnalyses = testCaliculatedUtil.addNewTestsToDBForCalculatedTests(allResults, sysUserId) ; reflexAnalysises.addAll(caclculatedAnalyses); return reflexAnalysises; } diff --git a/src/main/java/org/openelisglobal/testcalculated/action/util/TestCalculatedUtil.java b/src/main/java/org/openelisglobal/testcalculated/action/util/TestCalculatedUtil.java index 55d1e8610..d99f2931c 100644 --- a/src/main/java/org/openelisglobal/testcalculated/action/util/TestCalculatedUtil.java +++ b/src/main/java/org/openelisglobal/testcalculated/action/util/TestCalculatedUtil.java @@ -106,7 +106,7 @@ public List addNewTestsToDBForCalculatedTests(List resultSe tests.forEach(test -> { map.put(Integer.valueOf(test.getId()), null); }); - // insert innitail result value + // insert innitial result value map.put(Integer.valueOf(resultSet.result.getTestResult().getTest().getId()), Integer.valueOf(resultSet.result.getId())); calc.setTestResultMap(map); @@ -334,7 +334,11 @@ private void addNumericOperation(Operation operation, ResultCalculation resultCa Test test = testService.getActiveTestById(Integer.valueOf(operation.getValue())); if (test != null) { Integer resultId = resultCalculation.getTestResultMap().get(Integer.valueOf(test.getId())); - Result result = resultService.get(resultId.toString()); + Result result = null; + if(resultId != null){ + result = resultService.get(resultId.toString()); + } + if (result != null) { if (testService.getResultType(result.getTestResult().getTest()).equals("N")) { switch (inputType) { diff --git a/src/main/java/org/openelisglobal/testcalculated/valueholder/Operation.java b/src/main/java/org/openelisglobal/testcalculated/valueholder/Operation.java index d735e17b9..ab216127b 100644 --- a/src/main/java/org/openelisglobal/testcalculated/valueholder/Operation.java +++ b/src/main/java/org/openelisglobal/testcalculated/valueholder/Operation.java @@ -32,6 +32,8 @@ public class Operation implements Comparable{ public final static String LESS_OR_EQUALS = "<="; public final static String IN_NORMAL_RANGE = "IS_IN_NORMAL_RANGE"; public final static String OUTSIDE_NORMAL_RANGE = "IS_OUTSIDE_NORMAL_RANGE"; + public final static String LOGICAL_AND = "&&"; + public final static String LOGICAL_OR = "||"; // constants public final static String TEST_RESULT = "TEST_RESULT"; @@ -150,6 +152,8 @@ public static List mathFunctions(){ mathFunctions.add(new IdValuePair(LESS_OR_EQUALS ,"Is Less Than Or Equal")); mathFunctions.add(new IdValuePair(IN_NORMAL_RANGE ,"Is With In Normal Range")); mathFunctions.add(new IdValuePair(OUTSIDE_NORMAL_RANGE ,"Is Out Side Normal Range")); + mathFunctions.add(new IdValuePair(LOGICAL_AND ,"And")); + mathFunctions.add(new IdValuePair(LOGICAL_OR ,"Or")); return mathFunctions; } diff --git a/src/main/java/org/openelisglobal/testreflex/action/util/TestReflexResolver.java b/src/main/java/org/openelisglobal/testreflex/action/util/TestReflexResolver.java index 89912806c..f972dcd9a 100644 --- a/src/main/java/org/openelisglobal/testreflex/action/util/TestReflexResolver.java +++ b/src/main/java/org/openelisglobal/testreflex/action/util/TestReflexResolver.java @@ -22,8 +22,11 @@ import org.openelisglobal.analysis.service.AnalysisService; import org.openelisglobal.analysis.valueholder.Analysis; +import org.openelisglobal.analyte.valueholder.Analyte; +import org.openelisglobal.common.log.LogEvent; import org.openelisglobal.common.services.IStatusService; import org.openelisglobal.common.services.StatusService.AnalysisStatus; +import org.openelisglobal.result.action.util.ResultUtil; import org.openelisglobal.result.service.ResultService; import org.openelisglobal.result.valueholder.Result; import org.openelisglobal.sample.valueholder.Sample; @@ -74,6 +77,18 @@ public List getTestReflexesForResult(Result result) { List reflexes = testReflexService.getTestReflexsByTestResultAnalyteTest(testResultId, analyteId, testId); + // try to check if there other analyte macthicng for this result + List otherMatchingAnalyte = ResultUtil.getOtherAnalyteForResult(result); + if (otherMatchingAnalyte != null) { + if (!otherMatchingAnalyte.isEmpty()) { + for (Analyte otherAnalyte : otherMatchingAnalyte) { + reflexes.addAll( + testReflexService.getTestReflexsByTestResultAnalyteTest(testResultId, otherAnalyte.getId(), + testId)); + } + } + } + return reflexes != null ? reflexes : new ArrayList<>(); } @@ -86,6 +101,17 @@ public List getTestReflexsByAnalyteAndTest(Result result) { } List reflexes = testReflexService.getTestReflexsByAnalyteAndTest(analyteId, testId); + // try to check if there other analyte macthicng for this result + List otherMatchingAnalyte = ResultUtil.getOtherAnalyteForResult(result); + if (otherMatchingAnalyte != null) { + if (!otherMatchingAnalyte.isEmpty()) { + for (Analyte otherAnalyte : otherMatchingAnalyte) { + reflexes.addAll( + testReflexService.getTestReflexsByAnalyteAndTest(otherAnalyte.getId(), + testId)); + } + } + } return reflexes != null ? reflexes : new ArrayList<>(); } diff --git a/src/main/java/org/openelisglobal/testreflex/daoimpl/TestReflexDAOImpl.java b/src/main/java/org/openelisglobal/testreflex/daoimpl/TestReflexDAOImpl.java index 017b832bf..26b7d702f 100644 --- a/src/main/java/org/openelisglobal/testreflex/daoimpl/TestReflexDAOImpl.java +++ b/src/main/java/org/openelisglobal/testreflex/daoimpl/TestReflexDAOImpl.java @@ -263,7 +263,14 @@ public boolean duplicateTestReflexExists(TestReflex testReflex) throws LIMSRunti + "and t.id != :testId"; if (testReflex.getActionScriptlet() != null) { - sql = sql + "or trim(lower(t.actionScriptlet.scriptletName)) = :scriptletName "; + sql = sql + " or trim(lower(t.actionScriptlet.scriptletName)) = :scriptletName "; + } + if(testReflex.getRelation() != null){ + sql = sql + " and t.relation = :relation"; + } + + if(testReflex.getNonDictionaryValue() != null){ + sql = sql + " and t.nonDictionaryValue = :nonDictionaryValue"; } Query query = entityManager.unwrap(Session.class).createQuery(sql, TestReflex.class); @@ -280,7 +287,13 @@ public boolean duplicateTestReflexExists(TestReflex testReflex) throws LIMSRunti if (testReflex.getActionScriptlet() != null) { query.setParameter("scriptletName", testReflex.getActionScriptlet().getScriptletName().toLowerCase().trim()); } + if(testReflex.getRelation() != null){ + query.setParameter("relation", testReflex.getRelation().toString()); + } + if(testReflex.getNonDictionaryValue() != null){ + query.setParameter("nonDictionaryValue", testReflex.getNonDictionaryValue()); + } query.setParameter("testId", Integer.parseInt(testReflexId)); list = query.list(); diff --git a/src/test/java/org/openelisglobal/dictionary/rest/controller/DictionaryMenuRestControllerTest.java b/src/test/java/org/openelisglobal/dictionary/rest/controller/DictionaryMenuRestControllerTest.java index 34fec22b9..f57209afd 100644 --- a/src/test/java/org/openelisglobal/dictionary/rest/controller/DictionaryMenuRestControllerTest.java +++ b/src/test/java/org/openelisglobal/dictionary/rest/controller/DictionaryMenuRestControllerTest.java @@ -40,14 +40,13 @@ public void setUp() { @Test public void getDictionaryMenuList_shouldReturnDictionaryMenu() throws Exception { MvcResult mvcResult = super.mockMvc.perform( - get("/rest/dictionary-menu") + get("/rest/DictionaryMenu") .accept(MediaType.APPLICATION_JSON_VALUE) .contentType(MediaType.APPLICATION_JSON_VALUE)).andReturn(); int status = mvcResult.getResponse().getStatus(); assertEquals(200, status); String content = mvcResult.getResponse().getContentAsString(); - System.out.println("menuList: " + content); List menuList = Arrays.asList(super.mapFromJson(content, DictionaryMenuForm[].class)); assertThat(menuList.get(0).getMenuList().get(0).getId(), is("1")); assertThat(menuList.get(0).getMenuList().get(0).getIsActive(), is("Y")); @@ -67,7 +66,6 @@ public void fetchDictionaryCategories_shouldFetchDictionaryDescriptions() throws assertEquals(200, status); String content = mvcResult.getResponse().getContentAsString(); List menuList = Arrays.asList(super.mapFromJson(content, DictionaryCategory[].class)); - System.out.println("dictionary categories: " + menuList); assertThat(menuList, notNullValue()); } @@ -92,7 +90,7 @@ public void fetchDictionaryCategories_shouldFetchDictionaryDescriptions() throws @Test public void showDeleteDictionary_shouldSuccessfullyDeleteDictionary() throws Exception { - MvcResult getMenu = super.mockMvc.perform(get("/rest/dictionary-menu").accept(MediaType.APPLICATION_JSON_VALUE) + MvcResult getMenu = super.mockMvc.perform(get("/rest/DictionaryMenu").accept(MediaType.APPLICATION_JSON_VALUE) .contentType(MediaType.APPLICATION_JSON_VALUE)).andReturn(); int status = getMenu.getResponse().getStatus();