diff --git a/CHANGELOG.md b/CHANGELOG.md index ab1fef11..e967fc9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * *BREAKING* Display all versions in change log in fourth pane. Refs UIORGS-355. * Show in version history record view, which fields have been edited. Refs UIORGS-356. * Adapt organization metadata fields to version history mechanism. Refs UIORGS-359. +* Add claiming to organization integration details. Refs UIORGS-442. * *BREAKING* Add number generator for vendor code including settings page. Refs UIORGS-336, UIORGS-337. ## [5.2.0](https://github.com/folio-org/ui-organizations/tree/v5.2.0) (2024-10-31) diff --git a/src/OrganizationIntegration/OrganizationIntegrationCreate/OrganizationIntegrationCreate.js b/src/OrganizationIntegration/OrganizationIntegrationCreate/OrganizationIntegrationCreate.js index 46d0a37b..2ce8fe34 100644 --- a/src/OrganizationIntegration/OrganizationIntegrationCreate/OrganizationIntegrationCreate.js +++ b/src/OrganizationIntegration/OrganizationIntegrationCreate/OrganizationIntegrationCreate.js @@ -17,9 +17,12 @@ import { import { EDI_CODE_TYPES, + FILE_FORMAT, FTP_TYPES, + TRANSMISSION_METHOD, TRANSMISSION_MODES, CONNECTION_MODES, + INTEGRATION_TYPE, } from '../constants'; import { buildAvailableAccounts, @@ -38,6 +41,9 @@ const buildInitialValues = (organization, withMigration) => { exportTypeSpecificParameters: { vendorEdiOrdersExportConfig: { vendorId: organization.id, + integrationType: INTEGRATION_TYPE.claiming, + transmissionMethod: TRANSMISSION_METHOD.fileDownLoad, + fileFormat: FILE_FORMAT.csv, ediConfig: { vendorEdiCode: edi.vendorEdiCode, vendorEdiType: edi.vendorEdiType || EDI_CODE_TYPES[0].value, diff --git a/src/OrganizationIntegration/OrganizationIntegrationForm/EdiForm/EdiForm.js b/src/OrganizationIntegration/OrganizationIntegrationForm/EdiForm/EdiForm.js index 89027b65..bdca5176 100644 --- a/src/OrganizationIntegration/OrganizationIntegrationForm/EdiForm/EdiForm.js +++ b/src/OrganizationIntegration/OrganizationIntegrationForm/EdiForm/EdiForm.js @@ -1,7 +1,10 @@ -import React, { useMemo } from 'react'; import PropTypes from 'prop-types'; +import { useMemo } from 'react'; +import { + Field, + useForm, +} from 'react-final-form'; import { FormattedMessage } from 'react-intl'; -import { Field, useForm } from 'react-final-form'; import { Accordion, @@ -13,33 +16,23 @@ import { TextArea, TextField, } from '@folio/stripes/components'; -import { - validateRequired, -} from '@folio/stripes-acq-components'; +import { validateRequired } from '@folio/stripes-acq-components'; import { EDI_CODE_TYPES, EDI_NAMING_TOKENS, } from '../../constants'; import { - getAccountOptions, getAcqMethodOptions, + isFileFormatEDI, } from '../../utils'; -export const EdiForm = ({ - acqMethods = [], - accounts = [], -}) => { +export const EdiForm = ({ acqMethods }) => { const { getState } = useForm(); const acqMethodOptions = useMemo(() => getAcqMethodOptions(acqMethods), [acqMethods]); - const accountOptions = useMemo(() => getAccountOptions(accounts), [accounts]); - const isDefaultConfig = getState() - ?.values - ?.exportTypeSpecificParameters - ?.vendorEdiOrdersExportConfig - ?.isDefaultConfig; + const isFormatEDI = isFileFormatEDI(getState()?.values); return ( } > - { - !isDefaultConfig && ( - - } - name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.ediConfig.accountNoList" - component={Select} - dataOptions={accountOptions} - fullWidth - multiple - required - validate={validateRequired} - /> - - ) - } - } name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.ediConfig.vendorEdiCode" - required - validate={validateRequired} + required={isFormatEDI} + validate={isFormatEDI ? validateRequired : undefined} /> @@ -124,8 +96,8 @@ export const EdiForm = ({ id="libEdiCode" label={} name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.ediConfig.libEdiCode" - required - validate={validateRequired} + required={isFormatEDI} + validate={isFormatEDI ? validateRequired : undefined} /> @@ -226,5 +198,4 @@ export const EdiForm = ({ EdiForm.propTypes = { acqMethods: PropTypes.arrayOf(PropTypes.object), - accounts: PropTypes.arrayOf(PropTypes.string), }; diff --git a/src/OrganizationIntegration/OrganizationIntegrationForm/FtpForm/FtpForm.js b/src/OrganizationIntegration/OrganizationIntegrationForm/FtpForm/FtpForm.js index 74bcdd55..a4e8bafc 100644 --- a/src/OrganizationIntegration/OrganizationIntegrationForm/FtpForm/FtpForm.js +++ b/src/OrganizationIntegration/OrganizationIntegrationForm/FtpForm/FtpForm.js @@ -1,6 +1,8 @@ -import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { Field } from 'react-final-form'; +import { + Field, + useForm, +} from 'react-final-form'; import { Accordion, @@ -24,8 +26,13 @@ import { TRANSMISSION_MODES, CONNECTION_MODES, } from '../../constants'; +import { isTransmissionMethodFTP } from '../../utils'; export const FtpForm = () => { + const { getState } = useForm(); + + const isMethodFTP = isTransmissionMethodFTP(getState()?.values); + return ( { label={} name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.ediFtp.serverAddress" type="text" - validate={validateURLRequired} + validate={isMethodFTP ? validateURLRequired : undefined} component={TextField} fullWidth - required + required={isMethodFTP} validateFields={[]} /> @@ -139,9 +146,9 @@ export const FtpForm = () => { type="number" component={TextField} fullWidth - required + required={isMethodFTP} validateFields={[]} - validate={validateRequired} + validate={isMethodFTP ? validateRequired : undefined} /> { + const intl = useIntl(); + const { + batch, + change, + getState, + } = useForm(); + + const formValues = getState()?.values; + + const isFormatEDI = isFileFormatEDI(formValues); + const isOrderingType = isOrderingIntegration(formValues); + + const isDefaultConfig = formValues + ?.exportTypeSpecificParameters + ?.vendorEdiOrdersExportConfig + ?.isDefaultConfig; + + const accountOptions = useMemo(() => getAccountOptions(accounts), [accounts]); + + const integrationTypeOptions = useMemo(() => getIntegrationTypeOptions(intl), [intl]); + const transmissionMethodOptions = useMemo(() => getTransmissionMethodOptions(intl), [intl]); + const fileFormatOptions = useMemo(() => getFileFormatOptions(), []); + + const handleIntegrationTypeChange = ({ target: { value } }) => { + batch(() => { + change('exportTypeSpecificParameters.vendorEdiOrdersExportConfig.integrationType', value); + + switch (value) { + case INTEGRATION_TYPE.ordering: { + change('exportTypeSpecificParameters.vendorEdiOrdersExportConfig.transmissionMethod', TRANSMISSION_METHOD.ftp); + change('exportTypeSpecificParameters.vendorEdiOrdersExportConfig.fileFormat', FILE_FORMAT.edi); + break; + } + case INTEGRATION_TYPE.claiming: { + change('exportTypeSpecificParameters.vendorEdiOrdersExportConfig.ediSchedule', null); + break; + } + default: break; + } + }); + }; -export const IntegrationInfoForm = ({ defaultIntegration }) => { return ( { /> + + + } + name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.integrationType" + onChange={handleIntegrationTypeChange} + required + /> + + + } + name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.transmissionMethod" + required + /> + + + } + name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.fileFormat" + required + /> + + { + !isDefaultConfig && ( + + } + name="exportTypeSpecificParameters.vendorEdiOrdersExportConfig.ediConfig.accountNoList" + component={Select} + dataOptions={accountOptions} + fullWidth + multiple + required={isFormatEDI} + validate={isFormatEDI ? validateRequired : undefined} + /> + + ) + } + ); }; IntegrationInfoForm.propTypes = { + accounts: PropTypes.arrayOf(PropTypes.string), defaultIntegration: PropTypes.object, }; diff --git a/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.js b/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.js index c2b7561c..836d79ae 100644 --- a/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.js +++ b/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.js @@ -4,7 +4,7 @@ import React, { } from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; -import { useHistory } from 'react-router'; +import { useHistory } from 'react-router-dom'; import stripesForm from '@folio/stripes/final-form'; import { AppIcon } from '@folio/stripes/core'; @@ -28,6 +28,7 @@ import { } from '@folio/stripes-acq-components'; import { ORGANIZATIONS_ROUTE } from '../../common/constants'; +import { isClaimingIntegration } from '../utils'; import { IntegrationInfoForm } from './IntegrationInfoForm'; import { EdiForm } from './EdiForm'; import { FtpForm } from './FtpForm'; @@ -37,6 +38,7 @@ const OrganizationIntegrationForm = ({ acqMethods, accounts, defaultIntegration, + form: { getState }, onClose, paneTitle, handleSubmit, @@ -107,6 +109,8 @@ const OrganizationIntegrationForm = ({ }, ]; + const isClaimingType = isClaimingIntegration(getState()?.values); + return ( - - - + + - + {!isClaimingType && } @@ -163,6 +167,9 @@ OrganizationIntegrationForm.propTypes = { acqMethods: PropTypes.arrayOf(PropTypes.object), accounts: PropTypes.arrayOf(PropTypes.string), defaultIntegration: PropTypes.object, + form: PropTypes.shape({ + getState: PropTypes.func.isRequired, + }).isRequired, handleSubmit: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, paneTitle: PropTypes.node.isRequired, diff --git a/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.test.js b/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.test.js index c3b4e50a..c40725c1 100644 --- a/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.test.js +++ b/src/OrganizationIntegration/OrganizationIntegrationForm/OrganizationIntegrationForm.test.js @@ -1,9 +1,14 @@ -import React from 'react'; +import cloneDeep from 'lodash/cloneDeep'; +import set from 'lodash/set'; + +import { + useHistory, + MemoryRouter, +} from 'react-router-dom'; + import { render, screen } from '@folio/jest-config-stripes/testing-library/react'; import { queryHelpers } from '@folio/jest-config-stripes/testing-library/dom'; import user from '@folio/jest-config-stripes/testing-library/user-event'; -import { MemoryRouter } from 'react-router-dom'; -import { useHistory } from 'react-router'; import { HasCommand, @@ -17,11 +22,12 @@ import { FTP_TYPES, TRANSMISSION_MODES, CONNECTION_MODES, + INTEGRATION_TYPE, } from '../constants'; import OrganizationIntegrationForm from './OrganizationIntegrationForm'; -jest.mock('react-router', () => ({ - ...jest.requireActual('react-router'), +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), useHistory: jest.fn(), })); jest.mock('@folio/stripes-components/lib/Commander', () => ({ @@ -40,6 +46,7 @@ const initialValues = { exportTypeSpecificParameters: { vendorEdiOrdersExportConfig: { vendorId: 'orgId', + integrationType: INTEGRATION_TYPE.ordering, ediConfig: { accountNoList: [], defaultAcquisitionMethods: [], @@ -64,8 +71,12 @@ const defaultProps = { onClose: jest.fn(), paneTitle: 'Create integration', }; -const renderOrganizationIntegrationForm = (props = defaultProps) => render( - , + +const renderOrganizationIntegrationForm = (props = {}) => render( + , { wrapper: MemoryRouter }, ); @@ -86,6 +97,40 @@ describe('OrganizationIntegrationForm', () => { expect(asFragment()).toMatchSnapshot(); }); + it('should hide scheduling details for claiming integration', async () => { + renderOrganizationIntegrationForm(); + + expect(screen.getByText('ui-organizations.integration.scheduling')).toBeInTheDocument(); + + await user.selectOptions(screen.getByRole('combobox', { name: 'ui-organizations.integration.info.integrationType' }), INTEGRATION_TYPE.claiming); + + expect(screen.queryByText('ui-organizations.integration.scheduling')).not.toBeInTheDocument(); + }); + + it('should disable transmission and file type fields for ordering integration', async () => { + const clonedInitialValues = cloneDeep(initialValues); + + set( + clonedInitialValues, + [ + 'exportTypeSpecificParameters', + 'vendorEdiOrdersExportConfig', + 'integrationType', + ], + INTEGRATION_TYPE.claiming, + ); + + renderOrganizationIntegrationForm({ initialValues: clonedInitialValues }); + + expect(screen.getByRole('combobox', { name: 'ui-organizations.integration.info.transmissionMethod' })).not.toBeDisabled(); + expect(screen.getByRole('combobox', { name: 'ui-organizations.integration.info.fileFormat' })).not.toBeDisabled(); + + await user.selectOptions(screen.getByRole('combobox', { name: 'ui-organizations.integration.info.integrationType' }), INTEGRATION_TYPE.ordering); + + expect(screen.getByRole('combobox', { name: 'ui-organizations.integration.info.transmissionMethod' })).toBeDisabled(); + expect(screen.getByRole('combobox', { name: 'ui-organizations.integration.info.fileFormat' })).toBeDisabled(); + }); + describe('Sections toggle', () => { it('should have all expanded sections by default', () => { const { container } = renderOrganizationIntegrationForm(); diff --git a/src/OrganizationIntegration/OrganizationIntegrationForm/__snapshots__/OrganizationIntegrationForm.test.js.snap b/src/OrganizationIntegration/OrganizationIntegrationForm/__snapshots__/OrganizationIntegrationForm.test.js.snap index 5fe6df20..d07f3414 100644 --- a/src/OrganizationIntegration/OrganizationIntegrationForm/__snapshots__/OrganizationIntegrationForm.test.js.snap +++ b/src/OrganizationIntegration/OrganizationIntegrationForm/__snapshots__/OrganizationIntegrationForm.test.js.snap @@ -287,6 +287,208 @@ exports[`OrganizationIntegrationForm should render correct form structure 1`] = +
+
+
+ +
+ + + Icon + +
+
+
+
+
+
+ +
+ + + Icon + +
+
+
+
+
+
+ +
+ + + Icon + +
+
+
+
+
+
+ +
+ +
+
+
+
+
@@ -352,56 +554,6 @@ exports[`OrganizationIntegrationForm should render correct form structure 1`] =
-
-
- -
- -
-
-
-
@@ -421,9 +573,9 @@ exports[`OrganizationIntegrationForm should render correct form structure 1`] = > @@ -495,9 +640,9 @@ exports[`OrganizationIntegrationForm should render correct form structure 1`] = > @@ -592,9 +730,9 @@ exports[`OrganizationIntegrationForm should render correct form structure 1`] = >