Skip to content

Commit

Permalink
Merge branch 'master' into CIV-14774_accessibility
Browse files Browse the repository at this point in the history
  • Loading branch information
mounikahmcts committed Sep 13, 2024
2 parents 67e9abf + 63b019a commit c81b9ea
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 24 deletions.
4 changes: 4 additions & 0 deletions src/main/app/client/gaServiceClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export class GaServiceClient {
return this.submitEvent(ApplicationEvent.RESPOND_TO_APPLICATION, applicationId, generalApplication, req);
}

async submitRespondToApplicationEventForUrgent(applicationId: string, generalApplication: CCDRespondToApplication, req?: AppRequest): Promise<Application> {
return this.submitEvent(ApplicationEvent.RESPOND_TO_APPLICATION_URGENT_LIP, applicationId, generalApplication, req);
}

async submitEvent(event: ApplicationEvent, claimId: string, updatedApplication?: CCDGeneralApplication | CCDRespondToApplication | CCDGaHelpWithFees, req?: AppRequest): Promise<Application> {

const config = this.getConfig(req);
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
Expand Up @@ -3,6 +3,7 @@ export enum ApplicationEvent {
NOTIFY_HELP_WITH_FEE = 'NOTIFY_HELP_WITH_FEE',
UPLOAD_ADDL_DOCUMENTS = 'UPLOAD_ADDL_DOCUMENTS',
RESPOND_TO_APPLICATION = 'RESPOND_TO_APPLICATION',
RESPOND_TO_APPLICATION_URGENT_LIP = 'RESPOND_TO_APPLICATION_URGENT_LIP',
RESPOND_TO_JUDGE_ADDITIONAL_INFO = 'RESPOND_TO_JUDGE_ADDITIONAL_INFO',
RESPOND_TO_JUDGE_DIRECTIONS = 'RESPOND_TO_JUDGE_DIRECTIONS',
RESPOND_TO_JUDGE_WRITTEN_REPRESENTATION = 'RESPOND_TO_JUDGE_WRITTEN_REPRESENTATION',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {CcdGeneralApplicationDirectionsOrderDocument} from 'models/ccdGeneralApp
import { CcdGeneralApplicationRespondentResponse } from '../ccdGeneralApplication/ccdGeneralApplicationRespondentResponse';
import { DateTime } from 'luxon';
import {CcdGARequestWrittenRepDocument} from 'models/ccdGeneralApplication/ccdGARequestWrittenRepDocument';
import {GeneralAppUrgencyRequirement} from 'models/generalApplication/response/urgencyRequirement';

export class ApplicationResponse {
id: string;
Expand Down Expand Up @@ -75,6 +76,8 @@ export interface CCDApplication extends ApplicationUpdate {
writtenRepSequentialDocument?: CcdGARequestWrittenRepDocument[];
writtenRepConcurrentDocument?: CcdGARequestWrittenRepDocument[];
applicationIsUncloakedOnce?: YesNoUpperCamelCase;
generalAppUrgencyRequirement?: GeneralAppUrgencyRequirement;
generalAppNotificationDeadlineDate?: string;
}

export interface JudicialRequestMoreInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {AcceptDefendantOffer} from './acceptDefendantOffer';
import {StatementOfTruthForm} from 'models/generalApplication/statementOfTruthForm';
import {UploadGAFiles} from 'models/generalApplication/uploadGAFiles';
import {ApplicationTypeOption} from 'models/generalApplication/applicationType';
import {GeneralAppUrgencyRequirement} from 'models/generalApplication/response/urgencyRequirement';

// CUI GA respondent response
export class GaResponse {
Expand All @@ -26,7 +27,7 @@ export class GaResponse {
wantToUploadAddlDocuments?: YesNo;
writtenRepText?: string;
generalApplicationType?: ApplicationTypeOption[];

generalAppUrgencyRequirement?: GeneralAppUrgencyRequirement;
constructor(hearingArrangement?: HearingArrangement, hearingContactDetails?: HearingContactDetails, agreeToOrder?: YesNo,
hearingSupport?: HearingSupport, unavailableDatesHearing?: UnavailableDatesGaHearing, respondentAgreement?: RespondentAgreement,
acceptDefendantOffer?: AcceptDefendantOffer, statementOfTruth?: StatementOfTruthForm, wantToUploadDocuments?: YesNo, uploadEvidenceDocuments?: UploadGAFiles) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {YesNoUpperCamelCase} from 'form/models/yesNo';

export interface GeneralAppUrgencyRequirement {
generalAppUrgency: YesNoUpperCamelCase,
reasonsForUrgency?: string,
urgentAppConsiderationDate: string
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import {NextFunction, RequestHandler, Response, Router} from 'express';
import {DEFENDANT_SUMMARY_URL, GA_ACCEPT_DEFENDANT_OFFER_URL, GA_AGREE_TO_ORDER_URL, GA_RESPONDENT_AGREEMENT_URL, GA_RESPONSE_VIEW_APPLICATION_URL, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL, GA_APPLICATION_RESPONSE_SUMMARY_URL} from 'routes/urls';
import {
DEFENDANT_SUMMARY_URL,
GA_ACCEPT_DEFENDANT_OFFER_URL,
GA_AGREE_TO_ORDER_URL,
GA_RESPONDENT_AGREEMENT_URL,
GA_RESPONSE_VIEW_APPLICATION_URL,
GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL,
GA_APPLICATION_RESPONSE_SUMMARY_URL,
} from 'routes/urls';
import {AppRequest} from 'common/models/AppRequest';
import {
getApplicantDocuments,
getApplicationSections, getCourtDocuments, getRespondentDocuments, getResponseFromCourtSection,
getApplicationSections,
getCourtDocuments,
getRespondentDocuments,
getResponseFromCourtSection,
} from 'services/features/generalApplication/viewApplication/viewApplicationService';
import {queryParamNumber} from 'common/utils/requestUtils';
import {ApplicationResponse} from 'models/generalApplication/applicationResponse';
Expand All @@ -16,6 +27,7 @@ import {constructResponseUrlWithIdAndAppIdParams, constructResponseUrlWithIdPara
import {ApplicationTypeOption} from 'models/generalApplication/applicationType';
import {YesNoUpperCamelCase} from 'form/models/yesNo';
import {generateRedisKeyForGA} from 'modules/draft-store/draftStoreService';
import {isRespondentAllowedToRespond} from 'services/features/generalApplication/response/viewApplicationService';

const viewApplicationToRespondentController = Router();
const viewPath = 'features/generalApplication/response/view-application';
Expand All @@ -36,9 +48,10 @@ viewApplicationToRespondentController.get(GA_RESPONSE_VIEW_APPLICATION_URL, (asy
const additionalDocUrl = constructResponseUrlWithIdAndAppIdParams(req.params.id, applicationId, GA_UPLOAD_ADDITIONAL_DOCUMENTS_URL);
const responseFromCourt = await getResponseFromCourtSection(req, req.params.appId, lang);
const dashboardUrl = constructResponseUrlWithIdParams(claimId, DEFENDANT_SUMMARY_URL);
const isAllowedToRespond = isRespondentAllowedToRespond(applicationResponse);
const backLinkUrl = constructResponseUrlWithIdParams(claimId, GA_APPLICATION_RESPONSE_SUMMARY_URL);

await saveApplicationTypesToGaResponse(applicationResponse.state, generateRedisKeyForGA(req), applicationResponse.case_data.generalAppType.types);
await saveApplicationTypesToGaResponse(isAllowedToRespond, generateRedisKeyForGA(req), applicationResponse.case_data.generalAppType.types, applicationResponse.case_data.generalAppUrgencyRequirement);
res.render(viewPath, {
backLinkUrl,
summaryRows,
Expand All @@ -51,6 +64,7 @@ viewApplicationToRespondentController.get(GA_RESPONSE_VIEW_APPLICATION_URL, (asy
additionalDocUrl,
responseFromCourt,
dashboardUrl,
isAllowedToRespond,
});
} catch (error) {
next(error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {getDraftGAHWFDetails, saveDraftGAHWFDetails} from 'modules/draft-store/g
import { isApplicationVisibleToRespondent } from './response/generalApplicationResponseService';
import { iWantToLinks } from 'common/models/dashboard/iWantToLinks';
import { t } from 'i18next';
import {GeneralAppUrgencyRequirement} from 'models/generalApplication/response/urgencyRequirement';

const {Logger} = require('@hmcts/nodejs-logging');
const logger = Logger.getLogger('claimantResponseService');
Expand Down Expand Up @@ -481,9 +482,10 @@ export const getViewApplicationUrl = (claimId: string, claim: Claim, application
return `${constructResponseUrlWithIdAndAppIdParams(claimId, application.id, viewApplicationUrl)}?index=${index + 1}`;
};

export const saveApplicationTypesToGaResponse = async (gaState: ApplicationState, gaRedisKey: string, applicationTypes: ApplicationTypeOption[]): Promise<void> => {
if (gaState === ApplicationState.AWAITING_RESPONDENT_RESPONSE) {
export const saveApplicationTypesToGaResponse = async (isAllowedToRespond: boolean, gaRedisKey: string, applicationTypes: ApplicationTypeOption[], generalAppUrgencyRequirement: GeneralAppUrgencyRequirement): Promise<void> => {
if (isAllowedToRespond) {
const gaResponse = await getDraftGARespondentResponse(gaRedisKey);
gaResponse.generalAppUrgencyRequirement = generalAppUrgencyRequirement;
gaResponse.generalApplicationType = applicationTypes;
await saveDraftGARespondentResponse(gaRedisKey, gaResponse);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import {AppRequest} from 'common/models/AppRequest';
import config from 'config';
import {Application} from 'models/application';
import {GaServiceClient} from 'client/gaServiceClient';
import { toCcdGeneralApplicationWithResponse } from 'services/translation/generalApplication/ccdTranslation';
import { deleteDraftGARespondentResponseFromStore, getDraftGARespondentResponse } from './generalApplicationResponseStoreService';
import { generateRedisKeyForGA } from 'modules/draft-store/draftStoreService';
import {toCcdGeneralApplicationWithResponse} from 'services/translation/generalApplication/ccdTranslation';
import {
deleteDraftGARespondentResponseFromStore,
getDraftGARespondentResponse,
} from './generalApplicationResponseStoreService';
import {generateRedisKeyForGA} from 'modules/draft-store/draftStoreService';
import {YesNoUpperCamelCase} from 'form/models/yesNo';

const {Logger} = require('@hmcts/nodejs-logging');
const logger = Logger.getLogger('submitApplicationResponse');
Expand All @@ -16,9 +20,14 @@ export const submitApplicationResponse = async (req: AppRequest): Promise<Applic
try {
const applicationId = req.params.appId;
const gaRedisKey = generateRedisKeyForGA(req);
let application: Application;
const gaRespondentResponse = await getDraftGARespondentResponse(gaRedisKey);
const generalApplication = toCcdGeneralApplicationWithResponse(gaRespondentResponse);
const application = await gaServiceClient.submitRespondToApplicationEvent(applicationId, generalApplication, req);
if (gaRespondentResponse?.generalAppUrgencyRequirement?.generalAppUrgency === YesNoUpperCamelCase.YES) {
application = await gaServiceClient.submitRespondToApplicationEventForUrgent(applicationId, generalApplication, req);
} else {
application = await gaServiceClient.submitRespondToApplicationEvent(applicationId, generalApplication, req);
}
await deleteDraftGARespondentResponseFromStore(gaRedisKey);
return application;
} catch (err) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {ApplicationResponse} from 'models/generalApplication/applicationResponse';
import {ApplicationState} from 'models/generalApplication/applicationSummary';
import {YesNoUpperCamelCase} from 'form/models/yesNo';
import {isPastDeadline} from 'common/utils/dateUtils';

export const isRespondentAllowedToRespond = (applicationResponse: ApplicationResponse): boolean => {
const applicationResponseData = applicationResponse.case_data;
const isStateAwaitingResponse = applicationResponse.state === ApplicationState.AWAITING_RESPONDENT_RESPONSE;
const isUrgencyResponse = applicationResponseData.generalAppUrgencyRequirement.generalAppUrgency === YesNoUpperCamelCase.YES && (applicationResponseData.generalAppRespondentAgreement.hasAgreed === YesNoUpperCamelCase.YES || applicationResponse.case_data.generalAppInformOtherParty.isWithNotice === YesNoUpperCamelCase.YES);
const isAllowedToRespondForUrgent = isUrgencyResponse && !isPastDeadline(applicationResponseData.generalAppNotificationDeadlineDate) && !applicationResponseData.respondentsResponses && !applicationResponseData.judicialDecision && applicationResponse.state === ApplicationState.APPLICATION_SUBMITTED_AWAITING_JUDICIAL_DECISION;
return isStateAwaitingResponse || isAllowedToRespondForUrgent;
};
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,12 @@
}) }}
{% endif %}
</div>
{% if(isAllowedToRespond) %}
{{ govukButton({
text: t('COMMON.BUTTONS.RESPOND_TO_APPLICATION'),
href: redirectUrl
}) }}

{% endif %}
{{ govukButton({
text: t('COMMON.BUTTONS.CLOSE_AND_RETURN_TO_DASHBOARD'),
href: dashboardUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { CourtResponseSummaryList, ResponseButton } from 'common/models/generalA
jest.mock('../../../../../../../main/modules/oidc');
jest.mock('../../../../../../../main/services/features/generalApplication/viewApplication/viewApplicationService');
jest.mock('../../../../../../../main/app/client/gaServiceClient');

jest.mock('../../../../../../../main/services/features/generalApplication/response/viewApplicationService', () => ({isRespondentAllowedToRespond: jest.fn().mockReturnValue(false)}));
const mockedSummaryRows = getApplicationSections as jest.Mock;
const mockRespondentDocs = getRespondentDocuments as jest.Mock;
const mockApplicantDocs = getApplicantDocuments as jest.Mock;
Expand Down Expand Up @@ -185,24 +185,24 @@ describe('General Application - View application', () => {
const responseFromCourt : CourtResponseSummaryList[] = [];
const hearingNoticeRows : SummaryRow[] = [];
const judgeDirections = new CourtResponseSummaryList(judgeDirectionRows, new Date(),new ResponseButton('Judge Direction', ''));

judgeDirectionRows.push(
summaryRow(t('PAGES.GENERAL_APPLICATION.VIEW_APPLICATION.DATE_RESPONSE'), '1 Aug 2024'),
summaryRow(t('PAGES.GENERAL_APPLICATION.VIEW_APPLICATION.TYPE_RESPONSE'), 'Judge has made order'),
summaryRow(t('PAGES.GENERAL_APPLICATION.VIEW_APPLICATION.READ_RESPONSE'), '<a href="#">Judge Order</a>'));

const hearingNotices = new CourtResponseSummaryList(hearingNoticeRows);
hearingNoticeRows.push(
summaryRow(t('PAGES.GENERAL_APPLICATION.VIEW_APPLICATION.DATE_RESPONSE'), '2 Aug 2024'),
summaryRow(t('PAGES.GENERAL_APPLICATION.VIEW_APPLICATION.TYPE_RESPONSE'), 'Hearing Notice has been generated'),
summaryRow(t('PAGES.GENERAL_APPLICATION.VIEW_APPLICATION.READ_RESPONSE'), '<a href="#">Hearing Notice</a>'));
responseFromCourt.push(judgeDirections);
responseFromCourt.push(hearingNotices);

responseFromCourt.push(judgeDirections);
responseFromCourt.push(hearingNotices);

return Promise.resolve(responseFromCourt);
});

await request(app)
.get(GA_RESPONSE_VIEW_APPLICATION_URL)
.query({index: '1'})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,11 @@ describe('Save Accept defendant offer', () => {
const mockGetDraft = getDraftGARespondentResponse as jest.Mock;
const mockSaveDraft = saveDraftGARespondentResponse as jest.Mock;
mockGetDraft.mockResolvedValue(new GaResponse());
await saveApplicationTypesToGaResponse(ApplicationState.AWAITING_RESPONDENT_RESPONSE, '12345', [ApplicationTypeOption.STAY_THE_CLAIM]);
await saveApplicationTypesToGaResponse(true, '12345', [ApplicationTypeOption.STAY_THE_CLAIM], {
generalAppUrgency: YesNoUpperCamelCase.YES,
reasonsForUrgency: '',
urgentAppConsiderationDate: '2025-10-10',
});
expect(mockSaveDraft).toHaveBeenCalled();
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ import {AppRequest} from 'models/AppRequest';
import {submitApplicationResponse} from 'services/features/generalApplication/response/submitApplicationResponse';
import {TestMessages} from '../../../../../utils/errorMessageTestConstants';
import {GaServiceClient} from 'client/gaServiceClient';
import { CCDGeneralApplication, CCDRespondToApplication } from 'common/models/gaEvents/eventDto';
import { CcdGARespondentDebtorOfferGAspec, CcdGeneralApplicationHearingDetails } from 'common/models/ccdGeneralApplication/ccdGeneralApplicationHearingDetails';
import {CCDGeneralApplication, CCDRespondToApplication} from 'common/models/gaEvents/eventDto';
import {
CcdGARespondentDebtorOfferGAspec,
CcdGeneralApplicationHearingDetails,
} from 'common/models/ccdGeneralApplication/ccdGeneralApplicationHearingDetails';
import * as CcdTraslation from 'services/translation/generalApplication/ccdTranslation';
import { configureSpy } from '../../../../../utils/spyConfiguration';
import * as GeneralApplicationResponseStoreService from 'services/features/generalApplication/response/generalApplicationResponseStoreService';
import {configureSpy} from '../../../../../utils/spyConfiguration';
import * as GeneralApplicationResponseStoreService
from 'services/features/generalApplication/response/generalApplicationResponseStoreService';
import {GaResponse} from 'models/generalApplication/response/gaResponse';
import {YesNoUpperCamelCase} from 'form/models/yesNo';

jest.mock('../../../../../../main/modules/draft-store/draftStoreService');
jest.mock('../../../../../../main/modules/utilityService');
Expand Down Expand Up @@ -50,6 +56,36 @@ describe('Submit application to ccd', () => {
'17012012', ccdGaWithResponse, req);
});

it('should submit claim successfully for urgent cases', async () => {
const ccdGaWithResponse: Partial<CCDRespondToApplication> = {
hearingDetailsResp: {} as CcdGeneralApplicationHearingDetails,
gaRespondentDebtorOffer: {} as CcdGARespondentDebtorOfferGAspec,
};

ccdTranslationServiceMock.mockReturnValue(ccdGaWithResponse as CCDGeneralApplication);
const gaResponse = new GaResponse();
gaResponse.generalAppUrgencyRequirement = {
generalAppUrgency: YesNoUpperCamelCase.YES,
urgentAppConsiderationDate: '2025-10-10',
};
mockGetDraftGARespondentResponse.mockResolvedValue(gaResponse);
const submitRespondToApplicationEventForUrgentEventMock = configureSpy(GaServiceClient.prototype, 'submitRespondToApplicationEventForUrgent')
.mockResolvedValue({id: '17012012'});

(req as AppRequest).params = {id: '123', appId: '17012012'};
req.session.user = {...req.session?.user, id: 'a1b2'};

//When
const result = await submitApplicationResponse(req as AppRequest);

//then
expect(result).toMatchObject({id: '17012012'});
expect(ccdTranslationServiceMock).toBeCalledWith(claim.generalApplication);
expect(submitRespondToApplicationEventForUrgentEventMock).toHaveBeenCalled();
expect(submitRespondToApplicationEventForUrgentEventMock).toBeCalledWith(
'17012012', ccdGaWithResponse, req);
});

it('should return http 500 when has error in the get method', async () => {
mockGetDraftGARespondentResponse.mockRejectedValueOnce(new Error(TestMessages.REDIS_FAILURE));

Expand Down
Loading

0 comments on commit c81b9ea

Please sign in to comment.