From 7a208b3662786df2079cbcd09d9ff7da0ae88c38 Mon Sep 17 00:00:00 2001 From: Michal Kuklis Date: Wed, 24 Apr 2024 17:27:48 -0400 Subject: [PATCH 1/4] UICIRC-1077: Allow override for reminder fees with renewal blocked --- CHANGELOG.md | 1 + .../Loans/OpenLoans/OpenLoansControl.js | 2 +- src/components/Wrappers/withRenew.js | 48 ++++++++++++++----- translations/ui-users/en.json | 1 + 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73c45bffb..479c0520d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Trim input values and delete properties with empty string when user record save. Refs UIU-2049. * Update username field validation to trim leading and trailing spaces. Refs UIU-3099. * Fix "Total paid amount" value that set as "$NaN" on "Refund fee/fine" modal. Refs UIU-3094. +* Allow override for reminder fees with renewal blocked. Refs UICIRC-1077. ## [10.1.0](https://github.com/folio-org/ui-users/tree/v10.1.0) (2024-03-20) [Full Changelog](https://github.com/folio-org/ui-users/compare/v10.0.4...v10.1.0) diff --git a/src/components/Loans/OpenLoans/OpenLoansControl.js b/src/components/Loans/OpenLoans/OpenLoansControl.js index e5596b3d9..bea3dd3b4 100644 --- a/src/components/Loans/OpenLoans/OpenLoansControl.js +++ b/src/components/Loans/OpenLoans/OpenLoansControl.js @@ -393,9 +393,9 @@ class OpenLoansControl extends React.Component { } export default compose( + injectIntl, withRenew, withDeclareLost, withClaimReturned, withMarkAsMissing, - injectIntl, )(OpenLoansControl); diff --git a/src/components/Wrappers/withRenew.js b/src/components/Wrappers/withRenew.js index 37ec6fd5c..9448f4240 100644 --- a/src/components/Wrappers/withRenew.js +++ b/src/components/Wrappers/withRenew.js @@ -18,6 +18,7 @@ import { // HOC used to manage renew const withRenew = WrappedComponent => class WithRenewComponent extends React.Component { static propTypes = { + intl: PropTypes.object, loans: PropTypes.arrayOf(PropTypes.object), patronBlocks: PropTypes.arrayOf(PropTypes.object), mutator: PropTypes.shape({ @@ -143,22 +144,36 @@ const withRenew = WrappedComponent => class WithRenewComponent extends React.Com const bulkRenewal = (loansSize > 1); for (const [index, loan] of loans.entries()) { - try { - // We actually want to execute it in a sequence so turning off eslint warning - // https://issues.folio.org/browse/UIU-1299 - // eslint-disable-next-line no-await-in-loop - renewSuccess.push( - await this.renewItem(loan, patron, bulkRenewal, index !== loansSize - 1, additionalInfo) - ); - } catch (errors) { - const errorMessage = this.getMessage(errors); - + // Allow override for reminder fees with renewal blocked + // https://folio-org.atlassian.net/browse/UICIRC-1077 + if (loan?.reminders?.renewalBlocked) { renewFailure.push(loan); + const error = this.props.intl.formatMessage({ id: 'ui-users.errors.renewWithReminders' }); + errorMsg[loan.id] = { - ...errorMessage, - ...isOverridePossible(errors), + ...this.getMessage(error), + overridable: true, + autoNewDueDate: true, }; } + else { + try { + // We actually want to execute it in a sequence so turning off eslint warning + // https://issues.folio.org/browse/UIU-1299 + // eslint-disable-next-line no-await-in-loop + renewSuccess.push( + await this.renewItem(loan, patron, bulkRenewal, index !== loansSize - 1, additionalInfo) + ); + } catch (errors) { + const errorMessage = this.getMessage(errors); + + renewFailure.push(loan); + errorMsg[loan.id] = { + ...errorMessage, + ...isOverridePossible(errors), + }; + } + } } if (isEmpty(renewFailure) && renewSuccess.length <= 1) { @@ -205,7 +220,14 @@ const withRenew = WrappedComponent => class WithRenewComponent extends React.Com // eslint-disable-next-line class-methods-use-this getMessage = (errors) => { - if (!errors || !errors.length) return ''; + if (!errors) return ''; + + if (!Array.isArray(errors)) { + return ; + } const policyName = this.getPolicyName(errors); const message = errors.reduce((msg, err) => ((msg) ? `${msg}, ${err.message}` : err.message), ''); diff --git a/translations/ui-users/en.json b/translations/ui-users/en.json index 08d0ce2e1..46d544f37 100644 --- a/translations/ui-users/en.json +++ b/translations/ui-users/en.json @@ -395,6 +395,7 @@ "errors.personal.dateOfBirth": "Please enter correct birth date", "errors.extended.dateEnrolled": "Please enter correct enrolled date", "errors.expirationDate": "Please enter correct expiration date", + "errors.renewWithReminders": "Renewals not allowed for loans with reminders.", "hide": "Hide", "show": "Show", "active": "Active", From ae492e78605722c9958dfdf7d45c5ee3d9230427 Mon Sep 17 00:00:00 2001 From: Michal Kuklis Date: Wed, 24 Apr 2024 19:48:18 -0400 Subject: [PATCH 2/4] Cleanup --- src/components/Wrappers/withRenew.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Wrappers/withRenew.js b/src/components/Wrappers/withRenew.js index 9448f4240..f9c4f0b14 100644 --- a/src/components/Wrappers/withRenew.js +++ b/src/components/Wrappers/withRenew.js @@ -155,8 +155,7 @@ const withRenew = WrappedComponent => class WithRenewComponent extends React.Com overridable: true, autoNewDueDate: true, }; - } - else { + } else { try { // We actually want to execute it in a sequence so turning off eslint warning // https://issues.folio.org/browse/UIU-1299 From d5a02fbbe182e6ef294cdc9b1038e206bc6f7bcf Mon Sep 17 00:00:00 2001 From: Michal Kuklis Date: Wed, 24 Apr 2024 21:53:33 -0400 Subject: [PATCH 3/4] Add tests --- src/components/Wrappers/withRenew.test.js | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/components/Wrappers/withRenew.test.js diff --git a/src/components/Wrappers/withRenew.test.js b/src/components/Wrappers/withRenew.test.js new file mode 100644 index 000000000..68f330e7c --- /dev/null +++ b/src/components/Wrappers/withRenew.test.js @@ -0,0 +1,53 @@ +import React from 'react'; +import { render, screen, waitFor } from '@folio/jest-config-stripes/testing-library/react'; +import userEvent from '@folio/jest-config-stripes/testing-library/user-event'; + +import '__mock__/currencyData.mock'; +import '__mock__/stripesCore.mock'; +import '__mock__/intl.mock'; +import buildStripes from '__mock__/stripes.mock'; +import withRenew from './withRenew'; + +const BulkRenewalDialogMock = ({ errorMessages }) => { + return
{errorMessages?.[1]?.props?.values?.message ?? ''}
; +}; + +jest.mock('../BulkRenewalDialog', () => BulkRenewalDialogMock); + +const mutator = { + loanPolicies: { + GET: jest.fn(), + reset: jest.fn(), + }, + renew: { + POST: jest.fn().mockReturnValue(Promise.resolve()), + }, + requests: { + GET: jest.fn().mockReturnValue(Promise.resolve()), + reset: jest.fn(), + }, +}; + +const props = { + match: { params: { id: '1' } }, + mutator, + intl: { formatMessage: ({ id }) => id }, + stripes: buildStripes({ connect: (Component) => Component }), +}; + +const Wrapper = ({ renew }) => ( + +); +const WrappedComponent = withRenew(Wrapper); +const renderWithRenew = (extraProps = {}) => render(); + +describe('withRenew', () => { + it('should renew loans', async () => { + renderWithRenew(); + userEvent.click(screen.getByText('Renew')); + + await waitFor(() => { + expect(screen.getByText('ui-users.errors.renewWithReminders')).toBeInTheDocument(); + }); + }); +}); From b791db0d6d31edd8a553962965b1fa29d5317e60 Mon Sep 17 00:00:00 2001 From: Michal Kuklis Date: Wed, 24 Apr 2024 21:54:59 -0400 Subject: [PATCH 4/4] Cleanup --- src/components/Wrappers/withRenew.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Wrappers/withRenew.test.js b/src/components/Wrappers/withRenew.test.js index 68f330e7c..9442e628a 100644 --- a/src/components/Wrappers/withRenew.test.js +++ b/src/components/Wrappers/withRenew.test.js @@ -29,7 +29,6 @@ const mutator = { }; const props = { - match: { params: { id: '1' } }, mutator, intl: { formatMessage: ({ id }) => id }, stripes: buildStripes({ connect: (Component) => Component }),