Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9f25ce0
adding persistence and pre-population for confirmation-of-notice-given
AlexBuzea Mar 30, 2026
3d1f652
data persistence and pre population notice date unknown
AlexBuzea Mar 30, 2026
95825e2
Merge remote-tracking branch 'origin/master' into HDPI-4203-data-pers…
AlexBuzea Mar 31, 2026
4c0f0de
adding persistence and pre-population for confirmation of notice when…
AlexBuzea Mar 31, 2026
735273e
fixing linting issues
AlexBuzea Mar 31, 2026
22611f6
Merge remote-tracking branch 'origin/master' into HDPI-4203-data-pers…
AlexBuzea Mar 31, 2026
b0a3de2
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Mar 31, 2026
b3c9307
fixing failing tests
AlexBuzea Mar 31, 2026
857478f
fixing type
AlexBuzea Mar 31, 2026
b17c0b0
adding logging and changing type
AlexBuzea Apr 1, 2026
b5f1943
fixing linting..
AlexBuzea Apr 1, 2026
fdc4405
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Apr 1, 2026
cd91e82
removing TenancyTypeCorrectValue type alias as not needed, same as Ye…
AlexBuzea Apr 1, 2026
37ae749
Merge remote-tracking branch 'origin/master' into HDPI-4203-data-pers…
AlexBuzea Apr 1, 2026
fbf5cc3
updating missed type
AlexBuzea Apr 1, 2026
3977ce5
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Apr 2, 2026
7525c1e
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Apr 2, 2026
4c44659
Merge remote-tracking branch 'origin/master' into HDPI-4203-data-pers…
AlexBuzea Apr 10, 2026
243c45d
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Apr 13, 2026
147be9f
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Apr 14, 2026
9aad1ec
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Apr 14, 2026
a01af5c
Merge remote-tracking branch 'origin/master' into HDPI-4203-data-pers…
AlexBuzea Apr 14, 2026
d9a3b04
fixing linting issue
AlexBuzea Apr 14, 2026
ae9973e
Merge remote-tracking branch 'origin/master' into HDPI-4203-data-pers…
AlexBuzea Apr 14, 2026
ebc3e3b
updating getConfirmNoticeGivenAnswer to check correct value
AlexBuzea Apr 14, 2026
fd390f8
fix linting issue
AlexBuzea Apr 14, 2026
fe42f15
fixing broken tests
AlexBuzea Apr 15, 2026
ca34c39
Merge master
AlexBuzea Apr 15, 2026
56f809f
Merge remote-tracking branch 'origin/master' into HDPI-4203-data-pers…
AlexBuzea Apr 16, 2026
c4e7f6a
Merge branch 'master' into HDPI-4203-data-persistence-missing-pages-f…
AlexBuzea Apr 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions src/main/services/ccdCase.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ export interface HouseholdCircumstances {
otherTenantsDetails?: string;
}

export type PaymentAgreement = {
anyPaymentsMade?: YesNoValue;
paymentDetails?: string;
repaymentPlanAgreed?: YesNoNotSureValue;
repaymentAgreedDetails?: string;
repayArrearsInstalments?: YesNoValue;
additionalRentContribution?: unknown;
additionalContributionFrequency?: string;
};

export interface CcdUserCase {
id: string;
state: CaseState;
Expand Down Expand Up @@ -95,7 +105,7 @@ export interface CcdDefendantParty {

/** Defendant responses (e.g. receivedFreeLegalAdvice). */
export interface CcdDefendantResponses {
tenancyTypeCorrect?: TenancyTypeCorrectValue;
tenancyTypeCorrect?: YesNoNotSureValue;
tenancyType?: string;
freeLegalAdvice?: string;
confirmNoticeGiven?: string;
Expand All @@ -116,14 +126,10 @@ export interface CcdDefendantResponses {
writtenTerms?: YesNoNotSureValue;
disputeClaim?: YesNoValue;
disputeClaimDetails?: string;
paymentAgreement?: {
repaymentPlanAgreed?: YesNoNotSureValue;
repaymentAgreedDetails?: string;
repayArrearsInstalments?: YesNoValue;
additionalRentContribution?: unknown;
additionalContributionFrequency?: string;
};
paymentAgreement?: PaymentAgreement;
householdCircumstances?: HouseholdCircumstances;
possessionNoticeReceived?: YesNoNotSureValue;
noticeReceivedDate?: string;
}

export interface PossessionClaimResponse {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,16 @@
import type { Request } from 'express';
import { DateTime } from 'luxon';

import { formatDatePartsToISODate } from '../../utils/dateUtils';
import { getClaimantName } from '../../utils/getClaimantName';
import { buildCcdCaseForPossessionClaimResponse } from '../../utils/populateResponseToClaimPayloadmap';
import { flowConfig } from '../flow.config';

import { Logger } from '@modules/logger';
import { createFormStep, getTranslationFunction } from '@modules/steps';
import type { StepDefinition } from '@modules/steps/stepFormData.interface';
import type { PossessionClaimResponse } from '@services/ccdCaseData.model';

type NoticeDateFormValue = Record<
string,
{
day: string;
month: string;
year: string;
}
>;

function getNoticeDateFormValue(noticeDate?: string): NoticeDateFormValue {
if (!noticeDate) {
return {};
}

const parsed = DateTime.fromISO(noticeDate);
if (!parsed.isValid) {
return {};
}

return {
noticeDate: {
day: parsed.toFormat('d'),
month: parsed.toFormat('M'),
year: parsed.toFormat('yyyy'),
},
};
}
import type { CaseData, PossessionClaimResponse } from '@services/ccdCase.interface';
const logger = Logger.getLogger('confirmation-of-notice-date-when-not-provided');

export const step: StepDefinition = createFormStep({
stepName: 'confirmation-of-notice-date-when-not-provided',
Expand All @@ -51,7 +27,7 @@ export const step: StepDefinition = createFormStep({
},
fields: [
{
name: 'noticeDate',
name: 'noticeReceivedDate',
type: 'date',
required: false,
noFutureDate: true,
Expand All @@ -64,22 +40,49 @@ export const step: StepDefinition = createFormStep({
},
],
getInitialFormData: req => {
return getNoticeDateFormValue(req.res?.locals?.validatedCase?.defendantResponsesNoticeDate);
const caseData: CaseData | undefined = req.res?.locals.validatedCase?.data;
const noticeReceivedDateRaw: unknown = caseData?.possessionClaimResponse?.defendantResponses?.noticeReceivedDate;

if (!noticeReceivedDateRaw) {
return {};
}

if (typeof noticeReceivedDateRaw !== 'string') {
logger.warn('Unexpected noticeReceivedDate type in case data', {
type: typeof noticeReceivedDateRaw,
value: noticeReceivedDateRaw,
});
return {};
}
Comment thread
scottstewart-sl marked this conversation as resolved.

const dateTime: DateTime = DateTime.fromISO(noticeReceivedDateRaw);
if (!dateTime.isValid) {
logger.warn('Invalid noticeReceivedDate format in case data', {
value: noticeReceivedDateRaw,
reason: dateTime.invalidReason,
});
return {};
}

return {
noticeReceivedDate: {
day: dateTime.toFormat('dd'),
month: dateTime.toFormat('MM'),
year: dateTime.toFormat('yyyy'),
},
};
},
beforeRedirect: async req => {
const noticeDate = req.body?.noticeDate as { day?: string; month?: string; year?: string } | undefined;
const isoNoticeDate =
noticeDate?.day && noticeDate?.month && noticeDate?.year
? (DateTime.fromObject({
day: Number(noticeDate.day),
month: Number(noticeDate.month),
year: Number(noticeDate.year),
}).toISODate() ?? undefined)
: undefined;

beforeRedirect: async (req: Request) => {
const dateObject: { day?: string; month?: string; year?: string } | undefined = req.body?.noticeReceivedDate;
const day = dateObject?.day !== undefined ? String(dateObject.day).trim() : '';
const month = dateObject?.month !== undefined ? String(dateObject.month).trim() : '';
const year = dateObject?.year !== undefined ? String(dateObject.year).trim() : '';
const noticeReceivedDate = formatDatePartsToISODate(day, month, year);

const possessionClaimResponse: PossessionClaimResponse = {
defendantResponses: {
noticeDate: isoNoticeDate,
...(noticeReceivedDate && { noticeReceivedDate }),
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,17 @@
import type { Request } from 'express';
import { DateTime } from 'luxon';

import { formatDatePartsToISODate } from '../../utils/dateUtils';
import { getClaimantName } from '../../utils/getClaimantName';
import { buildCcdCaseForPossessionClaimResponse } from '../../utils/populateResponseToClaimPayloadmap';
import { flowConfig } from '../flow.config';

import { Logger } from '@modules/logger';
import { createFormStep, getTranslationFunction } from '@modules/steps';
import type { StepDefinition } from '@modules/steps/stepFormData.interface';
import type { PossessionClaimResponse } from '@services/ccdCaseData.model';

type NoticeDateFormValue = Record<
string,
{
day: string;
month: string;
year: string;
}
>;

function getNoticeDateFormValue(noticeDate?: string): NoticeDateFormValue {
if (!noticeDate) {
return {};
}

const parsed = DateTime.fromISO(noticeDate);
if (!parsed.isValid) {
return {};
}

return {
noticeDate: {
day: parsed.toFormat('d'),
month: parsed.toFormat('M'),
year: parsed.toFormat('yyyy'),
},
};
}
import type { CaseData, PossessionClaimResponse } from '@services/ccdCase.interface';

const logger = Logger.getLogger('confirmation-of-notice-date-when-provided');

export const step: StepDefinition = createFormStep({
stepName: 'confirmation-of-notice-date-when-provided',
Expand All @@ -54,7 +31,7 @@ export const step: StepDefinition = createFormStep({
},
fields: [
{
name: 'noticeDate',
name: 'noticeReceivedDate',
type: 'date',
required: false,
noFutureDate: true,
Expand All @@ -67,27 +44,55 @@ export const step: StepDefinition = createFormStep({
},
],
getInitialFormData: req => {
return getNoticeDateFormValue(req.res?.locals?.validatedCase?.defendantResponsesNoticeDate);
const caseData: CaseData | undefined = req.res?.locals.validatedCase?.data;
const noticeReceivedDateRaw: unknown = caseData?.possessionClaimResponse?.defendantResponses?.noticeReceivedDate;

if (!noticeReceivedDateRaw) {
return {};
}

if (typeof noticeReceivedDateRaw !== 'string') {
logger.warn('Unexpected noticeReceivedDate type in case data', {
type: typeof noticeReceivedDateRaw,
value: noticeReceivedDateRaw,
});
return {};
}

const dateTime: DateTime = DateTime.fromISO(noticeReceivedDateRaw);
if (!dateTime.isValid) {
logger.warn('Invalid noticeReceivedDate format in case data', {
value: noticeReceivedDateRaw,
reason: dateTime.invalidReason,
});
return {};
}

return {
noticeReceivedDate: {
day: dateTime.toFormat('dd'),
month: dateTime.toFormat('MM'),
year: dateTime.toFormat('yyyy'),
},
};
},
beforeRedirect: async req => {
const noticeDate = req.body?.noticeDate as { day?: string; month?: string; year?: string } | undefined;
const isoNoticeDate =
noticeDate?.day && noticeDate?.month && noticeDate?.year
? (DateTime.fromObject({
day: Number(noticeDate.day),
month: Number(noticeDate.month),
year: Number(noticeDate.year),
}).toISODate() ?? undefined)
: undefined;

beforeRedirect: async (req: Request) => {
const dateObject: { day?: string; month?: string; year?: string } | undefined = req.body?.noticeReceivedDate;
const day = dateObject?.day !== undefined ? String(dateObject.day).trim() : '';
const month = dateObject?.month !== undefined ? String(dateObject.month).trim() : '';
const year = dateObject?.year !== undefined ? String(dateObject.year).trim() : '';
const noticeReceivedDate = formatDatePartsToISODate(day, month, year);

const possessionClaimResponse: PossessionClaimResponse = {
defendantResponses: {
noticeDate: isoNoticeDate,
...(noticeReceivedDate && { noticeReceivedDate }),
},
};

await buildCcdCaseForPossessionClaimResponse(req, possessionClaimResponse);
},

extendGetContent: req => {
const validatedCase = req.res?.locals?.validatedCase;
const claimantName = getClaimantName(req);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { Request } from 'express';

import { getClaimantName } from '../../utils/getClaimantName';
import { buildCcdCaseForPossessionClaimResponse } from '../../utils/populateResponseToClaimPayloadmap';
import { flowConfig } from '../flow.config';

import { createFormStep } from '@modules/steps';
import type { StepDefinition } from '@modules/steps/stepFormData.interface';
import type { PossessionClaimResponse } from '@services/ccdCaseData.model';
import type { CaseData, PossessionClaimResponse, YesNoNotSureValue } from '@services/ccdCase.interface';

export const step: StepDefinition = createFormStep({
stepName: 'confirmation-of-notice-given',
Expand All @@ -18,57 +20,46 @@ export const step: StepDefinition = createFormStep({
question: 'question',
hintText: 'hintText',
},
beforeRedirect: async req => {
const confirmNoticeGiven = req.body?.confirmNoticeGiven as string | undefined;
const existingDefendantResponses = req.res?.locals?.validatedCase?.defendantResponses ?? {};

if (!confirmNoticeGiven) {
return;
}
fields: [
{
name: 'possessionNoticeReceived',
type: 'radio',
required: true,
translationKey: { label: 'question', hint: 'hintText' },
legendClasses: 'govuk-fieldset__legend--m',
options: [
{ value: 'YES', translationKey: 'options.yes' },
{ value: 'NO', translationKey: 'options.no' },
{ divider: 'options.or' },
{ value: 'NOT_SURE', translationKey: 'options.imNotSure' },
],
},
],
getInitialFormData: req => {
const caseData: CaseData | undefined = req.res?.locals.validatedCase?.data;
const possessionNoticeReceived: YesNoNotSureValue | undefined =
caseData?.possessionClaimResponse?.defendantResponses?.possessionNoticeReceived;

const enumMapping: Record<string, string> = {
yes: 'YES',
no: 'NO',
imNotSure: 'NOT_SURE',
};
return possessionNoticeReceived ? { possessionNoticeReceived } : {};
},
beforeRedirect: async (req: Request) => {
const possessionNoticeReceived: YesNoNotSureValue | undefined = req.body?.possessionNoticeReceived;

const ccdValue = enumMapping[confirmNoticeGiven];
if (!ccdValue) {
if (!possessionNoticeReceived) {
return;
}

const possessionClaimResponse: PossessionClaimResponse = {
defendantResponses: {
...existingDefendantResponses,
confirmNoticeGiven: ccdValue,
...(confirmNoticeGiven === 'yes' ? {} : { noticeDate: '' }),
possessionNoticeReceived,
},
};

await buildCcdCaseForPossessionClaimResponse(req, possessionClaimResponse);
},
getInitialFormData: req => {
const existingAnswer = req.res?.locals?.validatedCase?.defendantResponsesConfirmNoticeGiven as string | undefined;

return existingAnswer ? { confirmNoticeGiven: existingAnswer } : {};
},
fields: [
{
name: 'confirmNoticeGiven',
type: 'radio',
required: true,
translationKey: { label: 'question', hint: 'hintText' },
legendClasses: 'govuk-fieldset__legend--m',
options: [
{ value: 'yes', translationKey: 'options.yes' },
{ value: 'no', translationKey: 'options.no' },
{ divider: 'options.or' },
{ value: 'imNotSure', translationKey: 'options.imNotSure' },
],
},
],
extendGetContent: req => {
const claimantName = getClaimantName(req);

return {
claimantName,
};
Expand Down
Loading
Loading