From af2b091df00cbdeca396c8687524caa2f2fe5a41 Mon Sep 17 00:00:00 2001 From: gioelemella <128155546+gioelemella@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:46:29 +0200 Subject: [PATCH 1/4] Next Release 1.28.0 (#611) * [VAS-418] feat: Align tos page with design (#579) * Bump to version 1.26.0-1-next * merge * fix: PaymentNoticesDetailPage.tsx posteAuth (#577) * Bump to version 1.26.0-2-next * fix github.head_ref in the action * feat: Review channel flow (#573) * [VAS-998] feat: introducing ops review from channel * [VAS-998] feat: Updated ops review modal management for channels * [VAS-997] changed channels page structured and integrated new getChannels API * [VAS-997] updated tests * [VAS-998] feat: Updated addEdit, details and tests * [VAS-998] feat: Updated tests, introduced common header to avoid duplicates * [VAS-998] feat: temporary rollback test * [VAS-998] feat: Update GetChannelAlert.test.tsx * [VAS-998] feat: Update ci_code_review.yml * [VAS-998] feat: Updated GetChannelAlert.test.tsx * [VAS-997] fix after merge with VAS-998 * fix client after merge * [VAS-997] fix: Width row station name * [VAS-997] fix: Improve createdBy/modifiedBy station detail * [VAS-997] fix: Handle change page channels table * [VAS-997] feat: Add alert channels details * [VAS-997] chore: Refactor detail button station detail * [VAS-997] feat: Refactor ChannelDetail component & improve UI * [VAS-997] feat: New translations * [VAS-997] fix: Refactor & format + fix translations * [VAS-997] feat: Delete unused component * [VAS-997] fix: Wrapper status chip translation for operators * [VAS-997] chore: Clean code * fixed client * [VAS-997] fixed unit tests * [VAS-997] add unit tests * [VAS-997] improve tests * [VAS-997] improve coverage --------- Co-authored-by: Alessio Cialini Co-authored-by: svariant Co-authored-by: Samuele Varianti <128470180+svariant@users.noreply.github.com> Co-authored-by: Jacopo Carlini * Bump to version 1.26.0-3-next * [VAS-1123] feat: Remove unused Station and Channel API (#574) * [VAS-998] feat: introducing ops review from channel * [VAS-998] feat: Updated ops review modal management for channels * [VAS-997] changed channels page structured and integrated new getChannels API * [VAS-997] updated tests * [VAS-998] feat: Updated addEdit, details and tests * [VAS-998] feat: Updated tests, introduced common header to avoid duplicates * [VAS-998] feat: temporary rollback test * [VAS-998] feat: Update GetChannelAlert.test.tsx * [VAS-998] feat: Update ci_code_review.yml * [VAS-998] feat: Updated GetChannelAlert.test.tsx * [VAS-997] fix after merge with VAS-998 * fix client after merge * [VAS-1123] replace old merged API with new get Stations and Channels * [VAS-1123] fixed tests * [VAS-1123] fix after merge * [VAS-1123] fix test after merge * [VAS-1123] removed useless file and added tests * improve coverage * improve for coverage --------- Co-authored-by: Alessio Cialini Co-authored-by: Samuele Varianti <128470180+svariant@users.noreply.github.com> * Bump to version 1.26.0-4-next * [VAS-1104] feat: New bundle status for available but expired bundles (#580) * [VAS-1104] feat: New bundle status for available but expired bundles * [VAS-1104] feat: Add alert bundle expired * [VAS-1104] chore: BE openapi * [VAS-1104] feat: Changes after UI designer advice * [VAS-1104] chore: Fix unit tests * Bump to version 1.26.0-5-next * [VAS-1103] feat: Add new field pspBusinessName to bundle details (#583) * [VAS-1103] feat: Add new field pspBusinessName to bundle details * Update src/locale/it.json Co-authored-by: Jacopo Carlini * [VAS-1103] fix: Unit tests --------- Co-authored-by: Jacopo Carlini * Bump to version 1.26.0-6-next * [VAS-1095] feat: e2e PSP's & CI's actions on private bundle (#570) * [VAS-1096] feat: Define publicBundles e2e tests * [VAS-1096] feat: e2e validate bundle api * [VAS-1096] feat: Implement temporary new state for ci bundles + uniform code * [VAS-1096] feat: Conclude publicBundles e2e tests * [VAS-1095] feat: e2e private bundles * [VAS-1096] chore: fix unit tests * [VAS-1096] feat: Re-enable e2e paraller workers * [VAS-1095] fix: Click on popup * [VAS-1095] feat: Add control on login page * [VAS-1095] feat: Improve e2e tests * [VAS-1095] fix: Public bundles e2e * [VAS-1095] chore: Max number of failures e2e * [VAS-1095] fix: e2e subkey env name * {VAS-1095] fix: e2e Added condition * [VAS-1095] fix: Added timeout e2e * [VAS-1095] fix: Increase timeout * [VAS-1095] fix: Changed timeouts * [VAS-1095] fix: Increase timeout * [VAS-1095] chore: Delete obsolete puppeteer int test * [VAS-1095] fix: Improved check return homepage * [VAS-1095] timeout * [VAS-1095] fix: e2e change browser driver to firefox + timeout fixes * [VAS-1095] feat: Add delete bundle api to cleanup * [VAS-1095] chore: Add log response * [VAS-1095] feat: Add subkey int test keyvault * [VAS-1095] notify * [VAS-1095] fix: e2e clean up * [VAS-1095] special secret * [VAS-1095] debug * [VAS-1095] secret * [VAS-1095] create jwt * [VAS-1095] gitignore * [VAS-1095] github pages * [VAS-1095] chore: Re commit tsconfig * [VAS-1095] fix: e2e static analysis * [VAS-1095] chore: Sonar cpd exclusion e2e --------- Co-authored-by: Jacopo * Bump to version 1.26.0-7-next * chore: Merge main into next (#585) * build(deps-dev): Bump eslint-plugin-react from 7.30.0 to 7.34.3 Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.30.0 to 7.34.3. - [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases) - [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md) - [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.30.0...v7.34.3) --- updated-dependencies: - dependency-name: eslint-plugin-react dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * build(deps): Bump react-use-scrollspy from 3.0.2 to 3.1.1 (#565) * build(deps): Bump react-use-scrollspy from 3.0.2 to 3.1.1 Bumps [react-use-scrollspy](https://github.com/Purii/react-use-scrollspy) from 3.0.2 to 3.1.1. - [Release notes](https://github.com/Purii/react-use-scrollspy/releases) - [Changelog](https://github.com/Purii/react-use-scrollspy/blob/main/CHANGELOG.md) - [Commits](https://github.com/Purii/react-use-scrollspy/compare/v3.0.2...v3.1.1) --- updated-dependencies: - dependency-name: react-use-scrollspy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * build(deps): Bump react-use-scrollspy from 3.0.2 to 3.1.1 Bumps [react-use-scrollspy](https://github.com/Purii/react-use-scrollspy) from 3.0.2 to 3.1.1. - [Release notes](https://github.com/Purii/react-use-scrollspy/releases) - [Changelog](https://github.com/Purii/react-use-scrollspy/blob/main/CHANGELOG.md) - [Commits](https://github.com/Purii/react-use-scrollspy/compare/v3.0.2...v3.1.1) --- updated-dependencies: - dependency-name: react-use-scrollspy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * [react-use-scrollspy-3] delete branch * [react-use-scrollspy-3] if condition delete branch --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacopo * build(deps-dev): Bump @babel/core from 7.24.4 to 7.24.7 (#567) Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.24.4 to 7.24.7. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.24.7/packages/babel-core) --- updated-dependencies: - dependency-name: "@babel/core" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacopo Carlini * build(deps): Bump @mui/system from 5.15.15 to 5.15.20 (#566) Bumps [@mui/system](https://github.com/mui/material-ui/tree/HEAD/packages/mui-system) from 5.15.15 to 5.15.20. - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/v5.15.20/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v5.15.20/packages/mui-system) --- updated-dependencies: - dependency-name: "@mui/system" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacopo Carlini * added missing call for station in status TO_FIX_UPDATE (#581) Co-authored-by: Jacopo Carlini * Bump to version 1.26.1 [skip ci] * Pin actions/checkout action to ee0669b (#582) Co-authored-by: renovate-pagopa[bot] <164534245+renovate-pagopa[bot]@users.noreply.github.com> Co-authored-by: Jacopo Carlini * fix delete branch * Update README.md * Update README.md --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacopo Carlini Co-authored-by: gioelemella <128155546+gioelemella@users.noreply.github.com> Co-authored-by: pagopa-github-bot Co-authored-by: renovate-pagopa[bot] <164534245+renovate-pagopa[bot]@users.noreply.github.com> * Bump to version 1.26.1-1-next * [VAS-1133] feat: Add new api key for printPaymentsNotice product (#584) * [VAS-1133] feat: Introduce print notice api key list element * [VAS-1133] fix: Api key products psp * [VAS-1133] feat: Refactor api key products * [VAS-1133] feat: Introduce flag print notice for api keys * [VAS-1133] chore: Api key unit test coverage * Bump to version 1.26.1-2-next * fix: Updated AddEditCommissionBundleForm.tsx to call brokerDelegation as an institution (#587) * Bump to version 1.26.1-3-next * [VAS-1070] feat; Change station and channel detail view on pending update (#586) * [VAS-1070] improved station API and removed wrapper status value from body * [VAS-1070] integrated new station and channel detail API and removed unused ones. * [VAS-1070] fix unit tests * [VAS-1070] handled station and channel with pending update * [VAS-1070] added common component for alert in station and channel detail page * [VAS-1070] removed created by when undefined * [VAS-1070] fix unit tests * [VAS-1070] fix title * [VAS-1070] rename variable * Bump to version 1.26.3-1-next * notify * fix missing translate (#596) * Bump to version 1.26.4-1-next * fix: Bugs found before release (#597) * fix: Bundle -> hide delete & disable invite EC buttons if bundle is expired * fix: Newconnectivity select channels * fix: Margin top checkbox channels edit page * fix: Unit tests * empty commit * Bump to version 1.26.4-2-next * [VAS-1146] feat: Implement new boolean "cart" for bundles (#605) * [VAS-1146] feat: Implement new switch for cart bool in bundle add/edit page * [VAS-1146] chore: Unit tests * [VAS-1146] chore: Update packagejson openapi command * empty commit * [VAS-1146] fix: Unit tests * [VAS-1146] feat: Swap api call getChannelsDetails with primitive version check on list elements * [VAS-1146] feat: Improve unit test * [VAS-1146] fix: Unit tests * [VAS-1146] fix: Unit tests * [VAS-1146] feat: Add cart bool to bundle details drawer * fix unit test * [VAS-1146] feat: Improve code * Bump to version 1.26.4-3-next --------- Signed-off-by: dependabot[bot] Co-authored-by: Samuele Varianti <128470180+svariant@users.noreply.github.com> Co-authored-by: pagopa-github-bot Co-authored-by: Jacopo Co-authored-by: Alessio Cialini <63233981+alessio-cialini@users.noreply.github.com> Co-authored-by: Alessio Cialini Co-authored-by: svariant Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: renovate-pagopa[bot] <164534245+renovate-pagopa[bot]@users.noreply.github.com> --- src/locale/it.json | 4 +- .../AddEditCommissionBundlePage.tsx | 1 + .../AddEditCommissionBundleForm.tsx | 163 ++- .../AddEditCommissionBundleForm.test.tsx | 1037 +++++++++-------- .../CommissionBundleDetailConfiguration.tsx | 231 ++-- ...mmissionBundleDetailConfiguration.test.tsx | 116 +- src/services/__mocks__/bundleService.ts | 3 +- src/services/__mocks__/channelService.ts | 10 + src/services/__mocks__/institutionsService.ts | 2 +- 9 files changed, 840 insertions(+), 727 deletions(-) diff --git a/src/locale/it.json b/src/locale/it.json index e685a24a1..9523ab421 100644 --- a/src/locale/it.json +++ b/src/locale/it.json @@ -1257,7 +1257,9 @@ "paymentOnlyDigitalStamp": "Pagamento solo marca da bollo", "from": "Da", "to": "A", - "all": "Tutti" + "all": "Tutti", + "cart": "Gestione carrello di pagamenti", + "cartInfo": "La gestione del carrello รจ possibile soltanto per i canali configurati con le primitive in versione 2" }, "addTaxonomies": { "subTitle": "Cerca i servici di incasso sfogliando il catalogo oppure carica una lista di codici.", diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx index 5da031e91..e6229e65d 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx @@ -57,6 +57,7 @@ const toNewFormData = ( validityDateFrom: data?.validityDateFrom ?? minDateTomorrow(), validityDateTo: data?.validityDateTo ?? minDateTomorrow(), pspBusinessName: selectedParty?.description ?? '', + cart: data?.cart }); function getABIOrBIC( diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx index 08ad08f41..f971a7e04 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx @@ -1,7 +1,7 @@ /* eslint-disable functional/no-let */ /* eslint-disable complexity */ /* eslint-disable sonarjs/cognitive-complexity */ -import { MenuBook } from '@mui/icons-material'; +import {InfoOutlined, MenuBook} from '@mui/icons-material'; import BookmarkAddIcon from '@mui/icons-material/BookmarkAdd'; import DateRangeIcon from '@mui/icons-material/DateRange'; import EuroIcon from '@mui/icons-material/Euro'; @@ -18,38 +18,40 @@ import { Radio, RadioGroup, Select, + Switch, TextField, TextFieldProps, + Tooltip, Typography, } from '@mui/material'; -import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import { theme } from '@pagopa/mui-italia'; -import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; -import { FormikProps } from 'formik'; -import { useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { NumericFormat } from 'react-number-format'; -import { BundleRequest } from '../../../../api/generated/portal/BundleRequest'; -import { Delegation } from '../../../../api/generated/portal/Delegation'; -import { TypeEnum } from '../../../../api/generated/portal/PSPBundleResource'; -import { PaymentTypes } from '../../../../api/generated/portal/PaymentTypes'; -import { Touchpoints } from '../../../../api/generated/portal/Touchpoints'; +import {DesktopDatePicker, LocalizationProvider} from '@mui/x-date-pickers'; +import {AdapterDateFns} from '@mui/x-date-pickers/AdapterDateFns'; +import {theme} from '@pagopa/mui-italia'; +import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; +import {FormikProps} from 'formik'; +import {useEffect, useState} from 'react'; +import {useTranslation} from 'react-i18next'; +import {NumericFormat} from 'react-number-format'; +import {BundleRequest} from '../../../../api/generated/portal/BundleRequest'; +import {Delegation} from '../../../../api/generated/portal/Delegation'; +import {TypeEnum} from '../../../../api/generated/portal/PSPBundleResource'; +import {PaymentTypes} from '../../../../api/generated/portal/PaymentTypes'; +import {Touchpoints} from '../../../../api/generated/portal/Touchpoints'; import FormSectionTitle from '../../../../components/Form/FormSectionTitle'; -import { useFlagValue } from '../../../../hooks/useFeatureFlags'; -import { useOrganizationType } from "../../../../hooks/useOrganizationType"; -import { useUserRole } from "../../../../hooks/useUserRole"; -import { Party } from '../../../../model/Party'; -import { sortPaymentType } from '../../../../model/PaymentType'; -import { ConfigurationStatus } from '../../../../model/Station'; -import { useAppSelector } from '../../../../redux/hooks'; -import { partiesSelectors } from '../../../../redux/slices/partiesSlice'; -import { getTouchpoints } from '../../../../services/bundleService'; -import { getChannels } from '../../../../services/channelService'; -import { getPaymentTypes } from '../../../../services/configurationService'; -import { getBrokerDelegation } from '../../../../services/institutionService'; -import { addCurrentBroker } from '../../../../utils/channel-utils'; -import { LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS, LOADING_TASK_GET_CHANNELS_IDS, } from '../../../../utils/constants'; +import {useFlagValue} from '../../../../hooks/useFeatureFlags'; +import {useOrganizationType} from '../../../../hooks/useOrganizationType'; +import {Party} from '../../../../model/Party'; +import {sortPaymentType} from '../../../../model/PaymentType'; +import {ConfigurationStatus} from '../../../../model/Station'; +import {useAppSelector} from '../../../../redux/hooks'; +import {partiesSelectors} from '../../../../redux/slices/partiesSlice'; +import {getTouchpoints} from '../../../../services/bundleService'; +import {getChannels} from '../../../../services/channelService'; +import {getPaymentTypes} from '../../../../services/configurationService'; +import {getBrokerDelegation} from '../../../../services/institutionService'; +import {addCurrentBroker} from '../../../../utils/channel-utils'; +import {LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS, LOADING_TASK_GET_CHANNELS_IDS,} from '../../../../utils/constants'; +import {WrapperChannelResource} from '../../../../api/generated/portal/WrapperChannelResource'; type Props = { formik: FormikProps; @@ -59,19 +61,19 @@ type Props = { const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { const {t} = useTranslation(); - const {userIsPspDirectAdmin} = useUserRole(); - const {orgInfo, orgIsPspDirect} = useOrganizationType(); + const {orgIsPspDirect} = useOrganizationType(); const setLoading = useLoading(LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS); const setLoadingChannels = useLoading(LOADING_TASK_GET_CHANNELS_IDS); const addError = useErrorDispatcher(); - const isPrivateEnabled = useFlagValue("commission-bundles-private"); - const isPublicEnabled = useFlagValue("commission-bundles-public"); + const isPrivateEnabled = useFlagValue('commission-bundles-private'); + const isPublicEnabled = useFlagValue('commission-bundles-public'); const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); const [paymentOptions, setPaymentOptions] = useState(); const [touchpointList, setTouchpointList] = useState(); const [brokerDelegationList, setBrokerDelegationList] = useState>([]); - const [channelsId, setChannelsId] = useState>([]); + const [channels, setChannels] = useState>([]); + const [isChannelV2, setIsChannelV2] = useState(false); const inputGroupStyle = { borderRadius: 1, @@ -86,9 +88,10 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { getChannels({status: ConfigurationStatus.ACTIVE, brokerCode: selectedBrokerCode}) .then((data) => { if (data?.channels && data.channels.length > 0) { - setChannelsId(data.channels.map(ch => ch.channel_code)); + setChannels([...data.channels]); + handleIsChannelV2(formik.values.idChannel, [...data.channels]); } else { - setChannelsId([]); + setChannels([]); addError({ id: 'GET_BROKER_DELEGATIONS_DATA', blocking: false, @@ -104,7 +107,7 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { } }) .catch((error) => { - setChannelsId([]); + setChannels([]); addError({ id: 'GET_CHANNEL_IDS_DATA', blocking: false, @@ -135,15 +138,18 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { if (touchpoints) { setTouchpointList(touchpoints); } - let listBroker = brokerDelegation?.delegation_list ? [...brokerDelegation.delegation_list] : []; + let listBroker = brokerDelegation?.delegation_list + ? [...brokerDelegation.delegation_list] + : []; if (orgIsPspDirect) { listBroker = addCurrentBroker(listBroker, selectedParty as Party); } + if (listBroker.length > 0) { setBrokerDelegationList(listBroker); if (isEdit && idBrokerPsp) { const brokerTaxCode = listBroker?.find( - (el) => el.broker_id === idBrokerPsp + (el) => el.broker_tax_code === idBrokerPsp )?.broker_tax_code; if (brokerTaxCode) { getChannelsByBrokerCode(brokerTaxCode); @@ -185,24 +191,42 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { const shouldDisableDate = (date: Date) => date < new Date(); - function handleBrokerCodesSelection( - value: string | null | undefined - ) { + function handleBrokerCodesSelection(value: string | null | undefined) { formik.setFieldValue('idChannel', ''); + handleIsChannelV2(); if (value === null || value === undefined) { formik.setFieldValue('idBrokerPsp', ''); - setChannelsId([]); + setChannels([]); } else { - const broker = brokerDelegationList?.find( - (el) => el.broker_name === value - ); - formik.handleChange('idBrokerPsp')(broker?.broker_tax_code ?? ""); + const broker = brokerDelegationList?.find((el) => el.broker_name === value); + formik.handleChange('idBrokerPsp')(broker?.broker_tax_code ?? ''); if (broker?.broker_tax_code) { getChannelsByBrokerCode(broker?.broker_tax_code); } } } + const handleIsChannelV2 = ( + channelCode?: string | null, + channelList?: Array + ) => { + let bool = false; + if (channelCode) { + const arrayChannel = channelList ?? channels; + bool = arrayChannel.find((el) => el.channel_code === channelCode)?.primitive_version === 2; + } + + setIsChannelV2(bool); + if (!bool) { + formik.setFieldValue('cart', false); + } + }; + + const handleChangeChannel = (value: string | null) => { + formik.handleChange('idChannel')(value ?? ''); + handleIsChannelV2(value); + }; + return ( <> { ?.map((el) => el?.broker_name ?? '') ?.sort((a, b) => a.localeCompare(b))} disabled={!(brokerDelegationList && brokerDelegationList.length > 0)} - value={brokerDelegationList?.find(el => el.broker_tax_code === formik.values.idBrokerPsp)?.broker_name ?? ""} + value={ + brokerDelegationList?.find( + (el) => el.broker_tax_code === formik.values.idBrokerPsp + )?.broker_name ?? '' + } onChange={(_, value) => { handleBrokerCodesSelection(value); }} @@ -516,18 +544,9 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { a.localeCompare(b)) - } - disabled={!(channelsId && channelsId.length > 0)} - onChange={(_event, value) => { - if (value === null) { - formik.setFieldValue('idChannel', ''); - } else { - formik.handleChange('idChannel')(value); - } - }} + options={channels.map((el) => el.channel_code).sort((a, b) => a.localeCompare(b))} + disabled={!(channels && channels.length > 0)} + onChange={(_event, value) => handleChangeChannel(value)} value={formik.values.idChannel} fullWidth renderInput={(params) => ( @@ -546,6 +565,32 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { data-testid="channels-id-test" /> + + formik.setFieldValue('cart', e.target.checked)} + checked={formik.values.cart ?? false} + disabled={!isChannelV2} + data-testid="bundle-cart" + /> + } + label={ +
+ {t('commissionBundlesPage.addEditCommissionBundle.form.cart')} + + + +
+ } + /> +
diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx index 5b3368bca..b42bbad4f 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx @@ -1,24 +1,29 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react'; -import {MemoryRouter, Route} from 'react-router-dom'; -import {createStore, store} from '../../../../../redux/store'; -import {Provider} from 'react-redux'; +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { MemoryRouter, Route } from 'react-router-dom'; +import { createStore, store } from '../../../../../redux/store'; +import { Provider } from 'react-redux'; import React from 'react'; -import {mockedBundleRequest, mockedBundleRequestForEdit, mockedChannelsIdList,} from '../../../../../services/__mocks__/bundleService'; -import {partiesActions} from '../../../../../redux/slices/partiesSlice'; -import {pspOperatorSignedDirect} from '../../../../../services/__mocks__/partyService'; +import { + mockedBundleRequest, + mockedBundleRequestForEdit, + mockedChannelsIdList, +} from '../../../../../services/__mocks__/bundleService'; +import { partiesActions } from '../../../../../redux/slices/partiesSlice'; +import { pspOperatorSignedDirect } from '../../../../../services/__mocks__/partyService'; import AddEditCommissionBundleForm from '../AddEditCommissionBundleForm'; -import {useFormik} from 'formik'; -import {BundleRequest} from '../../../../../api/generated/portal/BundleRequest'; -import {FormAction} from '../../../../../model/CommissionBundle'; -import {mockedDelegatedPSP} from '../../../../../services/__mocks__/institutionsService'; -import {formatDateToDDMMYYYY} from '../../../../../utils/common-utils'; +import { useFormik } from 'formik'; +import { BundleRequest } from '../../../../../api/generated/portal/BundleRequest'; +import { FormAction } from '../../../../../model/CommissionBundle'; +import { mockedDelegatedPSP } from '../../../../../services/__mocks__/institutionsService'; +import { formatDateToDDMMYYYY } from '../../../../../utils/common-utils'; import * as useErrorDispatcher from '@pagopa/selfcare-common-frontend'; import * as useFeatureFlags from '../../../../../hooks/useFeatureFlags'; import * as useUserRole from '../../../../../hooks/useUserRole'; -import {ROLE} from '../../../../../model/RolePermission'; -import {TypeEnum} from '../../../../../api/generated/portal/PSPBundleResource'; +import { ROLE } from '../../../../../model/RolePermission'; +import { TypeEnum } from '../../../../../api/generated/portal/PSPBundleResource'; +import * as useOrganizationType from '../../../../../hooks/useOrganizationType'; let spyOnGetPaymentTypes: jest.SpyInstance; let spyOnGetTouchpoint: jest.SpyInstance; @@ -29,525 +34,567 @@ let spyOnErrorHook: jest.SpyInstance; let spyOnUseFlagValue: jest.SpyInstance; const TestAddEditCommissionBundleForm = ({ - formAction, - initialValues, - injectedStore, - }: { - formAction: string; - initialValues?: BundleRequest; - injectedStore?: ReturnType; + formAction, + initialValues, + injectedStore, +}: { + formAction: string; + initialValues?: BundleRequest; + injectedStore?: ReturnType; }) => { - const formik = useFormik>({ - initialValues: initialValues ?? {}, - onSubmit: async () => jest.fn(), - enableReinitialize: true, - validateOnBlur: true, - validateOnChange: true, - }); - return ( - - - - - - - - - - ); + const formik = useFormik>({ + initialValues: initialValues ?? {}, + onSubmit: async () => jest.fn(), + enableReinitialize: true, + validateOnBlur: true, + validateOnChange: true, + }); + return ( + + + + + + + + + + ); }; const bundleName = 'bundleName'; const bundleDescription = 'description'; describe('', () => { - beforeEach(() => { - spyOnGetPaymentTypes = jest.spyOn( - require('../../../../../services/configurationService'), - 'getPaymentTypes' - ); - spyOnGetTouchpoint = jest.spyOn( - require('../../../../../services/bundleService'), - 'getTouchpoints' - ); - spyOnGetInstitutionService = jest.spyOn( - require('../../../../../services/institutionService'), - 'getBrokerDelegation' - ); - spyOnCreateCommissionBundle = jest.spyOn( - require('../../../../../services/bundleService'), - 'createBundle' - ); - spyOnGetChannelService = jest.spyOn( - require('../../../../../services/channelService'), + jest.setTimeout(30000); + beforeEach(() => { + spyOnGetPaymentTypes = jest.spyOn( + require('../../../../../services/configurationService'), + 'getPaymentTypes' + ); + spyOnGetTouchpoint = jest.spyOn( + require('../../../../../services/bundleService'), + 'getTouchpoints' + ); + spyOnGetInstitutionService = jest.spyOn( + require('../../../../../services/institutionService'), + 'getBrokerDelegation' + ); + spyOnCreateCommissionBundle = jest.spyOn( + require('../../../../../services/bundleService'), + 'createBundle' + ); + spyOnGetChannelService = jest.spyOn( + require('../../../../../services/channelService'), 'getChannels' - ); - spyOnErrorHook = jest - .spyOn(useErrorDispatcher, 'useErrorDispatcher') - .mockReturnValue(jest.fn()); - spyOnUseFlagValue = jest.spyOn(useFeatureFlags, 'useFlagValue'); - jest.mock('../../../../../hooks/useUserRole'); - jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ - userRole: ROLE.PSP_ADMIN, - userIsPspAdmin: true, - userIsEcAdmin: false, - userIsPspDirectAdmin: false, - userIsPagopaOperator: false, - userIsAdmin: false, - }); - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); + ); + spyOnErrorHook = jest + .spyOn(useErrorDispatcher, 'useErrorDispatcher') + .mockReturnValue(jest.fn()); + spyOnUseFlagValue = jest.spyOn(useFeatureFlags, 'useFlagValue'); + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: true, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: false, + userIsAdmin: false, }); + jest.spyOn(useOrganizationType, 'useOrganizationType').mockReturnValue({ + orgInfo: { + types: { + isPsp: true, + isPspBroker: true, + isEc: false, + isEcBroker: false + }, + isSigned: true + }, + orgIsPspDirect: true, + orgIsEcDirect: false, + orgIsBrokerSigned: true, + orgIsPspSigned: true, + orgIsPspBrokerSigned: true, + orgIsEcSigned: false, + orgIsEcBrokerSigned: false, + }); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + cleanup(); + spyOnGetPaymentTypes.mockRestore(); + spyOnGetTouchpoint.mockRestore(); + spyOnGetInstitutionService.mockRestore(); + spyOnCreateCommissionBundle.mockRestore(); + spyOnGetChannelService.mockRestore(); + spyOnErrorHook.mockRestore(); + }); + + const componentRender = ( + formAction: string, + initialValues?: BundleRequest, + injectedStore?: ReturnType + ) => { + render( + + ); - afterEach(() => { - cleanup(); - spyOnGetPaymentTypes.mockRestore(); - spyOnGetTouchpoint.mockRestore(); - spyOnGetInstitutionService.mockRestore(); - spyOnCreateCommissionBundle.mockRestore(); - spyOnGetChannelService.mockRestore(); - spyOnErrorHook.mockRestore(); + const input = { + public: screen + .getByTestId('bundle-type-test') + .querySelector(`[value=${TypeEnum.PUBLIC}]`) as HTMLInputElement, + global: screen + .getByTestId('bundle-type-test') + .querySelector(`[value=${TypeEnum.GLOBAL}]`) as HTMLInputElement, + private: screen + .getByTestId('bundle-type-test') + .querySelector(`[value=${TypeEnum.PRIVATE}]`) as HTMLInputElement, + name: screen.getByTestId('name-test') as HTMLInputElement, + description: screen.getByTestId('description-test') as HTMLInputElement, + paymentType: screen.getByTestId('payment-type-test') as HTMLInputElement, + touchpoint: screen.getByTestId('touchpoint-test') as HTMLInputElement, + minImport: screen.getByTestId('min-import-test') as HTMLInputElement, + maxImport: screen.getByTestId('max-import-test') as HTMLInputElement, + feeApplied: screen.getByTestId('payment-amount-test') as HTMLInputElement, + brokerCodeList: screen + .getByTestId('broker-code-test') + .querySelector('input') as HTMLInputElement, + channelList: screen + .getByTestId('channels-id-test') + .querySelector('input') as HTMLInputElement, + digitalStampYes: screen + .getByTestId('digital-stamp-test') + .querySelector('[value="true"]') as HTMLInputElement, + digitalStampNo: screen + .getByTestId('digital-stamp-test') + .querySelector('[value="false"]') as HTMLInputElement, + digitalStampResYes: screen + .getByTestId('digital-stamp-restriction-test') + .querySelector('[value="true"]') as HTMLInputElement, + digitalStampResNo: screen + .getByTestId('digital-stamp-restriction-test') + .querySelector('[value="false"]') as HTMLInputElement, + fromDate: screen.getByTestId('from-date-test') as HTMLInputElement, + ToDate: screen.getByTestId('to-date-test') as HTMLInputElement, + cartSwitch: screen.getByTestId('bundle-cart') as HTMLInputElement, + }; + + return input; + }; + + test('Test AddEditCommissionBundleForm with all input change in CREATE', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockReturnValue(true); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); - const componentRender = ( - formAction: string, - initialValues?: BundleRequest, - injectedStore?: ReturnType - ) => { - render( - - ); - - const input = { - public: screen - .getByTestId('bundle-type-test') - .querySelector(`[value=${TypeEnum.PUBLIC}]`) as HTMLInputElement, - global: screen - .getByTestId('bundle-type-test') - .querySelector(`[value=${TypeEnum.GLOBAL}]`) as HTMLInputElement, - private: screen - .getByTestId('bundle-type-test') - .querySelector(`[value=${TypeEnum.PRIVATE}]`) as HTMLInputElement, - name: screen.getByTestId('name-test') as HTMLInputElement, - description: screen.getByTestId('description-test') as HTMLInputElement, - paymentType: screen.getByTestId('payment-type-test') as HTMLInputElement, - touchpoint: screen.getByTestId('touchpoint-test') as HTMLInputElement, - minImport: screen.getByTestId('min-import-test') as HTMLInputElement, - maxImport: screen.getByTestId('max-import-test') as HTMLInputElement, - feeApplied: screen.getByTestId('payment-amount-test') as HTMLInputElement, - brokerCodeList: screen - .getByTestId('broker-code-test') - .querySelector('input') as HTMLInputElement, - channelList: screen - .getByTestId('channels-id-test') - .querySelector('input') as HTMLInputElement, - digitalStampYes: screen - .getByTestId('digital-stamp-test') - .querySelector('[value="true"]') as HTMLInputElement, - digitalStampNo: screen - .getByTestId('digital-stamp-test') - .querySelector('[value="false"]') as HTMLInputElement, - digitalStampResYes: screen - .getByTestId('digital-stamp-restriction-test') - .querySelector('[value="true"]') as HTMLInputElement, - digitalStampResNo: screen - .getByTestId('digital-stamp-restriction-test') - .querySelector('[value="false"]') as HTMLInputElement, - fromDate: screen.getByTestId('from-date-test') as HTMLInputElement, - ToDate: screen.getByTestId('to-date-test') as HTMLInputElement, - }; - - return input; - }; + //Change radio group bundle type + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + + fireEvent.click(input.global); + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(true); + expect(input.private.checked).toBe(false); + + fireEvent.click(input.public); + expect(input.public.checked).toBe(true); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + + fireEvent.click(input.private); + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(true); + + // Change input name & description + fireEvent.change(input.name, { target: { value: bundleName } }); + expect(input.name.value).toBe(bundleName); + fireEvent.change(input.description, { target: { value: bundleDescription } }); + expect(input.description.value).toBe(bundleDescription); + + // Change paymentType + fireEvent.mouseDown( + screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.paymentType') + ); + fireEvent.click(screen.getByText(new RegExp('.*Bonifico - SEPA.*', 'i'))); + + expect(input.paymentType).toHaveTextContent('Bonifico - SEPA'); + + // Change touchpoint + fireEvent.mouseDown( + screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.touchpoint') + ); + fireEvent.click(screen.getByText(new RegExp('Tutti', 'i'))); + + expect(input.touchpoint).toHaveTextContent('Tutti'); + + // Change min import number + fireEvent.change(input.minImport, { target: { value: 10 } }); + expect(parseFloat(input.minImport.value)).toBe(10); + // Change max import number + fireEvent.change(input.maxImport, { target: { value: 10 } }); + expect(parseFloat(input.maxImport.value)).toBe(10); + + fireEvent.change(input.feeApplied, { target: { value: '10,8' } }); + expect(input.feeApplied.value).toBe('10,8'); + + fireEvent.change(input.feeApplied, { target: { value: 10.8 } }); + expect(input.feeApplied.value).toBe('10,8'); + + // Change broker code list + expect(input.channelList.disabled).toBe(true); + fireEvent.change(input.brokerCodeList, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + input.brokerCodeList.focus(); + + fireEvent.change(document.activeElement as Element, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + expect(input.brokerCodeList.value).toEqual(mockedDelegatedPSP.delegation_list![1].broker_name); + await waitFor(() => { + expect(spyOnGetChannelService).toBeCalledTimes(1); + expect(input.channelList.disabled).toBe(false); + }); + + fireEvent.change(document.activeElement as Element, { + target: { value: '' }, + }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + await waitFor(() => { + expect(input.channelList.disabled).toBe(true); + }); + + fireEvent.change(input.brokerCodeList, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + input.brokerCodeList.focus(); + + fireEvent.change(document.activeElement as Element, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + expect(input.brokerCodeList.value).toEqual(mockedDelegatedPSP.delegation_list![1].broker_name); + await waitFor(() => { + expect(spyOnGetChannelService).toBeCalledTimes(2); + expect(input.channelList.disabled).toBe(false); + }); - test('Test AddEditCommissionBundleForm with all input change in CREATE', async () => { - jest.setTimeout(30000); - const injectStore = createStore(); - spyOnUseFlagValue.mockReturnValue(true); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Change radio group bundle type - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); - - fireEvent.click(input.global); - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(true); - expect(input.private.checked).toBe(false); - - fireEvent.click(input.public); - expect(input.public.checked).toBe(true); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); - - fireEvent.click(input.private); - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(true); - - // Change input name & description - fireEvent.change(input.name, {target: {value: bundleName}}); - expect(input.name.value).toBe(bundleName); - fireEvent.change(input.description, {target: {value: bundleDescription}}); - expect(input.description.value).toBe(bundleDescription); - - // Change paymentType - fireEvent.mouseDown( - screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.paymentType') - ); - fireEvent.click(screen.getByText(new RegExp('.*Bonifico - SEPA.*', 'i'))); - - expect(input.paymentType).toHaveTextContent('Bonifico - SEPA'); - - // Change touchpoint - fireEvent.mouseDown( - screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.touchpoint') - ); - fireEvent.click(screen.getByText(new RegExp('Tutti', 'i'))); - - expect(input.touchpoint).toHaveTextContent('Tutti'); - - // Change min import number - fireEvent.change(input.minImport, {target: {value: 10}}); - expect(parseFloat(input.minImport.value)).toBe(10); - // Change max import number - fireEvent.change(input.maxImport, {target: {value: 10}}); - expect(parseFloat(input.maxImport.value)).toBe(10); - - fireEvent.change(input.feeApplied, {target: {value: '10,8'}}); - expect(input.feeApplied.value).toBe('10,8'); - - fireEvent.change(input.feeApplied, {target: {value: 10.8}}); - expect(input.feeApplied.value).toBe('10,8'); - - // Change broker code list - expect(input.channelList.disabled).toBe(true); - fireEvent.change(input.brokerCodeList, { - target: {value: mockedDelegatedPSP.delegation_list![1].broker_name}, - }); - input.brokerCodeList.focus(); - - fireEvent.change(document.activeElement as Element, { - target: {value: mockedDelegatedPSP.delegation_list![1].broker_name}, - }); - fireEvent.keyDown(document.activeElement as Element, {key: 'ArrowDown'}); - fireEvent.keyDown(document.activeElement as Element, {key: 'Enter'}); - expect(input.brokerCodeList.value).toEqual(mockedDelegatedPSP.delegation_list![1].broker_name); - await waitFor(() => { - expect(spyOnGetChannelService).toBeCalledTimes(1); - expect(input.channelList.disabled).toBe(false); - }); - - fireEvent.change(document.activeElement as Element, { - target: {value: ''}, - }); - fireEvent.keyDown(document.activeElement as Element, {key: 'ArrowDown'}); - fireEvent.keyDown(document.activeElement as Element, {key: 'Enter'}); - await waitFor(() => { - expect(input.channelList.disabled).toBe(true); - }); - - // Change channel id - fireEvent.mouseDown(input.channelList); - fireEvent.select(input.channelList, {target: {value: mockedChannelsIdList[0]}}); - expect(input.channelList.value).toBe(mockedChannelsIdList[0]); - - //Change radio buttons digitalStamp - expect(input.digitalStampYes.checked).toBe(false); - expect(input.digitalStampNo.checked).toBe(true); - expect(input.digitalStampResYes.disabled).toBe(false); - - fireEvent.click(input.digitalStampYes); - expect(input.digitalStampYes.checked).toBe(true); - expect(input.digitalStampNo.checked).toBe(false); - expect(input.digitalStampResYes.disabled).toBe(true); - - fireEvent.click(input.digitalStampNo); - expect(input.digitalStampYes.checked).toBe(false); - expect(input.digitalStampNo.checked).toBe(true); - expect(input.digitalStampResYes.disabled).toBe(false); - - //Change radio buttons digitalStampRes - expect(input.digitalStampResYes.checked).toBe(false); - expect(input.digitalStampResNo.checked).toBe(true); - expect(input.digitalStampYes.disabled).toBe(false); - - fireEvent.click(input.digitalStampResYes); - expect(input.digitalStampResYes.checked).toBe(true); - expect(input.digitalStampResNo.checked).toBe(false); - expect(input.digitalStampYes.disabled).toBe(true); - - fireEvent.click(input.digitalStampResNo); - expect(input.digitalStampResYes.checked).toBe(false); - expect(input.digitalStampResNo.checked).toBe(true); - expect(input.digitalStampYes.disabled).toBe(false); - - // Change dates - const formatDate = (date: Date) => { - const day = date.getDate().toString().padStart(2, '0'); - const month = (date.getMonth() + 1).toString().padStart(2, '0'); - const year = date.getFullYear(); - return `${day}/${month}/${year}`; - }; - - const fromDate = new Date(2028, 9, 27); - const toDate = new Date(2028, 9, 28); - - fireEvent.change(input.fromDate, {target: {value: formatDate(fromDate)}}); - expect(input.fromDate.value).toBe('27/10/2028'); - - fireEvent.change(input.ToDate, {target: {value: formatDate(toDate)}}); - expect(input.ToDate.value).toBe('28/10/2028'); + // Change channel id + fireEvent.change(input.channelList, { + target: { value: mockedChannelsIdList[0] }, }); + input.channelList.focus(); - test('Test AddEditCommissionBundleForm with all input change in EDIT', async () => { - const injectStore = createStore(); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Edit, mockedBundleRequestForEdit, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(true); - expect(input.global.disabled).toBe(true); - expect(input.private.disabled).toBe(true); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(true); - expect(input.private.checked).toBe(false); - - // Check input name & description - expect(input.name.value).toBe(mockedBundleRequest.name); - expect(input.description.value).toBe(mockedBundleRequest.description); - - // Check paymentType - //TODO FIX DEFAULT LIST - // const selectPaymentTypeBtn = await within(input.paymentType).getByRole('button'); - // expect(selectPaymentTypeBtn.textContent).toBe(mockedBundleRequest.paymentType); - - // Check touchpoint - //TODO FIX DEFAULT LIST - // const selectTouchPointBtn = await within(input.touchpoint).getByRole('button'); - // expect(selectTouchPointBtn.textContent).toBe(mockedBundleRequest.paymentType); - - // Check min import number - expect(input.minImport.value).toBe( - (mockedBundleRequest.minPaymentAmount! / 100)?.toString().replace('.', ',') - ); - // Check max import number - expect(input.maxImport.value).toBe( - (mockedBundleRequest.maxPaymentAmount! / 100)?.toString().replace('.', ',') - ); - - expect(input.feeApplied.value).toBe( - (mockedBundleRequest.paymentAmount! / 100)?.toString().replace('.', ',') - ); - - // Check broker code list - expect(input.brokerCodeList.value).toBe( - mockedDelegatedPSP.delegation_list!.find((el) => el.broker_tax_code === mockedBundleRequestForEdit.idBrokerPsp) - ?.broker_name - ); - - // Check channel id - expect(input.channelList.value).toBe(mockedBundleRequest.idChannel); - - //Check radio buttons digitalStamp - expect(input.digitalStampYes.checked).toBe(false); - expect(input.digitalStampNo.checked).toBe(true); - - expect(input.digitalStampYes.disabled).toBe(true); - - //Check radio buttons digitalStampRes - expect(input.digitalStampResYes.checked).toBe(true); - expect(input.digitalStampResNo.checked).toBe(false); - - expect(input.digitalStampResYes.disabled).toBe(false); - - fireEvent.click(input.digitalStampResYes); - expect(input.digitalStampResYes.checked).toBe(true); - expect(input.digitalStampResNo.checked).toBe(false); - expect(input.digitalStampYes.disabled).toBe(true); - - // Check dates - expect(input.fromDate.disabled).toBe(true); - expect(input.fromDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateFrom)); - - expect(input.ToDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateTo)); + fireEvent.change(document.activeElement as Element, { + target: { value: mockedChannelsIdList[0] }, }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + expect(input.channelList.value).toEqual(mockedChannelsIdList[0]); + + //Change radio buttons digitalStamp + expect(input.digitalStampYes.checked).toBe(false); + expect(input.digitalStampNo.checked).toBe(true); + expect(input.digitalStampResYes.disabled).toBe(false); + + fireEvent.click(input.digitalStampYes); + expect(input.digitalStampYes.checked).toBe(true); + expect(input.digitalStampNo.checked).toBe(false); + expect(input.digitalStampResYes.disabled).toBe(true); + + fireEvent.click(input.digitalStampNo); + expect(input.digitalStampYes.checked).toBe(false); + expect(input.digitalStampNo.checked).toBe(true); + expect(input.digitalStampResYes.disabled).toBe(false); + + //Change radio buttons digitalStampRes + expect(input.digitalStampResYes.checked).toBe(false); + expect(input.digitalStampResNo.checked).toBe(true); + expect(input.digitalStampYes.disabled).toBe(false); + + fireEvent.click(input.digitalStampResYes); + expect(input.digitalStampResYes.checked).toBe(true); + expect(input.digitalStampResNo.checked).toBe(false); + expect(input.digitalStampYes.disabled).toBe(true); + + fireEvent.click(input.digitalStampResNo); + expect(input.digitalStampResYes.checked).toBe(false); + expect(input.digitalStampResNo.checked).toBe(true); + expect(input.digitalStampYes.disabled).toBe(false); + + // Change dates + const formatDate = (date: Date) => { + const day = date.getDate().toString().padStart(2, '0'); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const year = date.getFullYear(); + return `${day}/${month}/${year}`; + }; + + const fromDate = new Date(2028, 9, 27); + const toDate = new Date(2028, 9, 28); + + fireEvent.change(input.fromDate, { target: { value: formatDate(fromDate) } }); + expect(input.fromDate.value).toBe('27/10/2028'); + + fireEvent.change(input.ToDate, { target: { value: formatDate(toDate) } }); + expect(input.ToDate.value).toBe('28/10/2028'); + }); - test('Test AddEditCommissionBundleForm feature flag only global types', async () => { - const injectStore = createStore(); - spyOnUseFlagValue.mockReturnValue(false); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(true); - expect(input.global.disabled).toBe(false); - expect(input.private.disabled).toBe(true); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); + test('Test AddEditCommissionBundleForm with all input change in EDIT', async () => { + const injectStore = createStore(); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Edit, mockedBundleRequestForEdit, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); }); - test('Test AddEditCommissionBundleForm feature flag only global & private types', async () => { - const injectStore = createStore(); - spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-private'); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(true); - expect(input.global.disabled).toBe(false); - expect(input.private.disabled).toBe(false); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); + //Check radio group bundle type + expect(input.public.disabled).toBe(true); + expect(input.global.disabled).toBe(true); + expect(input.private.disabled).toBe(true); + + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(true); + expect(input.private.checked).toBe(false); + + // Check input name & description + expect(input.name.value).toBe(mockedBundleRequest.name); + expect(input.description.value).toBe(mockedBundleRequest.description); + + // Check paymentType + //TODO FIX DEFAULT LIST + // const selectPaymentTypeBtn = await within(input.paymentType).getByRole('button'); + // expect(selectPaymentTypeBtn.textContent).toBe(mockedBundleRequest.paymentType); + + // Check touchpoint + //TODO FIX DEFAULT LIST + // const selectTouchPointBtn = await within(input.touchpoint).getByRole('button'); + // expect(selectTouchPointBtn.textContent).toBe(mockedBundleRequest.paymentType); + + // Check min import number + expect(input.minImport.value).toBe( + (mockedBundleRequest.minPaymentAmount! / 100)?.toString().replace('.', ',') + ); + // Check max import number + expect(input.maxImport.value).toBe( + (mockedBundleRequest.maxPaymentAmount! / 100)?.toString().replace('.', ',') + ); + + expect(input.feeApplied.value).toBe( + (mockedBundleRequest.paymentAmount! / 100)?.toString().replace('.', ',') + ); + + // Check broker code list + expect(input.brokerCodeList.value).toBe( + mockedDelegatedPSP.delegation_list!.find( + (el) => el.broker_tax_code === mockedBundleRequestForEdit.idBrokerPsp + )?.broker_name + ); + + // Check channel id + expect(input.channelList.value).toBe(mockedBundleRequest.idChannel); + + //Check radio buttons digitalStamp + expect(input.digitalStampYes.checked).toBe(false); + expect(input.digitalStampNo.checked).toBe(true); + + expect(input.digitalStampYes.disabled).toBe(true); + + //Check radio buttons digitalStampRes + expect(input.digitalStampResYes.checked).toBe(true); + expect(input.digitalStampResNo.checked).toBe(false); + + expect(input.digitalStampResYes.disabled).toBe(false); + + fireEvent.click(input.digitalStampResYes); + expect(input.digitalStampResYes.checked).toBe(true); + expect(input.digitalStampResNo.checked).toBe(false); + expect(input.digitalStampYes.disabled).toBe(true); + + // Check dates + expect(input.fromDate.disabled).toBe(true); + expect(input.fromDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateFrom)); + + expect(input.ToDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateTo)); + }); + + test('Test AddEditCommissionBundleForm feature flag only global types', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockReturnValue(false); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); - test('Test AddEditCommissionBundleForm feature flag only global & public types', async () => { - const injectStore = createStore(); - spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-public'); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(false); - expect(input.global.disabled).toBe(false); - expect(input.private.disabled).toBe(true); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); + //Check radio group bundle type + expect(input.public.disabled).toBe(true); + expect(input.global.disabled).toBe(false); + expect(input.private.disabled).toBe(true); + + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + }); + + test('Test AddEditCommissionBundleForm feature flag only global & private types', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-private'); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); + }); + + //Check radio group bundle type + expect(input.public.disabled).toBe(true); + expect(input.global.disabled).toBe(false); + expect(input.private.disabled).toBe(false); + + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + }); + + test('Test AddEditCommissionBundleForm feature flag only global & public types', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-public'); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); - test('Test fetch error getPaymentTypes', async () => { - const mockError = new Error('API error message getPaymentTypes'); - spyOnGetPaymentTypes.mockRejectedValue(mockError); + //Check radio group bundle type + expect(input.public.disabled).toBe(false); + expect(input.global.disabled).toBe(false); + expect(input.private.disabled).toBe(true); - componentRender(FormAction.Create); + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + }); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - }); + test('Test fetch error getPaymentTypes', async () => { + const mockError = new Error('API error message getPaymentTypes'); + spyOnGetPaymentTypes.mockRejectedValue(mockError); + + componentRender(FormAction.Create); + + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); }); + }); - test('Test fetch error getTouchpoint', async () => { - const mockError = new Error('API error message GetTouchpoint'); - spyOnGetTouchpoint.mockRejectedValue(mockError); + test('Test fetch error getTouchpoint', async () => { + const mockError = new Error('API error message GetTouchpoint'); + spyOnGetTouchpoint.mockRejectedValue(mockError); - componentRender(FormAction.Create); + componentRender(FormAction.Create); - await waitFor(() => { - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); }); + }); - test('Test fetch error getBrokerDelegation', async () => { - const mockError = new Error('API error message getBrokerDelegation'); - spyOnGetInstitutionService.mockRejectedValue(mockError); + test('Test fetch error getBrokerDelegation', async () => { + const mockError = new Error('API error message getBrokerDelegation'); + spyOnGetInstitutionService.mockRejectedValue(mockError); - componentRender(FormAction.Create); + componentRender(FormAction.Create); - await waitFor(() => { - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); + }); - test('Test fetch getBrokerDelegation empty list', async () => { - spyOnGetInstitutionService.mockReturnValue(new Promise((resolve) => resolve([]))); + test('Test fetch getBrokerDelegation empty list', async () => { + spyOnGetInstitutionService.mockReturnValue(new Promise((resolve) => resolve([]))); - componentRender(FormAction.Create); + componentRender(FormAction.Create); - await waitFor(() => { - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); + }); + + test('Test fetch getChannels empty list', async () => { + spyOnGetInstitutionService.mockReturnValue(Promise.resolve(mockedDelegatedPSP)); + spyOnGetChannelService.mockReturnValue(new Promise((resolve) => resolve([]))); + const injectStore = createStore(); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - test('Test fetch getChannels empty list', async () => { - spyOnGetChannelService.mockReturnValue(new Promise((resolve) => resolve([]))); - const injectStore = createStore(); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - - await waitFor(() => { - expect(spyOnGetChannelService).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetChannelService).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); }); + }); + + test('Test fetch getChannels throw error', async () => { + const mockError = new Error('API error message getChannels'); + spyOnGetChannelService.mockRejectedValue(mockError); + const injectStore = createStore(); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - test('Test fetch getChannels throw error', async () => { - const mockError = new Error('API error message getChannels'); - spyOnGetChannelService.mockRejectedValue(mockError); - const injectStore = createStore(); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - - await waitFor(() => { - expect(spyOnErrorHook).toHaveBeenCalled(); - expect(spyOnGetChannelService).toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnErrorHook).toHaveBeenCalled(); + expect(spyOnGetChannelService).toHaveBeenCalled(); }); + }); }); diff --git a/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx b/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx index 4cc1b56e3..4ee2e91c3 100644 --- a/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx +++ b/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx @@ -1,129 +1,134 @@ -import {Divider, Typography, Paper, Grid} from '@mui/material'; -import {useTranslation, TFunction} from 'react-i18next'; -import {Box} from '@mui/system'; -import {ButtonNaked} from '@pagopa/mui-italia'; -import {TitleBox} from '@pagopa/selfcare-common-frontend'; -import {useState} from 'react'; -import {PaddedDrawer} from '../../../../components/PaddedDrawer'; +import { Divider, Typography, Paper, Grid } from '@mui/material'; +import { useTranslation, TFunction } from 'react-i18next'; +import { Box } from '@mui/system'; +import { ButtonNaked } from '@pagopa/mui-italia'; +import { TitleBox } from '@pagopa/selfcare-common-frontend'; +import { useState } from 'react'; +import { PaddedDrawer } from '../../../../components/PaddedDrawer'; import { - formatBooleanValueToYesOrNo, - formatCurrencyEur, - formatDateToDDMMYYYY, + formatBooleanValueToYesOrNo, + formatCurrencyEur, + formatDateToDDMMYYYY, } from '../../../../utils/common-utils'; -import {BundleResource} from '../../../../model/CommissionBundle'; -import {CIBundleResource, CiBundleStatusEnum} from '../../../../api/generated/portal/CIBundleResource'; +import { BundleResource } from '../../../../model/CommissionBundle'; +import { + CIBundleResource, + CiBundleStatusEnum, +} from '../../../../api/generated/portal/CIBundleResource'; const bundleConfigurationFields = { - col1: [ - ['paymentType', 'commissionBundlesPage.addEditCommissionBundle.form.paymentType'], - ['touchpoint', 'commissionBundlesPage.addEditCommissionBundle.form.touchpoint'], - ['paymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.commission'], - ], - col2: [ - ['minPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.minImport'], - ['maxPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.maxImport'], - ['idBrokerPsp', 'commissionBundlesPage.addEditCommissionBundle.form.brokerCode'], - ['pspBusinessName', 'commissionBundlesPage.addEditCommissionBundle.form.pspName'], - ], - col3: [ - ['idChannel', 'commissionBundlesPage.addEditCommissionBundle.form.channelCode'], - ['digitalStamp', 'commissionBundlesPage.addEditCommissionBundle.form.paymentWithDigitalStamp'], - [ - 'digitalStampRestriction', - 'commissionBundlesPage.addEditCommissionBundle.form.paymentOnlyDigitalStamp', - ], + col1: [ + ['paymentType', 'commissionBundlesPage.addEditCommissionBundle.form.paymentType'], + ['touchpoint', 'commissionBundlesPage.addEditCommissionBundle.form.touchpoint'], + ['paymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.commission'], + ], + col2: [ + ['minPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.minImport'], + ['maxPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.maxImport'], + ['idBrokerPsp', 'commissionBundlesPage.addEditCommissionBundle.form.brokerCode'], + ['pspBusinessName', 'commissionBundlesPage.addEditCommissionBundle.form.pspName'], + ], + col3: [ + ['idChannel', 'commissionBundlesPage.addEditCommissionBundle.form.channelCode'], + ['cart', 'commissionBundlesPage.addEditCommissionBundle.form.cart'], + ['digitalStamp', 'commissionBundlesPage.addEditCommissionBundle.form.paymentWithDigitalStamp'], + [ + 'digitalStampRestriction', + 'commissionBundlesPage.addEditCommissionBundle.form.paymentOnlyDigitalStamp', ], - col4: [ - ['validityDateFrom', 'commissionBundlesPage.list.headerFields.startDate'], - ['validityDateTo', 'commissionBundlesPage.list.headerFields.endDate'], - ['lastUpdatedDate', 'commissionBundlesPage.commissionBundleDetail.lastChange'], - ] + ], + col4: [ + ['validityDateFrom', 'commissionBundlesPage.list.headerFields.startDate'], + ['validityDateTo', 'commissionBundlesPage.list.headerFields.endDate'], + ['lastUpdatedDate', 'commissionBundlesPage.commissionBundleDetail.lastChange'], + ], }; const formatConfigValues = (value: any, t: TFunction<'translation'>) => { - if (typeof value === 'string' && value) { - return t(value); - } - if (typeof value === 'boolean') { - return formatBooleanValueToYesOrNo(value, t); - } - if (typeof value === 'number') { - return formatCurrencyEur(value); - } - if (typeof value === 'object') { - return formatDateToDDMMYYYY(value); - } - return '-'; + if (typeof value === 'string' && value) { + return t(value); + } + if (typeof value === 'boolean') { + return formatBooleanValueToYesOrNo(value, t); + } + if (typeof value === 'number') { + return formatCurrencyEur(value); + } + if (typeof value === 'object') { + return formatDateToDDMMYYYY(value); + } + return '-'; }; export default function CommissionBundleDetailConfiguration({ - bundleDetail, - }: { - bundleDetail: BundleResource; + bundleDetail, +}: { + bundleDetail: BundleResource; }) { - const {t} = useTranslation(); - const [openDrawer, setOpenDrawer] = useState(false); + const { t } = useTranslation(); + const [openDrawer, setOpenDrawer] = useState(false); - const columns: Array>> = new Array(bundleConfigurationFields.col1); + const columns: Array>> = new Array(bundleConfigurationFields.col1); - const mapColumn = (col: Array>, isDrawer: boolean, isFirstColumn?: boolean) => - col.map((entry: Array, index: number) => ( - - {isDrawer && (!isFirstColumn || index !== 0) && } - - {t(entry[1])} - - - {formatConfigValues(bundleDetail?.[entry[0] as keyof BundleResource], t)} - - - )); + const mapColumn = (col: Array>, isDrawer: boolean, isFirstColumn?: boolean) => + col.map((entry: Array, index: number) => ( + + {isDrawer && (!isFirstColumn || index !== 0) && } + + {t(entry[1])} + + + {formatConfigValues(bundleDetail?.[entry[0] as keyof BundleResource], t)} + + + )); - return ( - 2 - ? '370px' - : '310px', - display: 'flex', - flexDirection: 'column', - }} - > - - {t('commissionBundlesPage.commissionBundleDetail.configuration')} - - - {columns.map((col, i) => ( - - {mapColumn(col, false)} - - ))} - - setOpenDrawer(true)} - sx={{color: 'primary.main', mt: 'auto', justifyContent: 'start'}} - weight="default" - data-testid="show-more-bundle-configuration-test" - > - + {t('general.showMore')} - - - <> - - {Object.values(bundleConfigurationFields).map((col, i) => mapColumn(col, true, i === 0))} - - - - ); + ? '370px' + : '310px', + display: 'flex', + flexDirection: 'column', + }} + > + + {t('commissionBundlesPage.commissionBundleDetail.configuration')} + + + {columns.map((col, i) => ( + + {mapColumn(col, false)} + + ))} + + setOpenDrawer(true)} + sx={{ color: 'primary.main', mt: 'auto', justifyContent: 'start' }} + weight="default" + data-testid="show-more-bundle-configuration-test" + > + + {t('general.showMore')} + + + <> + + {Object.values(bundleConfigurationFields).map((col, i) => mapColumn(col, true, i === 0))} + + +
+ ); } diff --git a/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx b/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx index 7bba95acf..45eb5726c 100644 --- a/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx +++ b/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx @@ -1,83 +1,85 @@ -import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react'; +import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; import React from 'react'; import CommissionBundleDetailConfiguration from '../CommissionBundleDetailConfiguration'; import { - mockedCommissionBundlePspDetailGlobal, - mockedCommissionBundlePspDetailPrivate, - mockedCommissionBundlePspDetailPublic, + mockedCommissionBundlePspDetailGlobal, + mockedCommissionBundlePspDetailPrivate, + mockedCommissionBundlePspDetailPublic, } from '../../../../../services/__mocks__/bundleService'; beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); }); afterEach(cleanup); describe('', () => { - test('render component CommissionBundleDetailConfiguration bundle type GLOBAl', async () => { - render( - - ); + test('render component CommissionBundleDetailConfiguration bundle type GLOBAl', async () => { + render( + + ); - await waitFor(async () => { - const buttonDrawer = await screen.findByTestId('show-more-bundle-configuration-test'); - expect(buttonDrawer).toBeDefined(); - expect(screen.queryAllByTestId('detail-column').length).toBe(3); + let buttonDrawer; + await waitFor(async () => { + buttonDrawer = screen.queryByTestId('show-more-bundle-configuration-test'); + expect(buttonDrawer).toBeDefined(); + expect(screen.queryAllByTestId('detail-column').length).toBe(3); + }); - //Open Drawer - fireEvent.click(buttonDrawer); - expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); - expect(screen.queryAllByTestId('detail-column').length).toBe(16); - }); + //Open Drawer + fireEvent.click(buttonDrawer); + expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); + expect(screen.queryAllByTestId('detail-column').length).toBe(17); - const closeDrawerButton = screen.getByTestId('close-drawer-button'); - fireEvent.click(closeDrawerButton); + const closeDrawerButton = screen.getByTestId('close-drawer-button'); + fireEvent.click(closeDrawerButton); - await waitFor(() => { - expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); - }); + await waitFor(() => { + expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); }); + }); - test('render component CommissionBundleDetailConfiguration bundle type PRIVATE', async () => { - render( - - ); + test('render component CommissionBundleDetailConfiguration bundle type PRIVATE', async () => { + render( + + ); - await waitFor(async () => { - const buttonDrawer = await screen.findByTestId('show-more-bundle-configuration-test'); - expect(buttonDrawer).toBeDefined(); - expect(screen.queryAllByTestId('detail-column').length).toBe(3); + let buttonDrawer; + await waitFor(async () => { + buttonDrawer = screen.queryByTestId('show-more-bundle-configuration-test'); + expect(buttonDrawer).toBeDefined(); + expect(screen.queryAllByTestId('detail-column').length).toBe(3); + }); - //Open Drawer - fireEvent.click(buttonDrawer); - expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); - expect(screen.queryAllByTestId('detail-column').length).toBe(16); - }); + //Open Drawer + fireEvent.click(buttonDrawer); + expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); + expect(screen.queryAllByTestId('detail-column').length).toBe(17); - const closeDrawerButton = screen.getByTestId('close-drawer-button'); - fireEvent.click(closeDrawerButton); + const closeDrawerButton = screen.getByTestId('close-drawer-button'); + fireEvent.click(closeDrawerButton); - await waitFor(() => { - expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); - }); + await waitFor(() => { + expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); }); + }); - test('render component CommissionBundleDetailConfiguration bundle type PUBLIC', async () => { - render( - - ); - - await waitFor(async () => { - const buttonDrawer = await screen.findByTestId('show-more-bundle-configuration-test'); - expect(buttonDrawer).toBeDefined(); - expect(screen.queryAllByTestId('detail-column').length).toBe(3); + test('render component CommissionBundleDetailConfiguration bundle type PUBLIC', async () => { + render( + + ); - //Open Drawer - fireEvent.click(buttonDrawer); - expect(screen.queryAllByTestId('detail-column').length).toBe(16); - }); + let buttonDrawer; + await waitFor(async () => { + buttonDrawer = screen.queryByTestId('show-more-bundle-configuration-test'); + expect(buttonDrawer).toBeDefined(); + expect(screen.queryAllByTestId('detail-column').length).toBe(3); }); + + //Open Drawer + fireEvent.click(buttonDrawer); + expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); + expect(screen.queryAllByTestId('detail-column').length).toBe(17); + }); }); diff --git a/src/services/__mocks__/bundleService.ts b/src/services/__mocks__/bundleService.ts index ffd59422a..6df433bbe 100644 --- a/src/services/__mocks__/bundleService.ts +++ b/src/services/__mocks__/bundleService.ts @@ -120,6 +120,7 @@ const baseCommissionBundlePspDetail: PSPBundleResource = { validityDateTo: new Date('2028-02-22'), insertedDate: new Date('2024-02-15T09:36:04.792731104'), lastUpdatedDate: new Date('2024-02-17T09:36:04.792731104'), + cart:false }; export const mockedCommissionBundlePspDetailGlobal: PSPBundleResource = { @@ -197,7 +198,7 @@ export const mockedBundleRequestForEdit: BundleRequest = { digitalStamp: false, digitalStampRestriction: true, idChannel: '97735020584_01', - idBrokerPsp: '800011104871', + idBrokerPsp: 'idBrokerPsp', name: 'Commission Bundle Name', description: 'Commission bundle description', paymentAmount: 5556, diff --git a/src/services/__mocks__/channelService.ts b/src/services/__mocks__/channelService.ts index 7398df01a..ef4f6488c 100644 --- a/src/services/__mocks__/channelService.ts +++ b/src/services/__mocks__/channelService.ts @@ -24,30 +24,35 @@ export const mockedChannels: WrapperChannelsResource = { enabled: true, broker_description: 'Intermediario XPAY', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 2, }, { channel_code: 'XPAY_03', enabled: true, broker_description: 'Intermediario XPAY', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, { channel_code: 'WFESP_07_tot', enabled: true, broker_description: 'Intermediario per test WFESP', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, { channel_code: 'WFESP_07_salvo', enabled: false, broker_description: 'Intermediario per test WFESP', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, { channel_code: 'WFESP_07_ila', enabled: true, broker_description: 'Intermediario per test WFESP', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, ], page_info: { @@ -216,30 +221,35 @@ export const mockedChannelsMerged: WrapperChannelsResource = { createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.APPROVED, modifiedAt: new Date(), + primitive_version: 2, }, { channel_code: '97735020584_02', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_CHECK, modifiedAt: new Date(), + primitive_version: 1, }, { channel_code: '97735020584_03', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_CHECK_UPDATE, modifiedAt: new Date(), + primitive_version: 1, }, { channel_code: '97735020584_04', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_FIX, modifiedAt: new Date(), + primitive_version: 1, }, { channel_code: '97735020584_05', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_FIX_UPDATE, modifiedAt: new Date(), + primitive_version: 1, }, ], }; diff --git a/src/services/__mocks__/institutionsService.ts b/src/services/__mocks__/institutionsService.ts index 30e480c8a..0980c4aa1 100644 --- a/src/services/__mocks__/institutionsService.ts +++ b/src/services/__mocks__/institutionsService.ts @@ -48,7 +48,7 @@ export const mockedDelegatedPSP: DelegationResource = { institution_name: 'Azienda Pubblica di Servizi alla Persona Test 1', broker_name: 'PSP1', tax_code: '800011104871', - broker_tax_code: '800011104871', + broker_tax_code: 'idBrokerPsp', }, { broker_id: 'fce5332f-56a4-45b8-8fdc-7667ccdfca5e2', From 0c69d07cf95d0359f616ecf7900a2521eb5cf2b8 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Mon, 15 Jul 2024 09:46:56 +0000 Subject: [PATCH 2/4] Bump to version 1.28.0 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f67608ec8..62060ee6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.27.0", + "version": "1.28.0", "homepage": "ui", "private": true, "scripts": { From a0a520d0e27b58794977d48ad9da4a506a98b698 Mon Sep 17 00:00:00 2001 From: gioelemella <128155546+gioelemella@users.noreply.github.com> Date: Thu, 18 Jul 2024 09:29:14 +0200 Subject: [PATCH 3/4] hotfix: Integration test action (#612) * fix integration test action * test * test 2 * clean integration test action * fix secret name * key_pem * external data * external data removed output * external data removed output * fix * set default environment value on schedule triggher --------- Co-authored-by: Jacopo --- .github/workflows/ci_integration_test.yml | 21 ++++++---------- .gitignore | 1 + .identity/00_data.tf | 5 ++++ .identity/03_github_environment.tf | 30 +++++++++++++++-------- .identity/download_pem.sh | 21 ++++++++++++++++ 5 files changed, 54 insertions(+), 24 deletions(-) create mode 100644 .identity/download_pem.sh diff --git a/.github/workflows/ci_integration_test.yml b/.github/workflows/ci_integration_test.yml index 659fb228e..6d01512eb 100644 --- a/.github/workflows/ci_integration_test.yml +++ b/.github/workflows/ci_integration_test.yml @@ -69,25 +69,18 @@ jobs: - name: Run Integration Tests Puppeteer shell: bash run: | - cd ./integration-test - yarn install - - if [ "${{ inputs.environment }}" = "local" ]; then - export KEY_PEM='${{ secrets.DEV_KEY_PEM }}' + export KEY_PEM='${{ secrets.DEV_KEY_PEM }}' + if [ "${{ inputs.environment || 'dev' }}" = "local" ]; then export FE_URL=https://icy-island-050778e03-${{ github.event.number }}.westeurope.5.azurestaticapps.net/ui fi - if [ "${{ inputs.environment }}" = "dev" ]; then - export KEY_PEM='${{ secrets.DEV_KEY_PEM }}' + if [ "${{ inputs.environment || 'dev' }}" = "dev" ]; then export FE_URL="https://selfcare.dev.platform.pagopa.it/ui" fi - - if [ "${{ inputs.environment }}" = "uat" ]; then - export KEY_PEM='${{ secrets.UAT_KEY_PEM }}' - export FE_URL="https://selfcare.uat.platform.pagopa.it/ui" - fi - + + cd ./integration-test + yarn install yarn run cucumber - name: Run Integration Tests Playwright @@ -157,7 +150,7 @@ jobs: status: ${{ needs.integration_test.result }} token: ${{ secrets.GITHUB_TOKEN }} notify_when: 'success,failure,skipped' - notification_title: '<{run_url}| Integration Test> has {status_message} in ${{ inputs.environment }}' + notification_title: "<{run_url}| Integration Test> has {status_message} in ${{ inputs.environment || 'dev'}}" message_format: '{emoji} <{run_url}|{workflow}> {status_message} in <{repo_url}|{repo}>' footer: 'Linked to <{workflow_url}| workflow file>' env: diff --git a/.gitignore b/.gitignore index e30c26bac..2f4090c7f 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,4 @@ public/version.json /blob-report/ /playwright/.cache/ **/key.pem +**/client_certificate.pfx diff --git a/.identity/00_data.tf b/.identity/00_data.tf index 46b87930a..1c43ba726 100644 --- a/.identity/00_data.tf +++ b/.identity/00_data.tf @@ -54,6 +54,11 @@ data "azurerm_key_vault_secret" "key_vault_key_pem" { key_vault_id = data.azurerm_key_vault.domain_key_vault.id } +data "azurerm_key_vault_certificate" "certificate_key_pem" { + name = "pagopa-${var.env_short}-weu-selfcare-jwt-signing-cert" + key_vault_id = data.azurerm_key_vault.domain_key_vault.id +} + data "azurerm_cdn_profile" "cdn_profile" { name = local.cdn.name resource_group_name = local.cdn.resource_group_name diff --git a/.identity/03_github_environment.tf b/.identity/03_github_environment.tf index a2c08f83f..1a5989877 100644 --- a/.identity/03_github_environment.tf +++ b/.identity/03_github_environment.tf @@ -25,7 +25,7 @@ locals { "TENANT_ID" : data.azurerm_client_config.current.tenant_id, "SUBSCRIPTION_ID" : data.azurerm_subscription.current.subscription_id, "SUBKEY" : data.azurerm_key_vault_secret.key_vault_integration_test_subkey.value, - + "REACT_APP_MIXPANEL_TOKEN" : data.azurerm_key_vault_secret.key_vault_mixpanel_token.value "REACT_APP_ONETRUST_DOMAIN_ID" : data.azurerm_key_vault_secret.key_vault_onetrust_domain.value "BLOB_CONNECTION_STRING" : data.azurerm_key_vault_secret.key_vault_blob_connection_string.value @@ -45,10 +45,29 @@ locals { "SUBKEY" : { "key" : "${upper(var.env)}_SUBKEY", "value" : data.azurerm_key_vault_secret.key_vault_integration_test_subkey.value + }, + "KEY_PEM" : { + "key" : "${upper(var.env)}_KEY_PEM", + "value" : var.env == "dev" ? data.external.pem.result.pem : "" } } } +data "external" "pem" { + program = [ + "bash", "download_pem.sh" + ] + query = { + env = var.env_short + } +} + +# output "certificate" { +# description = "certificate" +# value = data.external.pem.result.pem +# } + + ############### # ENV Secrets # ############### @@ -78,33 +97,24 @@ resource "github_actions_environment_variable" "github_environment_runner_variab # Secrets of the Repository # ############################# -#tfsec:ignore:github-actions-no-plain-text-action-secrets # not real secret resource "github_actions_secret" "secret_sonar_token" { repository = local.github.repository secret_name = "SONAR_TOKEN" plaintext_value = data.azurerm_key_vault_secret.key_vault_sonar.value } -#tfsec:ignore:github-actions-no-plain-text-action-secrets # not real secret resource "github_actions_secret" "secret_bot_token" { repository = local.github.repository secret_name = "BOT_TOKEN_GITHUB" plaintext_value = data.azurerm_key_vault_secret.key_vault_bot_token.value } -#tfsec:ignore:github-actions-no-plain-text-action-secrets # not real secret resource "github_actions_secret" "secret_cucumber_token" { repository = local.github.repository secret_name = "CUCUMBER_PUBLISH_TOKEN" plaintext_value = data.azurerm_key_vault_secret.key_vault_cucumber_token.value } -#tfsec:ignore:github-actions-no-plain-text-action-secrets # not real secret -resource "github_actions_secret" "secret_key_pem" { - repository = local.github.repository - secret_name = "KEY_PEM" - plaintext_value = var.env == "dev" ? data.azurerm_key_vault_secret.key_vault_key_pem[0].value : "" -} resource "github_actions_secret" "special_repo_secrets" { for_each = local.special_repo_secrets diff --git a/.identity/download_pem.sh b/.identity/download_pem.sh new file mode 100644 index 000000000..aec8dee45 --- /dev/null +++ b/.identity/download_pem.sh @@ -0,0 +1,21 @@ +# stackoverflow -> https://stackoverflow.com/questions/65097173/azure-key-vault-download-certificate-with-private-key + +eval "$(jq -r '@sh "export $short_env=\(.env)"')" + +# Define the passphrase for the PKCS#12 file. +passphrase="" + +pkcs12_file="client_certificate.pfx" +certificate_name='pagopa-d-weu-selfcare-jwt-signing-cert' +KeyVaultName='pagopa-d-selfcare-kv' + +# Retrieve the client certificate from the Key Vault +certificate_pfx_base64=$(az keyvault secret show --name ${certificate_name} --vault-name ${KeyVaultName} --query value --output tsv) + +echo "$certificate_pfx_base64" | base64 --decode > client_certificate.pfx + +# Extract private key and certificates +openssl pkcs12 -in "$pkcs12_file" -passin "pass:$passphrase" -nocerts -nodes -out key.pem + +json='{"pem": '$(cat key.pem | jq -Rsa . )'}' +echo -n $json From 5f19d4741d743981984c88e723456547af061155 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Thu, 18 Jul 2024 07:29:43 +0000 Subject: [PATCH 4/4] Bump to version 1.28.1 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 62060ee6d..bcb05047a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.28.0", + "version": "1.28.1", "homepage": "ui", "private": true, "scripts": {