From 52288e6959100fdc86c6903dc87c850b91e4f8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Fri, 18 Oct 2024 15:51:26 +0000 Subject: [PATCH 1/6] fix(j-s): Indictment Case Deletion (#16438) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../Prosecutor/caseFiles.ts | 68 ------------------- .../RestrictionCases/Prosecutor/caseFiles.ts | 68 ------------------- apps/judicial-system/web/messages/index.ts | 2 - .../CasesAwaitingConfirmationTable.tsx | 32 ++++++--- .../src/routes/Shared/Cases/ActiveCases.tsx | 26 ++++--- .../web/src/routes/Shared/Cases/Cases.tsx | 23 +++++-- 6 files changed, 56 insertions(+), 163 deletions(-) delete mode 100644 apps/judicial-system/web/messages/InvestigationCases/Prosecutor/caseFiles.ts delete mode 100644 apps/judicial-system/web/messages/RestrictionCases/Prosecutor/caseFiles.ts diff --git a/apps/judicial-system/web/messages/InvestigationCases/Prosecutor/caseFiles.ts b/apps/judicial-system/web/messages/InvestigationCases/Prosecutor/caseFiles.ts deleted file mode 100644 index fdbf7445bdcb..000000000000 --- a/apps/judicial-system/web/messages/InvestigationCases/Prosecutor/caseFiles.ts +++ /dev/null @@ -1,68 +0,0 @@ -// TODO: DELETE THIS FILE -import { defineMessage, defineMessages } from 'react-intl' - -export const icCaseFiles = { - heading: defineMessage({ - id: 'judicial.system.investigation_cases:case_files.heading', - defaultMessage: 'Rannsóknargögn', - description: - 'Notaður sem titill á rannsóknargagna skrefi í rannsóknarheimildum.', - }), - sections: { - files: defineMessages({ - heading: { - id: 'judicial.system.investigation_cases:case_files.files.heading', - defaultMessage: 'Rannsóknargögn', - description: - 'Notaður sem titill fyrir "rannsóknargögn" hlutann á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - introduction: { - id: 'judicial.system.investigation_cases:case_files.files.introduction', - defaultMessage: - 'Gögnin í pakkanum hér fyrir neðan munu liggja frammi í þinghaldinu.', - description: - 'Notaður sem skýring fyrir "rannsóknargögn" hlutann á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - label: { - id: 'judicial.system.investigation_cases:case_files.files.label', - defaultMessage: 'Dragðu skjöl hingað til að hlaða upp', - description: - 'Notaður sem titill í "rannsóknargögn" skjalaboxi á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - buttonLabel: { - id: 'judicial.system.investigation_cases:case_files.files.buttonLabel', - defaultMessage: 'Velja skjöl til að hlaða upp', - description: - 'Notaður sem titill í "velja gögn til að hlaða upp" takka á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - }), - comments: defineMessages({ - heading: { - id: 'judicial.system.investigation_cases:case_files.comments.heading', - defaultMessage: 'Athugasemdir vegna rannsóknargagna', - description: - 'Notaður sem titill fyrir "athugasemdir vegna rannsóknargagna" hlutann á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - tooltip: { - id: 'judicial.system.investigation_cases:case_files.comments.tooltip', - defaultMessage: - 'Hér er hægt að skrá athugasemdir til dómara og dómritara varðandi rannsóknargögnin.', - description: - 'Notaður sem upplýsingatexti í upplýsingasvæði við "athugasemdir vegna rannsóknargagna" titil á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - label: { - id: 'judicial.system.investigation_cases:case_files.comments.label', - defaultMessage: 'Skilaboð', - description: - 'Notaður sem titill í "skilaboð" textaboxi á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - placeholder: { - id: 'judicial.system.investigation_cases:case_files.comments.placeholder', - defaultMessage: - 'Er eitthvað sem þú vilt koma á framfæri við dómstólinn varðandi gögnin?', - description: - 'Notaður sem skýritexti í "skilaboð" textaboxi á rannsóknargagna skrefi í rannsóknarheimildum.', - }, - }), - }, -} diff --git a/apps/judicial-system/web/messages/RestrictionCases/Prosecutor/caseFiles.ts b/apps/judicial-system/web/messages/RestrictionCases/Prosecutor/caseFiles.ts deleted file mode 100644 index abcfe3222904..000000000000 --- a/apps/judicial-system/web/messages/RestrictionCases/Prosecutor/caseFiles.ts +++ /dev/null @@ -1,68 +0,0 @@ -// TODO: DELETE THIS FILE -import { defineMessage, defineMessages } from 'react-intl' - -export const rcCaseFiles = { - heading: defineMessage({ - id: 'judicial.system.restriction_cases:case_files.heading', - defaultMessage: 'Rannsóknargögn', - description: - 'Notaður sem titill á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }), - sections: { - files: defineMessages({ - heading: { - id: 'judicial.system.restriction_cases:case_files.files.heading', - defaultMessage: 'Rannsóknargögn', - description: - 'Notaður sem titill fyrir "rannsóknargögn" hlutann á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - introduction: { - id: 'judicial.system.restriction_cases:case_files.files.introduction', - defaultMessage: - 'Gögnin í pakkanum hér fyrir neðan munu liggja frammi í þinghaldinu.', - description: - 'Notaður sem skýring fyrir "rannsóknargögn" hlutann á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - label: { - id: 'judicial.system.restriction_cases:case_files.files.label', - defaultMessage: 'Dragðu skjöl hingað til að hlaða upp', - description: - 'Notaður sem titill í "rannsóknargögn" skjalaboxi á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - buttonLabel: { - id: 'judicial.system.restriction_cases:case_files.files.buttonLabel', - defaultMessage: 'Velja skjöl til að hlaða upp', - description: - 'Notaður sem titill í "velja gögn til að hlaða upp" takka á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - }), - comments: defineMessages({ - heading: { - id: 'judicial.system.restriction_cases:case_files.comments.heading', - defaultMessage: 'Athugasemdir vegna rannsóknargagna', - description: - 'Notaður sem titill fyrir "athugasemdir vegna rannsóknargagna" hlutann á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - tooltip: { - id: 'judicial.system.restriction_cases:case_files.comments.tooltip', - defaultMessage: - 'Hér er hægt að skrá athugasemdir til dómara og dómritara varðandi rannsóknargögnin.', - description: - 'Notaður sem upplýsingatexti í upplýsingasvæði við "athugasemdir vegna rannsóknargagna" titil á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - label: { - id: 'judicial.system.restriction_cases:case_files.comments.label', - defaultMessage: 'Skilaboð', - description: - 'Notaður sem titill í "skilaboð" textaboxi á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - placeholder: { - id: 'judicial.system.restriction_cases:case_files.comments.placeholder', - defaultMessage: - 'Er eitthvað sem þú vilt koma á framfæri við dómstólinn varðandi gögnin?', - description: - 'Notaður sem skýritexti í "skilaboð" textaboxi á rannsóknargagna skrefi í gæsluvarðhalds- og farbannsmálum.', - }, - }), - }, -} diff --git a/apps/judicial-system/web/messages/index.ts b/apps/judicial-system/web/messages/index.ts index ce0bd4bfbb5b..d505108db678 100644 --- a/apps/judicial-system/web/messages/index.ts +++ b/apps/judicial-system/web/messages/index.ts @@ -2,7 +2,6 @@ export * from './RestrictionCases/Prosecutor/accusedForm' export * from './RestrictionCases/Prosecutor/requestedHearingArrangementsForm' export * from './RestrictionCases/Prosecutor/reportForm' export * from './RestrictionCases/Prosecutor/demandsForm' -export * from './RestrictionCases/Prosecutor/caseFiles' export * from './RestrictionCases/Prosecutor/overview' export * from './/RestrictionCases/Prosecutor/demandsForm' export * from './RestrictionCases/Court/courtRecordForm' @@ -12,7 +11,6 @@ export * from './InvestigationCases/Prosecutor/defendantForm' export * from './InvestigationCases/Prosecutor/requestedHearingArrangements' export * from './InvestigationCases/Prosecutor/demandsForm' export * from './InvestigationCases/Prosecutor/reportForm' -export * from './InvestigationCases/Prosecutor/caseFiles' export * from './InvestigationCases/Prosecutor/overview' export * from './InvestigationCases/Court/courtRecordForm' export * from './InvestigationCases/Court/confirmation' diff --git a/apps/judicial-system/web/src/routes/Prosecutor/components/CasesAwaitingConfirmationTable/CasesAwaitingConfirmationTable.tsx b/apps/judicial-system/web/src/routes/Prosecutor/components/CasesAwaitingConfirmationTable/CasesAwaitingConfirmationTable.tsx index d75c63a9f223..3c6b6de3ba8f 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/components/CasesAwaitingConfirmationTable/CasesAwaitingConfirmationTable.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/components/CasesAwaitingConfirmationTable/CasesAwaitingConfirmationTable.tsx @@ -9,7 +9,10 @@ import { SectionHeading, TagCaseState, } from '@island.is/judicial-system-web/src/components' -import { useContextMenu } from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu' +import { + ContextMenuItem, + useContextMenu, +} from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu' import { contextMenu } from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu.strings' import { ColumnCaseType, @@ -33,12 +36,19 @@ interface CasesAwaitingConfirmationTableProps { isFiltering: boolean cases: CaseListEntry[] onContextMenuDeleteClick: (id: string) => void + canDeleteCase: (caseToDelete: CaseListEntry) => boolean } const CasesAwaitingConfirmationTable: FC< CasesAwaitingConfirmationTableProps > = (props) => { - const { loading, isFiltering, cases, onContextMenuDeleteClick } = props + const { + loading, + isFiltering, + cases, + onContextMenuDeleteClick, + canDeleteCase, + } = props const { formatMessage } = useIntl() const { openCaseInNewTabMenuItem } = useContextMenu() @@ -76,13 +86,17 @@ const CasesAwaitingConfirmationTable: FC< generateContextMenuItems={(row) => { return [ openCaseInNewTabMenuItem(row.id), - { - title: formatMessage(contextMenu.deleteCase), - onClick: () => { - onContextMenuDeleteClick(row.id) - }, - icon: 'trash', - }, + ...(canDeleteCase(row) + ? [ + { + title: formatMessage(contextMenu.deleteCase), + onClick: () => { + onContextMenuDeleteClick(row.id) + }, + icon: 'trash', + } as ContextMenuItem, + ] + : []), ] }} columns={[ diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx index ac0bcd019845..67a29cbc18bf 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx @@ -4,7 +4,10 @@ import { useIntl } from 'react-intl' import { capitalize } from '@island.is/judicial-system/formatters' import { core, tables } from '@island.is/judicial-system-web/messages' import { TagCaseState } from '@island.is/judicial-system-web/src/components' -import { useContextMenu } from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu' +import { + ContextMenuItem, + useContextMenu, +} from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu' import { contextMenu } from '@island.is/judicial-system-web/src/components/ContextMenu/ContextMenu.strings' import { ColumnCaseType, @@ -19,10 +22,11 @@ import { CaseListEntry } from '@island.is/judicial-system-web/src/graphql/schema interface Props { cases: CaseListEntry[] onContextMenuDeleteClick: (id: string) => void + canDeleteCase: (caseToDelete: CaseListEntry) => boolean } const ActiveCases: FC = (props) => { - const { cases, onContextMenuDeleteClick } = props + const { cases, onContextMenuDeleteClick, canDeleteCase } = props const { formatMessage } = useIntl() const { openCaseInNewTabMenuItem } = useContextMenu() @@ -56,13 +60,17 @@ const ActiveCases: FC = (props) => { generateContextMenuItems={(row) => { return [ openCaseInNewTabMenuItem(row.id), - { - title: formatMessage(contextMenu.deleteCase), - onClick: () => { - onContextMenuDeleteClick(row.id) - }, - icon: 'trash', - }, + ...(canDeleteCase(row) + ? [ + { + title: formatMessage(contextMenu.deleteCase), + onClick: () => { + onContextMenuDeleteClick(row.id) + }, + icon: 'trash', + } as ContextMenuItem, + ] + : []), ] }} columns={[ diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx index a3415cc35d3d..f2c6480de7f0 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/Cases.tsx @@ -10,6 +10,7 @@ import { isIndictmentCase, isProsecutionUser, isPublicProsecutor, + isRestrictionCase, } from '@island.is/judicial-system/types' import { core, @@ -213,15 +214,20 @@ export const Cases: FC = () => { pastCases, } = useFilter(allActiveCases, allPastCases, user) + const canDeleteCase = (caseToDelete: CaseListEntry) => + (isRestrictionCase(caseToDelete.type) && + (caseToDelete.state === CaseState.NEW || + caseToDelete.state === CaseState.DRAFT || + caseToDelete.state === CaseState.SUBMITTED || + caseToDelete.state === CaseState.RECEIVED)) || + (isIndictmentCase(caseToDelete.type) && + (caseToDelete.state === CaseState.DRAFT || + caseToDelete.state === CaseState.WAITING_FOR_CONFIRMATION)) + const deleteCase = async (caseToDelete: CaseListEntry) => { - if ( - caseToDelete.state === CaseState.NEW || - caseToDelete.state === CaseState.DRAFT || - caseToDelete.state === CaseState.WAITING_FOR_CONFIRMATION || - caseToDelete.state === CaseState.SUBMITTED || - caseToDelete.state === CaseState.RECEIVED - ) { + if (canDeleteCase(caseToDelete)) { await transitionCase(caseToDelete.id, CaseTransition.DELETE) + refetch() } } @@ -236,6 +242,7 @@ export const Cases: FC = () => { } await deleteCase(caseToDelete) + setVisibleModal(undefined) } @@ -287,6 +294,7 @@ export const Cases: FC = () => { isFiltering={isFiltering} cases={casesAwaitingConfirmation} onContextMenuDeleteClick={setVisibleModal} + canDeleteCase={canDeleteCase} /> {isPublicProsecutor(user) && ( { ) : (
From 6a593eeb0a37fdc08e5d58617681d63eb4ebd0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81sd=C3=ADs=20Erna=20Gu=C3=B0mundsd=C3=B3ttir?= Date: Fri, 18 Oct 2024 16:34:47 +0000 Subject: [PATCH 2/6] fix(my-pages): add locale param to oragn donation query (#16465) * fix: add locale param to query * fix: cahce * lang --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../health/src/screens/OrganDonation/OrganDonation.tsx | 7 +++++-- .../screens/OrganDonationRegistration/RegistrationForm.tsx | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/service-portal/health/src/screens/OrganDonation/OrganDonation.tsx b/libs/service-portal/health/src/screens/OrganDonation/OrganDonation.tsx index 4f6d6e6ff7d1..f873974f48ba 100644 --- a/libs/service-portal/health/src/screens/OrganDonation/OrganDonation.tsx +++ b/libs/service-portal/health/src/screens/OrganDonation/OrganDonation.tsx @@ -14,9 +14,12 @@ import { useGetDonorStatusQuery } from './OrganDonation.generated' const OrganDonation = () => { useNamespaces('sp.health') - const { formatMessage } = useLocale() + const { formatMessage, lang } = useLocale() const { data, loading, error } = useGetDonorStatusQuery({ fetchPolicy: 'no-cache', + variables: { + locale: lang, + }, }) const donorStatus = data?.healthDirectorateOrganDonation.donor const cardText: string = donorStatus?.isDonor @@ -26,7 +29,7 @@ const OrganDonation = () => { donorStatus?.limitations.limitedOrgansList ?.map((organ) => organ.name) .join(', '), - ].join(' ') + '.' ?? '' + ].join(' ') + '.' : formatMessage(m.iAmOrganDonorText) : formatMessage(m.iAmNotOrganDonorText) diff --git a/libs/service-portal/health/src/screens/OrganDonationRegistration/RegistrationForm.tsx b/libs/service-portal/health/src/screens/OrganDonationRegistration/RegistrationForm.tsx index eb0471d2f4e0..7977a58ca3a9 100644 --- a/libs/service-portal/health/src/screens/OrganDonationRegistration/RegistrationForm.tsx +++ b/libs/service-portal/health/src/screens/OrganDonationRegistration/RegistrationForm.tsx @@ -37,6 +37,7 @@ export const Form2 = () => { const { data, loading } = useGetOrgansListQuery({ variables: { locale: lang }, + fetchPolicy: 'no-cache', }) const isDonor = data?.healthDirectorateOrganDonation.donor?.isDonor From 446ee0445f2089211ff05d7f58ff1562504d246b Mon Sep 17 00:00:00 2001 From: berglindoma13 Date: Fri, 18 Oct 2024 17:38:43 +0000 Subject: [PATCH 3/6] fix(citizenship): indexing error on child support documents (#16469) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../ChildrenOtherDocumentsSubSection.ts | 4 ++-- .../ChildrenSupportingDocuments/ChildrenPassportSubSection.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenOtherDocumentsSubSection.ts b/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenOtherDocumentsSubSection.ts index bc30216bb35d..64ef7904bb4d 100644 --- a/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenOtherDocumentsSubSection.ts +++ b/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenOtherDocumentsSubSection.ts @@ -22,11 +22,11 @@ const FILE_SIZE_LIMIT = 10000000 export const ChildrenOtherDocumentsSubSection = (index: number) => buildSubSection({ - id: Routes.CHILDSUPPORTINGDOCUMENTS, + id: `${Routes.CHILDSUPPORTINGDOCUMENTS}[${index}]`, title: supportingDocuments.labels.otherDocuments.subSectionTitle, children: [ buildMultiField({ - id: Routes.CHILDSUPPORTINGDOCUMENTS, + id: `${Routes.CHILDSUPPORTINGDOCUMENTS}[${index}]`, title: supportingDocuments.labels.otherDocuments.pageTitle, description: (application: Application) => { return { diff --git a/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenPassportSubSection.ts b/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenPassportSubSection.ts index 2b6683acbcc5..bb5e6e8e0f91 100644 --- a/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenPassportSubSection.ts +++ b/libs/application/templates/directorate-of-immigration/citizenship/src/forms/CitizenshipForm/ChildrenSupportingDocuments/ChildrenPassportSubSection.ts @@ -24,7 +24,7 @@ export const ChildrenPassportSubSection = (index: number) => title: supportingDocuments.labels.passport.subSectionTitle, children: [ buildMultiField({ - id: Routes.CHILDRENPASSPORT, + id: `${Routes.CHILDRENPASSPORT}[${index}]`, title: supportingDocuments.labels.passport.pageTitle, description: (application: Application) => { return { From dda4b1358654f73af04e59a6f54e0c3de9a058f7 Mon Sep 17 00:00:00 2001 From: veronikasif <54938148+veronikasif@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:49:07 +0000 Subject: [PATCH 4/6] feat(social-insurance-administration): Add e2e tests (#16397) * [TS-106] e2e tests (Old-age-pension) * [TS-319] e2e tests (Additional-support-for-the-elderly) * Fixed typo in nationalRegistry.mock file after coderabbit review * [TS-156] e2e tests (Pension-supplement) * chore: nx format:write update dirty files * [TS-155] e2e tests (Household-supplement) * [TS-324] e2e test for 1/2 old age pension * Added a helper function that mocks each type of SIA application - coderabbit * Moved all common steps to a shared file so it can be used in multiple SIA tests - coderabbit * Updated all instances of faedingardagur in parentalLeave mocks to use ISO 8601 strings - coderabbit * Added more descriptive test names - coderabbit * Changed getByRole to getByText in submitApplication - coderabbit * Updated OAP tests - coderabbit * Updated all instances of faedingardagur in nationalRegistry mocks to use ISO 8601 strings - coderabbit * [TS-926] Only display available months in TR applications * Removed TODO comment * Refactor repeated heading visibility checks - coderabbit --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../acceptance/mocks/nationalRegistry.mock.ts | 169 ++++++++++ .../acceptance/mocks/parentalLeave.mock.ts | 264 ++++++++++++++++ .../socialInsuranceAdministration.mock.ts | 84 +++++ .../acceptance/setup-xroad.mocks.ts | 291 +----------------- ...additional-support-for-the-elderly.spec.ts | 105 +++++++ .../household-supplement.spec.ts | 140 +++++++++ .../old-age-pension.spec.ts | 229 ++++++++++++++ .../pension-supplement.spec.ts | 126 ++++++++ .../social-insurance-administration/shared.ts | 136 ++++++++ .../AdditionalSupportForTheElderlyForm.ts | 67 ++-- .../additionalSupportForTheElderlyUtils.ts | 48 ++- .../src/forms/HouseholdSupplementForm.ts | 72 +++-- .../src/lib/householdSupplementUtils.ts | 36 ++- .../src/forms/OldAgePensionForm.ts | 69 +++-- .../src/forms/Prerequisites.ts | 3 + .../src/lib/oldAgePensionUtils.ts | 50 +-- .../src/forms/PensionSupplementForm.ts | 74 +++-- .../pension-supplement/src/index.ts | 1 + .../src/lib/pensionSupplementUtils.ts | 30 +- 19 files changed, 1550 insertions(+), 444 deletions(-) create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/nationalRegistry.mock.ts create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/parentalLeave.mock.ts create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/socialInsuranceAdministration.mock.ts create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/additional-support-for-the-elderly.spec.ts create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/household-supplement.spec.ts create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/old-age-pension.spec.ts create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/pension-supplement.spec.ts create mode 100644 apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/shared.ts diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/nationalRegistry.mock.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/nationalRegistry.mock.ts new file mode 100644 index 000000000000..820ea70ac71d --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/nationalRegistry.mock.ts @@ -0,0 +1,169 @@ +import { Response } from '@anev/ts-mountebank' +import { NationalRegistry } from '../../../../../../../../infra/src/dsl/xroad' +import { addXroadMock } from '../../../../../support/wire-mocks' + +export const loadNationalRegistryXroadMocks = async () => { + /* Gervimaður Afríka */ + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitala: '0101303019', + nafn: 'Gervimaður Afríka', + eiginnafn: 'Gervimaður', + millinafn: null, + kenninafn: 'Afríka', + fulltNafn: 'Gervimaður Afríka', + kynkodi: '1', + bannmerking: false, + faedingardagur: '1930-01-01T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/hjuskapur', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitalaMaka: '0101307789', + nafnMaka: 'Gervimaður útlönd', + hjuskaparkodi: '1', + breytt: '2021-05-26T22:23:40.513', + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/rikisfang', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kodi: 'IS', + land: 'Ísland', + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/buseta', + prefixType: 'only-base-path', + response: new Response().withJSONBody([ + { + huskodi: '000031440040', + fasteignanumer: '', + heimilisfang: 'Gullengi 4', + postnumer: '112', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + landakodi: 'IS', + breytt: '2022-07-04T00:00:00', + }, + { + huskodi: '99XT00000000', + fasteignanumer: '', + heimilisfang: 'Afríka ótilgreint', + postnumer: null, + stadur: 'Afríka ótilgreint', + sveitarfelagsnumer: null, + landakodi: 'XT', + breytt: '1992-11-16T00:00:00', + }, + ]), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/samibuar', + prefixType: 'only-base-path', + response: new Response().withJSONBody(['0101303019']), + }) + + /* Gervimaður útlönd */ + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101307789', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitala: '0101307789', + nafn: 'Gervimaður útlönd', + eiginnafn: 'Gervimaður', + millinafn: null, + kenninafn: 'útlönd', + fulltNafn: 'Gervimaður útlönd', + kynkodi: '1', + bannmerking: false, + faedingardagur: '1930-01-01T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101307789/hjuskapur', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitalaMaka: '0101303019', + nafnMaka: 'Gervimaður Afríka', + hjuskaparkodi: '1', + breytt: '2021-05-26T22:23:40.513', + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101307789/rikisfang', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kodi: 'IS', + land: 'Ísland', + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101307789/faedingarstadur', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + sveitarfelagsnumer: '0000', + stadur: 'Reykjavík', + faedingardagur: '1930-01-01T00:00:00', + }), + }) + + /* Lyklar */ + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/lyklar/hjuskaparkodar/1/1', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kodi: '1', + lysing: 'Ógiftur', + }), + }) +} diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/parentalLeave.mock.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/parentalLeave.mock.ts new file mode 100644 index 000000000000..0190192a4648 --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/parentalLeave.mock.ts @@ -0,0 +1,264 @@ +import { HttpMethod, Response } from '@anev/ts-mountebank' +import addDays from 'date-fns/addDays' +import addMonths from 'date-fns/addMonths' +import formatISO from 'date-fns/formatISO' +import { + Labor, + NationalRegistry, +} from '../../../../../../../../infra/src/dsl/xroad' +import { addXroadMock } from '../../../../../support/wire-mocks' + +export const loadParentalLeaveXroadMocks = async () => { + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitala: '0101303019', + nafn: 'Gervimaður Afríka', + eiginnafn: 'Gervimaður', + millinafn: null, + kenninafn: 'Afríka', + fulltNafn: 'Gervimaður Afríka', + kynkodi: '1', + bannmerking: false, + faedingardagur: '1930-01-01T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/1111111119', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitala: '1111111119', + nafn: 'Stubbur Maack', + eiginnafn: 'Stubbur', + millinafn: null, + kenninafn: 'Maack', + fulltNafn: 'Stubbur Maack', + kynkodi: '3', + bannmerking: false, + faedingardagur: '2011-11-11T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101307789', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitala: '0101307789', + nafn: 'Gervimaður útlönd', + eiginnafn: 'Gervimaður', + millinafn: null, + kenninafn: 'útlönd', + fulltNafn: 'Gervimaður útlönd', + kynkodi: '1', + bannmerking: false, + faedingardagur: '1930-01-01T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/forsja', + prefixType: 'only-base-path', + response: new Response().withJSONBody(['1111111119']), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/forsja/1111111119', + prefixType: 'only-base-path', + response: new Response().withJSONBody(['0101307789']), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/hjuskapur', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + kennitalaMaka: '0101307789', + nafnMaka: 'Gervimaður útlönd', + hjuskaparkodi: '3', + breytt: '2021-05-26T22:23:40.513', + }), + }) + await addXroadMock({ + config: NationalRegistry, + prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', + apiPath: '/api/v1/einstaklingar/0101303019/fjolskyldumedlimir', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + fjolskyldunumer: '0101303019', + einstaklingar: [ + { + kennitala: '0101303019', + nafn: 'Gervimaður Afríka', + eiginnafn: 'Gervimaður', + millinafn: null, + kenninafn: 'Afríka', + fulltNafn: 'Gervimaður Afríka', + kynkodi: '1', + bannmerking: false, + faedingardagur: '1930-01-01T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }, + { + kennitala: '0101307789', + nafn: 'Gervimaður útlönd', + eiginnafn: 'Gervimaður', + millinafn: null, + kenninafn: 'útlönd', + fulltNafn: 'Gervimaður útlönd', + kynkodi: '1', + bannmerking: false, + faedingardagur: '1930-01-01T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }, + { + kennitala: '1111111119', + nafn: 'Stubbur Maack', + eiginnafn: 'Stubbur', + millinafn: null, + kenninafn: 'Maack', + fulltNafn: 'Stubbur Maack', + kynkodi: '3', + bannmerking: false, + faedingardagur: '2011-11-11T00:00:00', + logheimili: { + heiti: 'Engihjalli 3', + postnumer: '200', + stadur: 'Kópavogur', + sveitarfelagsnumer: '1000', + }, + adsetur: { + heiti: 'Fellsmúli 2', + postnumer: '108', + stadur: 'Reykjavík', + sveitarfelagsnumer: '0000', + }, + }, + ], + }), + }) + await addXroadMock({ + config: Labor, + prefix: 'XROAD_VMST_API_PATH', + apiPath: '/users/0101303019/parental-leaves/periods/length', + response: new Response().withJSONBody({ + periodLength: 98, + }), + prefixType: 'base-path-with-env', + serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', + }) + await addXroadMock({ + config: Labor, + prefix: 'XROAD_VMST_API_PATH', + serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', + apiPath: '/users/0101303019/parental-leaves', + response: [ + new Response().withJSONBody({ + status: 'TestOK', + }), + new Response().withJSONBody({ + status: 'OK', + id: '23234', + }), + ], + prefixType: 'base-path-with-env', + method: HttpMethod.POST, + }) + await addXroadMock({ + config: Labor, + prefix: 'XROAD_VMST_API_PATH', + serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', + apiPath: '/users/0101303019/parental-leaves', + response: [ + new Response().withJSONBody({ + parentalLeaves: [], + }), + ], + prefixType: 'base-path-with-env', + method: HttpMethod.GET, + }) + const babyBDayRandomFactor = Math.ceil(Math.random() * 85) + await addXroadMock({ + config: Labor, + prefix: 'XROAD_VMST_API_PATH', + serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', + apiPath: '/users/0101303019/pregnancy-status', + response: [ + new Response().withJSONBody({ + hasActivePregnancy: true, + expectedDateOfBirth: formatISO( + addDays(addMonths(new Date(), 6), babyBDayRandomFactor), + { + representation: 'date', + }, + ), + }), + ], + prefixType: 'base-path-with-env', + }) +} diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/socialInsuranceAdministration.mock.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/socialInsuranceAdministration.mock.ts new file mode 100644 index 000000000000..974d07e9eeae --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/mocks/socialInsuranceAdministration.mock.ts @@ -0,0 +1,84 @@ +import { HttpMethod, Response } from '@anev/ts-mountebank' +import { SocialInsuranceAdministration } from '../../../../../../../../infra/src/dsl/xroad' +import { addXroadMock } from '../../../../../support/wire-mocks' + +const setupApplicationMocks = async (applicationType: string) => { + await addXroadMock({ + config: SocialInsuranceAdministration, + prefix: 'XROAD_TR_PATH', + apiPath: `/api/protected/v1/Applicant/${applicationType}/eligible`, + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + isEligible: true, + reason: null, + reasonCode: null, + }), + }) + + await addXroadMock({ + config: SocialInsuranceAdministration, + prefix: 'XROAD_TR_PATH', + apiPath: `/api/protected/v1/Application/${applicationType}`, + response: new Response().withJSONBody({ + applicationLineId: 1234567, + }), + prefixType: 'only-base-path', + method: HttpMethod.POST, + }) +} + +export const loadSocialInsuranceAdministrationXroadMocks = async () => { + await addXroadMock({ + config: SocialInsuranceAdministration, + prefix: 'XROAD_TR_PATH', + apiPath: '/api/protected/v1/General/currencies', + prefixType: 'only-base-path', + response: new Response().withJSONBody([ + 'ZAR', + 'AUD', + 'CAD', + 'CHF', + 'DKK', + 'EUR', + 'GBP', + 'NOK', + 'PLN', + 'SEK', + 'USD', + 'LVL', + 'CZK', + 'SKK', + 'IKR', + 'LTL', + 'VND', + 'BGN', + 'RUB', + 'CNY', + 'ALL', + 'LEI', + 'UAH', + 'HUF', + ]), + }) + await addXroadMock({ + config: SocialInsuranceAdministration, + prefix: 'XROAD_TR_PATH', + apiPath: '/api/protected/v1/Applicant', + prefixType: 'only-base-path', + response: new Response().withJSONBody({ + emailAddress: 'mail@mail.is', + phoneNumber: null, + bankAccount: { + bank: '2222', + ledger: '00', + accountNumber: '123456', + }, + }), + }) + + await setupApplicationMocks('oldagepension') + await setupApplicationMocks('halfoldagepension') + await setupApplicationMocks('additionalsupportfortheelderly') + await setupApplicationMocks('pensionsupplement') + await setupApplicationMocks('householdsupplement') +} diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/setup-xroad.mocks.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/setup-xroad.mocks.ts index 7cc248b10d7d..f5f0475faa59 100644 --- a/apps/system-e2e/src/tests/islandis/application-system/acceptance/setup-xroad.mocks.ts +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/setup-xroad.mocks.ts @@ -1,288 +1,20 @@ -import { - addXroadMock, - resetMocks, - wildcard, -} from '../../../../support/wire-mocks' -import { HttpMethod, Response } from '@anev/ts-mountebank' -import { EinstaklingsupplysingarToJSON } from '@island.is/clients/national-registry-v2' -import { - Base, - Labor, - NationalRegistry, -} from '../../../../../../../infra/src/dsl/xroad' -import { PostParentalLeaveResponseToJSON } from '@island.is/clients/vmst' -import formatISO from 'date-fns/formatISO' -import addDays from 'date-fns/addDays' -import addMonths from 'date-fns/addMonths' import { getEnvVariables } from '../../../../../../../infra/src/dsl/service-to-environment/pre-process-service' -import { env } from '../../../../support/urls' import { EnvironmentConfig } from '../../../../../../../infra/src/dsl/types/charts' +import { Base } from '../../../../../../../infra/src/dsl/xroad' +import { env } from '../../../../support/urls' +import { resetMocks, wildcard } from '../../../../support/wire-mocks' +import { loadParentalLeaveXroadMocks } from './mocks/parentalLeave.mock' +import { loadSocialInsuranceAdministrationXroadMocks } from './mocks/socialInsuranceAdministration.mock' +import { loadNationalRegistryXroadMocks } from './mocks/nationalRegistry.mock' export const setupXroadMocks = async () => { await resetMocks() - await addXroadMock({ - config: NationalRegistry, - prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', - apiPath: '/api/v1/einstaklingar/0101303019', - prefixType: 'only-base-path', - response: new Response().withJSONBody( - EinstaklingsupplysingarToJSON({ - kennitala: '0101303019', - nafn: 'Gervimaður Afríka', - eiginnafn: 'Gervimaður', - millinafn: null, - kenninafn: 'Afríka', - fulltNafn: 'Gervimaður Afríka', - kynkodi: '1', - bannmerking: false, - faedingardagur: new Date('1930-01-01T00:00:00'), - logheimili: { - heiti: 'Engihjalli 3', - postnumer: '200', - stadur: 'Kópavogur', - sveitarfelagsnumer: '1000', - }, - adsetur: { - heiti: 'Fellsmúli 2', - postnumer: '108', - stadur: 'Reykjavík', - sveitarfelagsnumer: '0000', - }, - }), - ), - }) - await addXroadMock({ - config: NationalRegistry, - prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', - apiPath: '/api/v1/einstaklingar/1111111119', - prefixType: 'only-base-path', - response: new Response().withJSONBody( - EinstaklingsupplysingarToJSON({ - kennitala: '1111111119', - nafn: 'Stubbur Maack', - eiginnafn: 'Stubbur', - millinafn: null, - kenninafn: 'Maack', - fulltNafn: 'Stubbur Maack', - kynkodi: '3', - bannmerking: false, - faedingardagur: new Date('2011-11-11T00:00:00'), - logheimili: { - heiti: 'Engihjalli 3', - postnumer: '200', - stadur: 'Kópavogur', - sveitarfelagsnumer: '1000', - }, - adsetur: { - heiti: 'Fellsmúli 2', - postnumer: '108', - stadur: 'Reykjavík', - sveitarfelagsnumer: '0000', - }, - }), - ), - }) - await addXroadMock({ - config: NationalRegistry, - prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', - apiPath: '/api/v1/einstaklingar/0101307789', - prefixType: 'only-base-path', - response: new Response().withJSONBody( - EinstaklingsupplysingarToJSON({ - kennitala: '0101307789', - nafn: 'Gervimaður útlönd', - eiginnafn: 'Gervimaður', - millinafn: null, - kenninafn: 'útlönd', - fulltNafn: 'Gervimaður útlönd', - kynkodi: '1', - bannmerking: false, - faedingardagur: new Date('1930-01-01T00:00:00'), - logheimili: { - heiti: 'Engihjalli 3', - postnumer: '200', - stadur: 'Kópavogur', - sveitarfelagsnumer: '1000', - }, - adsetur: { - heiti: 'Fellsmúli 2', - postnumer: '108', - stadur: 'Reykjavík', - sveitarfelagsnumer: '0000', - }, - }), - ), - }) - await addXroadMock({ - config: NationalRegistry, - prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', - apiPath: '/api/v1/einstaklingar/0101303019/forsja', - prefixType: 'only-base-path', - response: new Response().withJSONBody(['1111111119']), - }) - await addXroadMock({ - config: NationalRegistry, - prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', - apiPath: '/api/v1/einstaklingar/0101303019/forsja/1111111119', - prefixType: 'only-base-path', - response: new Response().withJSONBody(['0101307789']), - }) - await addXroadMock({ - config: NationalRegistry, - prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', - apiPath: '/api/v1/einstaklingar/0101303019/hjuskapur', - prefixType: 'only-base-path', - response: new Response().withJSONBody({ - kennitalaMaka: '0101307789', - nafnMaka: 'Gervimaður útlönd', - hjuskaparkodi: '3', - breytt: '2021-05-26T22:23:40.513', - }), - }) - await addXroadMock({ - config: NationalRegistry, - prefix: 'XROAD_NATIONAL_REGISTRY_SERVICE_PATH', - apiPath: '/api/v1/einstaklingar/0101303019/fjolskyldumedlimir', - prefixType: 'only-base-path', - response: new Response().withJSONBody({ - fjolskyldunumer: '0101303019', - einstaklingar: [ - { - kennitala: '0101303019', - nafn: 'Gervimaður Afríka', - eiginnafn: 'Gervimaður', - millinafn: null, - kenninafn: 'Afríka', - fulltNafn: 'Gervimaður Afríka', - kynkodi: '1', - bannmerking: false, - faedingardagur: '1930-01-01T00:00:00', - logheimili: { - heiti: 'Engihjalli 3', - postnumer: '200', - stadur: 'Kópavogur', - sveitarfelagsnumer: '1000', - }, - adsetur: { - heiti: 'Fellsmúli 2', - postnumer: '108', - stadur: 'Reykjavík', - sveitarfelagsnumer: '0000', - }, - }, - { - kennitala: '0101307789', - nafn: 'Gervimaður útlönd', - eiginnafn: 'Gervimaður', - millinafn: null, - kenninafn: 'útlönd', - fulltNafn: 'Gervimaður útlönd', - kynkodi: '1', - bannmerking: false, - faedingardagur: '1930-01-01T00:00:00', - logheimili: { - heiti: 'Engihjalli 3', - postnumer: '200', - stadur: 'Kópavogur', - sveitarfelagsnumer: '1000', - }, - adsetur: { - heiti: 'Fellsmúli 2', - postnumer: '108', - stadur: 'Reykjavík', - sveitarfelagsnumer: '0000', - }, - }, - { - kennitala: '1111111119', - nafn: 'Stubbur Maack', - eiginnafn: 'Stubbur', - millinafn: null, - kenninafn: 'Maack', - fulltNafn: 'Stubbur Maack', - kynkodi: '3', - bannmerking: false, - faedingardagur: '2011-11-11T00:00:00', - logheimili: { - heiti: 'Engihjalli 3', - postnumer: '200', - stadur: 'Kópavogur', - sveitarfelagsnumer: '1000', - }, - adsetur: { - heiti: 'Fellsmúli 2', - postnumer: '108', - stadur: 'Reykjavík', - sveitarfelagsnumer: '0000', - }, - }, - ], - }), - }) - await addXroadMock({ - config: Labor, - prefix: 'XROAD_VMST_API_PATH', - apiPath: '/users/0101303019/parental-leaves/periods/length', - response: new Response().withJSONBody({ - periodLength: 98, - }), - prefixType: 'base-path-with-env', - serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', - }) - await addXroadMock({ - config: Labor, - prefix: 'XROAD_VMST_API_PATH', - serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', - apiPath: '/users/0101303019/parental-leaves', - response: [ - new Response().withJSONBody( - PostParentalLeaveResponseToJSON({ - status: 'TestOK', - }), - ), - new Response().withJSONBody( - PostParentalLeaveResponseToJSON({ - status: 'OK', - id: '23234', - }), - ), - ], - prefixType: 'base-path-with-env', - method: HttpMethod.POST, - }) - await addXroadMock({ - config: Labor, - prefix: 'XROAD_VMST_API_PATH', - serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', - apiPath: '/users/0101303019/parental-leaves', - response: [ - new Response().withJSONBody({ - parentalLeaves: [], - }), - ], - prefixType: 'base-path-with-env', - method: HttpMethod.GET, - }) - const babyBDayRandomFactor = Math.ceil(Math.random() * 85) - await addXroadMock({ - config: Labor, - prefix: 'XROAD_VMST_API_PATH', - serviceMemberCode: 'XROAD_VMST_MEMBER_CODE', - apiPath: '/users/0101303019/pregnancy-status', - response: [ - new Response().withJSONBody({ - hasActivePregnancy: true, - expectedDateOfBirth: formatISO( - addDays(addMonths(new Date(), 6), babyBDayRandomFactor), - { - representation: 'date', - }, - ), - }), - ], - prefixType: 'base-path-with-env', - }) + /* Xroad mocks */ + await loadParentalLeaveXroadMocks() + await loadSocialInsuranceAdministrationXroadMocks() + await loadNationalRegistryXroadMocks() + const { envs } = getEnvVariables(Base.getEnv(), 'system-e2e', env) const xroadBasePath = envs['XROAD_BASE_PATH'] const path = @@ -294,6 +26,5 @@ export const setupXroadMocks = async () => { }, env: {} as EnvironmentConfig, }) - await wildcard(path) } diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/additional-support-for-the-elderly.spec.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/additional-support-for-the-elderly.spec.ts new file mode 100644 index 000000000000..cd0beb0e65b0 --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/additional-support-for-the-elderly.spec.ts @@ -0,0 +1,105 @@ +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { test as base, expect, Page } from '@playwright/test' +import { + disableI18n, + disablePreviousApplications, +} from '../../../../../support/disablers' +import { label } from '../../../../../support/i18n' +import { session } from '../../../../../support/session' +import { setupXroadMocks } from '../setup-xroad.mocks' +import { + additionalAttachments, + expectHeadingToBeVisible, + fillApplicantInfo, + fillPaymentInfo, + selectPeriod, + submitApplication, + writeComment, +} from './shared' + +const homeUrl = '/umsoknir/felagslegur-vidbotarstudningur' + +const applicationTest = base.extend<{ applicationPage: Page }>({ + applicationPage: async ({ browser }, use) => { + const applicationContext = await session({ + browser, + homeUrl, + phoneNumber: '0103019', // Gervimaður Afríka + idsLoginOn: true, + }) + + const applicationPage = await applicationContext.newPage() + await disablePreviousApplications(applicationPage) + await disableI18n(applicationPage) + await applicationPage.goto(homeUrl) + await expect(applicationPage).toBeApplication( + 'felagslegur-vidbotarstudningur', + ) + await setupXroadMocks() + await use(applicationPage) + + await applicationPage.close() + await applicationContext.close() + }, +}) + +applicationTest.describe('Additional support for the elderly', () => { + applicationTest( + 'Should complete Additional support for the elderly application successfully', + async ({ applicationPage }) => { + const page = applicationPage + + await applicationTest.step('Agree to data providers', async () => { + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.pre.externalDataSection, + ) + await page.getByTestId('agree-to-data-providers').click() + await page + .getByRole('button', { + name: label( + socialInsuranceAdministrationMessage.pre.startApplication, + ), + }) + .click() + }) + + await applicationTest.step('Fill in applicant info', () => + fillApplicantInfo(page), + ) + + await applicationTest.step('Fill in payment information', () => + fillPaymentInfo(page, true), + ) + + await applicationTest.step('Select period', () => selectPeriod(page)) + + await applicationTest.step( + 'Check that additional documents header is visible', + () => additionalAttachments(page), + ) + + await applicationTest.step('Write comment', () => writeComment(page)) + + await applicationTest.step('Submit application', () => + submitApplication(page), + ) + + await applicationTest.step( + 'Check that conclusion screen header is visible', + async () => { + await expect( + page + .getByRole('heading', { + name: label( + socialInsuranceAdministrationMessage.conclusionScreen + .receivedAwaitingIncomePlanTitle, + ), + }) + .first(), + ).toBeVisible() + }, + ) + }, + ) +}) diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/household-supplement.spec.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/household-supplement.spec.ts new file mode 100644 index 000000000000..2827ea5c8238 --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/household-supplement.spec.ts @@ -0,0 +1,140 @@ +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { householdSupplementFormMessage } from '@island.is/application/templates/social-insurance-administration/household-supplement' +import { test as base, expect, Page } from '@playwright/test' +import { + disableI18n, + disablePreviousApplications, +} from '../../../../../support/disablers' +import { label } from '../../../../../support/i18n' +import { helpers } from '../../../../../support/locator-helpers' +import { session } from '../../../../../support/session' +import { setupXroadMocks } from '../setup-xroad.mocks' +import { + additionalAttachments, + expectHeadingToBeVisible, + fillApplicantInfo, + fillPaymentInfo, + selectPeriod, + submitApplication, + writeComment, +} from './shared' + +const homeUrl = '/umsoknir/heimilisuppbot' + +const applicationTest = base.extend<{ applicationPage: Page }>({ + applicationPage: async ({ browser }, use) => { + const applicationContext = await session({ + browser, + homeUrl, + phoneNumber: '0103019', // Gervimaður Afríka + idsLoginOn: true, + }) + + const applicationPage = await applicationContext.newPage() + await disablePreviousApplications(applicationPage) + await disableI18n(applicationPage) + await applicationPage.goto(homeUrl) + await expect(applicationPage).toBeApplication() + await setupXroadMocks() + await use(applicationPage) + + await applicationPage.close() + await applicationContext.close() + }, +}) + +applicationTest.describe('Household Supplement', () => { + applicationTest( + 'Should complete Household Supplement application successfully', + async ({ applicationPage }) => { + const page = applicationPage + const { proceed } = helpers(page) + + await applicationTest.step('Agree to data providers', async () => { + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.pre.externalDataSection, + ) + await page.getByTestId('agree-to-data-providers').click() + await page + .getByRole('button', { + name: label( + socialInsuranceAdministrationMessage.pre.startApplication, + ), + }) + .click() + }) + + await applicationTest.step('Fill in applicant info', () => + fillApplicantInfo(page), + ) + + await applicationTest.step('Fill in payment information', () => + fillPaymentInfo(page, false), + ) + + await applicationTest.step('Household supplement', async () => { + await expectHeadingToBeVisible( + page, + householdSupplementFormMessage.shared.householdSupplement, + ) + + await page + .getByRole('region', { + name: label( + householdSupplementFormMessage.info.householdSupplementHousing, + ), + }) + .getByRole('radio', { + name: label( + householdSupplementFormMessage.info + .householdSupplementHousingOwner, + ), + }) + .click() + + await page + .getByRole('region', { + name: label( + householdSupplementFormMessage.info + .householdSupplementChildrenBetween18And25, + ), + }) + .getByRole('radio', { + name: label(socialInsuranceAdministrationMessage.shared.no), + }) + .click() + await proceed() + }) + + await applicationTest.step('Select period', () => selectPeriod(page)) + + await applicationTest.step( + 'Check that additional documents header is visible', + () => additionalAttachments(page), + ) + + await applicationTest.step('Write comment', () => writeComment(page)) + + await applicationTest.step('Submit application', () => + submitApplication(page), + ) + + await applicationTest.step( + 'Check that conclusion screen header is visible', + async () => { + await expect( + page + .getByRole('heading', { + name: label( + socialInsuranceAdministrationMessage.conclusionScreen + .receivedTitle, + ), + }) + .first(), + ).toBeVisible() + }, + ) + }, + ) +}) diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/old-age-pension.spec.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/old-age-pension.spec.ts new file mode 100644 index 000000000000..580622c31d55 --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/old-age-pension.spec.ts @@ -0,0 +1,229 @@ +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { oldAgePensionFormMessage } from '@island.is/application/templates/social-insurance-administration/old-age-pension' +import { test as base, expect, Page } from '@playwright/test' +import { + disableI18n, + disablePreviousApplications, +} from '../../../../../support/disablers' +import { label } from '../../../../../support/i18n' +import { helpers } from '../../../../../support/locator-helpers' +import { session } from '../../../../../support/session' +import { setupXroadMocks } from '../setup-xroad.mocks' +import { + additionalAttachments, + expectHeadingToBeVisible, + fillApplicantInfo, + fillPaymentInfo, + selectPeriod, + submitApplication, + writeComment, +} from './shared' + +const oldAgeApplicationTest = async (page: Page, applicationType: string) => { + const { proceed } = helpers(page) + + await applicationTest.step('Select type of application', async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.pre.applicationTypeTitle, + ) + await page.getByTestId(applicationType).click() + await proceed() + }) + + await applicationTest.step('Agree to data providers', async () => { + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.pre.externalDataSection, + ) + await page.getByTestId('agree-to-data-providers').click() + await proceed() + }) + + await applicationTest.step( + 'Answer pension fund question and start application', + async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.pre.questionTitle, + ) + await page + .getByRole('radio', { + name: label(socialInsuranceAdministrationMessage.shared.yes), + }) + .click() + await page + .getByRole('button', { + name: label( + socialInsuranceAdministrationMessage.pre.startApplication, + ), + }) + .click() + }, + ) + + await applicationTest.step('Fill in applicant info', () => + fillApplicantInfo(page), + ) + + await applicationTest.step('Fill in payment information', () => + fillPaymentInfo(page, true), + ) + + await applicationTest.step('One payment per year', async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.onePaymentPerYear.onePaymentPerYearTitle, + ) + await page + .getByRole('radio', { + name: label(socialInsuranceAdministrationMessage.shared.no), + }) + .click() + await proceed() + }) + + await applicationTest.step('View residence history', async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.residence.residenceHistoryTitle, + ) + await proceed() + }) + + if (applicationType === 'half-old-age-pension') { + await applicationTest.step('Self-employed or employee', async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.employer.selfEmployedOrEmployeeTitle, + ) + + await page + .getByRole('radio', { + name: label(oldAgePensionFormMessage.employer.employee), + }) + .click() + await proceed() + }) + + await applicationTest.step('Employer registration', async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.employer.registrationTitle, + ) + + const employerEmail = page.getByRole('textbox', { + name: label(oldAgePensionFormMessage.employer.email), + }) + await employerEmail.selectText() + await employerEmail.fill('mockEmail@mail.is') + + await page + .getByRole('radio', { + name: label(oldAgePensionFormMessage.employer.ratioYearly), + }) + .click() + + const employmentRatio = page.getByRole('textbox', { + name: label(oldAgePensionFormMessage.employer.ratio), + }) + await employmentRatio.selectText() + await employmentRatio.fill('50') + await proceed() + }) + + await applicationTest.step('Employers', async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.employer.employerTitle, + ) + await proceed() + }) + } + + await applicationTest.step('Select period', () => selectPeriod(page)) + + await applicationTest.step( + 'Check that attachments for pension payments header is visible', + async () => { + await expectHeadingToBeVisible( + page, + oldAgePensionFormMessage.fileUpload.pensionFileTitle, + ) + await proceed() + }, + ) + + await applicationTest.step( + 'Check that additional documents header is visible', + () => additionalAttachments(page), + ) + + await applicationTest.step('Write comment', () => writeComment(page)) + + await applicationTest.step('Submit application', () => + submitApplication(page), + ) + + await applicationTest.step( + 'Check that conclusion screen header is visible', + async () => { + await expect( + page + .getByRole('heading', { + name: label( + socialInsuranceAdministrationMessage.conclusionScreen + .receivedAwaitingIncomePlanTitle, + ), + }) + .first(), + ).toBeVisible() + }, + ) +} + +const homeUrl = '/umsoknir/ellilifeyrir' + +const applicationTest = base.extend<{ applicationPage: Page }>({ + applicationPage: async ({ browser }, use) => { + const applicationContext = await session({ + browser, + homeUrl, + phoneNumber: '0103019', // Gervimaður Afríka + idsLoginOn: true, + }) + + const applicationPage = await applicationContext.newPage() + await disablePreviousApplications(applicationPage) + await disableI18n(applicationPage) + await applicationPage.goto(homeUrl) + await expect(applicationPage).toBeApplication() + await setupXroadMocks() + await use(applicationPage) + + await applicationPage.close() + await applicationContext.close() + }, +}) + +applicationTest.describe('Old Age Pension', () => { + applicationTest( + 'Should complete Old Age Pension application successfully', + async ({ applicationPage }) => { + const page = applicationPage + + await oldAgeApplicationTest(page, 'old-age-pension') + }, + ) +}) + +applicationTest.describe('Half Old Age Pension', () => { + applicationTest( + 'Should complete Half Old Age Pension application successfully', + async ({ applicationPage }) => { + const page = applicationPage + + await oldAgeApplicationTest(page, 'half-old-age-pension') + }, + ) +}) diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/pension-supplement.spec.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/pension-supplement.spec.ts new file mode 100644 index 000000000000..3df87bc4404e --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/pension-supplement.spec.ts @@ -0,0 +1,126 @@ +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { pensionSupplementFormMessage } from '@island.is/application/templates/social-insurance-administration/pension-supplement' +import { test as base, expect, Page } from '@playwright/test' +import { + disableI18n, + disablePreviousApplications, +} from '../../../../../support/disablers' +import { label } from '../../../../../support/i18n' +import { helpers } from '../../../../../support/locator-helpers' +import { session } from '../../../../../support/session' +import { setupXroadMocks } from '../setup-xroad.mocks' +import { + additionalAttachments, + expectHeadingToBeVisible, + fillApplicantInfo, + fillPaymentInfo, + selectPeriod, + submitApplication, + writeComment, +} from './shared' + +const homeUrl = '/umsoknir/uppbot-a-lifeyri' + +const applicationTest = base.extend<{ applicationPage: Page }>({ + applicationPage: async ({ browser }, use) => { + const applicationContext = await session({ + browser, + homeUrl, + phoneNumber: '0103019', // Gervimaður Afríka + idsLoginOn: true, + }) + + const applicationPage = await applicationContext.newPage() + await disablePreviousApplications(applicationPage) + await disableI18n(applicationPage) + await applicationPage.goto(homeUrl) + await expect(applicationPage).toBeApplication('uppbot-a-lifeyri') + await setupXroadMocks() + await use(applicationPage) + + await applicationPage.close() + await applicationContext.close() + }, +}) + +applicationTest.describe('Pension Supplement', () => { + applicationTest( + 'Should complete Pension Supplement application successfully', + async ({ applicationPage }) => { + const page = applicationPage + const { proceed } = helpers(page) + + await applicationTest.step('Agree to data providers', async () => { + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.pre.externalDataSection, + ) + await page.getByTestId('agree-to-data-providers').click() + await page + .getByRole('button', { + name: label( + socialInsuranceAdministrationMessage.pre.startApplication, + ), + }) + .click() + }) + + await applicationTest.step('Fill in applicant info', () => + fillApplicantInfo(page), + ) + + await applicationTest.step('Fill in payment information', () => + fillPaymentInfo(page, false), + ) + + await applicationTest.step('Select application reason', async () => { + await expectHeadingToBeVisible( + page, + pensionSupplementFormMessage.applicationReason.title, + ) + + await page + .getByRole('region', { + name: label(pensionSupplementFormMessage.applicationReason.title), + }) + .getByRole('checkbox', { + name: label( + pensionSupplementFormMessage.applicationReason.medicineCost, + ), + }) + .click() + + await proceed() + }) + + await applicationTest.step('Select period', () => selectPeriod(page)) + + await applicationTest.step( + 'Check that additional documents header is visible', + () => additionalAttachments(page), + ) + + await applicationTest.step('Write comment', () => writeComment(page)) + + await applicationTest.step('Submit application', () => + submitApplication(page), + ) + + await applicationTest.step( + 'Check that conclusion screen header is visible', + async () => { + await expect( + page + .getByRole('heading', { + name: label( + socialInsuranceAdministrationMessage.conclusionScreen + .receivedTitle, + ), + }) + .first(), + ).toBeVisible() + }, + ) + }, + ) +}) diff --git a/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/shared.ts b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/shared.ts new file mode 100644 index 000000000000..f48d38e521e2 --- /dev/null +++ b/apps/system-e2e/src/tests/islandis/application-system/acceptance/social-insurance-administration/shared.ts @@ -0,0 +1,136 @@ +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { expect, Page } from '@playwright/test' +import { MessageDescriptor } from 'react-intl' +import { label } from '../../../../../support/i18n' +import { helpers } from '../../../../../support/locator-helpers' + +export const expectHeadingToBeVisible = async ( + page: Page, + message: MessageDescriptor, +) => { + await expect( + page.getByRole('heading', { + name: label(message), + }), + ).toBeVisible() +} + +export const fillApplicantInfo = async (page: Page) => { + const { proceed } = helpers(page) + + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.info.infoSubSectionTitle, + ) + + const phoneNumber = page.getByRole('textbox', { + name: label(socialInsuranceAdministrationMessage.info.applicantPhonenumber), + }) + await phoneNumber.selectText() + await phoneNumber.fill('6555555') + await proceed() +} + +export const fillPaymentInfo = async (page: Page, includeTax: boolean) => { + const { proceed } = helpers(page) + + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.payment.title, + ) + const paymentBank = page.getByRole('textbox', { + name: label(socialInsuranceAdministrationMessage.payment.bank), + }) + await paymentBank.selectText() + await paymentBank.fill('051226054678') + + if (includeTax) { + await page + .getByRole('region', { + name: label( + socialInsuranceAdministrationMessage.payment.personalAllowance, + ), + }) + .getByRole('radio', { + name: label(socialInsuranceAdministrationMessage.shared.yes), + }) + .click() + + const personalAllowance = page.getByTestId('personal-allowance-usage') + await personalAllowance.selectText() + await personalAllowance.fill('100') + + await page + .getByRole('region', { + name: label(socialInsuranceAdministrationMessage.payment.taxLevel), + }) + .getByRole('radio', { + name: label( + socialInsuranceAdministrationMessage.payment.taxIncomeLevel, + ), + }) + .click() + } + await proceed() +} + +export const selectPeriod = async (page: Page) => { + const { proceed } = helpers(page) + + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.period.title, + ) + + await page.getByTestId('select-period.year').click() + await page.keyboard.press('Enter') + + await page.getByTestId('select-period.month').click() + await page.keyboard.press('ArrowUp') + await page.keyboard.press('Enter') + await proceed() +} + +export const additionalAttachments = async (page: Page) => { + const { proceed } = helpers(page) + + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.fileUpload.additionalFileTitle, + ) + await proceed() +} + +export const writeComment = async (page: Page) => { + const { proceed } = helpers(page) + + await expectHeadingToBeVisible( + page, + socialInsuranceAdministrationMessage.additionalInfo.commentSection, + ) + await page + .getByPlaceholder( + label( + socialInsuranceAdministrationMessage.additionalInfo.commentPlaceholder, + ), + ) + .fill( + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vehicula malesuada augue, sit amet pulvinar tortor pellentesque at. Nulla facilisi. Nunc vel mi ac mi commodo rhoncus sit amet ut neque.', + ) + await proceed() +} + +export const submitApplication = async (page: Page) => { + await expect( + page + .locator('form') + .getByText( + label(socialInsuranceAdministrationMessage.confirm.overviewTitle), + ), + ).toBeVisible() + await page + .getByRole('button', { + name: label(socialInsuranceAdministrationMessage.confirm.submitButton), + }) + .click() +} diff --git a/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/forms/AdditionalSupportForTheElderlyForm.ts b/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/forms/AdditionalSupportForTheElderlyForm.ts index 964f8df4af14..9772c3bdf933 100644 --- a/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/forms/AdditionalSupportForTheElderlyForm.ts +++ b/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/forms/AdditionalSupportForTheElderlyForm.ts @@ -3,50 +3,51 @@ import { buildCustomField, buildFileUploadField, buildForm, + buildHiddenInputWithWatchedValue, buildMultiField, buildRadioField, buildSection, buildSelectField, - buildSubSection, buildSubmitField, + buildSubSection, buildTextField, } from '@island.is/application/core' +import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' import { - Application, - DefaultEvents, - Form, - FormModes, - FormValue, - YES, -} from '@island.is/application/types' + BankAccountType, + fileUploadSharedProps, + TaxLevelOptions, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' import { friendlyFormatIBAN, friendlyFormatSWIFT, getBankIsk, - typeOfBankInfo, getCurrencies, - getYesNoOptions, getTaxOptions, + getYesNoOptions, + typeOfBankInfo, } from '@island.is/application/templates/social-insurance-administration-core/lib/socialInsuranceAdministrationUtils' -import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' -import { additionalSupportForTheElderyFormMessage } from '../lib/messages' -import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' import { - BankAccountType, - fileUploadSharedProps, - MONTHS, - TaxLevelOptions, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' -import { - getApplicationExternalData, - getAvailableYears, -} from '../lib/additionalSupportForTheElderlyUtils' + Application, + DefaultEvents, + Form, + FormModes, + FormValue, + YES, +} from '@island.is/application/types' import { applicantInformationMultiField, buildFormConclusionSection, } from '@island.is/application/ui-forms' -import { getApplicationAnswers } from '../lib/additionalSupportForTheElderlyUtils' import isEmpty from 'lodash/isEmpty' +import { + getApplicationAnswers, + getApplicationExternalData, + getAvailableMonths, + getAvailableYears, +} from '../lib/additionalSupportForTheElderlyUtils' +import { additionalSupportForTheElderyFormMessage } from '../lib/messages' export const AdditionalSupportForTheElderlyForm: Form = buildForm({ id: 'AdditionalSupportForTheElderlyDraft', @@ -287,6 +288,7 @@ export const AdditionalSupportForTheElderlyForm: Form = buildForm({ socialInsuranceAdministrationMessage.payment .personalAllowancePercentage, suffix: '%', + dataTestId: 'personal-allowance-usage', condition: (answers) => { const { personalAllowance } = getApplicationAnswers(answers) return personalAllowance === YES @@ -351,7 +353,24 @@ export const AdditionalSupportForTheElderlyForm: Form = buildForm({ width: 'half', placeholder: socialInsuranceAdministrationMessage.period.monthDefaultText, - options: MONTHS, + options: (application: Application) => { + const { selectedYear } = getApplicationAnswers( + application.answers, + ) + + return getAvailableMonths(selectedYear) + }, + condition: (answers) => { + const { selectedYear, selectedYearHiddenInput } = + getApplicationAnswers(answers) + + return selectedYear === selectedYearHiddenInput + }, + }), + buildHiddenInputWithWatchedValue({ + // Needed to trigger an update on options in the select above + id: 'period.hiddenInput', + watchValue: 'period.year', }), ], }), diff --git a/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/lib/additionalSupportForTheElderlyUtils.ts b/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/lib/additionalSupportForTheElderlyUtils.ts index 52578d67db00..d1dd74e3811e 100644 --- a/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/lib/additionalSupportForTheElderlyUtils.ts +++ b/libs/application/templates/social-insurance-administration/additional-support-for-the-elderly/src/lib/additionalSupportForTheElderlyUtils.ts @@ -1,4 +1,16 @@ import { getValueViaPath } from '@island.is/application/core' +import { + BankAccountType, + MONTHS, + TaxLevelOptions, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { + AdditionalInformation, + Attachments, + BankInfo, + FileType, + PaymentInfo, +} from '@island.is/application/templates/social-insurance-administration-core/types' import { Application, ExternalData, @@ -7,22 +19,17 @@ import { import addMonths from 'date-fns/addMonths' import subMonths from 'date-fns/subMonths' import { AttachmentLabel, AttachmentTypes } from './constants' -import { - FileType, - Attachments, - AdditionalInformation, - BankInfo, - PaymentInfo, -} from '@island.is/application/templates/social-insurance-administration-core/types' -import { - BankAccountType, - TaxLevelOptions, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' export const getApplicationAnswers = (answers: Application['answers']) => { const selectedYear = getValueViaPath(answers, 'period.year') as string const selectedMonth = getValueViaPath(answers, 'period.month') as string + + const selectedYearHiddenInput = getValueViaPath( + answers, + 'period.hiddenInput', + ) as string + const applicantPhonenumber = getValueViaPath( answers, 'applicant.phoneNumber', @@ -86,6 +93,7 @@ export const getApplicationAnswers = (answers: Application['answers']) => { applicantPhonenumber, selectedYear, selectedMonth, + selectedYearHiddenInput, comment, additionalAttachments, additionalAttachmentsRequired, @@ -230,6 +238,24 @@ export const getAvailableYears = () => { ) } +// returns available months for selected year, since available period is +// 3 months back in time and 6 months in the future. +export const getAvailableMonths = (selectedYear: string) => { + if (!selectedYear) return [] + + const threeMonthsBackInTime = subMonths(new Date(), 3) + const sixMonthsInTheFuture = addMonths(new Date(), 6) + + let months = MONTHS + if (threeMonthsBackInTime.getFullYear().toString() === selectedYear) { + months = months.slice(threeMonthsBackInTime.getMonth() + 1, months.length) + } else if (sixMonthsInTheFuture.getFullYear().toString() === selectedYear) { + months = months.slice(0, sixMonthsInTheFuture.getMonth() + 1) + } + + return months +} + export const isEligible = (externalData: ExternalData): boolean => { const { isEligible } = getApplicationExternalData(externalData) diff --git a/libs/application/templates/social-insurance-administration/household-supplement/src/forms/HouseholdSupplementForm.ts b/libs/application/templates/social-insurance-administration/household-supplement/src/forms/HouseholdSupplementForm.ts index 980124680daa..cbb1142f20ea 100644 --- a/libs/application/templates/social-insurance-administration/household-supplement/src/forms/HouseholdSupplementForm.ts +++ b/libs/application/templates/social-insurance-administration/household-supplement/src/forms/HouseholdSupplementForm.ts @@ -1,18 +1,33 @@ import { + buildAlertMessageField, + buildCustomField, + buildDescriptionField, + buildFileUploadField, buildForm, + buildHiddenInputWithWatchedValue, buildMultiField, buildPhoneField, + buildRadioField, buildSection, + buildSelectField, buildSubSection, buildSubmitField, buildTextField, - buildCustomField, - buildRadioField, - buildFileUploadField, - buildAlertMessageField, - buildSelectField, - buildDescriptionField, } from '@island.is/application/core' +import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' +import { + BankAccountType, + fileUploadSharedProps, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { + friendlyFormatIBAN, + friendlyFormatSWIFT, + getBankIsk, + getCurrencies, + getYesNoOptions, + typeOfBankInfo, +} from '@island.is/application/templates/social-insurance-administration-core/lib/socialInsuranceAdministrationUtils' import { Application, DefaultEvents, @@ -22,32 +37,18 @@ import { NationalRegistrySpouse, YES, } from '@island.is/application/types' -import { householdSupplementFormMessage } from '../lib/messages' -import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { buildFormConclusionSection } from '@island.is/application/ui-forms' +import * as kennitala from 'kennitala' +import isEmpty from 'lodash/isEmpty' import { HouseholdSupplementHousing, maritalStatuses } from '../lib/constants' import { - isExistsCohabitantOlderThan25, getApplicationAnswers, getApplicationExternalData, + getAvailableMonths, getAvailableYears, + isExistsCohabitantOlderThan25, } from '../lib/householdSupplementUtils' -import { - BankAccountType, - MONTHS, - fileUploadSharedProps, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' -import { buildFormConclusionSection } from '@island.is/application/ui-forms' -import isEmpty from 'lodash/isEmpty' -import { - friendlyFormatIBAN, - friendlyFormatSWIFT, - getBankIsk, - typeOfBankInfo, - getCurrencies, - getYesNoOptions, -} from '@island.is/application/templates/social-insurance-administration-core/lib/socialInsuranceAdministrationUtils' -import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' -import * as kennitala from 'kennitala' +import { householdSupplementFormMessage } from '../lib/messages' export const HouseholdSupplementForm: Form = buildForm({ id: 'HouseholdSupplementDraft', @@ -530,7 +531,24 @@ export const HouseholdSupplementForm: Form = buildForm({ width: 'half', placeholder: socialInsuranceAdministrationMessage.period.monthDefaultText, - options: MONTHS, + options: (application: Application) => { + const { selectedYear } = getApplicationAnswers( + application.answers, + ) + + return getAvailableMonths(selectedYear) + }, + condition: (answers) => { + const { selectedYear, selectedYearHiddenInput } = + getApplicationAnswers(answers) + + return selectedYear === selectedYearHiddenInput + }, + }), + buildHiddenInputWithWatchedValue({ + // Needed to trigger an update on options in the select above + id: 'period.hiddenInput', + watchValue: 'period.year', }), ], }), diff --git a/libs/application/templates/social-insurance-administration/household-supplement/src/lib/householdSupplementUtils.ts b/libs/application/templates/social-insurance-administration/household-supplement/src/lib/householdSupplementUtils.ts index 5fa576ae1a2c..5e21cf054916 100644 --- a/libs/application/templates/social-insurance-administration/household-supplement/src/lib/householdSupplementUtils.ts +++ b/libs/application/templates/social-insurance-administration/household-supplement/src/lib/householdSupplementUtils.ts @@ -1,29 +1,29 @@ import { getValueViaPath } from '@island.is/application/core' import { - HouseholdSupplementHousing, - AttachmentLabel, - AttachmentTypes, -} from './constants' + BankAccountType, + MONTHS, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { + Attachments, + BankInfo, + FileType, + PaymentInfo, +} from '@island.is/application/templates/social-insurance-administration-core/types' import { Application, - YesOrNo, - YES, ExternalData, + YES, + YesOrNo, } from '@island.is/application/types' import addMonths from 'date-fns/addMonths' import subYears from 'date-fns/subYears' import * as kennitala from 'kennitala' import { FileUpload } from '../types' import { - Attachments, - BankInfo, - FileType, - PaymentInfo, -} from '@island.is/application/templates/social-insurance-administration-core/types' -import { - BankAccountType, - MONTHS, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' + AttachmentLabel, + AttachmentTypes, + HouseholdSupplementHousing, +} from './constants' export const getApplicationAnswers = (answers: Application['answers']) => { const applicantPhonenumber = getValueViaPath( @@ -55,6 +55,11 @@ export const getApplicationAnswers = (answers: Application['answers']) => { const selectedMonth = getValueViaPath(answers, 'period.month') as string + const selectedYearHiddenInput = getValueViaPath( + answers, + 'period.hiddenInput', + ) as string + const additionalAttachments = getValueViaPath( answers, 'fileUploadAdditionalFiles.additionalDocuments', @@ -102,6 +107,7 @@ export const getApplicationAnswers = (answers: Application['answers']) => { leaseAgreementAttachments, selectedYear, selectedMonth, + selectedYearHiddenInput, additionalAttachments, additionalAttachmentsRequired, comment, diff --git a/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/OldAgePensionForm.ts b/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/OldAgePensionForm.ts index ef95ccb8fbfe..2d086a88fa4f 100644 --- a/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/OldAgePensionForm.ts +++ b/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/OldAgePensionForm.ts @@ -3,6 +3,7 @@ import { buildCustomField, buildFileUploadField, buildForm, + buildHiddenInputWithWatchedValue, buildMultiField, buildRadioField, buildRepeater, @@ -12,6 +13,23 @@ import { buildSubSection, buildTextField, } from '@island.is/application/core' +import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' +import { + BankAccountType, + fileUploadSharedProps, + IS, + TaxLevelOptions, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { + friendlyFormatIBAN, + friendlyFormatSWIFT, + getBankIsk, + getCurrencies, + getTaxOptions, + getYesNoOptions, + typeOfBankInfo, +} from '@island.is/application/templates/social-insurance-administration-core/lib/socialInsuranceAdministrationUtils' import { Application, DefaultEvents, @@ -21,37 +39,20 @@ import { NO, YES, } from '@island.is/application/types' -import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' -import { oldAgePensionFormMessage } from '../lib/messages' -import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { + applicantInformationMultiField, + buildFormConclusionSection, +} from '@island.is/application/ui-forms' +import isEmpty from 'lodash/isEmpty' import { ApplicationType, Employment, RatioType } from '../lib/constants' +import { oldAgePensionFormMessage } from '../lib/messages' import { getApplicationAnswers, getApplicationExternalData, + getAvailableMonths, getAvailableYears, isEarlyRetirement, } from '../lib/oldAgePensionUtils' -import { - friendlyFormatIBAN, - friendlyFormatSWIFT, - getBankIsk, - getCurrencies, - typeOfBankInfo, - getYesNoOptions, - getTaxOptions, -} from '@island.is/application/templates/social-insurance-administration-core/lib/socialInsuranceAdministrationUtils' -import { - applicantInformationMultiField, - buildFormConclusionSection, -} from '@island.is/application/ui-forms' -import isEmpty from 'lodash/isEmpty' -import { - BankAccountType, - fileUploadSharedProps, - IS, - MONTHS, - TaxLevelOptions, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' export const OldAgePensionForm: Form = buildForm({ id: 'OldAgePensionDraft', @@ -292,6 +293,7 @@ export const OldAgePensionForm: Form = buildForm({ socialInsuranceAdministrationMessage.payment .personalAllowancePercentage, suffix: '%', + dataTestId: 'personal-allowance-usage', condition: (answers) => { const { personalAllowance } = getApplicationAnswers(answers) return personalAllowance === YES @@ -585,7 +587,24 @@ export const OldAgePensionForm: Form = buildForm({ width: 'half', placeholder: socialInsuranceAdministrationMessage.period.monthDefaultText, - options: MONTHS, + options: (application: Application) => { + const { selectedYear } = getApplicationAnswers( + application.answers, + ) + + return getAvailableMonths(application, selectedYear) + }, + condition: (answers) => { + const { selectedYear, selectedYearHiddenInput } = + getApplicationAnswers(answers) + + return selectedYear === selectedYearHiddenInput + }, + }), + buildHiddenInputWithWatchedValue({ + // Needed to trigger an update on options in the select above + id: 'period.hiddenInput', + watchValue: 'period.year', }), buildAlertMessageField({ id: 'period.alert', diff --git a/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/Prerequisites.ts b/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/Prerequisites.ts index 0999301b21c9..e614d43380c3 100644 --- a/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/Prerequisites.ts +++ b/libs/application/templates/social-insurance-administration/old-age-pension/src/forms/Prerequisites.ts @@ -61,6 +61,7 @@ export const PrerequisitesForm: Form = buildForm({ options: [ { value: ApplicationType.OLD_AGE_PENSION, + dataTestId: 'old-age-pension', label: oldAgePensionFormMessage.shared.applicationTitle, subLabel: oldAgePensionFormMessage.pre @@ -68,6 +69,7 @@ export const PrerequisitesForm: Form = buildForm({ }, { value: ApplicationType.HALF_OLD_AGE_PENSION, + dataTestId: 'half-old-age-pension', label: oldAgePensionFormMessage.pre .halfRetirementPensionApplicationTitle, @@ -77,6 +79,7 @@ export const PrerequisitesForm: Form = buildForm({ }, { value: ApplicationType.SAILOR_PENSION, + dataTestId: 'sailor-pension', label: oldAgePensionFormMessage.pre.fishermenApplicationTitle, subLabel: oldAgePensionFormMessage.pre diff --git a/libs/application/templates/social-insurance-administration/old-age-pension/src/lib/oldAgePensionUtils.ts b/libs/application/templates/social-insurance-administration/old-age-pension/src/lib/oldAgePensionUtils.ts index 1834e636073e..7ddec140d8ad 100644 --- a/libs/application/templates/social-insurance-administration/old-age-pension/src/lib/oldAgePensionUtils.ts +++ b/libs/application/templates/social-insurance-administration/old-age-pension/src/lib/oldAgePensionUtils.ts @@ -1,40 +1,40 @@ import { getValueViaPath } from '@island.is/application/core' import { - oldAgePensionAge, - earlyRetirementMinAge, - earlyRetirementMaxAge, - ApplicationType, - Employment, - AttachmentLabel, - AttachmentTypes, -} from './constants' + BankAccountType, + MONTHS, + TaxLevelOptions, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { + Attachments, + BankInfo, + FileType, + PaymentInfo, +} from '@island.is/application/templates/social-insurance-administration-core/types' import { Application, NationalRegistryResidenceHistory, YesOrNo, } from '@island.is/application/types' -import { oldAgePensionFormMessage } from './messages' -import * as kennitala from 'kennitala' -import addYears from 'date-fns/addYears' import addMonths from 'date-fns/addMonths' +import addYears from 'date-fns/addYears' +import * as kennitala from 'kennitala' import { CombinedResidenceHistory, Employer, + FileUpload, IncompleteEmployer, SelfEmployed, - FileUpload, } from '../types' import { - BankAccountType, - MONTHS, - TaxLevelOptions, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' -import { - Attachments, - BankInfo, - FileType, - PaymentInfo, -} from '@island.is/application/templates/social-insurance-administration-core/types' + ApplicationType, + AttachmentLabel, + AttachmentTypes, + earlyRetirementMaxAge, + earlyRetirementMinAge, + Employment, + oldAgePensionAge, +} from './constants' +import { oldAgePensionFormMessage } from './messages' export const getApplicationAnswers = (answers: Application['answers']) => { const pensionFundQuestion = getValueViaPath( @@ -51,6 +51,11 @@ export const getApplicationAnswers = (answers: Application['answers']) => { const selectedMonth = getValueViaPath(answers, 'period.month') as string + const selectedYearHiddenInput = getValueViaPath( + answers, + 'period.hiddenInput', + ) as string + const applicantPhonenumber = getValueViaPath( answers, 'applicant.phoneNumber', @@ -154,6 +159,7 @@ export const getApplicationAnswers = (answers: Application['answers']) => { applicationType, selectedYear, selectedMonth, + selectedYearHiddenInput, applicantPhonenumber, bank, residenceHistoryQuestion, diff --git a/libs/application/templates/social-insurance-administration/pension-supplement/src/forms/PensionSupplementForm.ts b/libs/application/templates/social-insurance-administration/pension-supplement/src/forms/PensionSupplementForm.ts index 6f81b31315d5..4e9a5fd7af24 100644 --- a/libs/application/templates/social-insurance-administration/pension-supplement/src/forms/PensionSupplementForm.ts +++ b/libs/application/templates/social-insurance-administration/pension-supplement/src/forms/PensionSupplementForm.ts @@ -1,21 +1,31 @@ import { + buildAlertMessageField, + buildCheckboxField, + buildCustomField, + buildFileUploadField, buildForm, + buildHiddenInputWithWatchedValue, buildMultiField, + buildRadioField, buildSection, + buildSelectField, + buildSubmitField, buildSubSection, buildTextField, - buildCustomField, - buildSubmitField, - buildCheckboxField, - buildFileUploadField, - buildAlertMessageField, - buildRadioField, - buildSelectField, } from '@island.is/application/core' +import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' import { - applicantInformationMultiField, - buildFormConclusionSection, -} from '@island.is/application/ui-forms' + BankAccountType, + fileUploadSharedProps, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' +import { + friendlyFormatIBAN, + friendlyFormatSWIFT, + getBankIsk, + getCurrencies, + typeOfBankInfo, +} from '@island.is/application/templates/social-insurance-administration-core/lib/socialInsuranceAdministrationUtils' import { Application, DefaultEvents, @@ -23,29 +33,20 @@ import { FormModes, FormValue, } from '@island.is/application/types' +import { + applicantInformationMultiField, + buildFormConclusionSection, +} from '@island.is/application/ui-forms' +import isEmpty from 'lodash/isEmpty' +import { ApplicationReason } from '../lib/constants' import { pensionSupplementFormMessage } from '../lib/messages' import { - getApplicationReasonOptions, getApplicationAnswers, getApplicationExternalData, + getApplicationReasonOptions, + getAvailableMonths, getAvailableYears, } from '../lib/pensionSupplementUtils' -import { ApplicationReason } from '../lib/constants' -import { - MONTHS, - fileUploadSharedProps, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' -import isEmpty from 'lodash/isEmpty' -import { BankAccountType } from '@island.is/application/templates/social-insurance-administration-core/lib/constants' -import { - friendlyFormatIBAN, - friendlyFormatSWIFT, - getBankIsk, - getCurrencies, - typeOfBankInfo, -} from '@island.is/application/templates/social-insurance-administration-core/lib/socialInsuranceAdministrationUtils' -import Logo from '@island.is/application/templates/social-insurance-administration-core/assets/Logo' -import { socialInsuranceAdministrationMessage } from '@island.is/application/templates/social-insurance-administration-core/lib/messages' export const PensionSupplementForm: Form = buildForm({ id: 'PensionSupplementDraft', @@ -312,7 +313,24 @@ export const PensionSupplementForm: Form = buildForm({ width: 'half', placeholder: socialInsuranceAdministrationMessage.period.monthDefaultText, - options: MONTHS, + options: (application: Application) => { + const { selectedYear } = getApplicationAnswers( + application.answers, + ) + + return getAvailableMonths(selectedYear) + }, + condition: (answers) => { + const { selectedYear, selectedYearHiddenInput } = + getApplicationAnswers(answers) + + return selectedYear === selectedYearHiddenInput + }, + }), + buildHiddenInputWithWatchedValue({ + // Needed to trigger an update on options in the select above + id: 'period.hiddenInput', + watchValue: 'period.year', }), ], }), diff --git a/libs/application/templates/social-insurance-administration/pension-supplement/src/index.ts b/libs/application/templates/social-insurance-administration/pension-supplement/src/index.ts index a615305578e7..29cfff9c42cf 100644 --- a/libs/application/templates/social-insurance-administration/pension-supplement/src/index.ts +++ b/libs/application/templates/social-insurance-administration/pension-supplement/src/index.ts @@ -6,3 +6,4 @@ export const getFields = () => import('./fields') export default template export * from './lib/pensionSupplementUtils' +export * from './lib/messages' diff --git a/libs/application/templates/social-insurance-administration/pension-supplement/src/lib/pensionSupplementUtils.ts b/libs/application/templates/social-insurance-administration/pension-supplement/src/lib/pensionSupplementUtils.ts index 14615e6c3564..cdefa151c0ed 100644 --- a/libs/application/templates/social-insurance-administration/pension-supplement/src/lib/pensionSupplementUtils.ts +++ b/libs/application/templates/social-insurance-administration/pension-supplement/src/lib/pensionSupplementUtils.ts @@ -1,23 +1,23 @@ import { getValueViaPath } from '@island.is/application/core' -import { Application, ExternalData, Option } from '@island.is/application/types' import { - ApplicationReason, - AttachmentLabel, - AttachmentTypes, -} from './constants' -import { pensionSupplementFormMessage } from './messages' -import subYears from 'date-fns/subYears' -import addMonths from 'date-fns/addMonths' + BankAccountType, + MONTHS, +} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' import { Attachments, BankInfo, FileType, } from '@island.is/application/templates/social-insurance-administration-core/types' -import { - BankAccountType, - MONTHS, -} from '@island.is/application/templates/social-insurance-administration-core/lib/constants' +import { Application, ExternalData, Option } from '@island.is/application/types' +import addMonths from 'date-fns/addMonths' +import subYears from 'date-fns/subYears' import { PensionSupplementAttachments } from '../types' +import { + ApplicationReason, + AttachmentLabel, + AttachmentTypes, +} from './constants' +import { pensionSupplementFormMessage } from './messages' export const getApplicationAnswers = (answers: Application['answers']) => { const applicantPhonenumber = getValueViaPath( @@ -34,6 +34,11 @@ export const getApplicationAnswers = (answers: Application['answers']) => { const selectedMonth = getValueViaPath(answers, 'period.month') as string + const selectedYearHiddenInput = getValueViaPath( + answers, + 'period.hiddenInput', + ) as string + const additionalAttachments = getValueViaPath( answers, 'fileUploadAdditionalFiles.additionalDocuments', @@ -106,6 +111,7 @@ export const getApplicationAnswers = (answers: Application['answers']) => { applicationReason, selectedYear, selectedMonth, + selectedYearHiddenInput, additionalAttachments, additionalAttachmentsRequired, comment, From af0f4ca0e6b29436ba3f0ebe0c15dd45b245de91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3nas=20G=2E=20Sigur=C3=B0sson?= Date: Fri, 18 Oct 2024 17:59:19 +0000 Subject: [PATCH 5/6] fix: checkbox width bug (#16467) * fix: checkbox width bug * chore: revert the example form --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/lib/CheckboxFormField/CheckboxFormField.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx b/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx index 136d978de23a..32ac27632a3c 100644 --- a/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx +++ b/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx @@ -1,4 +1,4 @@ -import React, { FC, useMemo } from 'react' +import { useMemo } from 'react' import HtmlParser from 'react-html-parser' import { @@ -20,12 +20,12 @@ interface Props extends FieldBaseProps { field: CheckboxField } -export const CheckboxFormField: FC> = ({ +export const CheckboxFormField = ({ error, showFieldName = false, field, application, -}) => { +}: Props) => { const { id, title, @@ -68,7 +68,6 @@ export const CheckboxFormField: FC> = ({ large={large} name={`${id}`} onSelect={onSelect} - split={width === 'half' ? '1/2' : '1/1'} backgroundColor={backgroundColor} defaultValue={ ((getValueViaPath(application.answers, id) as string[]) ?? From 75ba90bbab698106499aac0a49fb422349c1e093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Fri, 18 Oct 2024 18:26:08 +0000 Subject: [PATCH 6/6] chore(j-s): Send notifications when subpoena changes (#16329) * Checkpoint * Refactor * Checkpoint * Add messages to queue * Checkpoint * Construct the emails * Fix build * Checkpoint * Implement failed notifications * Add failed and defenderchoice emails * Remove unused code * Remove unused code * Refactor * Refactor * Remove unused code * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Merge * Cleanup * Remove console.log * Refactor * Refactor * Refactor * Remove unused code * Refactor * Fix tests --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../20241015105921-update-notification.js | 70 +++++++ .../notification/baseNotification.service.ts | 24 +++ .../dto/subpoenaNotification.dto.ts | 18 ++ .../institutionNotification.service.ts | 8 +- .../internalNotification.controller.ts | 22 +- .../internalNotification.service.ts | 24 --- .../notification/notification.module.ts | 4 + .../subpoenaNotification.service.ts | 196 ++++++++++++++++++ .../subpoenaNotification.strings.ts | 43 ++++ .../limitedAccessSubpoena.controller.ts | 2 +- .../app/modules/subpoena/subpoena.module.ts | 3 + .../app/modules/subpoena/subpoena.service.ts | 52 ++++- .../test/createTestingSubpoenaModule.ts | 3 + .../message/src/lib/message.ts | 2 + libs/judicial-system/types/src/index.ts | 1 + .../types/src/lib/defendant.ts | 4 + .../types/src/lib/notification.ts | 3 + 17 files changed, 447 insertions(+), 32 deletions(-) create mode 100644 apps/judicial-system/backend/migrations/20241015105921-update-notification.js create mode 100644 apps/judicial-system/backend/src/app/modules/notification/dto/subpoenaNotification.dto.ts create mode 100644 apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.service.ts create mode 100644 apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.strings.ts diff --git a/apps/judicial-system/backend/migrations/20241015105921-update-notification.js b/apps/judicial-system/backend/migrations/20241015105921-update-notification.js new file mode 100644 index 000000000000..d3979f325f06 --- /dev/null +++ b/apps/judicial-system/backend/migrations/20241015105921-update-notification.js @@ -0,0 +1,70 @@ +'use strict' +const replaceEnum = require('sequelize-replace-enum-postgres').default + +module.exports = { + up: (queryInterface) => { + // replaceEnum does not support transactions + return replaceEnum({ + queryInterface, + tableName: 'notification', + columnName: 'type', + newValues: [ + 'HEADS_UP', + 'READY_FOR_COURT', + 'RECEIVED_BY_COURT', + 'COURT_DATE', + 'RULING', + 'MODIFIED', + 'REVOKED', + 'DEFENDER_ASSIGNED', + 'ADVOCATE_ASSIGNED', + 'DEFENDANTS_NOT_UPDATED_AT_COURT', + 'APPEAL_TO_COURT_OF_APPEALS', + 'APPEAL_RECEIVED_BY_COURT', + 'APPEAL_STATEMENT', + 'APPEAL_COMPLETED', + 'APPEAL_JUDGES_ASSIGNED', + 'APPEAL_CASE_FILES_UPDATED', + 'APPEAL_WITHDRAWN', + 'INDICTMENT_DENIED', + 'INDICTMENT_RETURNED', + 'INDICTMENTS_WAITING_FOR_CONFIRMATION', + 'SERVICE_SUCCESSFUL', // New value + 'SERVICE_FAILED', // New value + 'DEFENDANT_SELECTED_DEFENDER', // New value + ], + enumName: 'enum_notification_type', + }) + }, + + down: (queryInterface) => { + // replaceEnum does not support transactions + return replaceEnum({ + queryInterface, + tableName: 'notification', + columnName: 'type', + newValues: [ + 'HEADS_UP', + 'READY_FOR_COURT', + 'RECEIVED_BY_COURT', + 'COURT_DATE', + 'RULING', + 'MODIFIED', + 'REVOKED', + 'DEFENDER_ASSIGNED', + 'DEFENDANTS_NOT_UPDATED_AT_COURT', + 'APPEAL_TO_COURT_OF_APPEALS', + 'APPEAL_RECEIVED_BY_COURT', + 'APPEAL_STATEMENT', + 'APPEAL_COMPLETED', + 'APPEAL_JUDGES_ASSIGNED', + 'APPEAL_CASE_FILES_UPDATED', + 'APPEAL_WITHDRAWN', + 'INDICTMENT_DENIED', + 'INDICTMENT_RETURNED', + 'INDICTMENTS_WAITING_FOR_CONFIRMATION', + ], + enumName: 'enum_notification_type', + }) + }, +} diff --git a/apps/judicial-system/backend/src/app/modules/notification/baseNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/baseNotification.service.ts index 2bae99fff0e2..211d44dcd63d 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/baseNotification.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/baseNotification.service.ts @@ -145,4 +145,28 @@ export abstract class BaseNotificationService { ), } } + + protected hasSentNotification( + type: NotificationType, + notifications?: Notification[], + ) { + return notifications?.some((notification) => notification.type === type) + } + + protected hasReceivedNotification( + type?: NotificationType | NotificationType[], + address?: string, + notifications?: Notification[], + ) { + const types = type ? [type].flat() : Object.values(NotificationType) + + return notifications?.some((notification) => { + return ( + types.includes(notification.type) && + notification.recipients.some( + (recipient) => recipient.address === address && recipient.success, + ) + ) + }) + } } diff --git a/apps/judicial-system/backend/src/app/modules/notification/dto/subpoenaNotification.dto.ts b/apps/judicial-system/backend/src/app/modules/notification/dto/subpoenaNotification.dto.ts new file mode 100644 index 000000000000..e1b0bf519135 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/notification/dto/subpoenaNotification.dto.ts @@ -0,0 +1,18 @@ +import { IsEnum, IsNotEmpty } from 'class-validator' + +import { ApiProperty } from '@nestjs/swagger' + +import { NotificationType } from '@island.is/judicial-system/types' + +import { Subpoena } from '../../subpoena' + +export class SubpoenaNotificationDto { + @IsNotEmpty() + @IsEnum(NotificationType) + @ApiProperty({ enum: NotificationType }) + readonly type!: NotificationType + + @IsNotEmpty() + @ApiProperty({ type: Subpoena }) + readonly subpoena!: Subpoena +} diff --git a/apps/judicial-system/backend/src/app/modules/notification/institutionNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/institutionNotification.service.ts index 1562251ab13d..cad5fba282fa 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/institutionNotification.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/institutionNotification.service.ts @@ -46,8 +46,12 @@ export class InstitutionNotificationService extends BaseNotificationService { } private async sendIndictmentsWaitingForConfirmationNotification( - prosecutorsOfficeId: string, + prosecutorsOfficeId?: string, ): Promise { + if (!prosecutorsOfficeId) { + return + } + const count = await this.internalCaseService.countIndictmentsWaitingForConfirmation( prosecutorsOfficeId, @@ -87,7 +91,7 @@ export class InstitutionNotificationService extends BaseNotificationService { async sendNotification( type: NotificationType, - prosecutorsOfficeId: string, + prosecutorsOfficeId?: string, ): Promise { try { switch (type) { diff --git a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.controller.ts b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.controller.ts index aaa0b1441cd8..2b96d6aaac7a 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.controller.ts @@ -20,11 +20,12 @@ import { import { Case, CaseHasExistedGuard, CurrentCase } from '../case' import { CaseNotificationDto } from './dto/caseNotification.dto' import { InstitutionNotificationDto } from './dto/institutionNotification.dto' -import { NotificationDto } from './dto/notification.dto' +import { SubpoenaNotificationDto } from './dto/subpoenaNotification.dto' import { DeliverResponse } from './models/deliver.response' import { InstitutionNotificationService } from './institutionNotification.service' import { InternalNotificationService } from './internalNotification.service' import { NotificationDispatchService } from './notificationDispatch.service' +import { SubpoenaNotificationService } from './subpoenaNotification.service' @UseGuards(TokenGuard) @Controller('api/internal') @@ -34,6 +35,7 @@ export class InternalNotificationController { private readonly internalNotificationService: InternalNotificationService, private readonly notificationDispatchService: NotificationDispatchService, private readonly institutionNotificationService: InstitutionNotificationService, + private readonly subpoenaNotificationService: SubpoenaNotificationService, @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} @@ -75,13 +77,29 @@ export class InternalNotificationController { ) } + @Post(messageEndpoint[MessageType.SUBPOENA_NOTIFICATION]) + @ApiCreatedResponse({ + type: DeliverResponse, + description: 'Sends a new notification', + }) + sendSubpoenaNotification( + @Body() notificationDto: SubpoenaNotificationDto, + ): Promise { + this.logger.debug(`Sending ${notificationDto.type} notification`) + + return this.subpoenaNotificationService.sendNotification( + notificationDto.type, + notificationDto.subpoena, + ) + } + @Post(messageEndpoint[MessageType.NOTIFICATION_DISPATCH]) @ApiCreatedResponse({ type: DeliverResponse, description: 'Dispatches notifications', }) dispatchNotification( - @Body() notificationDto: NotificationDto, + @Body() notificationDto: InstitutionNotificationDto, ): Promise { this.logger.debug(`Dispatching ${notificationDto.type} notification`) diff --git a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts index 7be128ecb9b4..b8b670d07c24 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts @@ -118,30 +118,6 @@ export class InternalNotificationService extends BaseNotificationService { ) } - private hasSentNotification( - type: NotificationType, - notifications?: Notification[], - ) { - return notifications?.some((notification) => notification.type === type) - } - - private hasReceivedNotification( - type?: NotificationType | NotificationType[], - address?: string, - notifications?: Notification[], - ) { - const types = type ? [type].flat() : Object.values(NotificationType) - - return notifications?.some((notification) => { - return ( - types.includes(notification.type) && - notification.recipients.some( - (recipient) => recipient.address === address && recipient.success, - ) - ) - }) - } - private async shouldSendNotificationToPrison( theCase: Case, ): Promise { diff --git a/apps/judicial-system/backend/src/app/modules/notification/notification.module.ts b/apps/judicial-system/backend/src/app/modules/notification/notification.module.ts index 162c49216243..f2c3054e7845 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/notification.module.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/notification.module.ts @@ -13,6 +13,7 @@ import { DefendantModule, EventModule, InstitutionModule, + SubpoenaModule, UserModule, } from '../index' import { Notification } from './models/notification.model' @@ -22,6 +23,7 @@ import { InternalNotificationService } from './internalNotification.service' import { NotificationController } from './notification.controller' import { NotificationService } from './notification.service' import { NotificationDispatchService } from './notificationDispatch.service' +import { SubpoenaNotificationService } from './subpoenaNotification.service' @Module({ imports: [ @@ -31,6 +33,7 @@ import { NotificationDispatchService } from './notificationDispatch.service' MessageModule, InstitutionModule, UserModule, + forwardRef(() => SubpoenaModule), forwardRef(() => CaseModule), forwardRef(() => CourtModule), forwardRef(() => EventModule), @@ -43,6 +46,7 @@ import { NotificationDispatchService } from './notificationDispatch.service' InternalNotificationService, NotificationDispatchService, InstitutionNotificationService, + SubpoenaNotificationService, ], }) export class NotificationModule {} diff --git a/apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.service.ts new file mode 100644 index 000000000000..a8ac52f19be1 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.service.ts @@ -0,0 +1,196 @@ +import { MessageDescriptor } from 'react-intl' + +import { + Inject, + Injectable, + InternalServerErrorException, +} from '@nestjs/common' +import { InjectModel } from '@nestjs/sequelize' + +import { IntlService } from '@island.is/cms-translations' +import { EmailService } from '@island.is/email-service' +import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' +import { type ConfigType } from '@island.is/nest/config' + +import { INDICTMENTS_COURT_OVERVIEW_ROUTE } from '@island.is/judicial-system/consts' +import { NotificationType } from '@island.is/judicial-system/types' + +import { EventService } from '../event' +import { Subpoena } from '../subpoena' +import { DeliverResponse } from './models/deliver.response' +import { Notification, Recipient } from './models/notification.model' +import { BaseNotificationService } from './baseNotification.service' +import { notificationModuleConfig } from './notification.config' +import { strings } from './subpoenaNotification.strings' + +type SubpoenaNotificationType = + | NotificationType.SERVICE_SUCCESSFUL + | NotificationType.SERVICE_FAILED + | NotificationType.DEFENDANT_SELECTED_DEFENDER + +@Injectable() +export class SubpoenaNotificationService extends BaseNotificationService { + constructor( + @InjectModel(Notification) + notificationModel: typeof Notification, + @Inject(notificationModuleConfig.KEY) + config: ConfigType, + @Inject(LOGGER_PROVIDER) logger: Logger, + intlService: IntlService, + emailService: EmailService, + eventService: EventService, + ) { + super( + notificationModel, + emailService, + intlService, + config, + eventService, + logger, + ) + } + + private getEmailContents(notificationType: SubpoenaNotificationType): { + subject: MessageDescriptor + body: MessageDescriptor + } { + switch (notificationType) { + case NotificationType.SERVICE_SUCCESSFUL: + return { + subject: strings.serviceSuccessfulSubject, + body: strings.serviceSuccessfulBody, + } + case NotificationType.SERVICE_FAILED: + return { + subject: strings.serviceFailedSubject, + body: strings.serviceFailedBody, + } + case NotificationType.DEFENDANT_SELECTED_DEFENDER: + return { + subject: strings.defendantSelectedDefenderSubject, + body: strings.defendantSelectedDefenderBody, + } + default: + throw new InternalServerErrorException('Email contents not found') + } + } + + private async sendSubpoenaNotification( + notificationType: SubpoenaNotificationType, + subpoena: Subpoena, + ): Promise { + const theCase = subpoena.case + + if (!theCase) { + throw new InternalServerErrorException('Missing case') + } + + const hasSentSuccessfulServiceNotification = Boolean( + this.hasSentNotification( + NotificationType.SERVICE_SUCCESSFUL, + theCase.notifications, + ) && notificationType === NotificationType.SERVICE_SUCCESSFUL, + ) + + const hasSentFailedServiceNotification = Boolean( + this.hasSentNotification( + NotificationType.SERVICE_FAILED, + theCase.notifications, + ) && notificationType === NotificationType.SERVICE_FAILED, + ) + + const hasSendDefendantSelectedDefenderNotification = Boolean( + this.hasSentNotification( + NotificationType.DEFENDANT_SELECTED_DEFENDER, + theCase.notifications, + ) && notificationType === NotificationType.DEFENDANT_SELECTED_DEFENDER, + ) + + if ( + hasSentSuccessfulServiceNotification || + hasSentFailedServiceNotification || + hasSendDefendantSelectedDefenderNotification + ) { + return + } + + await this.refreshFormatMessage() + + const emailContents = this.getEmailContents(notificationType) + + const formattedSubject = this.formatMessage(emailContents.subject, { + courtCaseNumber: theCase.courtCaseNumber, + }) + + const formattedBody = this.formatMessage(emailContents.body, { + courtCaseNumber: theCase.courtCaseNumber, + linkStart: ``, + linkEnd: '', + }) + + return this.sendEmails( + theCase.id, + notificationType, + formattedSubject, + formattedBody, + theCase.judge?.name, + theCase.judge?.email, + theCase.registrar?.name, + theCase.registrar?.email, + ) + } + + private async sendEmails( + caseId: string, + notificationType: SubpoenaNotificationType, + subject: string, + body: string, + judgeName?: string, + judgeEmail?: string, + registrarName?: string, + registrarEmail?: string, + ) { + const promises: Promise[] = [] + + if (judgeName && judgeEmail) { + promises.push( + this.sendEmail(subject, body, judgeName, judgeEmail, undefined, true), + ) + } + + if (registrarName && registrarEmail) { + promises.push( + this.sendEmail( + subject, + body, + registrarName, + registrarEmail, + undefined, + true, + ), + ) + } + + const recipients = await Promise.all(promises) + + return this.recordNotification(caseId, notificationType, recipients) + } + + async sendNotification( + type: NotificationType, + subpoena: Subpoena, + ): Promise { + try { + await this.sendSubpoenaNotification( + type as SubpoenaNotificationType, + subpoena, + ) + } catch (error) { + this.logger.error('Failed to send notification', error) + + return { delivered: false } + } + + return { delivered: true } + } +} diff --git a/apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.strings.ts b/apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.strings.ts new file mode 100644 index 000000000000..8f08b6f475ae --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/notification/subpoenaNotification.strings.ts @@ -0,0 +1,43 @@ +import { defineMessage } from '@formatjs/intl' + +export const strings = { + serviceSuccessfulSubject: defineMessage({ + id: 'judicial.system.backend:subpoena_notifications.service_successful_subject', + defaultMessage: 'Birting tókst í máli {courtCaseNumber}', + description: + 'Subject of the notification sent when the serive status in an indictment has changed', + }), + serviceSuccessfulBody: defineMessage({ + id: 'judicial.system.backend:subpoena_notifications.service_successful_body', + defaultMessage: + 'Birting ákæru og fyrirkalls tókst í máli {courtCaseNumber}.

Sjá nánar á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}.', + description: + 'Body of the notification sent when the serive status in an indictment has changed', + }), + serviceFailedSubject: defineMessage({ + id: 'judicial.system.backend:subpoena_notifications.service_failed_subject', + defaultMessage: 'Birting árangurslaus í máli {courtCaseNumber}', + description: + 'Subject of the notification sent when the serive status in an indictment has changed', + }), + serviceFailedBody: defineMessage({ + id: 'judicial.system.backend:subpoena_notifications.service_failed_body', + defaultMessage: + 'Birting ákæru og fyrirkalls var árangurslaus í máli {courtCaseNumber}.

Sjá nánar á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}.', + description: + 'Body of the notification sent when the serive status in an indictment has changed', + }), + defendantSelectedDefenderSubject: defineMessage({ + id: 'judicial.system.backend:subpoena_notifications.defendant_selected_defender_subject', + defaultMessage: 'Val á verjanda í máli {courtCaseNumber}', + description: + 'Subject of the notification sent when the serive status in an indictment has changed', + }), + defendantSelectedDefenderBody: defineMessage({ + id: 'judicial.system.backend:subpoena_notifications.defendant_selected_defender_body', + defaultMessage: + 'Verjandi hefur verið valinn í máli {courtCaseNumber}.

Sjá nánar á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}.', + description: + 'Body of the notification sent when the serive status in an indictment has changed', + }), +} diff --git a/apps/judicial-system/backend/src/app/modules/subpoena/limitedAccessSubpoena.controller.ts b/apps/judicial-system/backend/src/app/modules/subpoena/limitedAccessSubpoena.controller.ts index 0da62cac4fa5..b805d15ba33e 100644 --- a/apps/judicial-system/backend/src/app/modules/subpoena/limitedAccessSubpoena.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/subpoena/limitedAccessSubpoena.controller.ts @@ -47,7 +47,7 @@ import { Subpoena } from './models/subpoena.model' DefendantExistsGuard, SubpoenaExistsOptionalGuard, ) -@ApiTags('limited access defendants') +@ApiTags('limited access subpoenas') export class LimitedAccessSubpoenaController { constructor( private readonly pdfService: PdfService, diff --git a/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.module.ts b/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.module.ts index fc8981500d91..42f6249d39f2 100644 --- a/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.module.ts +++ b/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.module.ts @@ -1,6 +1,8 @@ import { forwardRef, Module } from '@nestjs/common' import { SequelizeModule } from '@nestjs/sequelize' +import { MessageModule } from '@island.is/judicial-system/message' + import { CaseModule } from '../case/case.module' import { Defendant } from '../defendant/models/defendant.model' import { FileModule } from '../file/file.module' @@ -16,6 +18,7 @@ import { SubpoenaService } from './subpoena.service' forwardRef(() => CaseModule), forwardRef(() => PoliceModule), forwardRef(() => FileModule), + forwardRef(() => MessageModule), SequelizeModule.forFeature([Subpoena, Defendant]), ], controllers: [ diff --git a/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.service.ts b/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.service.ts index c476d085e835..26175ace9bb1 100644 --- a/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.service.ts +++ b/apps/judicial-system/backend/src/app/modules/subpoena/subpoena.service.ts @@ -14,10 +14,15 @@ import { InjectConnection, InjectModel } from '@nestjs/sequelize' import type { Logger } from '@island.is/logging' import { LOGGER_PROVIDER } from '@island.is/logging' +import { MessageService, MessageType } from '@island.is/judicial-system/message' import { CaseFileCategory, + DefenderChoice, + isFailedServiceStatus, + isSuccessfulServiceStatus, isTrafficViolationCase, - type User, + NotificationType, + type User as TUser, } from '@island.is/judicial-system/types' import { Case } from '../case/models/case.model' @@ -25,12 +30,26 @@ import { PdfService } from '../case/pdf.service' import { Defendant } from '../defendant/models/defendant.model' import { FileService } from '../file' import { PoliceService } from '../police' +import { User } from '../user' import { UpdateSubpoenaDto } from './dto/updateSubpoena.dto' import { DeliverResponse } from './models/deliver.response' import { Subpoena } from './models/subpoena.model' export const include: Includeable[] = [ - { model: Case, as: 'case' }, + { + model: Case, + as: 'case', + include: [ + { + model: User, + as: 'judge', + }, + { + model: User, + as: 'registrar', + }, + ], + }, { model: Defendant, as: 'defendant' }, ] @Injectable() @@ -40,6 +59,7 @@ export class SubpoenaService { @InjectModel(Subpoena) private readonly subpoenaModel: typeof Subpoena, @InjectModel(Defendant) private readonly defendantModel: typeof Defendant, private readonly pdfService: PdfService, + private readonly messageService: MessageService, @Inject(forwardRef(() => PoliceService)) private readonly policeService: PoliceService, @Inject(forwardRef(() => FileService)) @@ -92,11 +112,20 @@ export class SubpoenaService { defenderEmail, defenderPhoneNumber, defenderName, + serviceStatus, requestedDefenderChoice, requestedDefenderNationalId, requestedDefenderName, } = update + const notificationType = isSuccessfulServiceStatus(serviceStatus) + ? NotificationType.SERVICE_SUCCESSFUL + : isFailedServiceStatus(serviceStatus) + ? NotificationType.SERVICE_FAILED + : defenderChoice === DefenderChoice.CHOOSE && defenderNationalId + ? NotificationType.DEFENDANT_SELECTED_DEFENDER + : undefined + const [numberOfAffectedRows] = await this.subpoenaModel.update(update, { where: { subpoenaId: subpoena.subpoenaId }, returning: true, @@ -138,6 +167,23 @@ export class SubpoenaService { ) } + if (notificationType) { + this.messageService + .sendMessagesToQueue([ + { + type: MessageType.SUBPOENA_NOTIFICATION, + body: { + type: notificationType, + subpoena, + }, + }, + ]) + .catch((reason) => + // Tolerate failure, but log + this.logger.error('Failed to dispatch notifications', { reason }), + ) + } + const updatedSubpoena = await this.findBySubpoenaId(subpoena.subpoenaId) return updatedSubpoena @@ -185,7 +231,7 @@ export class SubpoenaService { theCase: Case, defendant: Defendant, subpoena: Subpoena, - user: User, + user: TUser, ): Promise { try { const subpoenaPdf = await this.pdfService.getSubpoenaPdf( diff --git a/apps/judicial-system/backend/src/app/modules/subpoena/test/createTestingSubpoenaModule.ts b/apps/judicial-system/backend/src/app/modules/subpoena/test/createTestingSubpoenaModule.ts index 3ae092fe8887..b25adab82dfa 100644 --- a/apps/judicial-system/backend/src/app/modules/subpoena/test/createTestingSubpoenaModule.ts +++ b/apps/judicial-system/backend/src/app/modules/subpoena/test/createTestingSubpoenaModule.ts @@ -10,6 +10,7 @@ import { SharedAuthModule, sharedAuthModuleConfig, } from '@island.is/judicial-system/auth' +import { MessageService } from '@island.is/judicial-system/message' import { CaseService, PdfService } from '../../case' import { Defendant } from '../../defendant' @@ -27,6 +28,7 @@ jest.mock('../../case/case.service') jest.mock('../../case/pdf.service') jest.mock('../../police/police.service') jest.mock('../../file/file.service') +jest.mock('@island.is/judicial-system/message') export const createTestingSubpoenaModule = async () => { const subpoenaModule = await Test.createTestingModule({ @@ -75,6 +77,7 @@ export const createTestingSubpoenaModule = async () => { }, }, SubpoenaService, + MessageService, ], }).compile() diff --git a/libs/judicial-system/message/src/lib/message.ts b/libs/judicial-system/message/src/lib/message.ts index 1b5aaf576864..2cdc08ea958e 100644 --- a/libs/judicial-system/message/src/lib/message.ts +++ b/libs/judicial-system/message/src/lib/message.ts @@ -26,6 +26,7 @@ export enum MessageType { DELIVERY_TO_POLICE_SIGNED_RULING = 'DELIVERY_TO_POLICE_SIGNED_RULING', DELIVERY_TO_POLICE_APPEAL = 'DELIVERY_TO_POLICE_APPEAL', NOTIFICATION = 'NOTIFICATION', + SUBPOENA_NOTIFICATION = 'SUBPOENA_NOTIFICATION', NOTIFICATION_DISPATCH = 'NOTIFICATION_DISPATCH', } @@ -59,6 +60,7 @@ export const messageEndpoint: { [key in MessageType]: string } = { DELIVERY_TO_POLICE_SIGNED_RULING: 'deliverSignedRulingToPolice', DELIVERY_TO_POLICE_APPEAL: 'deliverAppealToPolice', NOTIFICATION: 'notification', + SUBPOENA_NOTIFICATION: 'subpoenaNotification', NOTIFICATION_DISPATCH: 'notification/dispatch', } diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index 502e7ce2f93f..a63b26a41b5a 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -8,6 +8,7 @@ export { ServiceRequirement, ServiceStatus, isSuccessfulServiceStatus, + isFailedServiceStatus, } from './lib/defendant' export { InstitutionType } from './lib/institution' export { NotificationType } from './lib/notification' diff --git a/libs/judicial-system/types/src/lib/defendant.ts b/libs/judicial-system/types/src/lib/defendant.ts index be51efe47cef..a2cb9852d27a 100644 --- a/libs/judicial-system/types/src/lib/defendant.ts +++ b/libs/judicial-system/types/src/lib/defendant.ts @@ -45,3 +45,7 @@ export const successfulServiceStatus: string[] = [ export const isSuccessfulServiceStatus = (status?: ServiceStatus): boolean => { return Boolean(status && successfulServiceStatus.includes(status)) } + +export const isFailedServiceStatus = (status?: ServiceStatus): boolean => { + return Boolean(status && status === ServiceStatus.FAILED) +} diff --git a/libs/judicial-system/types/src/lib/notification.ts b/libs/judicial-system/types/src/lib/notification.ts index 26d38136f834..1860778fdedf 100644 --- a/libs/judicial-system/types/src/lib/notification.ts +++ b/libs/judicial-system/types/src/lib/notification.ts @@ -18,4 +18,7 @@ export enum NotificationType { INDICTMENT_DENIED = 'INDICTMENT_DENIED', INDICTMENT_RETURNED = 'INDICTMENT_RETURNED', INDICTMENTS_WAITING_FOR_CONFIRMATION = 'INDICTMENTS_WAITING_FOR_CONFIRMATION', + SERVICE_SUCCESSFUL = 'SERVICE_SUCCESSFUL', + SERVICE_FAILED = 'SERVICE_FAILED', + DEFENDANT_SELECTED_DEFENDER = 'DEFENDANT_SELECTED_DEFENDER', }