diff --git a/cds_ils/config.py b/cds_ils/config.py index 07911d740..a3e120da7 100644 --- a/cds_ils/config.py +++ b/cds_ils/config.py @@ -540,6 +540,7 @@ def _parse_env_bool(var_name, default=None): "series_url_access_restriction", "tag", "item_identifier_scheme", + "shelf_number", ] ############################################################################### diff --git a/cds_ils/vocabularies/data/shelf_numbers.json b/cds_ils/vocabularies/data/shelf_numbers.json new file mode 100644 index 000000000..d7c441882 --- /dev/null +++ b/cds_ils/vocabularies/data/shelf_numbers.json @@ -0,0 +1,127 @@ +[ + { "type": "shelf_number", "key": "01", "text": "SHELF 01" }, + { "type": "shelf_number", "key": "02", "text": "SHELF 02" }, + { "type": "shelf_number", "key": "03", "text": "SHELF 03" }, + { "type": "shelf_number", "key": "04", "text": "SHELF 04" }, + { "type": "shelf_number", "key": "05", "text": "SHELF 05" }, + { "type": "shelf_number", "key": "06", "text": "SHELF 06" }, + { "type": "shelf_number", "key": "07", "text": "SHELF 07" }, + { "type": "shelf_number", "key": "08", "text": "SHELF 08" }, + { "type": "shelf_number", "key": "09", "text": "SHELF 09" }, + { "type": "shelf_number", "key": "10", "text": "SHELF 10" }, + { "type": "shelf_number", "key": "11", "text": "SHELF 11" }, + { "type": "shelf_number", "key": "12", "text": "SHELF 12" }, + { "type": "shelf_number", "key": "13", "text": "SHELF 13" }, + { "type": "shelf_number", "key": "14", "text": "SHELF 14" }, + { "type": "shelf_number", "key": "15", "text": "SHELF 15" }, + { "type": "shelf_number", "key": "16", "text": "SHELF 16" }, + { "type": "shelf_number", "key": "17", "text": "SHELF 17" }, + { "type": "shelf_number", "key": "18", "text": "SHELF 18" }, + { "type": "shelf_number", "key": "19", "text": "SHELF 19" }, + { "type": "shelf_number", "key": "20", "text": "SHELF 20" }, + { "type": "shelf_number", "key": "21", "text": "SHELF 21" }, + { "type": "shelf_number", "key": "22", "text": "SHELF 22" }, + { "type": "shelf_number", "key": "23", "text": "SHELF 23" }, + { "type": "shelf_number", "key": "24", "text": "SHELF 24" }, + { "type": "shelf_number", "key": "25", "text": "SHELF 25" }, + { "type": "shelf_number", "key": "26", "text": "SHELF 26" }, + { "type": "shelf_number", "key": "27", "text": "SHELF 27" }, + { "type": "shelf_number", "key": "28", "text": "SHELF 28" }, + { "type": "shelf_number", "key": "29", "text": "SHELF 29" }, + { "type": "shelf_number", "key": "30", "text": "SHELF 30" }, + { "type": "shelf_number", "key": "31", "text": "SHELF 31" }, + { "type": "shelf_number", "key": "32", "text": "SHELF 32" }, + { "type": "shelf_number", "key": "33", "text": "SHELF 33" }, + { "type": "shelf_number", "key": "34", "text": "SHELF 34" }, + { "type": "shelf_number", "key": "35", "text": "SHELF 35" }, + { "type": "shelf_number", "key": "36", "text": "SHELF 36" }, + { "type": "shelf_number", "key": "37", "text": "SHELF 37" }, + { "type": "shelf_number", "key": "38", "text": "SHELF 38" }, + { "type": "shelf_number", "key": "39", "text": "SHELF 39" }, + { "type": "shelf_number", "key": "40", "text": "SHELF 40" }, + { "type": "shelf_number", "key": "41", "text": "SHELF 41" }, + { "type": "shelf_number", "key": "42", "text": "SHELF 42" }, + { "type": "shelf_number", "key": "43", "text": "SHELF 43" }, + { "type": "shelf_number", "key": "44", "text": "SHELF 44" }, + { "type": "shelf_number", "key": "45", "text": "SHELF 45" }, + { "type": "shelf_number", "key": "46", "text": "SHELF 46" }, + { "type": "shelf_number", "key": "47", "text": "SHELF 47" }, + { "type": "shelf_number", "key": "48", "text": "SHELF 48" }, + { "type": "shelf_number", "key": "49", "text": "SHELF 49" }, + { "type": "shelf_number", "key": "50", "text": "SHELF 50" }, + { "type": "shelf_number", "key": "51", "text": "SHELF 51" }, + { "type": "shelf_number", "key": "52", "text": "SHELF 52" }, + { "type": "shelf_number", "key": "53", "text": "SHELF 53" }, + { "type": "shelf_number", "key": "54", "text": "SHELF 54" }, + { "type": "shelf_number", "key": "55", "text": "SHELF 55" }, + { "type": "shelf_number", "key": "56", "text": "SHELF 56" }, + { "type": "shelf_number", "key": "57", "text": "SHELF 57" }, + { "type": "shelf_number", "key": "58", "text": "SHELF 58" }, + { "type": "shelf_number", "key": "59", "text": "SHELF 59" }, + { "type": "shelf_number", "key": "60", "text": "SHELF 60" }, + { "type": "shelf_number", "key": "61", "text": "SHELF 61" }, + { "type": "shelf_number", "key": "62", "text": "SHELF 62" }, + { "type": "shelf_number", "key": "63", "text": "SHELF 63" }, + { "type": "shelf_number", "key": "64", "text": "SHELF 64" }, + { "type": "shelf_number", "key": "65", "text": "SHELF 65" }, + { "type": "shelf_number", "key": "66", "text": "SHELF 66" }, + { "type": "shelf_number", "key": "67", "text": "SHELF 67" }, + { "type": "shelf_number", "key": "68", "text": "SHELF 68" }, + { "type": "shelf_number", "key": "69", "text": "SHELF 69" }, + { "type": "shelf_number", "key": "70", "text": "SHELF 70" }, + { "type": "shelf_number", "key": "71", "text": "SHELF 71" }, + { "type": "shelf_number", "key": "72", "text": "SHELF 72" }, + { "type": "shelf_number", "key": "73", "text": "SHELF 73" }, + { "type": "shelf_number", "key": "74", "text": "SHELF 74" }, + { "type": "shelf_number", "key": "75", "text": "SHELF 75" }, + { "type": "shelf_number", "key": "77", "text": "SHELF 77" }, + { "type": "shelf_number", "key": "78", "text": "SHELF 78" }, + { "type": "shelf_number", "key": "79", "text": "SHELF 79" }, + { "type": "shelf_number", "key": "80", "text": "SHELF 80" }, + { "type": "shelf_number", "key": "81", "text": "SHELF 81" }, + { "type": "shelf_number", "key": "82", "text": "SHELF 82" }, + { "type": "shelf_number", "key": "83", "text": "SHELF 83" }, + { "type": "shelf_number", "key": "84", "text": "SHELF 84" }, + { "type": "shelf_number", "key": "85", "text": "SHELF 85" }, + { "type": "shelf_number", "key": "86", "text": "SHELF 86" }, + { "type": "shelf_number", "key": "87", "text": "SHELF 87" }, + { "type": "shelf_number", "key": "88", "text": "SHELF 88" }, + { "type": "shelf_number", "key": "89", "text": "SHELF 89" }, + { "type": "shelf_number", "key": "90", "text": "SHELF 90" }, + { "type": "shelf_number", "key": "91", "text": "SHELF 91" }, + { "type": "shelf_number", "key": "92", "text": "SHELF 92" }, + { "type": "shelf_number", "key": "93", "text": "SHELF 93" }, + { "type": "shelf_number", "key": "94", "text": "SHELF 94" }, + { "type": "shelf_number", "key": "95", "text": "SHELF 95" }, + { "type": "shelf_number", "key": "96", "text": "SHELF 96" }, + { "type": "shelf_number", "key": "97", "text": "SHELF 97" }, + { "type": "shelf_number", "key": "98", "text": "SHELF 98" }, + { "type": "shelf_number", "key": "99", "text": "SHELF 99" }, + { "type": "shelf_number", "key": "100", "text": "SHELF 100" }, + { "type": "shelf_number", "key": "101", "text": "SHELF 101" }, + { "type": "shelf_number", "key": "102", "text": "SHELF 102" }, + { "type": "shelf_number", "key": "103", "text": "SHELF 103" }, + { "type": "shelf_number", "key": "104", "text": "SHELF 104" }, + { "type": "shelf_number", "key": "105", "text": "SHELF 105" }, + { "type": "shelf_number", "key": "106", "text": "SHELF 106" }, + { "type": "shelf_number", "key": "107", "text": "SHELF 107" }, + { "type": "shelf_number", "key": "108", "text": "SHELF 108" }, + { "type": "shelf_number", "key": "109", "text": "SHELF 109" }, + { "type": "shelf_number", "key": "110", "text": "SHELF 110" }, + { "type": "shelf_number", "key": "111", "text": "SHELF 111" }, + { "type": "shelf_number", "key": "112", "text": "SHELF 112" }, + { "type": "shelf_number", "key": "113", "text": "SHELF 113" }, + { "type": "shelf_number", "key": "114", "text": "SHELF 114" }, + { "type": "shelf_number", "key": "115", "text": "SHELF 115" }, + { "type": "shelf_number", "key": "116", "text": "SHELF 116" }, + { "type": "shelf_number", "key": "117", "text": "SHELF 117" }, + { "type": "shelf_number", "key": "118", "text": "SHELF 118" }, + { "type": "shelf_number", "key": "119", "text": "SHELF 119" }, + { "type": "shelf_number", "key": "120", "text": "SHELF 120" }, + { "type": "shelf_number", "key": "121", "text": "SHELF 121" }, + { "type": "shelf_number", "key": "122", "text": "SHELF 122" }, + { "type": "shelf_number", "key": "123", "text": "SHELF 123" }, + { "type": "shelf_number", "key": "124", "text": "SHELF 124" }, + { "type": "shelf_number", "key": "125", "text": "SHELF 125" }, + { "type": "shelf_number", "key": "126", "text": "SHELF 126" } +] diff --git a/ui/src/config.js b/ui/src/config.js index 59447401c..809e2f975 100644 --- a/ui/src/config.js +++ b/ui/src/config.js @@ -71,6 +71,11 @@ export const config = { doc_req_payment_method: "doc_req_payment_method", doc_req_medium: "doc_req_medium", }, + item: { + identifier: { + scheme: "item_identifier_scheme", + }, + }, }, DOCUMENTS: { extensions: { @@ -205,88 +210,15 @@ export const config = { "circulation_restriction", "medium", ], - properties: { - identifiers: { - items: { - properties: { - scheme: { - title: "Scheme name", - type: "string", - }, - value: { - title: "Value", - type: "string", - }, - }, - required: ["scheme", "value"], - title: "Identifier", - type: "object", - }, - title: "Identifiers", - type: "array", - }, - }, }, editorUiSchema: { - "identifiers": { + shelf: { + "ui:widget": "vocabulary", "ui:options": { - orderable: false, - }, - "items": { - "scheme": { - "ui:widget": "vocabulary", - "ui:options": { - vocabularyType: "item_identifier_scheme", - }, - }, - "custom:grid": [ - { - scheme: 8, - value: 8, - }, - ], + size: 125, // Make sure to update size when adding new shelfs + vocabularyType: "shelf_number", }, }, - "custom:grid": [ - { - barcode: 4, - medium: 4, - document_pid: 8, - }, - { - status: 4, - circulation_restriction: 4, - number_of_pages: 2, - description: 6, - }, - { - "custom:divider": 16, - }, - { - isbns: 10, - internal_notes: 6, - }, - { - "custom:divider": 16, - }, - { - internal_location_pid: 8, - shelf: 8, - }, - { - "custom:divider": 16, - }, - { - acquisition_pid: 6, - price: 10, - }, - { - "custom:divider": 16, - }, - { - identifiers: 10, - }, - ], }, mediums: [ { diff --git a/ui/src/overridableMapping.js b/ui/src/overridableMapping.js index 729989847..b6c6d1ae0 100644 --- a/ui/src/overridableMapping.js +++ b/ui/src/overridableMapping.js @@ -36,7 +36,7 @@ import { DocumentCirculationExtras } from "./overridden/frontsite/Document/Docum import { OpeningHoursDetails } from "./overridden/frontsite/OpeningHours/OpeningHoursDetails"; import { PaymentInformationGrid } from "./overridden/backoffice/PaymentInformation/PaymentInformation"; import { OrderDetailsLine } from "./overridden/backoffice/Acquisition/OrderDetails"; -import { ItemDetailsMetadata } from "./overridden/backoffice/Items/ItemDetailsMetadata"; +import { ItemCirculationShelf } from "./overridden/backoffice/Items/ItemCirculationShelf"; export const overriddenCmps = { "Backoffice.PatronDetails.Metadata": PatronMetadata, @@ -70,5 +70,5 @@ export const overriddenCmps = { "Backoffice.PaymentInformation": PaymentInformationGrid, "Acquisition.OrderLine": OrderDetailsLine, "DocumentCirculation.Extras": DocumentCirculationExtras, - "ItemMetadata": ItemDetailsMetadata, + "ItemCirculation.backoffice.shelf": ItemCirculationShelf, }; diff --git a/ui/src/overridden/backoffice/Items/ItemCirculationShelf.js b/ui/src/overridden/backoffice/Items/ItemCirculationShelf.js new file mode 100644 index 000000000..132c9ff2e --- /dev/null +++ b/ui/src/overridden/backoffice/Items/ItemCirculationShelf.js @@ -0,0 +1,37 @@ +import React from "react"; +import { Grid, Embed, Button, Icon } from "semantic-ui-react"; +import PropTypes from "prop-types"; +import { shelfLink } from "../../utils"; + +export const ItemCirculationShelf = ({ metadata }) => { + return ( + + <> + + + + + ); +}; + +ItemCirculationShelf.propTypes = { + metadata: PropTypes.object.isRequired, +}; diff --git a/ui/src/overridden/backoffice/Items/ItemDetailsMetadata.js b/ui/src/overridden/backoffice/Items/ItemDetailsMetadata.js deleted file mode 100644 index 968f1c549..000000000 --- a/ui/src/overridden/backoffice/Items/ItemDetailsMetadata.js +++ /dev/null @@ -1,72 +0,0 @@ -import { ItemMetadata } from "@inveniosoftware/react-invenio-app-ils"; -import React from "react"; -import { parametrize } from "react-overridable"; -import _isEmpty from "lodash/isEmpty"; -import capitalize from "lodash/capitalize"; -import { List } from "semantic-ui-react"; -import ShowMore from "react-show-more"; -import { getDisplayVal } from "../../utils"; - -function rightMetadata(itemDetails) { - const leftColumn = [ - { - name: "Status", - value: getDisplayVal("ITEMS.statuses", itemDetails.metadata.status), - }, - { - name: "Loan restrictions", - value: getDisplayVal( - "ITEMS.circulationRestrictions", - itemDetails.metadata.circulation_restriction - ), - }, - { - name: "Description", - value: ( - - {itemDetails.metadata.description || "-"} - - ), - }, - { - name: "Internal notes", - value: ( - - {itemDetails.metadata.internal_notes || "-"} - - ), - }, - ]; - const itemIdentifiers = itemDetails.metadata.identifiers; - if (!_isEmpty(itemIdentifiers)) { - leftColumn.push({ - name: "Identifiers", - value: ( - - {itemIdentifiers.map((entry) => ( - - - {entry.value + " (" + capitalize(entry.scheme).replace("_", " ") + ")"} - - - ))} - - ), - }); - } - return leftColumn; -} - -export const ItemDetailsMetadata = parametrize(ItemMetadata, { - rightMetadataColumn: rightMetadata, -}); diff --git a/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentCirculationExtras.js b/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentCirculationExtras.js index 2714ef409..90ffbfd30 100644 --- a/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentCirculationExtras.js +++ b/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentCirculationExtras.js @@ -1,27 +1,84 @@ import React from "react"; -import { Embed, Header, Button } from "semantic-ui-react"; +import _get from "lodash/get"; +import _isEmpty from "lodash/isEmpty"; +import { invenioConfig } from "@inveniosoftware/react-invenio-app-ils"; +import { Embed, Header, Button, Divider } from "semantic-ui-react"; +import PropTypes from "prop-types"; import { shelfLink } from "../../../utils"; +function canCirculateItem(item) { + return invenioConfig.ITEMS.canCirculateStatuses.includes(item.status); +} + +function isItemForReference(item) { + return invenioConfig.ITEMS.referenceStatuses.includes(item.status); +} + +function getLoanableItemShelf(locations) { + const locationEntries = Object.entries(locations); + if (_isEmpty(locationEntries)) return {}; + + var allRelevantItems = []; + + locationEntries.forEach(([locationName, internalLocations]) => { + const internalLocationEntries = Object.entries(internalLocations); + + internalLocationEntries.forEach(([internalLocationName, items]) => { + if (internalLocationName === "total") return; + + const relevantItems = items.filter( + (item) => canCirculateItem(item) || isItemForReference(item) + ); + allRelevantItems = allRelevantItems.concat(relevantItems); + }); + }); + + for (const item of allRelevantItems) { + const itemStatus = _get(item, "circulation.state"); + // If item is not on loan, return item's shelf value + if (!invenioConfig.CIRCULATION.loanActiveStates.includes(itemStatus)) { + return item.shelf; + } + } + return null; +} + export class DocumentCirculationExtras extends React.Component { render() { + const { + documentDetails: { + metadata: { + items: { on_shelf: onShelf }, + circulation: { available_items_for_loan_count: availableItems }, + }, + }, + } = this.props; + if (_isEmpty(onShelf) || availableItems === 0) { + return null; + } + + const shelfNumber = getLoanableItemShelf(onShelf); + if (shelfNumber === null || shelfNumber === undefined) { + // If no item can be loaned, don't display the cernmaps iframe + return null; + } + return ( -
-
+ <> + +
-
+ ); } } + +DocumentCirculationExtras.propTypes = { + documentDetails: PropTypes.object.isRequired, +}; diff --git a/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentItemBody.js b/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentItemBody.js index 0ce47c9b3..e81c0284b 100644 --- a/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentItemBody.js +++ b/ui/src/overridden/frontsite/Document/DocumentDetails/DocumentItemBody.js @@ -1,5 +1,9 @@ import React from "react"; -import { DocumentItemBody, InfoPopup } from "@inveniosoftware/react-invenio-app-ils"; +import { + DocumentItemBody, + InfoPopup, + invenioConfig, +} from "@inveniosoftware/react-invenio-app-ils"; import _get from "lodash/get"; import { parametrize } from "react-overridable"; import { shelfLink, shelfLinkComponent } from "../../../utils"; @@ -17,11 +21,15 @@ function renderCallNumber(item) { function renderShelflink(item) { const shelfNumber = _get(item, "shelf"); - if (shelfNumber === undefined) return; - const itemShelfLink = shelfLink(shelfNumber); + const itemStatus = _get(item, "circulation.state"); + + // If item is on loan, don't hyperlink the shelf + var itemShelf = invenioConfig.CIRCULATION.loanActiveStates.includes(itemStatus) + ? shelfNumber + : shelfLinkComponent(shelfLink(shelfNumber), shelfNumber); return ( - {shelfLinkComponent(itemShelfLink, shelfNumber)} + {itemShelf != undefined ? itemShelf : "-"} ); }