Repository: folio-org/stripes-util
Pull request #98: STUTL-55: Update convertToSlipData and supporting functions
Author: login: Dmitriy-Litvinenko
Created: 2025-03-04T16:54:19Z | Merged: 2025-03-07T14:14:12Z

## Purpose
Update convertToSlipData and supporting functions

## Approach

- In settings -> circulation -> staff slips we create template that contain token. When we try print this template in our modules checkin, requests, requests-mediated and etc we need match real data and token from template. For this match responsible convertToSlipData function and supporting functions. And in each of modules checkin, requests, requests-mediated and etc we have own exemplar of  convertToSlipData function and supporting functions. This mean that when we add new token in settings -> circulation -> staff slips we need updete convertToSlipData function in all modules checkin, requests, requests-mediated and etc. For resolve this problem we want move convertToSlipData function and supporting functions to one please and just reuse it in modules checkin, requests, requests-mediated and etc

- convertToSlipData and supporting functions from stripes-util is not currently used in other modules, but we want to use it in several modules and before this we need provide minor changes:
https://folio-org.atlassian.net/browse/UIREQ-1263
https://folio-org.atlassian.net/browse/UIREQMED-92
https://folio-org.atlassian.net/browse/UICHKIN-456

# Refs
https://issues.folio.org/browse/STUTL-55



Diff:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4db85b6..77ffaf4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 # Change history for stripes-util
 
 ## 7.1.0 IN PROGRESS
+* Update `convertToSlipData` and supporting functions. Refs STUTL-55.
 
 ## [7.0.0](https://github.com/folio-org/stripes-util/tree/v7.0.0) (2025-02-24)
 [Full Changelog](https://github.com/folio-org/stripes-util/compare/v6.2.0...v7.0.0)
diff --git a/lib/convertToSlipData.js b/lib/convertToSlipData.js
index 75912d4..54bc15b 100644
--- a/lib/convertToSlipData.js
+++ b/lib/convertToSlipData.js
@@ -4,14 +4,7 @@ export const STAFF_SLIP_TYPES = {
   HOLD: 'Hold',
 };
 
-export const convertToSlipData = (source = {}, intl, timeZone, locale, slipName = STAFF_SLIP_TYPES.HOLD) => {
-  const {
-    item = {},
-    request = {},
-    requester = {},
-    currentDateTime = null,
-  } = source;
-
+export const convertToSlipData = (source = [], intl, timeZone, locale, staffSlip = {}) => {
   const DEFAULT_DATE_OPTIONS = {
     timeZone,
     locale,
@@ -26,67 +19,83 @@ export const convertToSlipData = (source = {}, intl, timeZone, locale, slipName
     month: 'numeric',
   };
 
-  const slipData = {
-    'staffSlip.Name': slipName,
-    'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
-    'requester.firstName': requester.firstName,
-    'requester.lastName': requester.lastName,
-    'requester.middleName': requester.middleName,
-    'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
-    'requester.patronGroup': requester.patronGroup,
-    'requester.addressLine1': requester.addressLine1,
-    'requester.addressLine2': requester.addressLine2,
-    'requester.country': requester.countryId
-      ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
-      : DEFAULT_VIEW_VALUE,
-    'requester.city': requester.city,
-    'requester.stateProvRegion': requester.region,
-    'requester.zipPostalCode': requester.postalCode,
-    'requester.barcode': requester.barcode,
-    'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
-    'requester.departments': requester.departments,
-    'item.title': item.title,
-    'item.primaryContributor': item.primaryContributor,
-    'item.allContributors': item.allContributors,
-    'item.barcode': item.barcode,
-    'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
-    'item.callNumber': item.callNumber,
-    'item.callNumberPrefix': item.callNumberPrefix,
-    'item.callNumberSuffix': item.callNumberSuffix,
-    'item.displaySummary': item.displaySummary,
-    'item.enumeration': item.enumeration,
-    'item.volume': item.volume,
-    'item.chronology': item.chronology,
-    'item.copy': item.copy,
-    'item.yearCaption': item.yearCaption,
-    'item.materialType': item.materialType,
-    'item.loanType': item.loanType,
-    'item.numberOfPieces': item.numberOfPieces,
-    'item.descriptionOfPieces': item.descriptionOfPieces,
-    'item.lastCheckedInDateTime': item.lastCheckedInDateTime
-      ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
-      : item.lastCheckedInDateTime,
-    'item.fromServicePoint': item.fromServicePoint,
-    'item.toServicePoint': item.toServicePoint,
-    'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
-    'item.effectiveLocationCampus': item.effectiveLocationCampus,
-    'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
-    'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
-    'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
-    'request.servicePointPickup': request.servicePointPickup,
-    'request.deliveryAddressType': request.deliveryAddressType,
-    'request.requestExpirationDate': request.requestExpirationDate
-      ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.requestExpirationDate,
-    'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
-    'request.holdShelfExpirationDate': request.holdShelfExpirationDate
-      ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.holdShelfExpirationDate,
-    'request.requestID': request.requestID,
-    'request.patronComments': request.patronComments,
-  };
+  return source.map((slip) => {
+    const {
+      item = {},
+      request = {},
+      requester = {},
+      currentDateTime = null,
+    } = slip;
 
-  return slipData;
+    return {
+      'staffSlip.Name': staffSlip?.slipName || STAFF_SLIP_TYPES.HOLD,
+      'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
+      'staffSlip.staffUsername': staffSlip?.user?.username,
+      'requester.firstName': requester.firstName,
+      'requester.lastName': requester.lastName,
+      'requester.middleName': requester.middleName,
+      'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
+      'requester.patronGroup': requester.patronGroup,
+      'requester.addressLine1': requester.addressLine1,
+      'requester.addressLine2': requester.addressLine2,
+      'requester.country': requester.countryId
+        ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
+        : DEFAULT_VIEW_VALUE,
+      'requester.city': requester.city,
+      'requester.stateProvRegion': requester.region,
+      'requester.zipPostalCode': requester.postalCode,
+      'requester.barcode': requester.barcode,
+      'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
+      'requester.departments': requester.departments,
+      'item.title': item.title,
+      'item.primaryContributor': item.primaryContributor,
+      'item.allContributors': item.allContributors,
+      'item.barcode': item.barcode,
+      'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
+      'item.callNumber': item.callNumber,
+      'item.callNumberPrefix': item.callNumberPrefix,
+      'item.callNumberSuffix': item.callNumberSuffix,
+      'item.displaySummary': item.displaySummary,
+      'item.enumeration': item.enumeration,
+      'item.volume': item.volume,
+      'item.chronology': item.chronology,
+      'item.copy': item.copy,
+      'item.yearCaption': item.yearCaption,
+      'item.materialType': item.materialType,
+      'item.loanType': item.loanType,
+      'item.numberOfPieces': item.numberOfPieces,
+      'item.descriptionOfPieces': item.descriptionOfPieces,
+      'item.lastCheckedInDateTime': item.lastCheckedInDateTime
+        ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
+        : item.lastCheckedInDateTime,
+      'item.fromServicePoint': item.fromServicePoint,
+      'item.toServicePoint': item.toServicePoint,
+      'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
+      'item.effectiveLocationCampus': item.effectiveLocationCampus,
+      'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
+      'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
+      'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
+      'item.accessionNumber': item.accessionNumber,
+      'item.administrativeNotes': item.administrativeNotes,
+      'item.datesOfPublication': item.datesOfPublication,
+      'item.editions': item.editions,
+      'item.physicalDescriptions': item.physicalDescriptions,
+      'item.instanceHrid': item.instanceHrid,
+      'item.instanceHridImage': `<Barcode>${item.instanceHrid}</Barcode>`,
+      'request.servicePointPickup': request.servicePointPickup,
+      'request.deliveryAddressType': request.deliveryAddressType,
+      'request.requestExpirationDate': request.requestExpirationDate
+        ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
+        : request.requestExpirationDate,
+      'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
+      'request.holdShelfExpirationDate': request.holdShelfExpirationDate
+        ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
+        : request.holdShelfExpirationDate,
+      'request.requestID': request.requestID,
+      'request.patronComments': request.patronComments,
+      'request.barcodeImage': `<Barcode>${request.requestID}</Barcode>`,
+    };
+  });
 };
 
 export default convertToSlipData;
diff --git a/lib/convertToSlipData.test.js b/lib/convertToSlipData.test.js
index b099c95..d01f26b 100644
--- a/lib/convertToSlipData.test.js
+++ b/lib/convertToSlipData.test.js
@@ -4,6 +4,8 @@ import {
 } from './convertToSlipData';
 
 export const STAFF_SLIP_WITH_OUT_DATA = {
+  'item.accessionNumber': undefined,
+  'item.administrativeNotes': undefined,
   'item.allContributors': undefined,
   'item.barcode': undefined,
   'item.barcodeImage': '<Barcode>undefined</Barcode>',
@@ -12,8 +14,10 @@ export const STAFF_SLIP_WITH_OUT_DATA = {
   'item.callNumberSuffix': undefined,
   'item.chronology': undefined,
   'item.copy': undefined,
+  'item.datesOfPublication': undefined,
   'item.descriptionOfPieces': undefined,
   'item.displaySummary': undefined,
+  'item.editions': undefined,
   'item.effectiveLocationCampus': undefined,
   'item.effectiveLocationInstitution': undefined,
   'item.effectiveLocationLibrary': undefined,
@@ -21,15 +25,19 @@ export const STAFF_SLIP_WITH_OUT_DATA = {
   'item.effectiveLocationSpecific': undefined,
   'item.enumeration': undefined,
   'item.fromServicePoint': undefined,
+  'item.instanceHrid': undefined,
+  'item.instanceHridImage': '<Barcode>undefined</Barcode>',
   'item.lastCheckedInDateTime': undefined,
   'item.loanType': undefined,
   'item.materialType': undefined,
   'item.numberOfPieces': undefined,
+  'item.physicalDescriptions': undefined,
   'item.primaryContributor': undefined,
   'item.title': undefined,
   'item.toServicePoint': undefined,
   'item.volume': undefined,
   'item.yearCaption': undefined,
+  'request.barcodeImage': '<Barcode>undefined</Barcode>',
   'request.deliveryAddressType': undefined,
   'request.holdShelfExpirationDate': undefined,
   'request.patronComments': undefined,
@@ -53,6 +61,7 @@ export const STAFF_SLIP_WITH_OUT_DATA = {
   'requester.zipPostalCode': undefined,
   'staffSlip.Name': STAFF_SLIP_TYPES.HOLD,
   'staffSlip.currentDateTime': null,
+  'staffSlip.staffUsername': undefined,
 };
 
 export const SOURCE_FOR_STAFF_SLIP_DATA = {
@@ -74,6 +83,12 @@ export const SOURCE_FOR_STAFF_SLIP_DATA = {
   },
   item: {
     title: 'item.title',
+    accessionNumber: 'item.accessionNumber',
+    administrativeNotes: 'item.administrativeNotes',
+    datesOfPublication: 'item.datesOfPublication',
+    editions: 'item.editions',
+    instanceHrid: 'item.instanceHrid',
+    physicalDescriptions: 'item.physicalDescriptions',
     primaryContributor: 'item.primaryContributor',
     allContributors: 'item.allContributors',
     barcode: 'item.barcode',
@@ -100,6 +115,7 @@ export const SOURCE_FOR_STAFF_SLIP_DATA = {
     effectiveLocationPrimaryServicePointName: 'item.effectiveLocationPrimaryServicePointName',
   },
   request: {
+    barcodeImage: 'request.requestID',
     servicePointPickup: 'request.servicePointPickup',
     deliveryAddressType: 'request.deliveryAddressType',
     requestExpirationDate: '2024-12-31T24:00:00.000+00:00',
@@ -111,6 +127,8 @@ export const SOURCE_FOR_STAFF_SLIP_DATA = {
 };
 
 export const STAFF_SLIP_DATA = {
+  'item.accessionNumber': 'item.accessionNumber',
+  'item.administrativeNotes': 'item.administrativeNotes',
   'item.allContributors': 'item.allContributors',
   'item.barcode': 'item.barcode',
   'item.barcodeImage': '<Barcode>item.barcode</Barcode>',
@@ -119,8 +137,10 @@ export const STAFF_SLIP_DATA = {
   'item.callNumberSuffix': 'item.callNumberSuffix',
   'item.chronology': 'item.chronology',
   'item.copy': 'item.copy',
+  'item.datesOfPublication': 'item.datesOfPublication',
   'item.descriptionOfPieces': 'item.descriptionOfPieces',
   'item.displaySummary': 'item.displaySummary',
+  'item.editions': 'item.editions',
   'item.effectiveLocationCampus': 'item.effectiveLocationCampus',
   'item.effectiveLocationInstitution': 'item.effectiveLocationInstitution',
   'item.effectiveLocationLibrary': 'item.effectiveLocationLibrary',
@@ -128,15 +148,19 @@ export const STAFF_SLIP_DATA = {
   'item.effectiveLocationSpecific': 'item.effectiveLocationSpecific',
   'item.enumeration': 'item.enumeration',
   'item.fromServicePoint': 'item.fromServicePoint',
+  'item.instanceHrid': 'item.instanceHrid',
+  'item.instanceHridImage': '<Barcode>item.instanceHrid</Barcode>',
   'item.lastCheckedInDateTime': '2024-12-31T24:00:00.000+00:00',
   'item.loanType': 'item.loanType',
   'item.materialType': 'item.materialType',
   'item.numberOfPieces': 'item.numberOfPieces',
+  'item.physicalDescriptions': 'item.physicalDescriptions',
   'item.primaryContributor': 'item.primaryContributor',
   'item.title': 'item.title',
   'item.toServicePoint': 'item.toServicePoint',
   'item.volume': 'item.volume',
   'item.yearCaption': 'item.yearCaption',
+  'request.barcodeImage': '<Barcode>request.requestID</Barcode>',
   'request.deliveryAddressType': 'request.deliveryAddressType',
   'request.holdShelfExpirationDate': '2024-12-31T24:00:00.000+00:00',
   'request.patronComments': 'request.patronComments',
@@ -160,6 +184,7 @@ export const STAFF_SLIP_DATA = {
   'requester.zipPostalCode': 'requester.postalCode',
   'staffSlip.Name': STAFF_SLIP_TYPES.HOLD,
   'staffSlip.currentDateTime': '2024-12-31T24:00:00.000+00:00',
+  'staffSlip.staffUsername': 'staffSlip.staffUsername',
 };
 
 describe('convertToSlipData', () => {
@@ -173,10 +198,15 @@ describe('convertToSlipData', () => {
   it('should return slip data with out value', () => {
     const source = {};
 
-    expect(convertToSlipData(source, intl, timeZone, locale)).toEqual(STAFF_SLIP_WITH_OUT_DATA);
+    expect(convertToSlipData([source], intl, timeZone, locale)).toEqual([STAFF_SLIP_WITH_OUT_DATA]);
   });
 
   it('should return slip data with value', () => {
-    expect(convertToSlipData(SOURCE_FOR_STAFF_SLIP_DATA, intl, timeZone, locale)).toEqual(STAFF_SLIP_DATA);
+    expect(convertToSlipData([SOURCE_FOR_STAFF_SLIP_DATA], intl, timeZone, locale, {
+      slipName: STAFF_SLIP_TYPES.HOLD,
+      user: {
+        username: 'staffSlip.staffUsername',
+      },
+    })).toEqual([STAFF_SLIP_DATA]);
   });
 });


Reviews:
user: login: artem-blazhko
state: APPROVED
author_association: NONE
submitted_at: 2025-03-04T17:16:24Z
user: login: zburke
body: I found some nits about names and comments but no show stoppers. Please address these before you merge. 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-07T13:38:01Z
user: login: zburke
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T14:18:37Z
user: login: zburke
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T14:18:57Z

Review comments:
diff_hunk: @@ -1,6 +1,7 @@
 # Change history for stripes-util
 
 ## 7.1.0 IN PROGRESS
+* Update `convertToSlipData` and supporting functions. Refs STUTL-55.
path: CHANGELOG.md
user: login: zburke
body: Please briefly describe what you are actually changing, i.e. handling a list of sources instead of just one, and adding new fields. "Update" does not convey any information, just like a patch PR that says "fix bug". 
created_at: 2025-03-07T13:25:10Z
author_association: MEMBER
diff_hunk: @@ -26,67 +19,83 @@ export const convertToSlipData = (source = {}, intl, timeZone, locale, slipName
     month: 'numeric',
   };
 
-  const slipData = {
-    'staffSlip.Name': slipName,
-    'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
-    'requester.firstName': requester.firstName,
-    'requester.lastName': requester.lastName,
-    'requester.middleName': requester.middleName,
-    'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
-    'requester.patronGroup': requester.patronGroup,
-    'requester.addressLine1': requester.addressLine1,
-    'requester.addressLine2': requester.addressLine2,
-    'requester.country': requester.countryId
-      ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
-      : DEFAULT_VIEW_VALUE,
-    'requester.city': requester.city,
-    'requester.stateProvRegion': requester.region,
-    'requester.zipPostalCode': requester.postalCode,
-    'requester.barcode': requester.barcode,
-    'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
-    'requester.departments': requester.departments,
-    'item.title': item.title,
-    'item.primaryContributor': item.primaryContributor,
-    'item.allContributors': item.allContributors,
-    'item.barcode': item.barcode,
-    'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
-    'item.callNumber': item.callNumber,
-    'item.callNumberPrefix': item.callNumberPrefix,
-    'item.callNumberSuffix': item.callNumberSuffix,
-    'item.displaySummary': item.displaySummary,
-    'item.enumeration': item.enumeration,
-    'item.volume': item.volume,
-    'item.chronology': item.chronology,
-    'item.copy': item.copy,
-    'item.yearCaption': item.yearCaption,
-    'item.materialType': item.materialType,
-    'item.loanType': item.loanType,
-    'item.numberOfPieces': item.numberOfPieces,
-    'item.descriptionOfPieces': item.descriptionOfPieces,
-    'item.lastCheckedInDateTime': item.lastCheckedInDateTime
-      ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
-      : item.lastCheckedInDateTime,
-    'item.fromServicePoint': item.fromServicePoint,
-    'item.toServicePoint': item.toServicePoint,
-    'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
-    'item.effectiveLocationCampus': item.effectiveLocationCampus,
-    'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
-    'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
-    'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
-    'request.servicePointPickup': request.servicePointPickup,
-    'request.deliveryAddressType': request.deliveryAddressType,
-    'request.requestExpirationDate': request.requestExpirationDate
-      ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.requestExpirationDate,
-    'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
-    'request.holdShelfExpirationDate': request.holdShelfExpirationDate
-      ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.holdShelfExpirationDate,
-    'request.requestID': request.requestID,
-    'request.patronComments': request.patronComments,
-  };
+  return source.map((slip) => {
+    const {
+      item = {},
+      request = {},
+      requester = {},
+      currentDateTime = null,
+    } = slip;
 
-  return slipData;
+    return {
+      'staffSlip.Name': staffSlip?.slipName || STAFF_SLIP_TYPES.HOLD,
path: lib/convertToSlipData.js
user: login: zburke
body: Ugh, I was going to suggest using `staffSlip.name` here instead of `.Name` for consistency with the rest of the keys, but I see this is not really a new line, just `diff` making me think it was a new line. Do you think this can be safely changed to `.name` (because these keys are just used internally?) or does it need to stay as-is? Up to you. 
created_at: 2025-03-07T13:27:05Z
author_association: MEMBER
diff_hunk: @@ -26,67 +19,83 @@ export const convertToSlipData = (source = {}, intl, timeZone, locale, slipName
     month: 'numeric',
   };
 
-  const slipData = {
-    'staffSlip.Name': slipName,
-    'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
-    'requester.firstName': requester.firstName,
-    'requester.lastName': requester.lastName,
-    'requester.middleName': requester.middleName,
-    'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
-    'requester.patronGroup': requester.patronGroup,
-    'requester.addressLine1': requester.addressLine1,
-    'requester.addressLine2': requester.addressLine2,
-    'requester.country': requester.countryId
-      ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
-      : DEFAULT_VIEW_VALUE,
-    'requester.city': requester.city,
-    'requester.stateProvRegion': requester.region,
-    'requester.zipPostalCode': requester.postalCode,
-    'requester.barcode': requester.barcode,
-    'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
-    'requester.departments': requester.departments,
-    'item.title': item.title,
-    'item.primaryContributor': item.primaryContributor,
-    'item.allContributors': item.allContributors,
-    'item.barcode': item.barcode,
-    'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
-    'item.callNumber': item.callNumber,
-    'item.callNumberPrefix': item.callNumberPrefix,
-    'item.callNumberSuffix': item.callNumberSuffix,
-    'item.displaySummary': item.displaySummary,
-    'item.enumeration': item.enumeration,
-    'item.volume': item.volume,
-    'item.chronology': item.chronology,
-    'item.copy': item.copy,
-    'item.yearCaption': item.yearCaption,
-    'item.materialType': item.materialType,
-    'item.loanType': item.loanType,
-    'item.numberOfPieces': item.numberOfPieces,
-    'item.descriptionOfPieces': item.descriptionOfPieces,
-    'item.lastCheckedInDateTime': item.lastCheckedInDateTime
-      ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
-      : item.lastCheckedInDateTime,
-    'item.fromServicePoint': item.fromServicePoint,
-    'item.toServicePoint': item.toServicePoint,
-    'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
-    'item.effectiveLocationCampus': item.effectiveLocationCampus,
-    'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
-    'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
-    'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
-    'request.servicePointPickup': request.servicePointPickup,
-    'request.deliveryAddressType': request.deliveryAddressType,
-    'request.requestExpirationDate': request.requestExpirationDate
-      ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.requestExpirationDate,
-    'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
-    'request.holdShelfExpirationDate': request.holdShelfExpirationDate
-      ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.holdShelfExpirationDate,
-    'request.requestID': request.requestID,
-    'request.patronComments': request.patronComments,
-  };
+  return source.map((slip) => {
+    const {
+      item = {},
+      request = {},
+      requester = {},
+      currentDateTime = null,
+    } = slip;
 
-  return slipData;
+    return {
+      'staffSlip.Name': staffSlip?.slipName || STAFF_SLIP_TYPES.HOLD,
+      'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
+      'staffSlip.staffUsername': staffSlip?.user?.username,
+      'requester.firstName': requester.firstName,
+      'requester.lastName': requester.lastName,
+      'requester.middleName': requester.middleName,
+      'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
+      'requester.patronGroup': requester.patronGroup,
+      'requester.addressLine1': requester.addressLine1,
+      'requester.addressLine2': requester.addressLine2,
+      'requester.country': requester.countryId
+        ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
+        : DEFAULT_VIEW_VALUE,
+      'requester.city': requester.city,
+      'requester.stateProvRegion': requester.region,
+      'requester.zipPostalCode': requester.postalCode,
+      'requester.barcode': requester.barcode,
+      'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
+      'requester.departments': requester.departments,
+      'item.title': item.title,
+      'item.primaryContributor': item.primaryContributor,
+      'item.allContributors': item.allContributors,
+      'item.barcode': item.barcode,
+      'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
+      'item.callNumber': item.callNumber,
+      'item.callNumberPrefix': item.callNumberPrefix,
+      'item.callNumberSuffix': item.callNumberSuffix,
+      'item.displaySummary': item.displaySummary,
+      'item.enumeration': item.enumeration,
+      'item.volume': item.volume,
+      'item.chronology': item.chronology,
+      'item.copy': item.copy,
+      'item.yearCaption': item.yearCaption,
+      'item.materialType': item.materialType,
+      'item.loanType': item.loanType,
+      'item.numberOfPieces': item.numberOfPieces,
+      'item.descriptionOfPieces': item.descriptionOfPieces,
+      'item.lastCheckedInDateTime': item.lastCheckedInDateTime
+        ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
+        : item.lastCheckedInDateTime,
+      'item.fromServicePoint': item.fromServicePoint,
+      'item.toServicePoint': item.toServicePoint,
+      'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
+      'item.effectiveLocationCampus': item.effectiveLocationCampus,
+      'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
+      'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
+      'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
+      'item.accessionNumber': item.accessionNumber,
+      'item.administrativeNotes': item.administrativeNotes,
+      'item.datesOfPublication': item.datesOfPublication,
+      'item.editions': item.editions,
+      'item.physicalDescriptions': item.physicalDescriptions,
+      'item.instanceHrid': item.instanceHrid,
+      'item.instanceHridImage': `<Barcode>${item.instanceHrid}</Barcode>`,
+      'request.servicePointPickup': request.servicePointPickup,
+      'request.deliveryAddressType': request.deliveryAddressType,
+      'request.requestExpirationDate': request.requestExpirationDate
+        ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
+        : request.requestExpirationDate,
+      'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
+      'request.holdShelfExpirationDate': request.holdShelfExpirationDate
+        ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
+        : request.holdShelfExpirationDate,
+      'request.requestID': request.requestID,
+      'request.patronComments': request.patronComments,
+      'request.barcodeImage': `<Barcode>${request.requestID}</Barcode>`,
path: lib/convertToSlipData.js
user: login: zburke
body: This should be named `request.requestIDImage`.
created_at: 2025-03-07T13:32:26Z
author_association: MEMBER
diff_hunk: @@ -100,6 +115,7 @@ export const SOURCE_FOR_STAFF_SLIP_DATA = {
     effectiveLocationPrimaryServicePointName: 'item.effectiveLocationPrimaryServicePointName',
   },
   request: {
+    barcodeImage: 'request.requestID',
path: lib/convertToSlipData.test.js
user: login: zburke
body: `requestIDImage`
created_at: 2025-03-07T13:33:32Z
author_association: MEMBER
diff_hunk: @@ -26,67 +19,83 @@ export const convertToSlipData = (source = {}, intl, timeZone, locale, slipName
     month: 'numeric',
   };
 
-  const slipData = {
-    'staffSlip.Name': slipName,
-    'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
-    'requester.firstName': requester.firstName,
-    'requester.lastName': requester.lastName,
-    'requester.middleName': requester.middleName,
-    'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
-    'requester.patronGroup': requester.patronGroup,
-    'requester.addressLine1': requester.addressLine1,
-    'requester.addressLine2': requester.addressLine2,
-    'requester.country': requester.countryId
-      ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
-      : DEFAULT_VIEW_VALUE,
-    'requester.city': requester.city,
-    'requester.stateProvRegion': requester.region,
-    'requester.zipPostalCode': requester.postalCode,
-    'requester.barcode': requester.barcode,
-    'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
-    'requester.departments': requester.departments,
-    'item.title': item.title,
-    'item.primaryContributor': item.primaryContributor,
-    'item.allContributors': item.allContributors,
-    'item.barcode': item.barcode,
-    'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
-    'item.callNumber': item.callNumber,
-    'item.callNumberPrefix': item.callNumberPrefix,
-    'item.callNumberSuffix': item.callNumberSuffix,
-    'item.displaySummary': item.displaySummary,
-    'item.enumeration': item.enumeration,
-    'item.volume': item.volume,
-    'item.chronology': item.chronology,
-    'item.copy': item.copy,
-    'item.yearCaption': item.yearCaption,
-    'item.materialType': item.materialType,
-    'item.loanType': item.loanType,
-    'item.numberOfPieces': item.numberOfPieces,
-    'item.descriptionOfPieces': item.descriptionOfPieces,
-    'item.lastCheckedInDateTime': item.lastCheckedInDateTime
-      ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
-      : item.lastCheckedInDateTime,
-    'item.fromServicePoint': item.fromServicePoint,
-    'item.toServicePoint': item.toServicePoint,
-    'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
-    'item.effectiveLocationCampus': item.effectiveLocationCampus,
-    'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
-    'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
-    'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
-    'request.servicePointPickup': request.servicePointPickup,
-    'request.deliveryAddressType': request.deliveryAddressType,
-    'request.requestExpirationDate': request.requestExpirationDate
-      ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.requestExpirationDate,
-    'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
-    'request.holdShelfExpirationDate': request.holdShelfExpirationDate
-      ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.holdShelfExpirationDate,
-    'request.requestID': request.requestID,
-    'request.patronComments': request.patronComments,
-  };
+  return source.map((slip) => {
+    const {
+      item = {},
+      request = {},
+      requester = {},
+      currentDateTime = null,
+    } = slip;
 
-  return slipData;
+    return {
+      'staffSlip.Name': staffSlip?.slipName || STAFF_SLIP_TYPES.HOLD,
path: lib/convertToSlipData.js
user: login: zburke
body: 😒 @Dmitriy-Litvinenko has explained that this cannot be changed because it has already been published in a previous release.
created_at: 2025-03-07T14:18:37Z
author_association: MEMBER
diff_hunk: @@ -26,67 +19,83 @@ export const convertToSlipData = (source = {}, intl, timeZone, locale, slipName
     month: 'numeric',
   };
 
-  const slipData = {
-    'staffSlip.Name': slipName,
-    'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
-    'requester.firstName': requester.firstName,
-    'requester.lastName': requester.lastName,
-    'requester.middleName': requester.middleName,
-    'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
-    'requester.patronGroup': requester.patronGroup,
-    'requester.addressLine1': requester.addressLine1,
-    'requester.addressLine2': requester.addressLine2,
-    'requester.country': requester.countryId
-      ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
-      : DEFAULT_VIEW_VALUE,
-    'requester.city': requester.city,
-    'requester.stateProvRegion': requester.region,
-    'requester.zipPostalCode': requester.postalCode,
-    'requester.barcode': requester.barcode,
-    'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
-    'requester.departments': requester.departments,
-    'item.title': item.title,
-    'item.primaryContributor': item.primaryContributor,
-    'item.allContributors': item.allContributors,
-    'item.barcode': item.barcode,
-    'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
-    'item.callNumber': item.callNumber,
-    'item.callNumberPrefix': item.callNumberPrefix,
-    'item.callNumberSuffix': item.callNumberSuffix,
-    'item.displaySummary': item.displaySummary,
-    'item.enumeration': item.enumeration,
-    'item.volume': item.volume,
-    'item.chronology': item.chronology,
-    'item.copy': item.copy,
-    'item.yearCaption': item.yearCaption,
-    'item.materialType': item.materialType,
-    'item.loanType': item.loanType,
-    'item.numberOfPieces': item.numberOfPieces,
-    'item.descriptionOfPieces': item.descriptionOfPieces,
-    'item.lastCheckedInDateTime': item.lastCheckedInDateTime
-      ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
-      : item.lastCheckedInDateTime,
-    'item.fromServicePoint': item.fromServicePoint,
-    'item.toServicePoint': item.toServicePoint,
-    'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
-    'item.effectiveLocationCampus': item.effectiveLocationCampus,
-    'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
-    'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
-    'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
-    'request.servicePointPickup': request.servicePointPickup,
-    'request.deliveryAddressType': request.deliveryAddressType,
-    'request.requestExpirationDate': request.requestExpirationDate
-      ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.requestExpirationDate,
-    'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
-    'request.holdShelfExpirationDate': request.holdShelfExpirationDate
-      ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
-      : request.holdShelfExpirationDate,
-    'request.requestID': request.requestID,
-    'request.patronComments': request.patronComments,
-  };
+  return source.map((slip) => {
+    const {
+      item = {},
+      request = {},
+      requester = {},
+      currentDateTime = null,
+    } = slip;
 
-  return slipData;
+    return {
+      'staffSlip.Name': staffSlip?.slipName || STAFF_SLIP_TYPES.HOLD,
+      'staffSlip.currentDateTime': intl.formatDate(currentDateTime, CURRENT_DATE_TIME_DATE_OPTIONS),
+      'staffSlip.staffUsername': staffSlip?.user?.username,
+      'requester.firstName': requester.firstName,
+      'requester.lastName': requester.lastName,
+      'requester.middleName': requester.middleName,
+      'requester.preferredFirstName': requester.preferredFirstName ? requester.preferredFirstName : requester.firstName,
+      'requester.patronGroup': requester.patronGroup,
+      'requester.addressLine1': requester.addressLine1,
+      'requester.addressLine2': requester.addressLine2,
+      'requester.country': requester.countryId
+        ? intl.formatMessage({ id: `stripes-components.countries.${requester.countryId}` })
+        : DEFAULT_VIEW_VALUE,
+      'requester.city': requester.city,
+      'requester.stateProvRegion': requester.region,
+      'requester.zipPostalCode': requester.postalCode,
+      'requester.barcode': requester.barcode,
+      'requester.barcodeImage': requester.barcode ? `<Barcode>${requester.barcode}</Barcode>` : DEFAULT_VIEW_VALUE,
+      'requester.departments': requester.departments,
+      'item.title': item.title,
+      'item.primaryContributor': item.primaryContributor,
+      'item.allContributors': item.allContributors,
+      'item.barcode': item.barcode,
+      'item.barcodeImage': `<Barcode>${item.barcode}</Barcode>`,
+      'item.callNumber': item.callNumber,
+      'item.callNumberPrefix': item.callNumberPrefix,
+      'item.callNumberSuffix': item.callNumberSuffix,
+      'item.displaySummary': item.displaySummary,
+      'item.enumeration': item.enumeration,
+      'item.volume': item.volume,
+      'item.chronology': item.chronology,
+      'item.copy': item.copy,
+      'item.yearCaption': item.yearCaption,
+      'item.materialType': item.materialType,
+      'item.loanType': item.loanType,
+      'item.numberOfPieces': item.numberOfPieces,
+      'item.descriptionOfPieces': item.descriptionOfPieces,
+      'item.lastCheckedInDateTime': item.lastCheckedInDateTime
+        ? intl.formatDate(item.lastCheckedInDateTime, DEFAULT_DATE_OPTIONS)
+        : item.lastCheckedInDateTime,
+      'item.fromServicePoint': item.fromServicePoint,
+      'item.toServicePoint': item.toServicePoint,
+      'item.effectiveLocationInstitution': item.effectiveLocationInstitution,
+      'item.effectiveLocationCampus': item.effectiveLocationCampus,
+      'item.effectiveLocationLibrary': item.effectiveLocationLibrary,
+      'item.effectiveLocationSpecific': item.effectiveLocationSpecific,
+      'item.effectiveLocationPrimaryServicePointName': item.effectiveLocationPrimaryServicePointName,
+      'item.accessionNumber': item.accessionNumber,
+      'item.administrativeNotes': item.administrativeNotes,
+      'item.datesOfPublication': item.datesOfPublication,
+      'item.editions': item.editions,
+      'item.physicalDescriptions': item.physicalDescriptions,
+      'item.instanceHrid': item.instanceHrid,
+      'item.instanceHridImage': `<Barcode>${item.instanceHrid}</Barcode>`,
+      'request.servicePointPickup': request.servicePointPickup,
+      'request.deliveryAddressType': request.deliveryAddressType,
+      'request.requestExpirationDate': request.requestExpirationDate
+        ? intl.formatDate(request.requestExpirationDate, DEFAULT_DATE_OPTIONS)
+        : request.requestExpirationDate,
+      'request.requestDate': request.requestDate ? intl.formatDate(request.requestDate, DEFAULT_DATE_OPTIONS) : request.requestDate,
+      'request.holdShelfExpirationDate': request.holdShelfExpirationDate
+        ? intl.formatDate(request.holdShelfExpirationDate, DEFAULT_DATE_OPTIONS)
+        : request.holdShelfExpirationDate,
+      'request.requestID': request.requestID,
+      'request.patronComments': request.patronComments,
+      'request.barcodeImage': `<Barcode>${request.requestID}</Barcode>`,
path: lib/convertToSlipData.js
user: login: zburke
body: 😒 @Dmitriy-Litvinenko has explained that this cannot be changed because it has already been published in a previous release.
created_at: 2025-03-07T14:18:57Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-04T16:55:36Z
body: ## Jest Unit Test Results
 1 files  ±0  11 suites  ±0   6s ⏱️ ±0s
53 tests ±0  53 ✅ ±0  0 💤 ±0  0 ❌ ±0 
56 runs  ±0  56 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 97c3bb20. ± Comparison against base commit 23914f60.

[test-results]:data:application/gzip;base64,H4sIABV2yWcC/12Myw6CMBBFf4V07aIPodSfMe1QkolATWlXxH93qAjo7p5zk7OwHgc/s1slLhWbM6YPrNTlaBOGibghpCetX62+cJ8zwJ954JMM30VvcfgRPsYQNxPzVIrNtvfgIY5e4VOu8LkGYRwxETCjQTknOTijtOUaoIbW0OAgvVQGROevTrTs9QZRMhFDAAEAAA==

:recycle: This comment has been updated with latest results.
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-06T10:18:00Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=org.folio%3Astripes-util&pullRequest=98) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=org.folio%3Astripes-util&pullRequest=98&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=org.folio%3Astripes-util&pullRequest=98&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=org.folio%3Astripes-util&pullRequest=98&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [94.1% Coverage on New Code](https://sonarcloud.io/component_measures?id=org.folio%3Astripes-util&pullRequest=98&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=org.folio%3Astripes-util&pullRequest=98&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=org.folio%3Astripes-util&pullRequest=98)


author_association: NONE