diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67c56f59c..bc9bdfe4b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -86,6 +86,7 @@ UIIN-3437.
* Wrong message is displayed after updating ownership of item. Fixes UIIN-3560.
* When moving item within one holding manually, recalculate other item orders based on their position in the list. Fixes UIIN-3539.
* Handle audit-marc dependency: hide audit button. Refs UIIN-3576.
+* Include additional call numbers in Version History for Inventory Item. Refs UIIN-3558.
## [13.0.10](https://github.com/folio-org/ui-inventory/tree/v13.0.10) (2025-09-01)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v13.0.9...v13.0.10)
diff --git a/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.js b/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.js
index 3254e94b0..d35de7b80 100644
--- a/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.js
+++ b/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.js
@@ -58,6 +58,32 @@ export const createFieldFormatter = (referenceData, circulationHistory) => ({
},
});
+export const createItemFormatter = (fieldLabelsMap, fieldFormatter) => (element, i) => {
+ if (!element) return null;
+
+ const { name: fieldName, value, collectionName } = element;
+ const compositeKey = collectionName && fieldName
+ ? `${collectionName}.${fieldName}`
+ : null;
+
+ const label = (compositeKey && fieldLabelsMap?.[compositeKey])
+ || fieldLabelsMap?.[fieldName]
+ || fieldLabelsMap?.[collectionName];
+
+ const formattedValue = (compositeKey && fieldFormatter?.[compositeKey]?.(value))
+ || fieldFormatter?.[fieldName]?.(value)
+ || fieldFormatter?.[collectionName]?.(value)
+ || value;
+
+ return (
+
+ {fieldName && {label}: }
+ {formattedValue}
+
+ );
+};
+
+
const ItemVersionHistory = ({
item,
onClose,
@@ -137,9 +163,21 @@ const ItemVersionHistory = ({
typeId: formatMessage({ id: 'ui-inventory.effectiveCallNumberType' }),
volume: formatMessage({ id: 'ui-inventory.volume' }),
yearCaption: formatMessage({ id: 'ui-inventory.yearCaption' }),
+ additionalCallNumbers: formatMessage({ id: 'ui-inventory.additionalCallNumbers' }),
+ 'additionalCallNumbers.prefix': formatMessage({ id: 'ui-inventory.additionalCallNumberPrefix' }),
+ 'additionalCallNumbers.suffix': formatMessage({ id: 'ui-inventory.additionalCallNumberSuffix' }),
+ 'additionalCallNumbers.typeId': formatMessage({ id: 'ui-inventory.additionalCallNumberType' }),
+ 'additionalCallNumbers.callNumber': formatMessage({ id: 'ui-inventory.additionalCallNumber' }),
+ 'circulationNotes.noteType': formatMessage({ id: 'ui-inventory.noteType' }),
+ 'circulationNotes.note': formatMessage({ id: 'ui-inventory.note' }),
+ 'circulationNotes.id': formatMessage({ id: 'ui-inventory.identifier' }),
+ 'circulationNotes.date': formatMessage({ id: 'ui-inventory.date' }),
+ 'circulationNotes.staffOnly': formatMessage({ id: 'ui-inventory.staffOnly' }),
+ 'circulationNotes.source': formatMessage({ id: 'ui-inventory.source' }),
};
const fieldFormatter = createFieldFormatter(referenceData, circulationHistory);
+ const itemFormatter = createItemFormatter(fieldLabelsMap, fieldFormatter);
return (
diff --git a/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.test.js b/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.test.js
index 07e8da29a..16c378b0b 100644
--- a/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.test.js
+++ b/src/Item/ViewItem/components/ItemVersionHistory/ItemVersionHistory.test.js
@@ -11,7 +11,7 @@ import {
translationsProperties,
} from '../../../../../test/jest/helpers';
-import ItemVersionHistory, { createFieldFormatter } from './ItemVersionHistory';
+import ItemVersionHistory, { createFieldFormatter, createItemFormatter } from './ItemVersionHistory';
import { DataContext } from '../../../../contexts';
import {
@@ -278,3 +278,104 @@ describe('createFieldFormatter', () => {
expect(fieldFormatter.source({ personal: { lastName: 'Doe' } })).toBe('Doe');
});
});
+
+describe('createItemFormatter', () => {
+ const fieldLabelsMap = {
+ barcode: 'Item Barcode',
+ discoverySuppress: 'Discovery Suppress',
+ circulationNotes: 'Circulation History',
+ 'additionalCallNumbers.prefix': 'Additional call number prefix',
+ 'additionalCallNumbers.suffix': 'Additional call number suffix',
+ 'additionalCallNumbers.typeId': 'Additional call number type',
+ 'additionalCallNumbers.callNumber': 'Additional call number',
+ 'circulationNotes.staffOnly': 'Staff Only',
+ 'circulationNotes.note': 'Note',
+ 'circulationNotes.noteType': 'Note Type',
+ materialTypeId: 'Material Type',
+ };
+
+ const fieldFormatter = createFieldFormatter(mockReferenceData, {
+ servicePointName: 'Main Desk',
+ source: 'Librarian User',
+ });
+
+ const itemFormatter = createItemFormatter(fieldLabelsMap, fieldFormatter);
+
+ it('should return null for null element', () => {
+ expect(itemFormatter(null, 0)).toBeNull();
+ });
+
+ it('should return null for undefined element', () => {
+ expect(itemFormatter(undefined, 0)).toBeNull();
+ });
+
+ it('should format field with collectionName using composite key', () => {
+ const element = {
+ name: 'staffOnly',
+ value: false,
+ collectionName: 'circulationNotes',
+ };
+
+ const result = itemFormatter(element, 0);
+ const { container } = renderWithIntl(result, translationsProperties);
+
+ expect(container.querySelector('strong')).toHaveTextContent('Staff Only:');
+ expect(container.querySelector('li')).toHaveTextContent('Staff Only: false');
+ });
+
+ it('should fallback to fieldName label when composite key not found', () => {
+ const element = {
+ name: 'discoverySuppress',
+ value: true,
+ collectionName: 'unknownCollection',
+ };
+
+ const result = itemFormatter(element, 0);
+ const { container } = renderWithIntl(result, translationsProperties);
+
+ expect(container.querySelector('strong')).toHaveTextContent('Discovery Suppress:');
+ expect(container.querySelector('li')).toHaveTextContent('Discovery Suppress: true');
+ });
+
+ it('should fallback to collectionName label when fieldName not found', () => {
+ const element = {
+ name: 'unknownField',
+ value: 'test value',
+ collectionName: 'circulationNotes',
+ };
+
+ const result = itemFormatter(element, 0);
+ const { container } = renderWithIntl(result, translationsProperties);
+
+ expect(container.querySelector('strong')).toHaveTextContent('Circulation History:');
+ expect(container.querySelector('li')).toHaveTextContent('Circulation History: test value');
+ });
+
+ it('should render additionalCallNumbers.prefix with label and value', () => {
+ const element = {
+ name: 'prefix',
+ value: 'ABC',
+ collectionName: 'additionalCallNumbers',
+ };
+
+ const result = itemFormatter(element, 0);
+ const { container } = renderWithIntl(result, translationsProperties);
+
+ expect(container.querySelector('li'))
+ .toHaveTextContent('Additional call number prefix: ABC');
+ });
+
+ it('should render circulationNotes.note with label and value', () => {
+ const element = {
+ name: 'note',
+ value: 'Damaged cover',
+ collectionName: 'circulationNotes',
+ };
+
+ const result = itemFormatter(element, 0);
+ const { container } = renderWithIntl(result, translationsProperties);
+
+ expect(container.querySelector('li'))
+ .toHaveTextContent('Note: Damaged cover');
+ });
+});
diff --git a/src/edit/items/ItemForm.test.js b/src/edit/items/ItemForm.test.js
index f821c680e..7f429f952 100644
--- a/src/edit/items/ItemForm.test.js
+++ b/src/edit/items/ItemForm.test.js
@@ -258,7 +258,7 @@ describe('ItemForm', () => {
...mockReferenceTables,
callNumberTypes: [{ id: '1', name: 'Library of Congress classification' }],
};
- const { getByText, getAllByText, queryByText } = renderItemForm({
+ const { getByText, getAllByText } = renderItemForm({
initialValues,
referenceTables,
});
@@ -291,9 +291,9 @@ describe('ItemForm', () => {
'itemLevelCallNumberTypeId': { value: '2' },
'additionalCallNumbers': {
value: [{
- callNumber: 'cn1',
- prefix: 'prefix1',
- suffix: 'suffix1',
+ additionalCallNumber: 'cn1',
+ additionalCallNumberPrefix: 'prefix1',
+ additionalCallNumberSuffix: 'suffix1',
typeId: '1'
}]
}
diff --git a/translations/ui-inventory/en.json b/translations/ui-inventory/en.json
index 5667e6d83..965623bdd 100644
--- a/translations/ui-inventory/en.json
+++ b/translations/ui-inventory/en.json
@@ -216,6 +216,11 @@
"callNumberPrefix": "Call number prefix",
"callNumberSuffix": "Call number suffix",
"primaryItemCallNumber": "Primary item call number",
+ "additionalCallNumbers": "Additional call numbers",
+ "additionalCallNumber": "Additional call number",
+ "additionalCallNumberPrefix": "Additional call number prefix",
+ "additionalCallNumberSuffix": "Additional call number suffix",
+ "additionalCallNumberType": "Additional call number type",
"additionalItemCallNumbers": "Additional item call numbers",
"primaryHoldingsCallNumber": "Primary holdings call number",
"additionalHoldingsCallNumbers": "Additional holdings call numbers",