Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test civ 14228 #4220

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion Jenkinsfile_CNP
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def camundaBranch = "master"
def dmnBranch = "master"
def waStandaloneBranch = "master"
def ccdBranch = "master"
def generalappCCDBranch = "master"
def generalappCCDBranch = "CIV-14228-GA-Upload-additional-documents"
AppPipelineConfig pipelineConf

static Map<String, Object> secret(String secretName, String envVariable) {
Expand Down
1 change: 1 addition & 0 deletions src/main/common/models/gaEvents/applicationEvent.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum ApplicationEvent {
// TODO: Add events here for use by GA client
UPLOAD_ADDL_DOCUMENTS = 'UPLOAD_ADDL_DOCUMENTS',
}
36 changes: 26 additions & 10 deletions src/main/common/models/gaEvents/eventDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,31 @@ export interface EventDto {
}

export interface CCDGeneralApplication extends ClaimUpdate {
generalAppType: CcdGeneralApplicationTypes;
generalAppRespondentAgreement: CcdGeneralApplicationRespondentAgreement;
generalAppInformOtherParty: CcdGeneralApplicationInformOtherParty;
generalAppAskForCosts: YesNoUpperCamelCase;
generalAppDetailsOfOrder: string;
generalAppReasonsOfOrder: string;
generalAppEvidenceDocument: CcdGeneralApplicationEvidenceDocument[];
generalAppHearingDetails: CcdGeneralApplicationHearingDetails;
generalAppStatementOfTruth: CcdGeneralApplicationStatementOfTruth;
generalAppHelpWithFees: CCDHelpWithFees;
generalAppType?: CcdGeneralApplicationTypes;
generalAppRespondentAgreement?: CcdGeneralApplicationRespondentAgreement;
generalAppInformOtherParty?: CcdGeneralApplicationInformOtherParty;
generalAppAskForCosts?: YesNoUpperCamelCase;
generalAppDetailsOfOrder?: string;
generalAppReasonsOfOrder?: string;
generalAppEvidenceDocument?: CcdGeneralApplicationEvidenceDocument[];
generalAppHearingDetails?: CcdGeneralApplicationHearingDetails;
generalAppStatementOfTruth?: CcdGeneralApplicationStatementOfTruth;
generalAppHelpWithFees?: CCDHelpWithFees;
caseLink?: CaseLink;
uploadDocument?: AdditionalDocuments[]
}
interface DocumentDetails {
document_url: string;
document_binary_url: string;
document_filename: string;
}

interface AdditionDocDetails {
typeOfDocument: string,
documentUpload: DocumentDetails
}

export interface AdditionalDocuments {
id: string;
value: AdditionDocDetails
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {GaResponse} from 'models/generalApplication/response/gaResponse';
import {GaHelpWithFees} from 'models/generalApplication/gaHelpWithFees';
import {PaymentInformation} from 'models/feePayment/paymentInformation';
import {CaseLink} from 'models/generalApplication/CaseLink';
import { UploadAdditionalDocument } from './UploadAdditionalDocument';

export class GeneralApplication {

Expand All @@ -36,6 +37,7 @@ export class GeneralApplication {
helpWithFees?: GaHelpWithFees;
applicationFeePaymentDetails : PaymentInformation;
caseLink?: CaseLink;
uploadAdditionalDocuments?: UploadAdditionalDocument[] = [];

constructor(
applicationType?: ApplicationType,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IsNotEmpty, ValidateIf, ValidateNested } from 'class-validator';
import { FileUpload } from '../caseProgression/uploadDocumentsUserForm';
import { CaseDocument } from '../document/caseDocument';

export class UploadAdditionalDocument {
@ValidateNested()
@ValidateIf((object) => object.caseDocument === undefined || object.caseDocument === null || object.caseDocument === '')
@IsNotEmpty({ message: 'ERRORS.GENERAL_APPLICATION.UPLOAD_FILE_MESSAGE' })
fileUpload: FileUpload;
caseDocument: CaseDocument;

@IsNotEmpty({ message: 'ERRORS.GENERAL_APPLICATION.TYPE_OF_DOC' })
typeOfDocument: string;

constructor(fileUpload?: FileUpload) {
this.fileUpload = fileUpload;
}

}
4 changes: 4 additions & 0 deletions src/main/common/utils/urlFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ export function constructResponseUrlWithIdParams(id: string, path: string): stri
return path.replace(/(:id)/i, id);
}

export function constructResponseUrlWithIdAndAppIdParams(id: string, appId: string, path: string): string {
return path.replace(/(:id)/i, id).replace(/(:appId)/i, appId);
}

export function constructUrlWithNotEligibleReason(path: string, reason: NotEligibleReason): string {
return `${path}?reason=${reason}`;
}
Expand Down
12 changes: 12 additions & 0 deletions src/main/modules/i18n/locales/cy.json
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,16 @@
"WHY_NOT_ACCEPT": "Why do you not accept the defendant's offer?",
"WHY_NOT_ACCEPT_2": "Why you do not accept the defendant's offer?"
},
"ADDITIONAL_DOCUMENTS": {
"ADDITIONAL_DOCUMENTS_CAPTION": "Upload additional documents",
"ADDITIONAL_DOCUMENTS_ROW1": "You should only upload documents that are relevant to your application, for example if the judge has ordered a hearing and instructed you to provide documents ahead of this.",
"ADDITIONAL_DOCUMENTS_ROW2": "Before you upload the document you will need to describe the type of document you are uploading, for example, Bundle, witness statement or costs schedule.",
"JUDGE_WILL_REVIEW": "A judge will review the additional documents that you’ve uploaded. You’ll receive an update with their decision or next steps.",
"TYPE_OF_DOCUMENT_HINT": "For example, contract, invoice receipt, email, text message, photo, social media message",
"TYPE_OF_DOCUMENT": "Type of document",
"UPLOAD_DOCUMENTS_TITLE": "Upload documents",
"UPLOADED_ADDITIONAL_DOCS": "You've uploaded additional documents"
},
"AGREE_TO_ORDER": {
"MADE_AWARE": "If you have not been made aware of this application by the other parties, select 'No'.",
"RESPOND_TO": "Respond to an application to {{applicationType}}",
Expand Down Expand Up @@ -4952,7 +4962,9 @@
"NEED_TO_TELL": "You need to tell us if you agree that the court should make the order requested by the other party. Choose option Yes or No",
"EXPLAIN_WHY_DISAGREE_APPLICATION": "You need to explain why you disagree with the application"
},
"TYPE_OF_DOC": "You need to tell us what type of document you are uploading.",
"UPLOAD_FILE_MESSAGE": "You need to choose a file before clicking 'Upload file'",
"UPLOAD_ONE_FILE": "You need to upload at least one file.",
"WANT_TO_ADD_ANOTHER_APPLICATION": "You need to tell us if you want to add another application. Choose option: Yes or No",
"WANT_TO_UPLOAD_DOCUMENTS_YES_NO_SELECTION": "You need to tell us if you want to upload documents to support your application. Choose option: Yes or No",
"WHY_PREFER_THIS_HEARING_TYPE": "You need to tell us why you would prefer this type of hearing",
Expand Down
12 changes: 12 additions & 0 deletions src/main/modules/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,16 @@
"WHY_NOT_ACCEPT": "Why do you not accept the defendant's offer?",
"WHY_NOT_ACCEPT_2": "Why you do not accept the defendant's offer?"
},
"ADDITIONAL_DOCUMENTS": {
"ADDITIONAL_DOCUMENTS_CAPTION": "Upload additional documents",
"ADDITIONAL_DOCUMENTS_ROW1": "You should only upload documents that are relevant to your application, for example if the judge has ordered a hearing and instructed you to provide documents ahead of this.",
"ADDITIONAL_DOCUMENTS_ROW2": "Before you upload the document you will need to describe the type of document you are uploading, for example, Bundle, witness statement or costs schedule.",
"JUDGE_WILL_REVIEW": "A judge will review the additional documents that you’ve uploaded. You’ll receive an update with their decision or next steps.",
"TYPE_OF_DOCUMENT_HINT": "For example, contract, invoice receipt, email, text message, photo, social media message",
"TYPE_OF_DOCUMENT": "Type of document",
"UPLOAD_DOCUMENTS_TITLE": "Upload documents",
"UPLOADED_ADDITIONAL_DOCS": "You've uploaded additional documents"
},
"AGREE_TO_ORDER": {
"MADE_AWARE": "If you have not been made aware of this application by the other parties, select 'No'.",
"RESPOND_TO": "Respond to an application to {{applicationType}}",
Expand Down Expand Up @@ -4952,7 +4962,9 @@
"NEED_TO_TELL": "You need to tell us if you agree that the court should make the order requested by the other party. Choose option Yes or No",
"EXPLAIN_WHY_DISAGREE_APPLICATION": "You need to explain why you disagree with the application"
},
"TYPE_OF_DOC": "You need to tell us what type of document you are uploading.",
"UPLOAD_FILE_MESSAGE": "You need to choose a file before clicking 'Upload file'",
"UPLOAD_ONE_FILE": "You need to upload at least one file.",
"WANT_TO_ADD_ANOTHER_APPLICATION": "You need to tell us if you want to add another application. Choose option: Yes or No",
"WANT_TO_UPLOAD_DOCUMENTS_YES_NO_SELECTION": "You need to tell us if you want to upload documents to support your application. Choose option: Yes or No",
"WHY_PREFER_THIS_HEARING_TYPE": "You need to tell us why you would prefer this type of hearing",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ApplicationEvent } from 'common/models/gaEvents/applicationEvent';
import { AppRequest } from 'common/models/AppRequest';
import { buildSummarySectionForAdditionalDoc, getClaimDetailsById, prepareCCDData } from 'services/features/generalApplication/additionalDocumentService';
import { caseNumberPrettify } from 'common/utils/stringUtils';
import { GA_UPLOAD_ADDITIONAL_DOCUMENTS_CYA_URL, GA_UPLOAD_ADDITIONAL_DOCUMENTS_SUBMITTED_URL, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL } from 'routes/urls';
import { GaServiceClient } from 'client/gaServiceClient';
import { getCancelUrl } from 'services/features/generalApplication/generalApplicationService';
import { NextFunction, RequestHandler, Response, Router } from 'express';
import config from 'config';
import { constructResponseUrlWithIdAndAppIdParams } from 'common/utils/urlFormatter';

const gaAdditionalDocCheckAnswerController = Router();
const viewPath = 'features/generalApplication/additionalDocuments/check-answers';
const generalAppApiBaseUrl = config.get<string>('services.generalApplication.url');
const gaServiceClient: GaServiceClient = new GaServiceClient(generalAppApiBaseUrl);

gaAdditionalDocCheckAnswerController.get(GA_UPLOAD_ADDITIONAL_DOCUMENTS_CYA_URL, (async (req: AppRequest, res: Response, next: NextFunction) => {
try {
const { appId, id: claimId } = req.params;
const claimIdPrettified = caseNumberPrettify(claimId);
const claim = await getClaimDetailsById(req);
const cancelUrl = await getCancelUrl(claimId, claim);
const backLinkUrl = constructResponseUrlWithIdAndAppIdParams(claimId, appId, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL);
const summaryRows = buildSummarySectionForAdditionalDoc(claim.generalApplication.uploadAdditionalDocuments, claimId, appId);
res.render(viewPath, { backLinkUrl, cancelUrl, claimIdPrettified, claim, summaryRows });
} catch (error) {
next(error);
}
}) as RequestHandler);

gaAdditionalDocCheckAnswerController.post(GA_UPLOAD_ADDITIONAL_DOCUMENTS_CYA_URL, (async (req: AppRequest, res: Response, next: NextFunction) => {
try {
const { appId, id: claimId } = req.params;
const claim = await getClaimDetailsById(req);
const uploadedDocuments = prepareCCDData(claim.generalApplication.uploadAdditionalDocuments);
const generalApplication = {
uploadDocument: uploadedDocuments,
};
await gaServiceClient.submitEvent(ApplicationEvent.UPLOAD_ADDL_DOCUMENTS, appId, generalApplication as unknown, req);
res.redirect(constructResponseUrlWithIdAndAppIdParams(claimId, appId, GA_UPLOAD_ADDITIONAL_DOCUMENTS_SUBMITTED_URL));
} catch (error) {
next(error);
}
}) as RequestHandler);

export default gaAdditionalDocCheckAnswerController;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { AppRequest } from 'common/models/AppRequest';
import { NextFunction, RequestHandler, Response, Router } from 'express';
import { deleteDraftClaimFromStore, generateRedisKey } from 'modules/draft-store/draftStoreService';
import { getClaimById } from 'modules/utilityService';
import { GA_UPLOAD_ADDITIONAL_DOCUMENTS_SUBMITTED_URL } from 'routes/urls';
import { getContentForBody, getContentForCloseButton, getContentForPanel } from 'services/features/generalApplication/additionalDocumentService';
import { getCancelUrl } from 'services/features/generalApplication/generalApplicationService';

const additionalDocSubmittedController = Router();
const viewPath = 'features/generalApplication/additionalDocuments/submitted';

additionalDocSubmittedController.get(GA_UPLOAD_ADDITIONAL_DOCUMENTS_SUBMITTED_URL, (async (req: AppRequest, res: Response, next: NextFunction) => {
try {
const lng = req.query.lang ? req.query.lang : req.cookies.lang;
const { id: claimId } = req.params;
const claim = await getClaimById(claimId, req, true);
const redisKey = generateRedisKey(req);
await deleteDraftClaimFromStore(redisKey);
res.render(viewPath, {
gaPaymentSuccessfulPanel: getContentForPanel(lng),
gaPaymentSuccessfulBody: getContentForBody(lng),
gaPaymentSuccessfulButton: getContentForCloseButton(await getCancelUrl(claimId, claim)),
});
} catch (err) {
next(err);
}
}) as RequestHandler);

export default additionalDocSubmittedController;
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { GenericForm } from 'common/form/models/genericForm';
import { AppRequest } from 'common/models/AppRequest';
import { NextFunction, RequestHandler, Response, Router } from 'express';
import { GA_UPLOAD_ADDITIONAL_DOCUMENTS_CYA_URL, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL, GA_VIEW_APPLICATION_URL } from 'routes/urls';
import multer from 'multer';
import { UploadAdditionalDocument } from 'common/models/generalApplication/UploadAdditionalDocument';
import { generateRedisKey } from 'modules/draft-store/draftStoreService';
import { constructResponseUrlWithIdAndAppIdParams, constructResponseUrlWithIdParams } from 'common/utils/urlFormatter';
import { getCancelUrl } from 'services/features/generalApplication/generalApplicationService';
import { getClaimDetailsById, getSummaryList, removeSelectedDocument, uploadSelectedFile } from 'services/features/generalApplication/additionalDocumentService';

const uploadAdditionalDocumentsController = Router();

const viewPath = 'features/generalApplication/additionalDocuments/upload-additional-documents';
const fileSize = Infinity;
const upload = multer({
limits: {
fileSize: fileSize,
},
});

uploadAdditionalDocumentsController.get(GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL, (async (req: AppRequest, res: Response, next: NextFunction) => {
try {
const { appId:gaId, id } = req.params;
const uploadedDocument = new UploadAdditionalDocument();
let form = new GenericForm(uploadedDocument);
const redisKey = generateRedisKey(req);
const claim = await getClaimDetailsById(req);
const gaDetails = claim.generalApplication;

if (req.session?.fileUpload) {
const parsedData = JSON.parse(req?.session?.fileUpload);
form = new GenericForm(uploadedDocument, parsedData);
req.session.fileUpload = undefined;
}
if (req.query?.indexId) {
const index = req.query.indexId;
await removeSelectedDocument(redisKey, claim, Number(index) - 1);
}
const cancelUrl = await getCancelUrl(id, claim);
const backLinkUrl = `${constructResponseUrlWithIdParams(id, GA_VIEW_APPLICATION_URL)}?applicationId=${gaId}`;
const formattedSummary = getSummaryList(gaDetails.uploadAdditionalDocuments, id, gaId);
res.render(viewPath, { cancelUrl, backLinkUrl, form, formattedSummary });
} catch (err) {
next(err);
}
}) as RequestHandler);

uploadAdditionalDocumentsController.post(GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL, upload.single('selectedFile'), (async (req: AppRequest, res: Response, next: NextFunction) => {
try {
const { appId, id: claimId } = req.params;
const currentUrl = constructResponseUrlWithIdAndAppIdParams(claimId, appId, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL);
const claim = await getClaimDetailsById(req);
const gaDetails = claim.generalApplication;
if (req.body.action === 'uploadButton') {
await uploadSelectedFile(req, claim);
return res.redirect(`${currentUrl}`);
}
if (gaDetails.uploadAdditionalDocuments.length === 0) {
const errors = [{
target: {
fileUpload: '',
typeOfDocument: '',
},
value: '',
property: '',

constraints: {
isNotEmpty: 'ERRORS.GENERAL_APPLICATION.UPLOAD_ONE_FILE',
},
}];
req.session.fileUpload = JSON.stringify(errors);
return res.redirect(`${currentUrl}`);
}
res.redirect(constructResponseUrlWithIdAndAppIdParams(claimId, appId, GA_UPLOAD_ADDITIONAL_DOCUMENTS_CYA_URL));
} catch (err) {
next(err);
}
}));

export default uploadAdditionalDocumentsController;
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {NextFunction, RequestHandler, Response, Router} from 'express';
import {DASHBOARD_URL, GA_VIEW_APPLICATION_URL} from 'routes/urls';
import { DASHBOARD_URL, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL, GA_VIEW_APPLICATION_URL } from 'routes/urls';
import {AppRequest} from 'common/models/AppRequest';
import {getApplicationSections} from 'services/features/generalApplication/viewApplication/viewApplicationService';
import {queryParamNumber} from 'common/utils/requestUtils';
import { constructResponseUrlWithIdAndAppIdParams } from 'common/utils/urlFormatter';

const viewApplicationController = Router();
const viewPath = 'features/generalApplication/view-applications';
Expand All @@ -15,7 +16,8 @@ viewApplicationController.get(GA_VIEW_APPLICATION_URL, (async (req: AppRequest,
const lang = req.query.lang ? req.query.lang : req.cookies.lang;
const summaryRows = await getApplicationSections(req, applicationId, lang);
const pageTitle = 'PAGES.GENERAL_APPLICATION.VIEW_APPLICATION.PAGE_TITLE';
res.render(viewPath, {backLinkUrl, summaryRows, pageTitle, dashboardUrl: DASHBOARD_URL, applicationIndex });
const additionalDocUrl = constructResponseUrlWithIdAndAppIdParams(req.params.id, applicationId, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL);
res.render(viewPath, { backLinkUrl, summaryRows, additionalDocUrl, pageTitle, dashboardUrl: DASHBOARD_URL, applicationIndex });
} catch (error) {
next(error);
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ import whyNotSubjectToFRCController
from 'routes/features/directionsQuestionnaire/fixedRecoverableCosts/whyNotSubjectToFRCController';
import backController from 'routes/common/backController';
import applicationFeePaymentConfirmationController from './features/generalApplication/payment/applicationFeePaymentConfirmationController';
import uploadAdditionalDocumentsController from './features/generalApplication/additionalDocuments/uploadAdditionalDocumentsController';
import gaAdditionalDocCheckAnswerController from './features/generalApplication/additionalDocuments/checkAnswersController';
import additionalDocSubmittedController from './features/generalApplication/additionalDocuments/submittedController';
import viewApplicationToRespondentController from 'routes/features/generalApplication/response/viewApplicationController';
import applicationSummaryController from './features/generalApplication/applicationSummaryController';
import requestForReviewCommentsController
Expand Down Expand Up @@ -721,4 +724,7 @@ export default [
respondentHearingPreferenceController,
respondentWantToUploadDocumentsController,
respondentUploadEvidenceDocumentsController,
uploadAdditionalDocumentsController,
gaAdditionalDocCheckAnswerController,
additionalDocSubmittedController,
];
Loading
Loading