Skip to content

Commit

Permalink
Merge pull request #703 from companieshouse/feature/ecct-616-new-stat…
Browse files Browse the repository at this point in the history
…ement-checkboxes-for-cs-submission

add two new checkboxes with accompanying html text, centralise common ecct function
  • Loading branch information
CHssmith2 authored Dec 13, 2023
2 parents 05a4aa3 + 1ed7fa2 commit 81993db
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 85 deletions.
7 changes: 6 additions & 1 deletion src/controllers/review.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { links } from "../utils/constants";
import { toReadableFormat } from "../utils/date";
import { ConfirmationStatementSubmission } from "@companieshouse/api-sdk-node/dist/services/confirmation-statement";
import { getConfirmationStatement } from "../services/confirmation.statement.service";
import { ecctDayOneEnabled } from "../utils/feature.flag";

export const get = async (req: Request, res: Response, next: NextFunction) => {
try {
Expand All @@ -31,11 +32,15 @@ export const get = async (req: Request, res: Response, next: NextFunction) => {

const csSubmission: ConfirmationStatementSubmission = await getConfirmationStatement(session, transactionId, submissionId);

const statementDate: Date = new Date(company.confirmationStatement?.nextMadeUpTo as string);
const ecctEnabled: boolean = ecctDayOneEnabled(statementDate);

return res.render(Templates.REVIEW, {
backLinkUrl,
company,
nextMadeUpToDate: toReadableFormat(csSubmission.data?.confirmationStatementMadeUpToDate),
isPaymentDue: isPaymentDue(transaction, submissionId)
isPaymentDue: isPaymentDue(transaction, submissionId),
ecctEnabled
});
} catch (e) {
return next(e);
Expand Down
25 changes: 4 additions & 21 deletions src/controllers/task.list.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { getCompanyProfile } from "../services/company.profile.service";
import { doesCompanyHaveEmailAddress } from "../services/registered.email.address.service";
import { REVIEW_PATH, TRADING_STATUS_PATH } from "../types/page.urls";
import { isInFuture, toReadableFormat } from "../utils/date";
import { createAndLogError, logger } from "../utils/logger";
import { createAndLogError } from "../utils/logger";
import { urlUtils } from "../utils/url";
import { getConfirmationStatement } from "../services/confirmation.statement.service";
import { Session } from "@companieshouse/node-session-handler";
import { ConfirmationStatementSubmission } from "@companieshouse/api-sdk-node/dist/services/confirmation-statement";
import { FEATURE_FLAG_ECCT_START_DATE_14082023 } from "../utils/properties";
import { ecctDayOneEnabled } from "../utils/feature.flag";

export const get = async (req: Request, res: Response, next: NextFunction) => {
try {
Expand All @@ -30,7 +30,8 @@ export const get = async (req: Request, res: Response, next: NextFunction) => {
const taskList: TaskList = initTaskList(company.companyNumber, transactionId, submissionId, confirmationStatement, companyHasExistingRea);
taskList.recordDate = calculateFilingDate(taskList.recordDate, company);

const registeredEmailAddressOptionEnabled: boolean = enableRegisteredEmailAdressOption(company);
const statementDate: Date = new Date(company.confirmationStatement?.nextMadeUpTo as string);
const registeredEmailAddressOptionEnabled: boolean = ecctDayOneEnabled(statementDate);

return res.render(Templates.TASK_LIST, {
backLinkUrl,
Expand Down Expand Up @@ -69,21 +70,3 @@ const calculateFilingDate = (recordDate: string, companyProfile: CompanyProfile)
}
throw createAndLogError(`Company Profile is missing confirmationStatement info for company number: ${companyProfile.companyNumber}`);
};

const enableRegisteredEmailAdressOption = (company: CompanyProfile): boolean => {
const ecctStartDateAsString: string = FEATURE_FLAG_ECCT_START_DATE_14082023;

if (!isValidDate(ecctStartDateAsString)) {
logger.info(`Environment Variable "FEATURE_FLAG_ECCT_START_DATE_14082023" must be in yyyy-mm-dd format`);
return false;
}

const ecctStartDate: Date = new Date(ecctStartDateAsString);
const statementDate: Date = new Date(company.confirmationStatement?.nextMadeUpTo as string);

return statementDate >= ecctStartDate;
};

const isValidDate = (dateAsString: string): boolean => {
return !isNaN(Date.parse(dateAsString));
};
4 changes: 4 additions & 0 deletions src/utils/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ export const toReadableFormatMonthYear = (monthNum: number, year: number): strin

return `${convertedMonth} ${year}`;
};

export const isValidDate = (dateAsString: string): boolean => {
return !isNaN(Date.parse(dateAsString));
};
17 changes: 17 additions & 0 deletions src/utils/feature.flag.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { FEATURE_FLAG_ECCT_START_DATE_14082023 } from "./properties";
import { isValidDate } from "./date";
import { logger } from "./logger";

/**
* Feature flags will be determined by environment variables and all environment variables in nodejs are
* either string or undefined. This function will ensure that 'false', '0', 'off' etc remain falsy
Expand All @@ -13,3 +17,16 @@ export const isActiveFeature = (flag: string | undefined): boolean => {
featureFlag === "");

};

export const ecctDayOneEnabled = (dateToCompare: Date): boolean => {
const ecctStartDateAsString: string = FEATURE_FLAG_ECCT_START_DATE_14082023;

if (!isValidDate(ecctStartDateAsString)) {
logger.info(`Environment Variable "FEATURE_FLAG_ECCT_START_DATE_14082023" must be in yyyy-mm-dd format`);
return false;
}

const ecctStartDate: Date = new Date(ecctStartDateAsString);

return dateToCompare >= ecctStartDate;
};
16 changes: 8 additions & 8 deletions src/utils/update.confirmation.statement.submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ const generateSectionData = (section: SECTIONS, status: SectionStatus, extraData
}

case SECTIONS.EMAIL: {
const newEmailData: RegisteredEmailAddressData = {
sectionStatus: status
};
if (extraData) {
newEmailData.registeredEmailAddress = extraData;
}
return newEmailData;
}
const newEmailData: RegisteredEmailAddressData = {
sectionStatus: status
};
if (extraData) {
newEmailData.registeredEmailAddress = extraData;
}
return newEmailData;
}

default: {
return {
Expand Down
28 changes: 28 additions & 0 deletions test/controllers/review.controller.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import { dummyPayment, PAYMENT_JOURNEY_URL } from "../mocks/payment.mock";
import { mockConfirmationStatementSubmission } from "../mocks/confirmation.statement.submission.mock";
import { getConfirmationStatement } from "../../src/services/confirmation.statement.service";

const PropertiesMock = jest.requireMock('../../src/utils/properties');
jest.mock('../../src/utils/properties', () => ({
...jest.requireActual('../../src/utils/properties'),
}));
const mockGetCompanyProfile = getCompanyProfile as jest.Mock;
const mockGetTransaction = getTransaction as jest.Mock;
const mockCloseTransaction = closeTransaction as jest.Mock;
Expand All @@ -40,6 +44,9 @@ const PAYMENT_URL = "/payment/1234";
const PAGE_HEADING = "Submit the confirmation statement";
const ERROR_PAGE_HEADING = "Service offline - File a confirmation statement";
const COSTS_TEXT = "You will need to pay a fee";
const CONFIRMATION_STATEMENT_TEXT = "By continuing, you confirm that all information required to be delivered by the company pursuant to";
const CONFIRMATION_STATEMENT_ECCT_TEXT = "I confirm that all information required to be delivered by the company pursuant to";
const LAWFUL_ACTIVITY_STATEMENT_TEXT = "I confirm that the intended future activities of the company are lawful";
const COMPANY_NUMBER = "12345678";
const TRANSACTION_ID = "66454";
const SUBMISSION_ID = "435435";
Expand Down Expand Up @@ -158,6 +165,27 @@ describe("review controller tests", () => {
expect(response.text).not.toContain(COSTS_TEXT);
expect(mocks.mockAuthenticationMiddleware).toHaveBeenCalled();
});

it("Should show review page with standard confirmation statement text when cs date (2020-03-15) before ECCT Day One start date", async () => {
mockGetCompanyProfile.mockResolvedValueOnce(validCompanyProfile);
mockGetTransaction.mockResolvedValueOnce(dummyTransactionWithCosts);
PropertiesMock.FEATURE_FLAG_ECCT_START_DATE_14082023 = "2020-06-28";
const response = await request(app)
.get(URL);
expect(response.status).toBe(200);
expect(response.text).toContain(CONFIRMATION_STATEMENT_TEXT);
});

it("Should show review page with revised confirmation and lawful activity statement texts when cs date (2020-03-15) on or after ECCT Day One start date", async () => {
mockGetCompanyProfile.mockResolvedValueOnce(validCompanyProfile);
mockGetTransaction.mockResolvedValueOnce(dummyTransactionWithCosts);
PropertiesMock.FEATURE_FLAG_ECCT_START_DATE_14082023 = "2020-02-01";
const response = await request(app)
.get(URL);
expect(response.status).toBe(200);
expect(response.text).toContain(CONFIRMATION_STATEMENT_ECCT_TEXT);
expect(response.text).toContain(LAWFUL_ACTIVITY_STATEMENT_TEXT);
});
});

describe("post tests", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const mockSendUpdate = sendUpdate as jest.Mock;
describe("Confirm Email Address controller tests", () => {

describe("When entered email has been provided", () => {

beforeEach(() => {
mocks.mockAuthenticationMiddleware.mockClear();
mocks.mockServiceAvailabilityMiddleware.mockClear();
Expand Down Expand Up @@ -57,10 +57,10 @@ describe("Confirm Email Address controller tests", () => {
const spyGetUrlToPath = jest.spyOn(urlUtils, "getUrlToPath");
spyGetUrlToPath.mockImplementationOnce(() => { throw new Error(); });
const response = await request(app).get(CONFIRM_EMAIL_ADDRESS_URL);

expect(response.text).toContain(EXPECTED_ERROR_TEXT);

spyGetUrlToPath.mockRestore();
});
});
});
});
2 changes: 1 addition & 1 deletion test/mocks/session.middleware.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const session = new Session();
mockSessionMiddleware.mockImplementation((req: Request, res: Response, next: NextFunction) => {
req.session = session;
req.session.data.extra_data["payment-nonce"] = "123456";
req.session.data.extra_data["entered-email-address"] = "[email protected]"
req.session.data.extra_data["entered-email-address"] = "[email protected]";
next();
});

Expand Down
21 changes: 20 additions & 1 deletion test/utils/date.unit.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
jest.mock("../../src/utils/logger");

import { isInFuture, toReadableFormat, toReadableFormatMonthYear } from "../../src/utils/date";
import { isInFuture, isValidDate, toReadableFormat, toReadableFormatMonthYear } from "../../src/utils/date";
import { createAndLogError } from "../../src/utils/logger";
import { Settings as luxonSettings } from "luxon";

Expand Down Expand Up @@ -111,4 +111,23 @@ describe("Date tests", () => {
}
});
});

describe("valid date tests", () => {

it("Should return true for a valid date string", () => {
const validity = isValidDate("2023-12-12");
expect(validity).toEqual(true);
});

it("Should return false for an ivalid date string", () => {
const validity = isValidDate("12-2023-12");
expect(validity).toEqual(false);
});

it("Should return false for unsupplied date string", () => {
const validity = isValidDate("");
expect(validity).toEqual(false);
});

});
});
129 changes: 86 additions & 43 deletions test/utils/feature.flag.unit.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,102 @@
import { isActiveFeature } from "../../src/utils/feature.flag";
jest.mock("../../src/services/confirmation.statement.service");

import { ecctDayOneEnabled, isActiveFeature } from "../../src/utils/feature.flag";

const PropertiesMock = jest.requireMock('../../src/utils/properties');
jest.mock('../../src/utils/properties', () => ({
...jest.requireActual('../../src/utils/properties'),
}));

describe("feature flag tests", function() {

it("should return false if variable is 'false'", function() {
const active = isActiveFeature("false");
expect(active).toBeFalsy;
});
describe("active feature tests", function() {

it("should return false if variable is '0'", function() {
const active = isActiveFeature("0");
expect(active).toBeFalsy;
});
it("should return false if variable is 'false'", function() {
const active = isActiveFeature("false");
expect(active).toBeFalsy;
});

it("should return false if variable is ''", function() {
const active = isActiveFeature("");
expect(active).toBeFalsy;
});
it("should return false if variable is '0'", function() {
const active = isActiveFeature("0");
expect(active).toBeFalsy;
});

it("should return false if variable is undefined", function() {
const active = isActiveFeature(undefined);
expect(active).toBeFalsy;
});
it("should return false if variable is ''", function() {
const active = isActiveFeature("");
expect(active).toBeFalsy;
});

it("should return true if variable is random", function() {
const active = isActiveFeature("kdjhskjf");
expect(active).toBeTruthy;
});
it("should return false if variable is undefined", function() {
const active = isActiveFeature(undefined);
expect(active).toBeFalsy;
});

it("should return false if variable is 'off'", function() {
const active = isActiveFeature("off");
expect(active).toBeFalsy;
});
it("should return true if variable is random", function() {
const active = isActiveFeature("kdjhskjf");
expect(active).toBeTruthy;
});

it("should return false if variable is 'OFF'", function() {
const active = isActiveFeature("OFF");
expect(active).toBeFalsy;
});
it("should return false if variable is 'off'", function() {
const active = isActiveFeature("off");
expect(active).toBeFalsy;
});

it("should return true if variable is 'on'", function() {
const active = isActiveFeature("on");
expect(active).toBeTruthy;
});
it("should return false if variable is 'OFF'", function() {
const active = isActiveFeature("OFF");
expect(active).toBeFalsy;
});

it("should return true if variable is 'true'", function() {
const active = isActiveFeature("true");
expect(active).toBeTruthy;
});
it("should return true if variable is 'on'", function() {
const active = isActiveFeature("on");
expect(active).toBeTruthy;
});

it("should return true if variable is 'true'", function() {
const active = isActiveFeature("true");
expect(active).toBeTruthy;
});

it("should return true if variable is 'TRUE'", function() {
const active = isActiveFeature("TRUE");
expect(active).toBeTruthy;
});

it("should return true if variable is '1'", function() {
const active = isActiveFeature("1");
expect(active).toBeTruthy;
});

it("should return true if variable is 'TRUE'", function() {
const active = isActiveFeature("TRUE");
expect(active).toBeTruthy;
});

it("should return true if variable is '1'", function() {
const active = isActiveFeature("1");
expect(active).toBeTruthy;
describe("ECCT Day One enablement tests", function() {

it("should return false if supplied date is before ECCT start date", () => {
PropertiesMock.FEATURE_FLAG_ECCT_START_DATE_14082023 = "2022-04-01";
const supplyDate = new Date("2022-02-20");
const ecctEnabled = ecctDayOneEnabled(supplyDate);
expect(ecctEnabled).toEqual(false);
});

it("should return true if supplied date is the same as ECCT start date", function() {
PropertiesMock.FEATURE_FLAG_ECCT_START_DATE_14082023 = "2022-04-01";
const supplyDate = new Date("2022-04-01");
const ecctEnabled = ecctDayOneEnabled(supplyDate);
expect(ecctEnabled).toEqual(true);
});

it("should return true if supplied date is past ECCT start date", function() {
PropertiesMock.FEATURE_FLAG_ECCT_START_DATE_14082023 = "2022-04-01";
const supplyDate = new Date("2023-10-27");
const ecctEnabled = ecctDayOneEnabled(supplyDate);
expect(ecctEnabled).toEqual(true);
});

it("should return an error if ECCT start date is invalid", function() {
PropertiesMock.FEATURE_FLAG_ECCT_START_DATE_14082023 = "2022-99-99";
const supplyDate = new Date("2023-10-27");
const ecctEnabled = ecctDayOneEnabled(supplyDate);
expect(ecctEnabled).toEqual(false);
});
});

});
1 change: 1 addition & 0 deletions views/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
{% from "govuk/components/table/macro.njk" import govukTable %}
{% from "govuk/components/tag/macro.njk" import govukTag %}
{% from "govuk/components/input/macro.njk" import govukInput %}
{% from "govuk/components/checkboxes/macro.njk" import govukCheckboxes %}

{% block head %}

Expand Down
Loading

0 comments on commit 81993db

Please sign in to comment.