From da2ec6864b34649581a9f48e99145437a64878b2 Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Wed, 25 Mar 2026 10:18:44 +0000 Subject: [PATCH 01/14] feat: extend CCD and form config for household circumstances --- src/main/interfaces/ccdCase.interface.ts | 8 ++++++++ src/main/interfaces/formFieldConfig.interface.ts | 2 ++ src/main/modules/steps/formBuilder/schema.ts | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/main/interfaces/ccdCase.interface.ts b/src/main/interfaces/ccdCase.interface.ts index 313309604..b5b707bf3 100644 --- a/src/main/interfaces/ccdCase.interface.ts +++ b/src/main/interfaces/ccdCase.interface.ts @@ -67,6 +67,14 @@ export interface PossessionClaimResponse { writtenTerms?: YesNoNotSureValue; disputeClaim?: YesNoValue; disputeClaimDetails?: string; + householdCircumstances?: { + universalCredit?: YesNoValue; + ucApplicationDate?: string; + priorityDebts?: YesNoValue; + debtTotal?: string; + debtContribution?: string; + debtContributionFrequency?: string; + }; paymentAgreement?: { repaymentPlanAgreed?: YesNoNotSureValue; repaymentAgreedDetails?: string; diff --git a/src/main/interfaces/formFieldConfig.interface.ts b/src/main/interfaces/formFieldConfig.interface.ts index 1d163f23d..c48720d2c 100644 --- a/src/main/interfaces/formFieldConfig.interface.ts +++ b/src/main/interfaces/formFieldConfig.interface.ts @@ -33,6 +33,8 @@ export interface FormFieldConfig { errorMessage?: string; label?: string | ((translations: Record) => string); labelClasses?: string; + formGroupClasses?: string; + hintClasses?: string; hint?: string; translationKey?: { label?: string; diff --git a/src/main/modules/steps/formBuilder/schema.ts b/src/main/modules/steps/formBuilder/schema.ts index c0fd81586..e4ed6a144 100644 --- a/src/main/modules/steps/formBuilder/schema.ts +++ b/src/main/modules/steps/formBuilder/schema.ts @@ -65,6 +65,8 @@ export const FormFieldConfigSchema: z.ZodType = z.lazy(() => // Label can be string or function label: LabelFunctionSchema.optional(), labelClasses: z.string().optional(), + formGroupClasses: z.string().optional(), + hintClasses: z.string().optional(), hint: z.string().optional(), translationKey: z .object({ From 400edba4207b4cd285f30c9a8387ba3da70e2fa3 Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Wed, 25 Mar 2026 15:52:33 +0000 Subject: [PATCH 02/14] feat: allow hint and form group classes on text inputs --- .../steps/formBuilder/componentBuilders.ts | 13 +++++++++++- .../formBuilder/componentBuilders.test.ts | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main/modules/steps/formBuilder/componentBuilders.ts b/src/main/modules/steps/formBuilder/componentBuilders.ts index e02959cc6..e4d467f53 100644 --- a/src/main/modules/steps/formBuilder/componentBuilders.ts +++ b/src/main/modules/steps/formBuilder/componentBuilders.ts @@ -56,7 +56,12 @@ export function buildComponentConfig({ id: field.name, name: field.name, label: { text: label, classes: field.labelClasses }, - hint: hint ? { text: hint } : null, + hint: hint + ? { + text: hint, + ...(field.hintClasses ? { classes: field.hintClasses } : {}), + } + : null, errorMessage: hasError && errorText ? { text: errorText } : null, classes: field.classes || (field.type === 'text' ? 'govuk-!-width-three-quarters' : undefined), attributes: field.attributes || {}, @@ -70,6 +75,12 @@ export function buildComponentConfig({ if (field.prefix) { component.prefix = field.prefix; } + if (field.formGroupClasses) { + component.formGroup = { + classes: field.formGroupClasses, + attributes: {}, + }; + } componentType = 'input'; break; } diff --git a/src/test/unit/modules/steps/formBuilder/componentBuilders.test.ts b/src/test/unit/modules/steps/formBuilder/componentBuilders.test.ts index de0520c12..cfbce486c 100644 --- a/src/test/unit/modules/steps/formBuilder/componentBuilders.test.ts +++ b/src/test/unit/modules/steps/formBuilder/componentBuilders.test.ts @@ -109,6 +109,26 @@ describe('componentBuilders', () => { expect(items[1].checked).toBe(true); }); + it('passes hintClasses onto the GOV.UK hint object for text inputs', () => { + const field: FormFieldConfig = { + name: 'amount', + type: 'text', + translationKey: { label: 'amount' }, + hintClasses: 'govuk-!-margin-bottom-1', + }; + + const result = buildComponentConfig( + buildArgs(field, { + hint: 'Enter a number', + }) + ); + + expect(result.component.hint).toEqual({ + text: 'Enter a number', + classes: 'govuk-!-margin-bottom-1', + }); + }); + it('falls back to input component type for unknown field types', () => { const field = { name: 'legacy', From d5498829bed4770ce7672aa95ea022dbefd1c7cd Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Thu, 26 Mar 2026 09:44:21 +0000 Subject: [PATCH 03/14] feat: add CCD pence to pounds helper for money fields --- src/main/steps/utils/moneyAmountTransforms.ts | 15 +++++++++ .../steps/utils/moneyAmountTransforms.test.ts | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/test/unit/steps/utils/moneyAmountTransforms.test.ts diff --git a/src/main/steps/utils/moneyAmountTransforms.ts b/src/main/steps/utils/moneyAmountTransforms.ts index 1fc08846c..16bbd8ffd 100644 --- a/src/main/steps/utils/moneyAmountTransforms.ts +++ b/src/main/steps/utils/moneyAmountTransforms.ts @@ -11,6 +11,21 @@ export function poundsStringToPence(value: string): number | undefined { return undefined; } +/** MoneyGBP-style values stored as whole pence (digit-only string or numeric pence). */ +export function ccdPenceToPoundsString(value: unknown): string | undefined { + if (value === undefined || value === null) { + return undefined; + } + if (typeof value === 'string' && /^\d+$/.test(value.trim())) { + const pence = Number(value.trim()); + return Number.isFinite(pence) ? (pence / 100).toFixed(2) : undefined; + } + if (typeof value === 'number' && Number.isFinite(value)) { + return (value / 100).toFixed(2); + } + return undefined; +} + function penceToPoundsString(value: unknown): string | undefined { const getPenceAmount = (amountValue: unknown): number | undefined => { if (typeof amountValue === 'number' && Number.isFinite(amountValue)) { diff --git a/src/test/unit/steps/utils/moneyAmountTransforms.test.ts b/src/test/unit/steps/utils/moneyAmountTransforms.test.ts new file mode 100644 index 000000000..923000031 --- /dev/null +++ b/src/test/unit/steps/utils/moneyAmountTransforms.test.ts @@ -0,0 +1,31 @@ +import { ccdPenceToPoundsString, poundsStringToPence } from '../../../../main/steps/utils/moneyAmountTransforms'; + +describe('moneyAmountTransforms', () => { + describe('poundsStringToPence', () => { + it('converts pounds string to integer pence', () => { + expect(poundsStringToPence('148.50')).toBe(14850); + expect(poundsStringToPence(' 20 ')).toBe(2000); + }); + }); + + describe('ccdPenceToPoundsString', () => { + it('returns undefined for nullish values', () => { + expect(ccdPenceToPoundsString(undefined)).toBeUndefined(); + expect(ccdPenceToPoundsString(null)).toBeUndefined(); + }); + + it('maps digit-only pence strings to pounds with two decimals', () => { + expect(ccdPenceToPoundsString('14850')).toBe('148.50'); + expect(ccdPenceToPoundsString('2000')).toBe('20.00'); + }); + + it('maps numeric pence to pounds with two decimals', () => { + expect(ccdPenceToPoundsString(14850)).toBe('148.50'); + }); + + it('returns undefined for non-pence string shapes', () => { + expect(ccdPenceToPoundsString('148.50')).toBeUndefined(); + expect(ccdPenceToPoundsString('')).toBeUndefined(); + }); + }); +}); From e68ad36f74f5972da0dfa5d1400d4e0428253b24 Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Mon, 30 Mar 2026 10:08:55 +0100 Subject: [PATCH 04/14] feat: add English copy for UC, priority debts and guidance --- .../haveYouAppliedForUniversalCredit.json | 21 ++++++++++++++++ .../respondToClaim/priorityDebtDetails.json | 24 +++++++++++++++++++ .../en/respondToClaim/priorityDebts.json | 12 ++++++++++ .../respondToClaim/priorityDebtsGuidance.json | 14 +++++++++++ 4 files changed, 71 insertions(+) create mode 100644 src/main/assets/locales/en/respondToClaim/haveYouAppliedForUniversalCredit.json create mode 100644 src/main/assets/locales/en/respondToClaim/priorityDebtDetails.json create mode 100644 src/main/assets/locales/en/respondToClaim/priorityDebts.json create mode 100644 src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json diff --git a/src/main/assets/locales/en/respondToClaim/haveYouAppliedForUniversalCredit.json b/src/main/assets/locales/en/respondToClaim/haveYouAppliedForUniversalCredit.json new file mode 100644 index 000000000..243c4f7f8 --- /dev/null +++ b/src/main/assets/locales/en/respondToClaim/haveYouAppliedForUniversalCredit.json @@ -0,0 +1,21 @@ +{ + "pageTitle": "Have you applied for Universal Credit?", + "caption": "Respond to a property possession claim", + "question": "Have you applied for Universal Credit?", + "dateLabel": "When did you apply?", + "dateHint": "For example, 27 9 2022", + "options": { + "yes": "Yes", + "no": "No" + }, + "errors": { + "haveAppliedForUniversalCredit": "Select if you’ve applied for Universal Credit", + "date": { + "required": "Enter the date you applied for Universal Credit", + "missingOne": "The date you applied for Universal Credit must include a {{missingField}}", + "missingTwo": "The date you applied for Universal Credit must include a {{first}} and {{second}}", + "notRealDate": "The date you applied for Universal Credit must be a real date", + "futureDate": "The date you applied for Universal Credit must must either be today’s date or in the past" + } + } +} diff --git a/src/main/assets/locales/en/respondToClaim/priorityDebtDetails.json b/src/main/assets/locales/en/respondToClaim/priorityDebtDetails.json new file mode 100644 index 000000000..5ff8627ef --- /dev/null +++ b/src/main/assets/locales/en/respondToClaim/priorityDebtDetails.json @@ -0,0 +1,24 @@ +{ + "pageTitle": "Priority debt details", + "caption": "Respond to a property possession claim", + "totalQuestion": "What is the total amount you owe for all your priority debts?", + "contributionQuestion": "How much do you pay towards your priority debts each week or month?", + "frequencyQuestion": "Paid every:", + "amountHint": "Enter total amount in pounds and pence, for example £148.00 or £148.50", + "frequency": { + "week": "Week", + "month": "Month" + }, + "errors": { + "priorityDebtTotal": "Enter the total amount you owe for all your priority debts", + "priorityDebtTotalMin": "The total amount you owe for all your priority debts must be £0.00 or above", + "priorityDebtTotalMax": "The total amount you owe for all your priority debts must be less than £1 billion", + "priorityDebtContribution": "Enter the amount you pay towards your priority debts each week or month", + "priorityDebtContributionMin": "The amount you pay towards your priority debts each week or month must be £0.00 or above", + "priorityDebtContributionMax": "The amount you pay towards your priority debts each week or month must be less than £1 billion", + "priorityDebtContributionFrequency": "Select how frequently you pay the amount you entered above", + "amount": { + "invalidFormat": "Enter an amount in the correct format, for example £148.00 or £148.50" + } + } +} diff --git a/src/main/assets/locales/en/respondToClaim/priorityDebts.json b/src/main/assets/locales/en/respondToClaim/priorityDebts.json new file mode 100644 index 000000000..3a1ed7c16 --- /dev/null +++ b/src/main/assets/locales/en/respondToClaim/priorityDebts.json @@ -0,0 +1,12 @@ +{ + "pageTitle": "Priority debts", + "caption": "Respond to a property possession claim", + "question": "Do you have any priority debts?", + "options": { + "yes": "Yes", + "no": "No" + }, + "errors": { + "havePriorityDebts": "Select if you have any priority debts" + } +} diff --git a/src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json b/src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json new file mode 100644 index 000000000..ba195b262 --- /dev/null +++ b/src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json @@ -0,0 +1,14 @@ +{ + "paragraph1": "Priority debts are debts which could lead to serious consequences if you do not pay them.", + "paragraph2": "Excluding rent or mortgage arrears, priority debts are:", + "bullet1": "council tax arrears", + "bullet2": "gas or electricity arrears", + "bullet3": "phone or internet arrears", + "bullet4": "TV licence arrears", + "bullet5": "court fines", + "bullet6": "overpaid tax credits", + "bullet7": "payments for goods bought on hire purchase or conditional sale", + "bullet8": "unpaid income tax, National Insurance or VAT", + "bullet9": "unpaid child maintenance", + "guidanceLinkText": "Read guidance from Citizens Advice on what counts as a priority debt (opens in new tab)" +} From ea0a90c959a682a14ffc6674f83b1b5859ad48c2 Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Mon, 30 Mar 2026 11:39:17 +0100 Subject: [PATCH 05/14] feat: add Welsh copy for UC and priority debts --- .../haveYouAppliedForUniversalCredit.json | 21 ++++++++++++++++ .../respondToClaim/priorityDebtDetails.json | 24 +++++++++++++++++++ .../cy/respondToClaim/priorityDebts.json | 12 ++++++++++ .../respondToClaim/priorityDebtsGuidance.json | 14 +++++++++++ 4 files changed, 71 insertions(+) create mode 100644 src/main/assets/locales/cy/respondToClaim/haveYouAppliedForUniversalCredit.json create mode 100644 src/main/assets/locales/cy/respondToClaim/priorityDebtDetails.json create mode 100644 src/main/assets/locales/cy/respondToClaim/priorityDebts.json create mode 100644 src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json diff --git a/src/main/assets/locales/cy/respondToClaim/haveYouAppliedForUniversalCredit.json b/src/main/assets/locales/cy/respondToClaim/haveYouAppliedForUniversalCredit.json new file mode 100644 index 000000000..243c4f7f8 --- /dev/null +++ b/src/main/assets/locales/cy/respondToClaim/haveYouAppliedForUniversalCredit.json @@ -0,0 +1,21 @@ +{ + "pageTitle": "Have you applied for Universal Credit?", + "caption": "Respond to a property possession claim", + "question": "Have you applied for Universal Credit?", + "dateLabel": "When did you apply?", + "dateHint": "For example, 27 9 2022", + "options": { + "yes": "Yes", + "no": "No" + }, + "errors": { + "haveAppliedForUniversalCredit": "Select if you’ve applied for Universal Credit", + "date": { + "required": "Enter the date you applied for Universal Credit", + "missingOne": "The date you applied for Universal Credit must include a {{missingField}}", + "missingTwo": "The date you applied for Universal Credit must include a {{first}} and {{second}}", + "notRealDate": "The date you applied for Universal Credit must be a real date", + "futureDate": "The date you applied for Universal Credit must must either be today’s date or in the past" + } + } +} diff --git a/src/main/assets/locales/cy/respondToClaim/priorityDebtDetails.json b/src/main/assets/locales/cy/respondToClaim/priorityDebtDetails.json new file mode 100644 index 000000000..5ff8627ef --- /dev/null +++ b/src/main/assets/locales/cy/respondToClaim/priorityDebtDetails.json @@ -0,0 +1,24 @@ +{ + "pageTitle": "Priority debt details", + "caption": "Respond to a property possession claim", + "totalQuestion": "What is the total amount you owe for all your priority debts?", + "contributionQuestion": "How much do you pay towards your priority debts each week or month?", + "frequencyQuestion": "Paid every:", + "amountHint": "Enter total amount in pounds and pence, for example £148.00 or £148.50", + "frequency": { + "week": "Week", + "month": "Month" + }, + "errors": { + "priorityDebtTotal": "Enter the total amount you owe for all your priority debts", + "priorityDebtTotalMin": "The total amount you owe for all your priority debts must be £0.00 or above", + "priorityDebtTotalMax": "The total amount you owe for all your priority debts must be less than £1 billion", + "priorityDebtContribution": "Enter the amount you pay towards your priority debts each week or month", + "priorityDebtContributionMin": "The amount you pay towards your priority debts each week or month must be £0.00 or above", + "priorityDebtContributionMax": "The amount you pay towards your priority debts each week or month must be less than £1 billion", + "priorityDebtContributionFrequency": "Select how frequently you pay the amount you entered above", + "amount": { + "invalidFormat": "Enter an amount in the correct format, for example £148.00 or £148.50" + } + } +} diff --git a/src/main/assets/locales/cy/respondToClaim/priorityDebts.json b/src/main/assets/locales/cy/respondToClaim/priorityDebts.json new file mode 100644 index 000000000..3a1ed7c16 --- /dev/null +++ b/src/main/assets/locales/cy/respondToClaim/priorityDebts.json @@ -0,0 +1,12 @@ +{ + "pageTitle": "Priority debts", + "caption": "Respond to a property possession claim", + "question": "Do you have any priority debts?", + "options": { + "yes": "Yes", + "no": "No" + }, + "errors": { + "havePriorityDebts": "Select if you have any priority debts" + } +} diff --git a/src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json b/src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json new file mode 100644 index 000000000..ba195b262 --- /dev/null +++ b/src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json @@ -0,0 +1,14 @@ +{ + "paragraph1": "Priority debts are debts which could lead to serious consequences if you do not pay them.", + "paragraph2": "Excluding rent or mortgage arrears, priority debts are:", + "bullet1": "council tax arrears", + "bullet2": "gas or electricity arrears", + "bullet3": "phone or internet arrears", + "bullet4": "TV licence arrears", + "bullet5": "court fines", + "bullet6": "overpaid tax credits", + "bullet7": "payments for goods bought on hire purchase or conditional sale", + "bullet8": "unpaid income tax, National Insurance or VAT", + "bullet9": "unpaid child maintenance", + "guidanceLinkText": "Read guidance from Citizens Advice on what counts as a priority debt (opens in new tab)" +} From 73ab6be7a2aee9444826bd2b53068dca660d433a Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Mon, 30 Mar 2026 15:41:22 +0100 Subject: [PATCH 06/14] feat: implement Universal Credit application step --- .../universal-credit/index.ts | 114 +++++++++++++++- .../respond-to-claim/universal-credit.test.ts | 123 ++++++++++++++++++ 2 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 src/test/unit/steps/respond-to-claim/universal-credit.test.ts diff --git a/src/main/steps/respond-to-claim/universal-credit/index.ts b/src/main/steps/respond-to-claim/universal-credit/index.ts index 78f9a6dac..3872a7fcd 100644 --- a/src/main/steps/respond-to-claim/universal-credit/index.ts +++ b/src/main/steps/respond-to-claim/universal-credit/index.ts @@ -1,4 +1,8 @@ +import { DateTime } from 'luxon'; + +import type { PossessionClaimResponse } from '../../../interfaces/ccdCase.interface'; import type { StepDefinition } from '../../../interfaces/stepFormData.interface'; +import { buildCcdCaseForPossessionClaimResponse } from '../../utils/populateResponseToClaimPayloadmap'; import { flowConfig } from '../flow.config'; import { createFormStep } from '@modules/steps'; @@ -8,6 +12,114 @@ export const step: StepDefinition = createFormStep({ journeyFolder: 'respondToClaim', stepDir: __dirname, flowConfig, - fields: [], + beforeRedirect: async req => { + const selection = req.body?.haveAppliedForUniversalCredit as string | undefined; + const nestedDate = req.body?.ucApplicationDate as { day?: string; month?: string; year?: string } | undefined; + const ucApplicationDate = { + day: nestedDate?.day || (req.body?.['ucApplicationDate-day'] as string | undefined), + month: nestedDate?.month || (req.body?.['ucApplicationDate-month'] as string | undefined), + year: nestedDate?.year || (req.body?.['ucApplicationDate-year'] as string | undefined), + }; + + let universalCredit: 'YES' | 'NO' | undefined; + if (selection === 'yes') { + universalCredit = 'YES'; + } else if (selection === 'no') { + universalCredit = 'NO'; + } + + let isoDate: string | undefined; + if (selection === 'yes' && ucApplicationDate?.day && ucApplicationDate?.month && ucApplicationDate?.year) { + const dateTime = DateTime.fromObject({ + year: Number(ucApplicationDate.year), + month: Number(ucApplicationDate.month), + day: Number(ucApplicationDate.day), + }); + if (dateTime.isValid) { + isoDate = dateTime.toISODate() || undefined; + } + } + + if (!universalCredit) { + return; + } + + const possessionClaimResponse: PossessionClaimResponse = { + defendantResponses: { + householdCircumstances: { + universalCredit, + ucApplicationDate: isoDate, + }, + }, + }; + await buildCcdCaseForPossessionClaimResponse(req, possessionClaimResponse); + }, + getInitialFormData: req => { + const householdCircumstances = ( + req.res?.locals?.validatedCase?.data as + | { + possessionClaimResponse?: { + defendantResponses?: { + householdCircumstances?: { universalCredit?: string; ucApplicationDate?: string }; + }; + }; + } + | undefined + )?.possessionClaimResponse?.defendantResponses?.householdCircumstances; + + const data: Record = {}; + if (householdCircumstances?.universalCredit === 'YES') { + data.haveAppliedForUniversalCredit = 'yes'; + } else if (householdCircumstances?.universalCredit === 'NO') { + data.haveAppliedForUniversalCredit = 'no'; + } + + if (householdCircumstances?.ucApplicationDate) { + const parsed = DateTime.fromISO(householdCircumstances.ucApplicationDate); + if (parsed.isValid) { + data.ucApplicationDate = { + day: parsed.toFormat('dd'), + month: parsed.toFormat('MM'), + year: parsed.toFormat('yyyy'), + }; + } + } + return data; + }, + translationKeys: { + pageTitle: 'pageTitle', + caption: 'caption', + }, + fields: [ + { + name: 'haveAppliedForUniversalCredit', + type: 'radio', + required: true, + legendClasses: 'govuk-fieldset__legend--l', + translationKey: { label: 'question' }, + errorMessage: 'errors.haveAppliedForUniversalCredit', + options: [ + { + value: 'yes', + translationKey: 'options.yes', + subFields: { + ucApplicationDate: { + name: 'ucApplicationDate', + type: 'date', + required: true, + noFutureDate: true, + noCurrentDate: false, + translationKey: { + label: 'dateLabel', + hint: 'dateHint', + }, + legendClasses: 'govuk-fieldset__legend--s', + }, + }, + }, + { value: 'no', translationKey: 'options.no' }, + ], + }, + ], customTemplate: `${__dirname}/universalCredit.njk`, }); diff --git a/src/test/unit/steps/respond-to-claim/universal-credit.test.ts b/src/test/unit/steps/respond-to-claim/universal-credit.test.ts new file mode 100644 index 000000000..016ffb916 --- /dev/null +++ b/src/test/unit/steps/respond-to-claim/universal-credit.test.ts @@ -0,0 +1,123 @@ +import type { Environment } from 'nunjucks'; + +jest.mock('../../../../main/modules/steps/i18n', () => ({ + loadStepNamespace: jest.fn(), + getStepTranslations: jest.fn(() => ({})), + getTranslationFunction: jest.fn(() => (key: string) => key), +})); + +jest.mock('../../../../main/modules/i18n', () => ({ + getRequestLanguage: jest.fn(() => 'en'), + getCommonTranslations: jest.fn(() => ({})), +})); + +jest.mock('../../../../main/modules/steps/flow', () => ({ + stepNavigation: { + getBackUrl: jest.fn(async () => null), + getNextStepUrl: jest.fn(async () => '/next-step'), + }, + createStepNavigation: jest.fn(() => ({ + getBackUrl: jest.fn(async () => '/previous-step'), + getNextStepUrl: jest.fn(async () => '/next-step'), + })), +})); + +jest.mock('../../../../main/modules/steps/formBuilder/helpers', () => { + const actual = jest.requireActual('../../../../main/modules/steps/formBuilder/helpers'); + return { + ...actual, + validateForm: jest.fn(), + }; +}); + +const mockBuildCcdCaseForPossessionClaimResponse = jest.fn(); +jest.mock('../../../../main/steps/utils/populateResponseToClaimPayloadmap', () => ({ + buildCcdCaseForPossessionClaimResponse: mockBuildCcdCaseForPossessionClaimResponse, +})); + +import { validateForm } from '../../../../main/modules/steps/formBuilder/helpers'; +import { step } from '../../../../main/steps/respond-to-claim/universal-credit'; + +describe('respond-to-claim universal-credit step', () => { + const nunjucksEnv = { render: jest.fn() } as unknown as Environment; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const createReq = (overrides: Record = {}): any => ({ + body: {}, + originalUrl: '/case/1234567890123456/respond-to-claim/have-you-applied-for-universal-credit', + query: { lang: 'en' }, + params: { caseReference: '1234567890123456' }, + session: { + formData: {}, + ccdCase: { id: '1234567890123456' }, + }, + app: { locals: { nunjucksEnv } }, + i18n: { getResourceBundle: jest.fn(() => ({})) }, + res: { locals: { validatedCase: { id: '1234567890123456', data: {} } } }, + ...overrides, + }); + + beforeEach(() => { + jest.clearAllMocks(); + mockBuildCcdCaseForPossessionClaimResponse.mockResolvedValue({ id: '1234567890123456', data: {} }); + }); + + it('maps yes selection with application date', async () => { + (validateForm as jest.Mock).mockReturnValue({}); + const req = createReq({ + body: { + action: 'continue', + haveAppliedForUniversalCredit: 'yes', + 'ucApplicationDate-day': '10', + 'ucApplicationDate-month': '02', + 'ucApplicationDate-year': '2024', + }, + }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res = { redirect: jest.fn() } as any; + const next = jest.fn(); + + if (!step.postController) { + throw new Error('expected postController'); + } + + await step.postController.post(req, res, next); + + expect(mockBuildCcdCaseForPossessionClaimResponse).toHaveBeenCalledWith(expect.anything(), { + defendantResponses: { + householdCircumstances: { + universalCredit: 'YES', + ucApplicationDate: '2024-02-10', + }, + }, + }); + }); + + it('maps no selection without date', async () => { + (validateForm as jest.Mock).mockReturnValue({}); + const req = createReq({ + body: { + action: 'continue', + haveAppliedForUniversalCredit: 'no', + }, + }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res = { redirect: jest.fn() } as any; + const next = jest.fn(); + + if (!step.postController) { + throw new Error('expected postController'); + } + + await step.postController.post(req, res, next); + + expect(mockBuildCcdCaseForPossessionClaimResponse).toHaveBeenCalledWith(expect.anything(), { + defendantResponses: { + householdCircumstances: { + universalCredit: 'NO', + ucApplicationDate: undefined, + }, + }, + }); + }); +}); From b2b1b5f9246d8688d6aacee5b843ab07e678804a Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Mon, 30 Mar 2026 16:08:44 +0100 Subject: [PATCH 07/14] feat: refine Universal Credit step template --- .../universal-credit/universalCredit.njk | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/steps/respond-to-claim/universal-credit/universalCredit.njk b/src/main/steps/respond-to-claim/universal-credit/universalCredit.njk index f28dab5d0..7de43eb04 100644 --- a/src/main/steps/respond-to-claim/universal-credit/universalCredit.njk +++ b/src/main/steps/respond-to-claim/universal-credit/universalCredit.njk @@ -1,14 +1,23 @@ {% extends "stepsTemplate.njk" %} {% from "macros/stepButtons.njk" import stepButtons %} {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %} +{% from "govuk/components/radios/macro.njk" import govukRadios %} {% from "macros/csrf.njk" import csrfProtection %} +{% block pageTitle %} + {{ pageTitle }} - HM Courts & Tribunals Service – GOV.UK +{% endblock %} {% block mainContent %} {% if errorSummary %} {{ govukErrorSummary(errorSummary) }} {% endif %} -

Have you applied for Universal Credit? (placeholder)

-

This is a placeholder for Have You Applied For Universal Credit step.

-
+ {{ caption }} + + + {% for field in fields %} + {% if field.componentType == 'radios' %} + {{ govukRadios(field.component) }} + {% endif %} + {% endfor %} {{ stepButtons(continue, saveForLater) }} {{ csrfProtection(csrfToken) }}
From 265323bf85fa672d8aa11c96b74012721f20162a Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Tue, 31 Mar 2026 10:22:51 +0100 Subject: [PATCH 08/14] feat: add priority debts question step --- .../respond-to-claim/priority-debts/index.ts | 75 +++++++++++++++- .../priority-debts/priorityDebts.njk | 38 +++++++- .../respond-to-claim/priority-debts.test.ts | 86 +++++++++++++++++++ 3 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 src/test/unit/steps/respond-to-claim/priority-debts.test.ts diff --git a/src/main/steps/respond-to-claim/priority-debts/index.ts b/src/main/steps/respond-to-claim/priority-debts/index.ts index b925177a5..0ed2858b0 100644 --- a/src/main/steps/respond-to-claim/priority-debts/index.ts +++ b/src/main/steps/respond-to-claim/priority-debts/index.ts @@ -1,4 +1,6 @@ +import type { PossessionClaimResponse } from '../../../interfaces/ccdCase.interface'; import type { StepDefinition } from '../../../interfaces/stepFormData.interface'; +import { buildCcdCaseForPossessionClaimResponse } from '../../utils/populateResponseToClaimPayloadmap'; import { flowConfig } from '../flow.config'; import { createFormStep } from '@modules/steps'; @@ -8,6 +10,77 @@ export const step: StepDefinition = createFormStep({ journeyFolder: 'respondToClaim', stepDir: __dirname, flowConfig, - fields: [], + beforeRedirect: async req => { + const selection = req.body?.havePriorityDebts as string | undefined; + let priorityDebts: 'YES' | 'NO' | undefined; + if (selection === 'yes') { + priorityDebts = 'YES'; + } else if (selection === 'no') { + priorityDebts = 'NO'; + } + if (!priorityDebts) { + return; + } + + const possessionClaimResponse: PossessionClaimResponse = { + defendantResponses: { + householdCircumstances: { + priorityDebts, + }, + }, + }; + await buildCcdCaseForPossessionClaimResponse(req, possessionClaimResponse); + }, + getInitialFormData: req => { + const priorityDebts = ( + req.res?.locals?.validatedCase?.data as + | { + possessionClaimResponse?: { + defendantResponses?: { + householdCircumstances?: { priorityDebts?: string }; + }; + }; + } + | undefined + )?.possessionClaimResponse?.defendantResponses?.householdCircumstances?.priorityDebts; + + if (priorityDebts === 'YES') { + return { havePriorityDebts: 'yes' }; + } + if (priorityDebts === 'NO') { + return { havePriorityDebts: 'no' }; + } + return {}; + }, + translationKeys: { + pageTitle: 'pageTitle', + caption: 'caption', + paragraph1: 'paragraph1', + paragraph2: 'paragraph2', + bullet1: 'bullet1', + bullet2: 'bullet2', + bullet3: 'bullet3', + bullet4: 'bullet4', + bullet5: 'bullet5', + bullet6: 'bullet6', + bullet7: 'bullet7', + bullet8: 'bullet8', + bullet9: 'bullet9', + guidanceLinkText: 'guidanceLinkText', + }, + fields: [ + { + name: 'havePriorityDebts', + type: 'radio', + required: true, + legendClasses: 'govuk-fieldset__legend--l', + translationKey: { label: 'question' }, + errorMessage: 'errors.havePriorityDebts', + options: [ + { value: 'yes', translationKey: 'options.yes' }, + { value: 'no', translationKey: 'options.no' }, + ], + }, + ], customTemplate: `${__dirname}/priorityDebts.njk`, }); diff --git a/src/main/steps/respond-to-claim/priority-debts/priorityDebts.njk b/src/main/steps/respond-to-claim/priority-debts/priorityDebts.njk index dd2b9ed61..872bac92b 100644 --- a/src/main/steps/respond-to-claim/priority-debts/priorityDebts.njk +++ b/src/main/steps/respond-to-claim/priority-debts/priorityDebts.njk @@ -1,14 +1,46 @@ {% extends "stepsTemplate.njk" %} {% from "macros/stepButtons.njk" import stepButtons %} {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %} +{% from "govuk/components/radios/macro.njk" import govukRadios %} {% from "macros/csrf.njk" import csrfProtection %} +{% block pageTitle %} + {{ pageTitle }} - HM Courts & Tribunals Service – GOV.UK +{% endblock %} {% block mainContent %} {% if errorSummary %} {{ govukErrorSummary(errorSummary) }} {% endif %} -

Priority debts (placeholder)

-

This is a placeholder for Priority Debts step.

-
+ {{ caption }} +

{{ pageTitle }}

+

{{ paragraph1 }}

+

{{ paragraph2 }}

+
    +
  • {{ bullet1 }}
  • +
  • {{ bullet2 }}
  • +
  • {{ bullet3 }}
  • +
  • {{ bullet4 }}
  • +
  • {{ bullet5 }}
  • +
  • {{ bullet6 }}
  • +
  • {{ bullet7 }}
  • +
  • {{ bullet8 }}
  • +
  • {{ bullet9 }}
  • +
+

+ + {{ guidanceLinkText }} + . +

+ + {% for field in fields %} + {% if field.componentType == 'radios' %} + {{ govukRadios(field.component) }} + {% endif %} + {% endfor %} {{ stepButtons(continue, saveForLater) }} {{ csrfProtection(csrfToken) }}
diff --git a/src/test/unit/steps/respond-to-claim/priority-debts.test.ts b/src/test/unit/steps/respond-to-claim/priority-debts.test.ts new file mode 100644 index 000000000..96a8a1341 --- /dev/null +++ b/src/test/unit/steps/respond-to-claim/priority-debts.test.ts @@ -0,0 +1,86 @@ +import type { Environment } from 'nunjucks'; + +jest.mock('../../../../main/modules/steps/i18n', () => ({ + loadStepNamespace: jest.fn(), + getStepTranslations: jest.fn(() => ({})), + getTranslationFunction: jest.fn(() => (key: string) => key), +})); + +jest.mock('../../../../main/modules/i18n', () => ({ + getRequestLanguage: jest.fn(() => 'en'), + getCommonTranslations: jest.fn(() => ({})), +})); + +jest.mock('../../../../main/modules/steps/flow', () => ({ + stepNavigation: { + getBackUrl: jest.fn(async () => null), + getNextStepUrl: jest.fn(async () => '/next-step'), + }, + createStepNavigation: jest.fn(() => ({ + getBackUrl: jest.fn(async () => '/previous-step'), + getNextStepUrl: jest.fn(async () => '/next-step'), + })), +})); + +jest.mock('../../../../main/modules/steps/formBuilder/helpers', () => { + const actual = jest.requireActual('../../../../main/modules/steps/formBuilder/helpers'); + return { + ...actual, + validateForm: jest.fn(), + }; +}); + +const mockBuildCcdCaseForPossessionClaimResponse = jest.fn(); +jest.mock('../../../../main/steps/utils/populateResponseToClaimPayloadmap', () => ({ + buildCcdCaseForPossessionClaimResponse: mockBuildCcdCaseForPossessionClaimResponse, +})); + +import { validateForm } from '../../../../main/modules/steps/formBuilder/helpers'; +import { step } from '../../../../main/steps/respond-to-claim/priority-debts'; + +describe('respond-to-claim priority-debts step', () => { + const nunjucksEnv = { render: jest.fn() } as unknown as Environment; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const createReq = (overrides: Record = {}): any => ({ + body: {}, + originalUrl: '/case/1234567890123456/respond-to-claim/priority-debts', + query: { lang: 'en' }, + params: { caseReference: '1234567890123456' }, + session: { + formData: {}, + ccdCase: { id: '1234567890123456' }, + }, + app: { locals: { nunjucksEnv } }, + i18n: { getResourceBundle: jest.fn(() => ({})) }, + res: { locals: { validatedCase: { id: '1234567890123456', data: {} } } }, + ...overrides, + }); + + beforeEach(() => { + jest.clearAllMocks(); + mockBuildCcdCaseForPossessionClaimResponse.mockResolvedValue({ id: '1234567890123456', data: {} }); + }); + + it('maps yes selection', async () => { + (validateForm as jest.Mock).mockReturnValue({}); + const req = createReq({ body: { action: 'continue', havePriorityDebts: 'yes' } }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res = { redirect: jest.fn() } as any; + const next = jest.fn(); + + if (!step.postController) { + throw new Error('expected postController'); + } + + await step.postController.post(req, res, next); + + expect(mockBuildCcdCaseForPossessionClaimResponse).toHaveBeenCalledWith(expect.anything(), { + defendantResponses: { + householdCircumstances: { + priorityDebts: 'YES', + }, + }, + }); + }); +}); From b687f75f92de57c8929a72635ec5c60d2e53fa1c Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Tue, 31 Mar 2026 14:55:03 +0100 Subject: [PATCH 09/14] feat: add priority debt amounts and payment frequency --- src/main/assets/scss/main.scss | 10 ++ .../priority-debt-details/index.ts | 143 +++++++++++++++++- .../priorityDebtDetails.njk | 18 ++- .../priority-debt-details.test.ts | 95 ++++++++++++ 4 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 src/test/unit/steps/respond-to-claim/priority-debt-details.test.ts diff --git a/src/main/assets/scss/main.scss b/src/main/assets/scss/main.scss index eec9718bf..72920495a 100644 --- a/src/main/assets/scss/main.scss +++ b/src/main/assets/scss/main.scss @@ -28,6 +28,16 @@ font-weight: 300; } +// Priority debt details: "Paid every:" week/month radios (15px gap; GOV.UK default is 10px) +.priority-debt-details-paid-every-radios .govuk-radios__item { + margin-bottom: govuk-spacing(3); +} + +.priority-debt-details-paid-every-radios .govuk-radios__item:last-child, +.priority-debt-details-paid-every-radios .govuk-radios__item:last-of-type { + margin-bottom: 0; +} + .correspondence-address-form { .pcs-address-component { .govuk-details__text { diff --git a/src/main/steps/respond-to-claim/priority-debt-details/index.ts b/src/main/steps/respond-to-claim/priority-debt-details/index.ts index 75680acf8..e5130d6a4 100644 --- a/src/main/steps/respond-to-claim/priority-debt-details/index.ts +++ b/src/main/steps/respond-to-claim/priority-debt-details/index.ts @@ -1,13 +1,154 @@ +import type { PossessionClaimResponse } from '../../../interfaces/ccdCase.interface'; import type { StepDefinition } from '../../../interfaces/stepFormData.interface'; +import { ccdPenceToPoundsString, poundsStringToPence } from '../../utils'; +import { buildCcdCaseForPossessionClaimResponse } from '../../utils/populateResponseToClaimPayloadmap'; import { flowConfig } from '../flow.config'; import { createFormStep } from '@modules/steps'; +const MAX_AMOUNT = 1_000_000_000; +const AMOUNT_REGEX = /^\d+(\.\d{1,2})?$/; + +const validateMoney = + (negativeKey: string, largeKey: string) => + (value: unknown): boolean | string => { + if (typeof value !== 'string' || !value.trim()) { + return true; + } + const normalized = value.trim().split(',').join(''); + if (!AMOUNT_REGEX.test(normalized)) { + return 'errors.amount.invalidFormat'; + } + const parsed = Number(normalized); + if (Number.isNaN(parsed)) { + return 'errors.amount.invalidFormat'; + } + if (parsed < 0) { + return negativeKey; + } + if (parsed >= MAX_AMOUNT) { + return largeKey; + } + return true; + }; + export const step: StepDefinition = createFormStep({ stepName: 'priority-debt-details', journeyFolder: 'respondToClaim', stepDir: __dirname, flowConfig, - fields: [], + beforeRedirect: async req => { + const total = req.body?.priorityDebtTotal as string | undefined; + const contribution = req.body?.priorityDebtContribution as string | undefined; + const frequency = req.body?.priorityDebtContributionFrequency as string | undefined; + + const householdCircumstances: Record = {}; + + if (typeof total === 'string' && total.trim()) { + const pence = poundsStringToPence(total); + if (pence !== undefined) { + householdCircumstances.debtTotal = String(pence); + } + } + if (typeof contribution === 'string' && contribution.trim()) { + const pence = poundsStringToPence(contribution); + if (pence !== undefined) { + householdCircumstances.debtContribution = String(pence); + } + } + if (typeof frequency === 'string' && frequency.trim()) { + householdCircumstances.debtContributionFrequency = frequency.toUpperCase(); + } + + if (Object.keys(householdCircumstances).length === 0) { + return; + } + + const possessionClaimResponse: PossessionClaimResponse = { + defendantResponses: { + householdCircumstances, + }, + }; + await buildCcdCaseForPossessionClaimResponse(req, possessionClaimResponse); + }, + getInitialFormData: req => { + const householdCircumstances = ( + req.res?.locals?.validatedCase?.data as + | { + possessionClaimResponse?: { + defendantResponses?: { + householdCircumstances?: { + debtTotal?: unknown; + debtContribution?: unknown; + debtContributionFrequency?: string; + }; + }; + }; + } + | undefined + )?.possessionClaimResponse?.defendantResponses?.householdCircumstances; + + const priorityDebtTotal = ccdPenceToPoundsString(householdCircumstances?.debtTotal); + const priorityDebtContribution = ccdPenceToPoundsString(householdCircumstances?.debtContribution); + const priorityDebtContributionFrequency = householdCircumstances?.debtContributionFrequency?.toLowerCase(); + + return { + ...(priorityDebtTotal ? { priorityDebtTotal } : {}), + ...(priorityDebtContribution ? { priorityDebtContribution } : {}), + ...(priorityDebtContributionFrequency ? { priorityDebtContributionFrequency } : {}), + }; + }, + translationKeys: { + pageTitle: 'pageTitle', + caption: 'caption', + }, + fields: [ + { + name: 'priorityDebtTotal', + type: 'text', + required: true, + translationKey: { + label: 'totalQuestion', + hint: 'amountHint', + }, + labelClasses: 'govuk-label--s', + formGroupClasses: 'govuk-!-margin-bottom-2', + hintClasses: 'govuk-!-margin-bottom-1', + errorMessage: 'errors.priorityDebtTotal', + prefix: { text: '£' }, + classes: 'govuk-input--width-10', + attributes: { inputmode: 'decimal' }, + validator: validateMoney('errors.priorityDebtTotalMin', 'errors.priorityDebtTotalMax'), + }, + { + name: 'priorityDebtContribution', + type: 'text', + required: true, + translationKey: { + label: 'contributionQuestion', + hint: 'amountHint', + }, + labelClasses: 'govuk-label--s', + formGroupClasses: 'govuk-!-margin-bottom-2', + hintClasses: 'govuk-!-margin-bottom-1', + errorMessage: 'errors.priorityDebtContribution', + prefix: { text: '£' }, + classes: 'govuk-input--width-10', + attributes: { inputmode: 'decimal' }, + validator: validateMoney('errors.priorityDebtContributionMin', 'errors.priorityDebtContributionMax'), + }, + { + name: 'priorityDebtContributionFrequency', + type: 'radio', + required: true, + classes: 'priority-debt-details-paid-every-radios', + translationKey: { label: 'frequencyQuestion' }, + errorMessage: 'errors.priorityDebtContributionFrequency', + options: [ + { value: 'week', translationKey: 'frequency.week' }, + { value: 'month', translationKey: 'frequency.month' }, + ], + }, + ], customTemplate: `${__dirname}/priorityDebtDetails.njk`, }); diff --git a/src/main/steps/respond-to-claim/priority-debt-details/priorityDebtDetails.njk b/src/main/steps/respond-to-claim/priority-debt-details/priorityDebtDetails.njk index b3be7884a..3ebfd1f2a 100644 --- a/src/main/steps/respond-to-claim/priority-debt-details/priorityDebtDetails.njk +++ b/src/main/steps/respond-to-claim/priority-debt-details/priorityDebtDetails.njk @@ -1,14 +1,26 @@ {% extends "stepsTemplate.njk" %} {% from "macros/stepButtons.njk" import stepButtons %} {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %} +{% from "govuk/components/input/macro.njk" import govukInput %} +{% from "govuk/components/radios/macro.njk" import govukRadios %} {% from "macros/csrf.njk" import csrfProtection %} +{% block pageTitle %} + {{ pageTitle }} - HM Courts & Tribunals Service – GOV.UK +{% endblock %} {% block mainContent %} {% if errorSummary %} {{ govukErrorSummary(errorSummary) }} {% endif %} -

Priority debt details (placeholder)

-

This is a placeholder for Priority Debt Details step.

-
+ {{ caption }} +

{{ pageTitle }}

+ + {% for field in fields %} + {% if field.componentType == 'input' %} + {{ govukInput(field.component) }} + {% elif field.componentType == 'radios' %} + {{ govukRadios(field.component) }} + {% endif %} + {% endfor %} {{ stepButtons(continue, saveForLater) }} {{ csrfProtection(csrfToken) }}
diff --git a/src/test/unit/steps/respond-to-claim/priority-debt-details.test.ts b/src/test/unit/steps/respond-to-claim/priority-debt-details.test.ts new file mode 100644 index 000000000..884c734c3 --- /dev/null +++ b/src/test/unit/steps/respond-to-claim/priority-debt-details.test.ts @@ -0,0 +1,95 @@ +import type { Environment } from 'nunjucks'; + +jest.mock('../../../../main/modules/steps/i18n', () => ({ + loadStepNamespace: jest.fn(), + getStepTranslations: jest.fn(() => ({})), + getTranslationFunction: jest.fn(() => (key: string) => key), +})); + +jest.mock('../../../../main/modules/i18n', () => ({ + getRequestLanguage: jest.fn(() => 'en'), + getCommonTranslations: jest.fn(() => ({})), +})); + +jest.mock('../../../../main/modules/steps/flow', () => ({ + stepNavigation: { + getBackUrl: jest.fn(async () => null), + getNextStepUrl: jest.fn(async () => '/next-step'), + }, + createStepNavigation: jest.fn(() => ({ + getBackUrl: jest.fn(async () => '/previous-step'), + getNextStepUrl: jest.fn(async () => '/next-step'), + })), +})); + +jest.mock('../../../../main/modules/steps/formBuilder/helpers', () => { + const actual = jest.requireActual('../../../../main/modules/steps/formBuilder/helpers'); + return { + ...actual, + validateForm: jest.fn(), + }; +}); + +const mockBuildCcdCaseForPossessionClaimResponse = jest.fn(); +jest.mock('../../../../main/steps/utils/populateResponseToClaimPayloadmap', () => ({ + buildCcdCaseForPossessionClaimResponse: mockBuildCcdCaseForPossessionClaimResponse, +})); + +import { validateForm } from '../../../../main/modules/steps/formBuilder/helpers'; +import { step } from '../../../../main/steps/respond-to-claim/priority-debt-details'; + +describe('respond-to-claim priority-debt-details step', () => { + const nunjucksEnv = { render: jest.fn() } as unknown as Environment; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const createReq = (overrides: Record = {}): any => ({ + body: {}, + originalUrl: '/case/1234567890123456/respond-to-claim/priority-debt-details', + query: { lang: 'en' }, + params: { caseReference: '1234567890123456' }, + session: { + formData: {}, + ccdCase: { id: '1234567890123456' }, + }, + app: { locals: { nunjucksEnv } }, + i18n: { getResourceBundle: jest.fn(() => ({})) }, + res: { locals: { validatedCase: { id: '1234567890123456', data: {} } } }, + ...overrides, + }); + + beforeEach(() => { + jest.clearAllMocks(); + mockBuildCcdCaseForPossessionClaimResponse.mockResolvedValue({ id: '1234567890123456', data: {} }); + }); + + it('maps amounts to pence and normalizes frequency', async () => { + (validateForm as jest.Mock).mockReturnValue({}); + const req = createReq({ + body: { + action: 'continue', + priorityDebtTotal: '148.50', + priorityDebtContribution: '20.00', + priorityDebtContributionFrequency: 'week', + }, + }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res = { redirect: jest.fn() } as any; + const next = jest.fn(); + + if (!step.postController) { + throw new Error('expected postController'); + } + + await step.postController.post(req, res, next); + + expect(mockBuildCcdCaseForPossessionClaimResponse).toHaveBeenCalledWith(expect.anything(), { + defendantResponses: { + householdCircumstances: { + debtTotal: '14850', + debtContribution: '2000', + debtContributionFrequency: 'WEEK', + }, + }, + }); + }); +}); From f946fc5ccb5849c1b4e397211d92a6afd2372792 Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Thu, 2 Apr 2026 08:49:27 +0100 Subject: [PATCH 10/14] feat: add UC selection and expenses back-link journey helpers --- .../utils/getPreviousStepForWhatOtherRegularExpenses.ts | 8 ++++++++ src/main/steps/utils/hasSelectedUniversalCredit.ts | 9 +++++++++ src/main/steps/utils/index.ts | 8 +++++++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/main/steps/utils/getPreviousStepForWhatOtherRegularExpenses.ts create mode 100644 src/main/steps/utils/hasSelectedUniversalCredit.ts diff --git a/src/main/steps/utils/getPreviousStepForWhatOtherRegularExpenses.ts b/src/main/steps/utils/getPreviousStepForWhatOtherRegularExpenses.ts new file mode 100644 index 000000000..c520f06c3 --- /dev/null +++ b/src/main/steps/utils/getPreviousStepForWhatOtherRegularExpenses.ts @@ -0,0 +1,8 @@ +import type { Request } from 'express'; + +export const getPreviousStepForWhatOtherRegularExpenses = async (req: Request): Promise => { + const caseData = req.res?.locals?.validatedCase?.data; + const priorityDebts = caseData?.possessionClaimResponse?.defendantResponses?.householdCircumstances?.priorityDebts; + + return priorityDebts === 'YES' ? 'priority-debt-details' : 'priority-debts'; +}; diff --git a/src/main/steps/utils/hasSelectedUniversalCredit.ts b/src/main/steps/utils/hasSelectedUniversalCredit.ts new file mode 100644 index 000000000..e98ca0fa1 --- /dev/null +++ b/src/main/steps/utils/hasSelectedUniversalCredit.ts @@ -0,0 +1,9 @@ +import type { Request } from 'express'; + +export const hasSelectedUniversalCredit = async (req: Request): Promise => { + const caseData = req.res?.locals?.validatedCase?.data; + const universalCredit = + caseData?.possessionClaimResponse?.defendantResponses?.householdCircumstances?.universalCredit; + + return universalCredit === 'YES'; +}; diff --git a/src/main/steps/utils/index.ts b/src/main/steps/utils/index.ts index 514af4655..ca2e55a77 100644 --- a/src/main/steps/utils/index.ts +++ b/src/main/steps/utils/index.ts @@ -11,5 +11,11 @@ export { getStepBeforeDisputePages } from './journeyHelpers'; export { formatDatePartsToISODate } from './dateUtils'; export { normalizeYesNoValue } from './normalizeYesNoValue'; export { getPreviousStepForYourHouseholdAndCircumstances } from './getPreviousStepForYourHouseholdAndCircumstances'; -export { poundsStringToPence, additionalRentContributionToPoundsString } from './moneyAmountTransforms'; +export { getPreviousStepForWhatOtherRegularExpenses } from './getPreviousStepForWhatOtherRegularExpenses'; +export { hasSelectedUniversalCredit } from './hasSelectedUniversalCredit'; +export { + poundsStringToPence, + ccdPenceToPoundsString, + additionalRentContributionToPoundsString, +} from './moneyAmountTransforms'; export { toYesNoEnum, fromYesNoEnum } from './yesNoEnum'; From 8b7ae35ba58a5e376d4d25a1393cc5a2d7f36ab4 Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Thu, 2 Apr 2026 09:24:17 +0100 Subject: [PATCH 11/14] feat: extend regular income options for UC routing --- .../respond-to-claim/regular-income/index.ts | 47 +++++++ .../regular-income/regularIncome.njk | 24 +++- .../respond-to-claim/regular-income.test.ts | 117 ++++++++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/test/unit/steps/respond-to-claim/regular-income.test.ts diff --git a/src/main/steps/respond-to-claim/regular-income/index.ts b/src/main/steps/respond-to-claim/regular-income/index.ts index f0a5879cf..dd519dcb0 100644 --- a/src/main/steps/respond-to-claim/regular-income/index.ts +++ b/src/main/steps/respond-to-claim/regular-income/index.ts @@ -1,13 +1,60 @@ +import type { Request } from 'express'; + +import type { PossessionClaimResponse, YesNoValue } from '../../../interfaces/ccdCase.interface'; import type { StepDefinition } from '../../../interfaces/stepFormData.interface'; +import { buildCcdCaseForPossessionClaimResponse } from '../../utils/populateResponseToClaimPayloadmap'; import { flowConfig } from '../flow.config'; import { createFormStep } from '@modules/steps'; +function includesUniversalCreditSelection(value: unknown): boolean { + if (Array.isArray(value)) { + return value.includes('universalCredit'); + } + return value === 'universalCredit'; +} + +function toYesNoValue(selected: boolean): YesNoValue { + return selected ? 'YES' : 'NO'; +} + export const step: StepDefinition = createFormStep({ stepName: 'what-regular-income-do-you-receive', journeyFolder: 'respondToClaim', stepDir: __dirname, flowConfig, + beforeRedirect: async (req: Request) => { + const universalCreditSelected = includesUniversalCreditSelection(req.body?.regularIncome); + + const possessionClaimResponse: PossessionClaimResponse = { + defendantResponses: { + householdCircumstances: { + universalCredit: toYesNoValue(universalCreditSelected), + }, + }, + }; + + await buildCcdCaseForPossessionClaimResponse(req, possessionClaimResponse); + }, + getInitialFormData: req => { + const householdCircumstances = ( + req.res?.locals?.validatedCase?.data as + | { + possessionClaimResponse?: { + defendantResponses?: { + householdCircumstances?: { universalCredit?: YesNoValue }; + }; + }; + } + | undefined + )?.possessionClaimResponse?.defendantResponses?.householdCircumstances; + + if (householdCircumstances?.universalCredit === 'YES') { + return { regularIncome: ['universalCredit'] }; + } + + return {}; + }, fields: [], customTemplate: `${__dirname}/regularIncome.njk`, }); diff --git a/src/main/steps/respond-to-claim/regular-income/regularIncome.njk b/src/main/steps/respond-to-claim/regular-income/regularIncome.njk index 70473eab5..4564b049a 100644 --- a/src/main/steps/respond-to-claim/regular-income/regularIncome.njk +++ b/src/main/steps/respond-to-claim/regular-income/regularIncome.njk @@ -6,9 +6,31 @@ {% if errorSummary %} {{ govukErrorSummary(errorSummary) }} {% endif %} + Respond to a property possession claim

What regular income do you receive? (placeholder)

-

This is a placeholder for What Regular Income Do You Receive step.

+

Select all that apply.

+ {% set selectedRegularIncome = (formData and formData.regularIncome) or [] %} +
+
+ Regular income options +
+
+ + +
+
+
+
{{ stepButtons(continue, saveForLater) }} {{ csrfProtection(csrfToken) }}
diff --git a/src/test/unit/steps/respond-to-claim/regular-income.test.ts b/src/test/unit/steps/respond-to-claim/regular-income.test.ts new file mode 100644 index 000000000..4a1d2c7bd --- /dev/null +++ b/src/test/unit/steps/respond-to-claim/regular-income.test.ts @@ -0,0 +1,117 @@ +import type { Environment } from 'nunjucks'; + +jest.mock('../../../../main/modules/steps/i18n', () => ({ + loadStepNamespace: jest.fn(), + getStepTranslations: jest.fn(() => ({})), + getTranslationFunction: jest.fn(() => (key: string) => key), +})); + +jest.mock('../../../../main/modules/i18n', () => ({ + getRequestLanguage: jest.fn(() => 'en'), + getCommonTranslations: jest.fn(() => ({})), +})); + +jest.mock('../../../../main/modules/steps/flow', () => ({ + stepNavigation: { + getBackUrl: jest.fn(async () => null), + getNextStepUrl: jest.fn(async () => '/next-step'), + }, + createStepNavigation: jest.fn(() => ({ + getBackUrl: jest.fn(async () => '/previous-step'), + getNextStepUrl: jest.fn(async () => '/next-step'), + })), +})); + +jest.mock('../../../../main/modules/steps/formBuilder/helpers', () => { + const actual = jest.requireActual('../../../../main/modules/steps/formBuilder/helpers'); + return { + ...actual, + validateForm: jest.fn(), + }; +}); + +const mockBuildCcdCaseForPossessionClaimResponse = jest.fn(); +jest.mock('../../../../main/steps/utils/populateResponseToClaimPayloadmap', () => ({ + buildCcdCaseForPossessionClaimResponse: mockBuildCcdCaseForPossessionClaimResponse, +})); + +import { validateForm } from '../../../../main/modules/steps/formBuilder/helpers'; +import { step } from '../../../../main/steps/respond-to-claim/regular-income'; + +describe('respond-to-claim regular-income step', () => { + const nunjucksEnv = { render: jest.fn() } as unknown as Environment; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const createReq = (overrides: Record = {}): any => ({ + body: {}, + originalUrl: '/case/1234567890123456/respond-to-claim/what-regular-income-do-you-receive', + query: { lang: 'en' }, + params: { caseReference: '1234567890123456' }, + session: { + formData: {}, + ccdCase: { id: '1234567890123456' }, + }, + app: { locals: { nunjucksEnv } }, + i18n: { getResourceBundle: jest.fn(() => ({})) }, + res: { locals: { validatedCase: { id: '1234567890123456', data: {} } } }, + ...overrides, + }); + + beforeEach(() => { + jest.clearAllMocks(); + mockBuildCcdCaseForPossessionClaimResponse.mockResolvedValue({ id: '1234567890123456', data: {} }); + }); + + it('POST maps universal credit selection to YES', async () => { + (validateForm as jest.Mock).mockReturnValue({}); + const req = createReq({ + body: { + action: 'continue', + regularIncome: 'universalCredit', + }, + }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res = { redirect: jest.fn() } as any; + const next = jest.fn(); + + if (!step.postController) { + throw new Error('expected postController'); + } + + await step.postController.post(req, res, next); + + expect(mockBuildCcdCaseForPossessionClaimResponse).toHaveBeenCalledWith(expect.anything(), { + defendantResponses: { + householdCircumstances: { + universalCredit: 'YES', + }, + }, + }); + }); + + it('POST maps absent universal credit selection to NO', async () => { + (validateForm as jest.Mock).mockReturnValue({}); + const req = createReq({ + body: { + action: 'continue', + }, + }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const res = { redirect: jest.fn() } as any; + const next = jest.fn(); + + if (!step.postController) { + throw new Error('expected postController'); + } + + await step.postController.post(req, res, next); + + expect(mockBuildCcdCaseForPossessionClaimResponse).toHaveBeenCalledWith(expect.anything(), { + defendantResponses: { + householdCircumstances: { + universalCredit: 'NO', + }, + }, + }); + }); +}); From 64615dff183d01e33bd2409f40e06791c1b8084f Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Thu, 2 Apr 2026 11:48:33 +0100 Subject: [PATCH 12/14] feat: wire UC, priority debts and expenses in respond-to-claim flow --- .../steps/respond-to-claim/flow.config.ts | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/src/main/steps/respond-to-claim/flow.config.ts b/src/main/steps/respond-to-claim/flow.config.ts index bceeb6a04..c7393b1b5 100644 --- a/src/main/steps/respond-to-claim/flow.config.ts +++ b/src/main/steps/respond-to-claim/flow.config.ts @@ -2,10 +2,12 @@ import { type Request } from 'express'; import type { JourneyFlowConfig } from '../../interfaces/stepFlow.interface'; import { + getPreviousStepForWhatOtherRegularExpenses, getPreviousStepForYourHouseholdAndCircumstances, getStepBeforeDisputePages, hasAnyRentArrearsGround, hasOnlyRentArrearsGrounds, + hasSelectedUniversalCredit, isDefendantNameKnown, isNoticeDateProvided, isNoticeServed, @@ -419,6 +421,36 @@ export const flowConfig: JourneyFlowConfig = { }, 'what-regular-income-do-you-receive': { previousStep: 'income-and-expenditure', + routes: [ + { + condition: async ( + _req: Request, + _formData: Record, + currentStepData: Record + ): Promise => { + const selected = currentStepData.regularIncome; + if (Array.isArray(selected)) { + return selected.includes('universalCredit'); + } + return selected === 'universalCredit'; + }, + nextStep: 'priority-debts', + }, + { + condition: async ( + _req: Request, + _formData: Record, + currentStepData: Record + ): Promise => { + const selected = currentStepData.regularIncome; + if (Array.isArray(selected)) { + return !selected.includes('universalCredit'); + } + return selected !== 'universalCredit'; + }, + nextStep: 'have-you-applied-for-universal-credit', + }, + ], defaultNext: 'have-you-applied-for-universal-credit', }, 'have-you-applied-for-universal-credit': { @@ -426,15 +458,36 @@ export const flowConfig: JourneyFlowConfig = { defaultNext: 'priority-debts', }, 'priority-debts': { - previousStep: 'have-you-applied-for-universal-credit', - defaultNext: 'priority-debt-details', + previousStep: async (req: Request): Promise => { + const selectedUniversalCredit = await hasSelectedUniversalCredit(req); + return selectedUniversalCredit ? 'what-regular-income-do-you-receive' : 'have-you-applied-for-universal-credit'; + }, + routes: [ + { + condition: async ( + _req: Request, + _formData: Record, + currentStepData: Record + ): Promise => currentStepData.havePriorityDebts === 'yes', + nextStep: 'priority-debt-details', + }, + { + condition: async ( + _req: Request, + _formData: Record, + currentStepData: Record + ): Promise => currentStepData.havePriorityDebts === 'no', + nextStep: 'what-other-regular-expenses-do-you-have', + }, + ], + defaultNext: 'what-other-regular-expenses-do-you-have', }, 'priority-debt-details': { previousStep: 'priority-debts', defaultNext: 'what-other-regular-expenses-do-you-have', }, 'what-other-regular-expenses-do-you-have': { - previousStep: 'priority-debt-details', + previousStep: getPreviousStepForWhatOtherRegularExpenses, defaultNext: 'end-now', }, }, From 1782346158f8022254e90d46305ad96698f8b4bd Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Thu, 2 Apr 2026 14:22:41 +0100 Subject: [PATCH 13/14] test: add flow routing coverage for income and debts --- .../priority-debts-flow-routing.test.ts | 96 +++++++++++++++++++ .../regular-income-flow-routing.test.ts | 58 +++++++++++ ...ther-regular-expenses-flow-routing.test.ts | 87 +++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 src/test/unit/steps/respond-to-claim/priority-debts-flow-routing.test.ts create mode 100644 src/test/unit/steps/respond-to-claim/regular-income-flow-routing.test.ts create mode 100644 src/test/unit/steps/respond-to-claim/what-other-regular-expenses-flow-routing.test.ts diff --git a/src/test/unit/steps/respond-to-claim/priority-debts-flow-routing.test.ts b/src/test/unit/steps/respond-to-claim/priority-debts-flow-routing.test.ts new file mode 100644 index 000000000..f17bef4a4 --- /dev/null +++ b/src/test/unit/steps/respond-to-claim/priority-debts-flow-routing.test.ts @@ -0,0 +1,96 @@ +import { flowConfig } from '../../../../main/steps/respond-to-claim/flow.config'; + +describe('respond-to-claim priority-debts flow routing', () => { + const previousStep = flowConfig.steps['priority-debts'].previousStep; + const routes = flowConfig.steps['priority-debts'].routes || []; + const yesRouteCondition = routes[0]?.condition; + const noRouteCondition = routes[1]?.condition; + + it('routes to priority-debt-details when yes selected', async () => { + if (!yesRouteCondition) { + throw new Error('expected yes route condition'); + } + + const result = await yesRouteCondition( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + {} as any, + {}, + { havePriorityDebts: 'yes' } + ); + + expect(result).toBe(true); + expect(routes[0]?.nextStep).toBe('priority-debt-details'); + }); + + it('routes to regular-expenses when no selected', async () => { + if (!noRouteCondition) { + throw new Error('expected no route condition'); + } + + const result = await noRouteCondition( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + {} as any, + {}, + { havePriorityDebts: 'no' } + ); + + expect(result).toBe(true); + expect(routes[1]?.nextStep).toBe('what-other-regular-expenses-do-you-have'); + }); + + it('uses regular-income as previous step when universal credit selected', async () => { + if (!previousStep || typeof previousStep === 'string') { + throw new Error('expected previousStep function'); + } + + const req = { + res: { + locals: { + validatedCase: { + data: { + possessionClaimResponse: { + defendantResponses: { + householdCircumstances: { + universalCredit: 'YES', + }, + }, + }, + }, + }, + }, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + + const result = await previousStep(req, {}); + expect(result).toBe('what-regular-income-do-you-receive'); + }); + + it('uses have-you-applied-for-universal-credit as previous step when universal credit not selected', async () => { + if (!previousStep || typeof previousStep === 'string') { + throw new Error('expected previousStep function'); + } + + const req = { + res: { + locals: { + validatedCase: { + data: { + possessionClaimResponse: { + defendantResponses: { + householdCircumstances: { + universalCredit: 'NO', + }, + }, + }, + }, + }, + }, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + + const result = await previousStep(req, {}); + expect(result).toBe('have-you-applied-for-universal-credit'); + }); +}); diff --git a/src/test/unit/steps/respond-to-claim/regular-income-flow-routing.test.ts b/src/test/unit/steps/respond-to-claim/regular-income-flow-routing.test.ts new file mode 100644 index 000000000..c72b9204e --- /dev/null +++ b/src/test/unit/steps/respond-to-claim/regular-income-flow-routing.test.ts @@ -0,0 +1,58 @@ +import { flowConfig } from '../../../../main/steps/respond-to-claim/flow.config'; + +describe('respond-to-claim regular-income flow routing', () => { + const routes = flowConfig.steps['what-regular-income-do-you-receive'].routes || []; + const universalCreditRouteCondition = routes[0]?.condition; + const noUniversalCreditRouteCondition = routes[1]?.condition; + + it('routes to priority-debts when universal credit is selected', async () => { + if (!universalCreditRouteCondition) { + throw new Error('expected universal credit route condition'); + } + const result = await universalCreditRouteCondition( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + {} as any, + {}, + { regularIncome: ['incomeFromJobs', 'universalCredit'] } + ); + + expect(result).toBe(true); + expect(routes[0]?.nextStep).toBe('priority-debts'); + }); + + it('routes to universal-credit step when universal credit is not selected', async () => { + if (!noUniversalCreditRouteCondition) { + throw new Error('expected non-universal-credit route condition'); + } + const result = await noUniversalCreditRouteCondition( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + {} as any, + {}, + { regularIncome: ['incomeFromJobs'] } + ); + + expect(result).toBe(true); + expect(routes[1]?.nextStep).toBe('have-you-applied-for-universal-credit'); + }); + + it('handles single-string checkbox payload values', async () => { + if (!universalCreditRouteCondition || !noUniversalCreditRouteCondition) { + throw new Error('expected regular-income route conditions'); + } + const yesResult = await universalCreditRouteCondition( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + {} as any, + {}, + { regularIncome: 'universalCredit' } + ); + const noResult = await noUniversalCreditRouteCondition( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + {} as any, + {}, + { regularIncome: 'incomeFromJobs' } + ); + + expect(yesResult).toBe(true); + expect(noResult).toBe(true); + }); +}); diff --git a/src/test/unit/steps/respond-to-claim/what-other-regular-expenses-flow-routing.test.ts b/src/test/unit/steps/respond-to-claim/what-other-regular-expenses-flow-routing.test.ts new file mode 100644 index 000000000..060292715 --- /dev/null +++ b/src/test/unit/steps/respond-to-claim/what-other-regular-expenses-flow-routing.test.ts @@ -0,0 +1,87 @@ +import { flowConfig } from '../../../../main/steps/respond-to-claim/flow.config'; + +describe('respond-to-claim what-other-regular-expenses-do-you-have back navigation', () => { + const previousStep = flowConfig.steps['what-other-regular-expenses-do-you-have'].previousStep; + + it('returns priority-debt-details when priority debts answer was yes', async () => { + if (!previousStep || typeof previousStep === 'string') { + throw new Error('expected previousStep function'); + } + + const req = { + res: { + locals: { + validatedCase: { + data: { + possessionClaimResponse: { + defendantResponses: { + householdCircumstances: { + priorityDebts: 'YES', + }, + }, + }, + }, + }, + }, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + + const result = await previousStep(req, {}); + expect(result).toBe('priority-debt-details'); + }); + + it('returns priority-debts when priority debts answer was no', async () => { + if (!previousStep || typeof previousStep === 'string') { + throw new Error('expected previousStep function'); + } + + const req = { + res: { + locals: { + validatedCase: { + data: { + possessionClaimResponse: { + defendantResponses: { + householdCircumstances: { + priorityDebts: 'NO', + }, + }, + }, + }, + }, + }, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + + const result = await previousStep(req, {}); + expect(result).toBe('priority-debts'); + }); + + it('returns priority-debts when priority debts is not set', async () => { + if (!previousStep || typeof previousStep === 'string') { + throw new Error('expected previousStep function'); + } + + const req = { + res: { + locals: { + validatedCase: { + data: { + possessionClaimResponse: { + defendantResponses: { + householdCircumstances: {}, + }, + }, + }, + }, + }, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + + const result = await previousStep(req, {}); + expect(result).toBe('priority-debts'); + }); +}); From 9360ee7d60cee1d34522caf95c7ff91e50cc52f2 Mon Sep 17 00:00:00 2001 From: Andrew Ajube Date: Thu, 2 Apr 2026 18:42:27 +0100 Subject: [PATCH 14/14] feat: consolidate priority debts information into main JSON files and remove guidance files --- .../locales/cy/respondToClaim/priorityDebts.json | 12 ++++++++++++ .../cy/respondToClaim/priorityDebtsGuidance.json | 14 -------------- .../locales/en/respondToClaim/priorityDebts.json | 12 ++++++++++++ .../en/respondToClaim/priorityDebtsGuidance.json | 14 -------------- 4 files changed, 24 insertions(+), 28 deletions(-) delete mode 100644 src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json delete mode 100644 src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json diff --git a/src/main/assets/locales/cy/respondToClaim/priorityDebts.json b/src/main/assets/locales/cy/respondToClaim/priorityDebts.json index 3a1ed7c16..679cbcbc2 100644 --- a/src/main/assets/locales/cy/respondToClaim/priorityDebts.json +++ b/src/main/assets/locales/cy/respondToClaim/priorityDebts.json @@ -1,6 +1,18 @@ { "pageTitle": "Priority debts", "caption": "Respond to a property possession claim", + "paragraph1": "Priority debts are debts which could lead to serious consequences if you do not pay them.", + "paragraph2": "Excluding rent or mortgage arrears, priority debts are:", + "bullet1": "council tax arrears", + "bullet2": "gas or electricity arrears", + "bullet3": "phone or internet arrears", + "bullet4": "TV licence arrears", + "bullet5": "court fines", + "bullet6": "overpaid tax credits", + "bullet7": "payments for goods bought on hire purchase or conditional sale", + "bullet8": "unpaid income tax, National Insurance or VAT", + "bullet9": "unpaid child maintenance", + "guidanceLinkText": "Read guidance from Citizens Advice on what counts as a priority debt (opens in new tab)", "question": "Do you have any priority debts?", "options": { "yes": "Yes", diff --git a/src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json b/src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json deleted file mode 100644 index ba195b262..000000000 --- a/src/main/assets/locales/cy/respondToClaim/priorityDebtsGuidance.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "paragraph1": "Priority debts are debts which could lead to serious consequences if you do not pay them.", - "paragraph2": "Excluding rent or mortgage arrears, priority debts are:", - "bullet1": "council tax arrears", - "bullet2": "gas or electricity arrears", - "bullet3": "phone or internet arrears", - "bullet4": "TV licence arrears", - "bullet5": "court fines", - "bullet6": "overpaid tax credits", - "bullet7": "payments for goods bought on hire purchase or conditional sale", - "bullet8": "unpaid income tax, National Insurance or VAT", - "bullet9": "unpaid child maintenance", - "guidanceLinkText": "Read guidance from Citizens Advice on what counts as a priority debt (opens in new tab)" -} diff --git a/src/main/assets/locales/en/respondToClaim/priorityDebts.json b/src/main/assets/locales/en/respondToClaim/priorityDebts.json index 3a1ed7c16..679cbcbc2 100644 --- a/src/main/assets/locales/en/respondToClaim/priorityDebts.json +++ b/src/main/assets/locales/en/respondToClaim/priorityDebts.json @@ -1,6 +1,18 @@ { "pageTitle": "Priority debts", "caption": "Respond to a property possession claim", + "paragraph1": "Priority debts are debts which could lead to serious consequences if you do not pay them.", + "paragraph2": "Excluding rent or mortgage arrears, priority debts are:", + "bullet1": "council tax arrears", + "bullet2": "gas or electricity arrears", + "bullet3": "phone or internet arrears", + "bullet4": "TV licence arrears", + "bullet5": "court fines", + "bullet6": "overpaid tax credits", + "bullet7": "payments for goods bought on hire purchase or conditional sale", + "bullet8": "unpaid income tax, National Insurance or VAT", + "bullet9": "unpaid child maintenance", + "guidanceLinkText": "Read guidance from Citizens Advice on what counts as a priority debt (opens in new tab)", "question": "Do you have any priority debts?", "options": { "yes": "Yes", diff --git a/src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json b/src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json deleted file mode 100644 index ba195b262..000000000 --- a/src/main/assets/locales/en/respondToClaim/priorityDebtsGuidance.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "paragraph1": "Priority debts are debts which could lead to serious consequences if you do not pay them.", - "paragraph2": "Excluding rent or mortgage arrears, priority debts are:", - "bullet1": "council tax arrears", - "bullet2": "gas or electricity arrears", - "bullet3": "phone or internet arrears", - "bullet4": "TV licence arrears", - "bullet5": "court fines", - "bullet6": "overpaid tax credits", - "bullet7": "payments for goods bought on hire purchase or conditional sale", - "bullet8": "unpaid income tax, National Insurance or VAT", - "bullet9": "unpaid child maintenance", - "guidanceLinkText": "Read guidance from Citizens Advice on what counts as a priority debt (opens in new tab)" -}