Skip to content

Commit

Permalink
Merge pull request #1689 from companieshouse/defect/roe-2732/add-paym…
Browse files Browse the repository at this point in the history
…ent-metadata-to-application-data-for-api

feat/roe-2732: save payment metadata to API
  • Loading branch information
mwejuli-ch authored Feb 14, 2025
2 parents e767084 + e86845d commit 1c44638
Show file tree
Hide file tree
Showing 22 changed files with 477 additions and 283 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"license": "MIT",
"homepage": "https://github.com/companieshouse/overseas-entities-web#readme",
"dependencies": {
"@companieshouse/api-sdk-node": "^2.0.209",
"@companieshouse/api-sdk-node": "^2.0.234",
"@companieshouse/node-session-handler": "^5.0.1",
"@companieshouse/structured-logging-node": "^2.0.1",
"@companieshouse/web-security-node": "^4.1.1",
Expand Down
3 changes: 2 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ export const REVIEW_OWNER_INDEX_PARAM = "?index=";
export const UPDATE_REVIEW_OWNERS_PARAMS = REVIEW_OWNER_INDEX_PARAM + ID;
export const ROUTE_PARAM_TRANSACTION_ID = "transactionId";
export const ROUTE_PARAM_SUBMISSION_ID = "submissionId";
export const ROUTE_PARAM_OVERSEAS_ENTITY_ID = "overseasEntityId";
export const LANDING_PAGE_QUERY_PARAM = "start";
export const JOURNEY_QUERY_PARAM = "journey";
export const PREVIOUS_PAGE_QUERY_PARAM = "previousPage";
Expand Down Expand Up @@ -327,7 +328,7 @@ export const TRANSACTION = "transaction";
export const OVERSEAS_ENTITY = "overseas-entity";

const TRANSACTION_PATH = TRANSACTION + "/:transactionId/";
const OVERSEAS_ENTITY_PATH = OVERSEAS_ENTITY + "/:overseaEntityId/";
const OVERSEAS_ENTITY_PATH = OVERSEAS_ENTITY + "/:overseasEntityId/";
export const PAYMENT_WITH_TRANSACTION_URL = REGISTER_AN_OVERSEAS_ENTITY_URL + TRANSACTION_PATH + OVERSEAS_ENTITY_PATH + PAYMENT;
export const OVERSEAS_ENTITY_PAYMENT_WITH_TRANSACTION_URL = UPDATE_AN_OVERSEAS_ENTITY_URL + TRANSACTION_PATH + OVERSEAS_ENTITY_PATH + PAYMENT;

Expand Down
48 changes: 29 additions & 19 deletions src/controllers/beneficial.owner.delete.warning.controller.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import { NextFunction, Request, Response } from "express";

import { Session } from "@companieshouse/node-session-handler";
import { createAndLogErrorRequest, logger } from "../utils/logger";
import * as config from "../config";
import { ApplicationData } from "../model";
import { isActiveFeature } from "../utils/feature.flag";
import { BeneficialOwnerGovKey } from "../model/beneficial.owner.gov.model";
import { BeneficialOwnerIndividualKey } from "../model/beneficial.owner.individual.model";
import { BeneficialOwnerOtherKey } from "../model/beneficial.owner.other.model";
import { ManagingOfficerCorporateKey } from "../model/managing.officer.corporate.model";
import { ManagingOfficerKey } from "../model/managing.officer.model";
import { TrustKey } from "../model/trust.model";
import { updateOverseasEntity } from "../service/overseas.entities.service";

import { getUrlWithParamsToPath, isRegistrationJourney } from "../utils/url";

import {
setExtraData,
fetchApplicationData,
checkBOsDetailsEntered,
checkMOsDetailsEntered,
getApplicationData,
setExtraData
} from "../utils/application.data";
import { createAndLogErrorRequest, logger } from "../utils/logger";

import {
BeneficialOwnersStatementType,
BeneficialOwnersStatementTypes,
BeneficialOwnerStatementKey
} from "../model/beneficial.owner.statement.model";
import { isActiveFeature } from "../utils/feature.flag";
import { BeneficialOwnerGovKey } from "../model/beneficial.owner.gov.model";
import { BeneficialOwnerIndividualKey } from "../model/beneficial.owner.individual.model";
import { BeneficialOwnerOtherKey } from "../model/beneficial.owner.other.model";
import { ManagingOfficerCorporateKey } from "../model/managing.officer.corporate.model";
import { ManagingOfficerKey } from "../model/managing.officer.model";
import { TrustKey } from "../model/trust.model";
import { getUrlWithParamsToPath } from "../utils/url";

export const get = (req: Request, res: Response, next: NextFunction) => {

try {

logger.debugRequest(req, `GET ${config.BENEFICIAL_OWNER_DELETE_WARNING_PAGE}`);

const beneficialOwnerStatement = req.query[BeneficialOwnerStatementKey] as string;
Expand All @@ -46,30 +51,35 @@ export const get = (req: Request, res: Response, next: NextFunction) => {
};

export const post = async (req: Request, res: Response, next: NextFunction): Promise<void> => {

try {

logger.debugRequest(req, `POST ${config.BENEFICIAL_OWNER_DELETE_WARNING_PAGE}`);

if (req.body["delete_beneficial_owners"] === '1') {
const boStatement = req.body[BeneficialOwnerStatementKey];
const appData: ApplicationData = await getApplicationData(req.session);
const isRegistration: boolean = isRegistrationJourney(req);
const appData: ApplicationData = await fetchApplicationData(req, isRegistration);

if ( boStatement === BeneficialOwnersStatementType.NONE_IDENTIFIED && checkBOsDetailsEntered(appData) ) {
if (boStatement === BeneficialOwnersStatementType.NONE_IDENTIFIED && checkBOsDetailsEntered(appData)) {
appData[BeneficialOwnerIndividualKey] = [];
appData[TrustKey] = [];
appData[BeneficialOwnerOtherKey] = [];
appData[BeneficialOwnerGovKey] = [];
} else if ( boStatement === BeneficialOwnersStatementType.ALL_IDENTIFIED_ALL_DETAILS && checkMOsDetailsEntered(appData) ) {
} else if (boStatement === BeneficialOwnersStatementType.ALL_IDENTIFIED_ALL_DETAILS && checkMOsDetailsEntered(appData)) {
appData[ManagingOfficerKey] = [];
appData[ManagingOfficerCorporateKey] = [];
}

appData[BeneficialOwnerStatementKey] = boStatement;

setExtraData(req.session, appData);
let nextPageUrl = config.BENEFICIAL_OWNER_TYPE_URL;
if (isActiveFeature(config.FEATURE_FLAG_ENABLE_REDIS_REMOVAL)) {
nextPageUrl = getUrlWithParamsToPath(config.BENEFICIAL_OWNER_TYPE_WITH_PARAMS_URL, req);
if (isActiveFeature(config.FEATURE_FLAG_ENABLE_REDIS_REMOVAL) && isRegistration) {
await updateOverseasEntity(req, req.session as Session, appData);
}
setExtraData(req.session, appData);
const nextPageUrl = isActiveFeature(config.FEATURE_FLAG_ENABLE_REDIS_REMOVAL)
? getUrlWithParamsToPath(config.BENEFICIAL_OWNER_TYPE_WITH_PARAMS_URL, req)
: config.BENEFICIAL_OWNER_TYPE_URL;

return res.redirect(nextPageUrl);
}
Expand Down
1 change: 0 additions & 1 deletion src/controllers/check.your.answers.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ export const post = async (req: Request, res: Response, next: NextFunction) => {
logger.infoRequest(req, `Transaction Closed, ID: ${transactionID}`);
const redirectPath = await startPaymentsSession(req, session, transactionID, overseasEntityID, transactionClosedResponse);
logger.infoRequest(req, `Payments Session created with, Trans_ID: ${transactionID}, OE_ID: ${overseasEntityID}. Redirect to: ${redirectPath}`);

return res.redirect(redirectPath);

} catch (error) {
Expand Down
46 changes: 27 additions & 19 deletions src/controllers/confirmation.controller.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
import { Request, Response } from "express";

import { NextFunction, Request, Response } from "express";
import { logger } from "../utils/logger";
import { CONFIRMATION_PAGE, PAYMENT_FEE } from "../config";
import { getLoggedInUserEmail } from "../utils/session";
import { deleteApplicationData, getApplicationData } from "../utils/application.data";
import { ApplicationData } from "../model/application.model";
import { Transactionkey } from "../model/data.types.model";
import { WhoIsRegisteringType } from "../model/who.is.making.filing.model";
import { isRegistrationJourney } from "../utils/url";
import { deleteApplicationData, fetchApplicationData } from "../utils/application.data";
import { Transactionkey } from "../model/data.types.model";
import { CONFIRMATION_PAGE, PAYMENT_FEE } from "../config";

export const get = async (req: Request, res: Response, next: NextFunction) => {

try {

export const get = async (req: Request, res: Response) => {
logger.debugRequest(req, `GET ${CONFIRMATION_PAGE}`);
logger.debugRequest(req, `GET ${CONFIRMATION_PAGE}`);

const appData: ApplicationData = await getApplicationData(req.session);
const referenceNumber = appData[Transactionkey];
const isRegistration: boolean = isRegistrationJourney(req);
const appData: ApplicationData = await fetchApplicationData(req, isRegistration, true);
const referenceNumber = appData[Transactionkey];

deleteApplicationData(req.session);
deleteApplicationData(req.session);

return res.render(CONFIRMATION_PAGE, {
isAgentRegistering: appData.who_is_registering === WhoIsRegisteringType.AGENT,
referenceNumber,
entityEmail: appData.entity?.email,
userEmail: getLoggedInUserEmail(req.session),
verificationCheckDays: 14,
paymentFee: PAYMENT_FEE,
templateName: CONFIRMATION_PAGE
});
return res.render(CONFIRMATION_PAGE, {
isAgentRegistering: appData.who_is_registering === WhoIsRegisteringType.AGENT,
referenceNumber,
entityEmail: appData.entity?.email,
userEmail: getLoggedInUserEmail(req.session),
verificationCheckDays: 14,
paymentFee: PAYMENT_FEE,
templateName: CONFIRMATION_PAGE
});
} catch (error: any) {
logger.errorRequest(req, error);
next(error);
}
};
30 changes: 12 additions & 18 deletions src/controllers/payment.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { NextFunction, Request, Response } from "express";
import { CreatePaymentRequest } from "@companieshouse/api-sdk-node/dist/services/payment";

import { isActiveFeature } from "../utils/feature.flag";
import { ApplicationData } from "../model";
import { fetchApplicationData } from "../utils/application.data";
import { logger, createAndLogErrorRequest } from "../utils/logger";
import { OverseasEntityKey, PaymentKey } from "../model/data.types.model";
import { getUrlWithParamsToPath, isRegistrationJourney } from "../utils/url";
import {
CONFIRMATION_URL,
CONFIRMATION_WITH_PARAMS_URL,
Expand All @@ -10,47 +14,37 @@ import {
PAYMENT_FAILED_WITH_PARAMS_URL,
PAYMENT_PAID
} from "../config";
import { ApplicationData } from "../model";
import { getApplicationData } from "../utils/application.data";
import { OverseasEntityKey, PaymentKey } from "../model/data.types.model";
import { isActiveFeature } from "../utils/feature.flag";
import { getUrlWithParamsToPath } from "../utils/url";

// The Payment Platform will redirect the user's browser back to the `redirectUri` supplied when the payment session was created,
// and this controller is dealing with the completion of the payment journey
export const get = async (req: Request, res: Response, next: NextFunction): Promise<void> => {

try {
const { status, state } = req.query;

const appData: ApplicationData = await getApplicationData(req.session);
const { status, state } = req.query;
const isRegistration: boolean = isRegistrationJourney(req);
const appData: ApplicationData = await fetchApplicationData(req, isRegistration);
const savedPayment = appData[PaymentKey] || {} as CreatePaymentRequest;

logger.infoRequest(req, `Returned state: ${ state }, saved state: ${savedPayment.state}, with status: ${ status }`);

// The application must ensure that the returned `state` matches the nonce
// sent by the application to the Payment Platform. Protection against CSRF
if ( !savedPayment.state || savedPayment.state !== state) {
if (!savedPayment.state || savedPayment.state !== state) {
return next(createAndLogErrorRequest(req, `Rejecting payment redirect, payment state does not match. Payment Request: ${ JSON.stringify(savedPayment)}`));
}

// Validate the status of the payment
if (status === PAYMENT_PAID) {

let confirmationPageUrl = CONFIRMATION_URL;
if (isActiveFeature(FEATURE_FLAG_ENABLE_REDIS_REMOVAL)) {

if (isActiveFeature(FEATURE_FLAG_ENABLE_REDIS_REMOVAL) && isRegistration) {
confirmationPageUrl = getUrlWithParamsToPath(CONFIRMATION_WITH_PARAMS_URL, req);
}

logger.debugRequest(req, `Overseas Entity id: ${ appData[OverseasEntityKey] }, Payment status: ${status}, Redirecting to: ${confirmationPageUrl}`);

// Payment Successful, redirect to confirmation page
return res.redirect(confirmationPageUrl);
} else {
// Dealing with failures payment (User cancelled, Insufficient funds, Payment error ...)
logger.debugRequest(req, `Overseas Entity id: ${ appData[OverseasEntityKey] }, Payment status: ${status}, Redirecting to: ${PAYMENT_FAILED_URL}`);
let nextPageUrl = PAYMENT_FAILED_URL;
if (isActiveFeature(FEATURE_FLAG_ENABLE_REDIS_REMOVAL)){
if (isActiveFeature(FEATURE_FLAG_ENABLE_REDIS_REMOVAL) && isRegistration) {
nextPageUrl = getUrlWithParamsToPath(PAYMENT_FAILED_WITH_PARAMS_URL, req);
}
return res.redirect(nextPageUrl);
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/resume.submission.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { getResumePage } from "./shared/common.resume.submission.controller";
import { getUrlWithTransactionIdAndSubmissionId } from "../utils/url";

export const get = async (req: Request, res: Response, next: NextFunction) => {
const { transactionId, overseaEntityId } = req.params;
const { transactionId, overseasEntityId } = req.params;
const resumeUrl: string = isActiveFeature(config.FEATURE_FLAG_ENABLE_REDIS_REMOVAL)
? getUrlWithTransactionIdAndSubmissionId(config.SOLD_LAND_FILTER_WITH_PARAMS_URL, transactionId, overseaEntityId)
? getUrlWithTransactionIdAndSubmissionId(config.SOLD_LAND_FILTER_WITH_PARAMS_URL, transactionId, overseasEntityId)
: config.SOLD_LAND_FILTER_URL;
await getResumePage(req, res, next, resumeUrl);
};
Loading

0 comments on commit 1c44638

Please sign in to comment.