Skip to content

Commit

Permalink
Merge branch 'master' into NFDIV-3985
Browse files Browse the repository at this point in the history
  • Loading branch information
pallavijustice authored Feb 11, 2025
2 parents 4ee0fed + 275d859 commit c37c391
Show file tree
Hide file tree
Showing 51 changed files with 3,495 additions and 262 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ plugins {
id 'org.springframework.boot' version '3.3.5'
id 'com.github.ben-manes.versions' version '0.52.0'
id 'hmcts.ccd.sdk' version '5.5.16'
id 'com.github.hmcts.rse-cft-lib' version '0.19.1563'
id 'com.github.hmcts.rse-cft-lib' version '0.19.1573'
}

apply plugin: 'cz.habarta.typescript-generator'
Expand Down Expand Up @@ -270,7 +270,7 @@ dependencies {
}
implementation group: 'com.github.hmcts', name: 'ccd-client', version: '5.0.3'
implementation group: 'com.github.hmcts', name: 'idam-java-client', version: '3.0.3'
implementation group: 'com.github.hmcts', name: 'java-logging', version: '6.1.7'
implementation group: 'com.github.hmcts', name: 'java-logging', version: '6.1.8'
implementation group: 'com.github.hmcts', name: 'send-letter-client', version: '4.0.4'
implementation group: 'com.github.hmcts', name: 'service-auth-provider-java-client', version: '5.2.0'
implementation group: 'com.github.hmcts', name: 'ccd-case-document-am-client', version: '1.7.3'
Expand Down Expand Up @@ -327,7 +327,7 @@ dependencies {

// Provides fast-reload of just the NFDIV service.
cftlibImplementation 'org.springframework.boot:spring-boot-devtools'
cftlibTestImplementation 'com.microsoft.playwright:playwright:1.49.0'
cftlibTestImplementation 'com.microsoft.playwright:playwright:1.50.0'
cftlibTestImplementation 'org.junit-pioneer:junit-pioneer:2.3.0'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
import uk.gov.hmcts.divorce.idam.User;
import uk.gov.hmcts.reform.authorisation.generators.AuthTokenGenerator;
import uk.gov.hmcts.reform.ccd.client.CaseAssignmentApi;
import uk.gov.hmcts.reform.ccd.client.model.CaseAssignmentUserRole;
import uk.gov.hmcts.reform.ccd.client.model.CaseAssignmentUserRoleWithOrganisation;
import uk.gov.hmcts.reform.ccd.client.model.CaseAssignmentUserRolesRequest;
import uk.gov.hmcts.reform.ccd.client.model.CaseAssignmentUserRolesResource;
import uk.gov.hmcts.reform.idam.client.models.UserInfo;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -84,8 +88,23 @@ void shouldRetryRemovingRolesThreeTimesWhenRemovingRolesThrowsException() {
@Test
void shouldRetryAddCaseRolesThreeTimesWhenAddingCaseRolesThrowsException() {
when(idamService.retrieveUser(CASEWORKER_AUTH_TOKEN)).thenReturn(caseworkerUser());
when(idamService.retrieveSystemUpdateUserDetails()).thenReturn(caseworkerUser());
when(authTokenGenerator.generate()).thenReturn(TEST_SERVICE_AUTH_TOKEN);

var response = CaseAssignmentUserRolesResource.builder()
.caseAssignmentUserRoles(List.of(
CaseAssignmentUserRole.builder().userId("1").caseRole("NOT_THIS_ONE").build(),
CaseAssignmentUserRole.builder().userId("2").caseRole("NOT_THIS_ONE").build()
))
.build();

when(caseAssignmentApi.getUserRoles(
eq(CASEWORKER_AUTH_TOKEN),
eq(TEST_SERVICE_AUTH_TOKEN),
anyList()
)
).thenReturn(response);

doThrow(feignException(500, "some error"))
.when(caseAssignmentApi).addCaseUserRoles(
CASEWORKER_AUTH_TOKEN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import uk.gov.hmcts.ccd.sdk.api.CCDConfig;
import uk.gov.hmcts.ccd.sdk.api.CaseDetails;
Expand All @@ -13,9 +15,13 @@
import uk.gov.hmcts.divorce.caseworker.service.CaseFlagsService;
import uk.gov.hmcts.divorce.caseworker.service.NoticeOfChangeService;
import uk.gov.hmcts.divorce.citizen.notification.NocCitizenToSolsNotifications;
import uk.gov.hmcts.divorce.citizen.notification.NocSolsToCitizenNotifications;
import uk.gov.hmcts.divorce.common.ccd.PageBuilder;
import uk.gov.hmcts.divorce.divorcecase.model.Applicant;
import uk.gov.hmcts.divorce.divorcecase.model.ApplicationType;
import uk.gov.hmcts.divorce.divorcecase.model.CaseData;
import uk.gov.hmcts.divorce.divorcecase.model.CaseInvite;
import uk.gov.hmcts.divorce.divorcecase.model.CaseInviteApp1;
import uk.gov.hmcts.divorce.divorcecase.model.NoticeOfChange;
import uk.gov.hmcts.divorce.divorcecase.model.Solicitor;
import uk.gov.hmcts.divorce.divorcecase.model.State;
Expand All @@ -28,6 +34,8 @@
import java.util.ArrayList;
import java.util.List;

import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static uk.gov.hmcts.ccd.sdk.type.YesOrNo.NO;
import static uk.gov.hmcts.ccd.sdk.type.YesOrNo.YES;
import static uk.gov.hmcts.divorce.divorcecase.model.NoticeOfChange.WhichApplicant.APPLICANT_1;
Expand All @@ -54,6 +62,7 @@ public class CaseworkerNoticeOfChange implements CCDConfig<CaseData, State, User
private final SolicitorValidationService solicitorValidationService;
private final ChangeOfRepresentativeService changeOfRepresentativeService;
private final NocCitizenToSolsNotifications nocCitizenToSolsNotifications;
private final NocSolsToCitizenNotifications nocSolsToCitizenNotifications;
private final NotificationDispatcher notificationDispatcher;
private final CaseFlagsService caseFlagsService;

Expand Down Expand Up @@ -96,6 +105,7 @@ public void configure(final ConfigBuilder<CaseData, State, UserRole> configBuild
.optional(OrganisationPolicy::getOrgPolicyReference, NEVER_SHOW, true)
.done()
.done()
.optional(Applicant::getEmail, "nocWhichApplicant=\"applicant1\" AND nocAreTheyRepresented=\"No\"", true)
.mandatory(Applicant::getAddress, "nocWhichApplicant=\"applicant1\" AND nocAreTheyRepresented=\"No\"", true)
.mandatory(Applicant::getAddressOverseas, "nocWhichApplicant=\"applicant1\" AND nocAreTheyRepresented=\"No\"", true)
.done()
Expand All @@ -117,6 +127,7 @@ public void configure(final ConfigBuilder<CaseData, State, UserRole> configBuild
.optional(OrganisationPolicy::getOrgPolicyReference, NEVER_SHOW, true)
.done()
.done()
.optional(Applicant::getEmail, "nocWhichApplicant=\"applicant2\" AND nocAreTheyRepresented=\"No\"", true)
.mandatory(Applicant::getAddress, "nocWhichApplicant=\"applicant2\" AND nocAreTheyRepresented=\"No\"", true)
.mandatory(Applicant::getAddressOverseas, "nocWhichApplicant=\"applicant2\" AND nocAreTheyRepresented=\"No\"", true)
.done();
Expand All @@ -129,14 +140,28 @@ public AboutToStartOrSubmitResponse<CaseData, State> midEvent(
CaseData data = details.getData();
List<String> errors = new ArrayList<>();

final boolean isApplicant1 = data.getNoticeOfChange().getWhichApplicant() == APPLICANT_1;
final Applicant applicant = isApplicant1 ? data.getApplicant1() : data.getApplicant2();

if (data.getNoticeOfChange().getAreTheyRepresented().equals(NO)) {
CaseData beforeData = detailsBefore.getData();
final Applicant beforeApplicant = isApplicant1 ? beforeData.getApplicant1() : beforeData.getApplicant2();

if (isNotBlank(beforeApplicant.getEmail()) && isBlank(applicant.getEmail())) {
errors.add("Email address cannot be removed. It can only be updated.");
return AboutToStartOrSubmitResponse.<CaseData, State>builder()
.data(data)
.errors(errors)
.build();
}
}

if (data.getNoticeOfChange().isNotAddingNewDigitalSolicitor()) {
return AboutToStartOrSubmitResponse.<CaseData, State>builder()
.data(data)
.build();
}

final boolean isApplicant1 = data.getNoticeOfChange().getWhichApplicant() == APPLICANT_1;
final Applicant applicant = isApplicant1 ? data.getApplicant1() : data.getApplicant2();
String email = applicant.getSolicitor().getEmail();
String orgId = applicant.getSolicitor().getOrganisationPolicy().getOrganisation().getOrganisationId();

Expand Down Expand Up @@ -194,6 +219,14 @@ public AboutToStartOrSubmitResponse<CaseData, State> aboutToSubmit(
notificationDispatcher.sendNOC(nocCitizenToSolsNotifications, details.getData(),
beforeData, details.getId(), isApplicant1, noticeType);

if (hasRepresentationBeenRemoved(isApplicant1, data, beforeData)
&& shouldSendInviteToParty(data, isApplicant1)) {
//Send email to party with case invites
generateCaseInvite(data, isApplicant1, applicant);
notificationDispatcher.sendNOCCaseInvite(nocSolsToCitizenNotifications, details.getData(), details.getId(),
isApplicant1);
}

return AboutToStartOrSubmitResponse.<CaseData, State>builder()
.data(correctRepresentationDetails(details.getData(), beforeData))
.build();
Expand Down Expand Up @@ -309,4 +342,38 @@ private Solicitor solicitorWithDefaultOrganisationPolicy(Solicitor solicitor, Us
solicitor.setOrganisationPolicy(defaultOrgPolicy);
return solicitor;
}

private boolean shouldSendInviteToParty(final CaseData data, boolean isApplicant1) {
Applicant applicant = isApplicant1 ? data.getApplicant1() : data.getApplicant2();
boolean hasEmailAddressOnCase = StringUtils.isNotEmpty(applicant.getEmail());

return (hasEmailAddressOnCase
&& (data.getApplicationType() == ApplicationType.SOLE_APPLICATION)
&& (isApplicant1 || (!isApplicant1 && ObjectUtils.isNotEmpty(data.getApplication().getIssueDate()))));
}

private void generateCaseInvite(final CaseData data, boolean isApplicant1, Applicant applicant) {
if (isApplicant1) {
CaseInviteApp1 invite = CaseInviteApp1.builder()
.applicant1InviteEmailAddress(applicant.getEmail())
.build()
.generateAccessCode();
data.setCaseInviteApp1(invite);
} else {
CaseInvite invite = CaseInvite.builder()
.applicant2InviteEmailAddress(applicant.getEmail())
.build()
.generateAccessCode();
data.setCaseInvite(invite);
}
}

private boolean hasRepresentationBeenRemoved(final boolean isApplicant1,
final CaseData caseData,
final CaseData previousCaseData) {
Applicant beforeApplicant = isApplicant1 ? previousCaseData.getApplicant1() : previousCaseData.getApplicant2();
Applicant afterApplicant = isApplicant1 ? caseData.getApplicant1() : caseData.getApplicant2();

return beforeApplicant.isRepresented() && !afterApplicant.isRepresented();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package uk.gov.hmcts.divorce.caseworker.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import uk.gov.hmcts.ccd.sdk.api.CCDConfig;
import uk.gov.hmcts.ccd.sdk.api.CaseDetails;
import uk.gov.hmcts.ccd.sdk.api.ConfigBuilder;
import uk.gov.hmcts.ccd.sdk.api.callback.AboutToStartOrSubmitResponse;
import uk.gov.hmcts.divorce.caseworker.service.EmailUpdateService;
import uk.gov.hmcts.divorce.common.ccd.PageBuilder;
import uk.gov.hmcts.divorce.divorcecase.model.Applicant;
import uk.gov.hmcts.divorce.divorcecase.model.CaseData;
import uk.gov.hmcts.divorce.divorcecase.model.State;
import uk.gov.hmcts.divorce.divorcecase.model.UserRole;

import static java.util.Collections.singletonList;
import static uk.gov.hmcts.divorce.divorcecase.model.State.POST_SUBMISSION_STATES;
import static uk.gov.hmcts.divorce.divorcecase.model.UserRole.CASE_WORKER;
import static uk.gov.hmcts.divorce.divorcecase.model.UserRole.LEGAL_ADVISOR;
import static uk.gov.hmcts.divorce.divorcecase.model.UserRole.SOLICITOR;
import static uk.gov.hmcts.divorce.divorcecase.model.UserRole.SUPER_USER;
import static uk.gov.hmcts.divorce.divorcecase.model.access.Permissions.CREATE_READ_UPDATE_DELETE;

@Component
@Slf4j
public class CaseworkerUpdateApplicant1Email implements CCDConfig<CaseData, State, UserRole> {

public static final String CASEWORKER_UPDATE_APP1_EMAIL = "caseworker-update-app1-email";

@Autowired
private EmailUpdateService emailUpdateService;

private static final String EMAIL_LABEL = "${%s} email address";
private static final String APPLICANTS_OR_APPLICANT1S = "labelContentApplicantsOrApplicant1s";

@Override
public void configure(final ConfigBuilder<CaseData, State, UserRole> configBuilder) {
new PageBuilder(configBuilder
.event(CASEWORKER_UPDATE_APP1_EMAIL)
.forStates(POST_SUBMISSION_STATES)
.name("Update App or App1 Email")
.description("Update applicant/applicant1 email")
.aboutToSubmitCallback(this::aboutToSubmit)
.showSummary()
.showEventNotes()
.grant(CREATE_READ_UPDATE_DELETE, SUPER_USER, CASE_WORKER)
.grantHistoryOnly(
SOLICITOR,
LEGAL_ADVISOR))
.page("updateApp1Email", this::midEvent)
.pageLabel("Update applicant/applicant1 email")
.complex(CaseData::getApplicant1)
.optionalWithLabel(Applicant::getEmail, getLabel(EMAIL_LABEL, APPLICANTS_OR_APPLICANT1S))
.done();
}

public AboutToStartOrSubmitResponse<CaseData, State> midEvent(final CaseDetails<CaseData, State> details,
final CaseDetails<CaseData, State> detailsBefore) {
log.info("midEvent callback invoked for {}, Case Id: {}", CASEWORKER_UPDATE_APP1_EMAIL, details.getId());

CaseData caseData = details.getData();
CaseData caseDataBefore = detailsBefore.getData();

if (!validApplicant1Update(caseDataBefore, caseData)) {

return AboutToStartOrSubmitResponse.<CaseData, State>builder()
.errors(singletonList("You cannot leave the email field blank. "
+ "You can only use this event to update the email of the party."))
.build();
}

return AboutToStartOrSubmitResponse.<CaseData, State>builder()
.data(caseData)
.build();
}

public AboutToStartOrSubmitResponse<CaseData, State> aboutToSubmit(
final CaseDetails<CaseData, State> details,
final CaseDetails<CaseData, State> beforeDetails
) {
log.info("{} aboutToSubmit callback invoked for Case Id: {}", CASEWORKER_UPDATE_APP1_EMAIL, details.getId());

final CaseDetails<CaseData, State> result = emailUpdateService.processEmailUpdate(details, beforeDetails, true);

return AboutToStartOrSubmitResponse.<CaseData, State>builder()
.data(result.getData())
.build();
}

private boolean validApplicant1Update(CaseData caseDataBefore, CaseData caseData) {

if (caseDataBefore.getApplicant1().getEmail() != null && !caseDataBefore.getApplicant1().getEmail().isBlank()
&& (caseData.getApplicant1().getEmail() == null || caseData.getApplicant1().getEmail().isBlank())) {
return false;
}
return true;
}

private String getLabel(final String label, final Object... value) {
return String.format(label, value);
}
}
Loading

0 comments on commit c37c391

Please sign in to comment.