Skip to content

Commit

Permalink
Merge pull request #177 from companieshouse/feature/add-no-dob-match-…
Browse files Browse the repository at this point in the history
…stop-screen
  • Loading branch information
hepsimo authored Dec 3, 2024
2 parents efdae50 + 90462d8 commit ebf9fa8
Show file tree
Hide file tree
Showing 28 changed files with 486 additions and 85 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
}
],
"rules": {
"indent": ["error", 4],
"indent": ["error", 4, { "SwitchCase": 1}],
"quotes": ["error", "double", { "allowTemplateLiterals": true }],
"semi": [2, "always"],
"no-unused-vars": "off",
Expand Down
6 changes: 5 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@
},
"jest.runMode": "on-save",
"javascript.preferences.importModuleSpecifier": "relative",
"typescript.preferences.importModuleSpecifier": "relative"
"typescript.preferences.importModuleSpecifier": "relative",
"cSpell.words": [
"PIWIK",
"uvid"
]
}
12 changes: 11 additions & 1 deletion locales/cy/stop-screens.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,15 @@
"dob_mismatch_corrections_link_text": "to be translated",
"dob_mismatch_up_to_date": "to be translated",
"dob_mismatch_authorised_agent": "to be translated",
"dob_mismatch_verified_identity": "to be translated"
"dob_mismatch_verified_identity": "to be translated",
"rp01_guidance_main_title": "to be translated",
"rp01_guidance_intro": "to be translated",
"rp01_guidance_step_1": "to be translated",
"rp01_guidance_step_1_link_text": "to be translated",
"rp01_guidance_step_2": "to be translated",
"rp01_guidance_step_2_link_text": "to be translated",
"rp01_guidance_step_3": "to be translated",
"rp01_guidance_step_3_link_text": "to be translated",
"rp01_guidance_summary": "to be translated",
"rp01_guidance_summary_link_text": "to be translated"
}
20 changes: 15 additions & 5 deletions locales/en/stop-screens.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
{
"dob_mismatch_main_title": "The details linked to this personal code do not match the details on our records",
"dob_mismatch_reasons": "This may be for a number of reasons - depending on how the identity was verified, or how the PSC's details were entered into our system. You cannot continue without fixing the issue.",
"dob_mismatch_reasons": "This may be for a number of reasons depending on how the identity was verified, or how the PSC's details were entered into our system. You cannot continue without fixing the issue.",
"dob_mismatch_check_personal_code": "Check you've entered the correct personal code",
"dob_mismatch_character_code": "Make sure the 11 character code you entered matches the code received when you verified your identity.",
"dob_mismatch_try_again_link_text": "Go back to the previous screen and try again.",
"dob_mismatch_try_again_link_text": "Go back to the previous screen and try again",
"dob_mismatch_check_dob": "Check the PSC's date of birth on the Companies House register",
"dob_mismatch_if_wrong": "If the date of birth entered into the Companies House register is wrong, you need to contact the company to",
"dob_mismatch_corrections_link_text": "submit the paper corrections forms with the correct date of birth.",
"dob_mismatch_corrections_link_text": "submit the paper corrections forms with the correct date of birth",
"dob_mismatch_up_to_date": "When the details are up to date on the register, you will be able to return to this service and provide your Companies House personal code.",
"dob_mismatch_authorised_agent": "If you verififed using an authroised agent, check they entered the correct date of birth",
"dob_mismatch_verified_identity": "If you verififed your identity through an authorised agent (such as an accountant), confirm that they typed your details in correctly when they verified your identity."
"dob_mismatch_authorised_agent": "If you verified using an authorised agent, check they entered the correct date of birth",
"dob_mismatch_verified_identity": "If you verified your identity through an authorised agent (such as an accountant), confirm that they typed your details in correctly when they verified your identity.",
"rp01_guidance_main_title": "Correcting the PSC date of birth on the Companies House register",
"rp01_guidance_intro": "To correct the date of birth on the Companies House register, someone authorised to file for this company will need to submit a paper corrections form. They should follow this process.",
"rp01_guidance_step_1": "Print and fill in the RP01 form:",
"rp01_guidance_step_1_link_text": "‘Replace a document not meeting requirements’",
"rp01_guidance_step_2": "Print and fill in the PSC01 form with the correct date of birth:",
"rp01_guidance_step_2_link_text": "‘Give notice of individual person with significant control’",
"rp01_guidance_step_3": "Send the completed paper forms together",
"rp01_guidance_step_3_link_text": "by post to Companies House",
"rp01_guidance_summary": "Once received, the submitted updates may take up to a couple of weeks to show on the register. When the PSC details are up to date, you will be able to successfully",
"rp01_guidance_summary_link_text": "provide identity verification details for the PSC"
}
9 changes: 9 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export const env = readEnv(process.env, {
FEEDBACK_URL: str
.describe("Link for the user to give feedback on the service")
.default(""),
GET_PSC01_LINK: url
.describe("Link to obtaining paper form PSC01")
.default("https://www.gov.uk/government/publications/give-notice-of-individual-person-with-significant-control-psc01"),
GET_RP01_LINK: url
.describe("Link to obtaining paper form RP01")
.default("https://www.gov.uk/government/publications/replace-a-document-not-meeting-requirements-rp01"),
IDV_IMPLEMENTATION_DATE: str
.describe("Date when IDV comes into effect for PSCs")
.default(""),
Expand Down Expand Up @@ -141,6 +147,9 @@ export const env = readEnv(process.env, {
.describe("Link to policies")
.default("https://resources.companieshouse.gov.uk/legal/termsAndConditions.shtml"),
PORT: port.describe("Port to run the web server on").default(3000),
POST_TO_CH_LINK: url
.describe("Link to guidance on submission by post")
.default("https://www.gov.uk/government/news/posting-documents-to-companies-house"),
SERVICE_LIVE: str
.describe("Prevent use of service until Implementation")
.default("false"),
Expand Down
44 changes: 22 additions & 22 deletions src/config/validator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Just<T> {
// eslint-disable-next-line no-useless-constructor
constructor (public value: T) {}
constructor (public value: T) { }
isJust (): this is Just<T> {
return true;
}
Expand Down Expand Up @@ -30,7 +30,7 @@ class ValidatorBuilder<T> {
constructor (
private validateFn: (input?: string | null) => Maybe<T>,
private description: string = ""
) {}
) { }

static from<T> (validateFn: Validator<T>): ValidatorBuilder<T> { // NOSONAR
return new ValidatorBuilder(validateFn);
Expand Down Expand Up @@ -146,22 +146,22 @@ const portValidator = strValidator

const boolValidator = strValidator.map<string>((s) => s.trim().toLowerCase()).map<boolean>((s) => {
switch (s) {
case "true":
case "1":
case "yes":
case "y":
case "on":
return true;
case "false":
case "0":
case "no":
case "n":
case "off":
return false;
default:
throw new Error(
`Invalid boolean value '${s}'. Expected true/false, 1/0, yes/no, y/n, on/off.`
);
case "true":
case "1":
case "yes":
case "y":
case "on":
return true;
case "false":
case "0":
case "no":
case "n":
case "off":
return false;
default:
throw new Error(
`Invalid boolean value '${s}'. Expected true/false, 1/0, yes/no, y/n, on/off.`
);
}
});

Expand All @@ -177,14 +177,14 @@ export const Validators = {

export type Env<S> = S extends Record<string, ValidatorBuilder<unknown>>
? {
[K in keyof S]: S[K] extends ValidatorBuilder<infer U> ? U : never;
}
[K in keyof S]: S[K] extends ValidatorBuilder<infer U> ? U : never;
}
: never;

export function readEnv<S extends Record<string, ValidatorBuilder<unknown>>> (source: Record<string, string | undefined>, schema: S): Readonly<Env<S>> {
const vars: Record<string, unknown> = {};

const errors: {key: string, message: string}[] = [];
const errors: { key: string, message: string }[] = [];

for (const [k, v] of Object.entries(schema)) {
const err = { key: k };
Expand Down Expand Up @@ -216,7 +216,7 @@ export function readEnv<S extends Record<string, ValidatorBuilder<unknown>>> (so

const protocolRegex = /^(http:\/\/|https:\/\/|\/\/)/i;
// Some config parameters don't have protocols e.g. CDN_HOST.
// This funciton adds '//' which is a protocol relative protocol to the url.
// This function adds '//' which is a protocol relative protocol to the url.
// This means if the site is hosted on http it will try to access http://${CDN_HOST}
// If the site is hosted on https it will use https://${CDN_HOST}
export function addProtocolIfMissing (url: string): string {
Expand Down
31 changes: 30 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
export const servicePathPrefix = "/persons-with-significant-control-verification";
const urlWithTransactionIdAndSubmissionId = "/transaction/:transactionId/submission/:submissionId";

export enum STOP_TYPE {
PSC_DOB_MISMATCH = "psc-dob-mismatch",
RP01_GUIDANCE = "rp01-guidance"
};

export function toStopScreenUrl (stopType: STOP_TYPE) {
switch (stopType) {
case STOP_TYPE.PSC_DOB_MISMATCH:
case STOP_TYPE.RP01_GUIDANCE:
return Urls.STOP_SCREEN_SUBMISSION;
default:
return Urls.STOP_SCREEN;
}
}

export function toStopScreenPrefixedUrl (stopType: STOP_TYPE) {
switch (stopType) {
case STOP_TYPE.PSC_DOB_MISMATCH:
case STOP_TYPE.RP01_GUIDANCE:
return PrefixedUrls.STOP_SCREEN_SUBMISSION;
default:
return PrefixedUrls.STOP_SCREEN;
}
}

export const Urls = {
ACCESSIBILITY_STATEMENT: "/persons-with-significant-control-verification",
HEALTHCHECK: "/healthcheck",
Expand All @@ -13,7 +38,9 @@ export const Urls = {
INDIVIDUAL_STATEMENT: `${urlWithTransactionIdAndSubmissionId}/individual/psc-statement`,
PSC_VERIFIED: `${urlWithTransactionIdAndSubmissionId}/psc-verified`,
PSC_TYPE: `${urlWithTransactionIdAndSubmissionId}/psc-type`,
RLE_LIST: `${urlWithTransactionIdAndSubmissionId}/rle/rle-list`
RLE_LIST: `${urlWithTransactionIdAndSubmissionId}/rle/rle-list`,
STOP_SCREEN: "/stop/:stopType",
STOP_SCREEN_SUBMISSION: `${urlWithTransactionIdAndSubmissionId}/stop/:stopType`
} as const;

export const PrefixedUrls = {
Expand All @@ -29,6 +56,8 @@ export const PrefixedUrls = {
PSC_VERIFIED: servicePathPrefix + Urls.PSC_VERIFIED,
RLE_LIST: servicePathPrefix + Urls.RLE_LIST,
PSC_TYPE: servicePathPrefix + Urls.PSC_TYPE,
STOP_SCREEN: servicePathPrefix + Urls.STOP_SCREEN,
STOP_SCREEN_SUBMISSION: servicePathPrefix + Urls.STOP_SCREEN_SUBMISSION,
COOKIES: "/help/cookies"
} as const;

Expand Down
7 changes: 5 additions & 2 deletions src/routerDispatch.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Do Router dispatch here, i.e. map incoming routes to appropriate router
import { Application, Request, Response, Router } from "express";
import { Urls, servicePathPrefix } from "./constants";
import { CompanyNumberRouter, ConfirmCompanyRouter, HealthCheckRouter, IndividualPscListRouter, IndividualStatementRouter, NewSubmissionRouter, PersonalCodeRouter, PscTypeRouter, PscVerifiedRouter, RlePscListRouter, StartRouter } from "./routers/utils";
import { CompanyNumberRouter, ConfirmCompanyRouter, HealthCheckRouter, IndividualPscListRouter, IndividualStatementRouter, NewSubmissionRouter, PersonalCodeRouter, PscTypeRouter, PscVerifiedRouter, RlePscListRouter, StartRouter, StopScreenRouter } from "./routers/utils";
import { authenticate } from "./middleware/authentication";
import { fetchVerification } from "./middleware/fetchVerification";
import { fetchCompany } from "./middleware/fetchCompany";
import { HttpStatusCode } from "axios";

const routerDispatch = (app: Application) => {

Expand All @@ -24,9 +25,11 @@ const routerDispatch = (app: Application) => {
router.use(Urls.PSC_VERIFIED, authenticate, fetchVerification, fetchCompany, PscVerifiedRouter);
router.use(Urls.RLE_LIST, authenticate, RlePscListRouter);
router.use(Urls.PSC_TYPE, authenticate, fetchVerification, PscTypeRouter);
router.use(Urls.STOP_SCREEN, authenticate, StopScreenRouter);
router.use(Urls.STOP_SCREEN_SUBMISSION, authenticate, StopScreenRouter);

router.use("*", (req: Request, res: Response) => {
res.status(404).render("partials/error_400");
res.status(HttpStatusCode.NotFound).render("partials/error_400");
});
};

Expand Down
6 changes: 3 additions & 3 deletions src/routers/handlers/psc-type/pscTypeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ export class PscTypeHandler extends GenericHandler<PscTypeViewData> {
// TODO update default when error page available.
const selectPscType = (pscType: any): string => {
switch (pscType) {
case "individual": return PrefixedUrls.INDIVIDUAL_PSC_LIST;
case "rle": return PrefixedUrls.RLE_LIST;
default: return PrefixedUrls.INDIVIDUAL_PSC_LIST;
case "individual": return PrefixedUrls.INDIVIDUAL_PSC_LIST;
case "rle": return PrefixedUrls.RLE_LIST;
default: return PrefixedUrls.INDIVIDUAL_PSC_LIST;
}
};
76 changes: 76 additions & 0 deletions src/routers/handlers/stop-screen/stopScreenHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Request, Response } from "express";
import { PrefixedUrls, STOP_TYPE, toStopScreenPrefixedUrl } from "../../../constants";
import { getLocaleInfo, getLocalesService, selectLang } from "../../../utils/localise";
import { BaseViewData, GenericHandler, ViewModel } from "../generic";
import { addSearchParams } from "../../../utils/queryParams";
import { getUrlWithStopType, getUrlWithTransactionIdAndSubmissionId } from "../../../utils/url";
import { env } from "../../../config";

interface StopScreenHandlerViewData extends BaseViewData {
extraData?: string[];
}

export class StopScreenHandler extends GenericHandler<StopScreenHandlerViewData> {

private static templateBasePath = "router_views/stop_screen/";

public async getViewData (req: Request, res: Response): Promise<StopScreenHandlerViewData> {

const baseViewData = await super.getViewData(req, res);
const stopType = req.params?.stopType as STOP_TYPE;

return setContent(req, stopType, baseViewData);
}

public async executeGet (req: Request, res: Response): Promise<ViewModel<StopScreenHandlerViewData>> {
const viewData = await this.getViewData(req, res);

return {
templatePath: StopScreenHandler.templateBasePath + req.params?.stopType,
viewData
};
}
}

const setContent = async (req: Request, stopType: STOP_TYPE, baseViewData: BaseViewData) => {

const lang = selectLang(req.query.lang);
const locales = getLocalesService();
const stopScreenPrefixedUrl = toStopScreenPrefixedUrl(stopType);

switch (stopType) {
case STOP_TYPE.PSC_DOB_MISMATCH: {
return {
...baseViewData,
...getLocaleInfo(locales, lang),
templateName: stopType,
currentUrl: resolveUrlTemplate(stopScreenPrefixedUrl, stopType),
backURL: resolveUrlTemplate(PrefixedUrls.PERSONAL_CODE),
backLinkDataEvent: "psc-dob-mismatch-back-link",
extraData: [resolveUrlTemplate(stopScreenPrefixedUrl, STOP_TYPE.RP01_GUIDANCE)]
};
}
case STOP_TYPE.RP01_GUIDANCE: {
return {
...baseViewData,
...getLocaleInfo(locales, lang),
templateName: stopType,
currentUrl: resolveUrlTemplate(stopScreenPrefixedUrl, stopType),
backURL: resolveUrlTemplate(stopScreenPrefixedUrl, STOP_TYPE.PSC_DOB_MISMATCH),
backLinkDataEvent: "rp01-guidance-back-link",
extraData: [env.GET_RP01_LINK, env.GET_PSC01_LINK, env.POST_TO_CH_LINK, PrefixedUrls.START]
};
}
default: {
throw new Error("Unrecognised stop screen type: " + stopType);
}

}

function resolveUrlTemplate (prefixedUrl: string, stopType?: STOP_TYPE): string {
const url = stopType ? getUrlWithStopType(prefixedUrl, stopType) : prefixedUrl;

return addSearchParams(getUrlWithTransactionIdAndSubmissionId(url, req.params.transactionId, req.params.submissionId), { lang });
}

};
13 changes: 13 additions & 0 deletions src/routers/stopScreenRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Request, Response, Router } from "express";
import { handleExceptions } from "../utils/asyncHandler";
import { StopScreenHandler } from "./handlers/stop-screen/stopScreenHandler";

const stopScreenRouter: Router = Router({ mergeParams: true });

stopScreenRouter.get("/", handleExceptions(async (req: Request, res: Response) => {
const handler = new StopScreenHandler();
const { templatePath, viewData } = await handler.executeGet(req, res);
res.render(templatePath, viewData);
}));

export default stopScreenRouter;
3 changes: 2 additions & 1 deletion src/routers/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import PersonalCodeRouter from "../personalCodeRouter";
import IndividualStatementRouter from "../individualStatementRouter";
import PscVerifiedRouter from "./../pscVerifiedRouter";
import RlePscListRouter from "./../rlePscListRouter";
import StopScreenRouter from "./../stopScreenRouter";

import { logger } from "../../lib/logger";
export { StartRouter, HealthCheckRouter, CompanyNumberRouter, ConfirmCompanyRouter, PscTypeRouter, IndividualPscListRouter, PersonalCodeRouter, IndividualStatementRouter, NewSubmissionRouter, PscVerifiedRouter, RlePscListRouter };
export { StartRouter, HealthCheckRouter, CompanyNumberRouter, ConfirmCompanyRouter, PscTypeRouter, IndividualPscListRouter, PersonalCodeRouter, IndividualStatementRouter, NewSubmissionRouter, PscVerifiedRouter, RlePscListRouter, StopScreenRouter };

export function formatDateBorn (dateOfBirth: any, lang: string): string {
try {
Expand Down
9 changes: 4 additions & 5 deletions src/utils/localise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { env } from "../config/index";

export const selectLang = (lang: any): string => {
switch (lang) {
case "cy": return "cy";
case "en":
default: return "en";
case "cy": return "cy";
case "en":
default: return "en";
}
};

Expand All @@ -29,5 +29,4 @@ export const getLocaleInfo = (locales: LocalesService, lang: string) => {
};
};

const localesService = LocalesService.getInstance(env.LOCALES_PATH, env.LOCALES_ENABLED === "true");
export const getLocalesService = () => localesService;
export const getLocalesService = () => LocalesService.getInstance(env.LOCALES_PATH, env.LOCALES_ENABLED === "true");
3 changes: 3 additions & 0 deletions src/utils/queryParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ export const addSearchParams = (uri: string, params: { [key: string]: string | s
});
return [baseUri, searchParams.toString()].filter(Boolean).join("?"); // ignore falsy values
};

export const setStopTypeQueryParam = (url: string, paramName: "stopType", value: string) =>
url.replace(`{${paramName}}`, value);
Loading

0 comments on commit ebf9fa8

Please sign in to comment.