diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index 0c17c09c93..a7b0c72939 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -74,7 +74,8 @@ public void configure(final ConfigBuilder builder) { .field("nextStepsMarkdown", NEVER_SHOW); builder.tab("summary", "Summary") - .showCondition(ShowConditions.stateNotEquals(AWAITING_SUBMISSION_TO_HMCTS)) + .label("confirmEvictionSummaryMarkupLabel", null, "${confirmEvictionSummaryMarkup}") + .field("confirmEvictionSummaryMarkup", NEVER_SHOW) .field(PCSCase::getPropertyAddress); builder.tab("CaseHistory", "History") diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index 67c12b6cea..fe2ee2fd1d 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -13,6 +13,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.State; +import uk.gov.hmcts.reform.pcs.ccd.enforcementorder.EnforcementOrderMediator; import uk.gov.hmcts.reform.pcs.ccd.entity.AddressEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.PcsCaseEntity; @@ -69,7 +70,7 @@ public class PCSCaseView implements CaseView { private final NoticeOfPossessionView noticeOfPossessionView; private final StatementOfTruthView statementOfTruthView; private final CaseFieldsView caseFieldsView; - + private final EnforcementOrderMediator enforcementOrderMediator; /** * Invoked by CCD to load PCS cases by reference. @@ -80,12 +81,12 @@ public PCSCase getCase(CaseViewRequest request) { long caseReference = request.caseRef(); State state = request.state(); PCSCase pcsCase = getSubmittedCase(caseReference); - boolean hasUnsubmittedCaseData = caseHasUnsubmittedData(caseReference, state); caseFieldsView.setCaseFields(pcsCase); setMarkdownFields(pcsCase, hasUnsubmittedCaseData); + enforcementOrderMediator.handleEnforcementRequirements(caseReference, pcsCase); //allows indexing for Global Search pcsCase.setSearchCriteria(new SearchCriteria()); diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index 51e0ef2d04..cd3af19b6e 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -532,4 +532,10 @@ public class PCSCase { ) private String caseManagementLocationFormatted; + @CCD(searchable = false) + private String confirmEvictionSummaryMarkup; + + @CCD(searchable = false, access = {ClaimantAccess.class}) + private YesOrNo showConfirmEvictionJourney; + } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/enforcementorder/EnforcementOrderMediator.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/enforcementorder/EnforcementOrderMediator.java new file mode 100644 index 0000000000..7b4d89f3a8 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/enforcementorder/EnforcementOrderMediator.java @@ -0,0 +1,82 @@ +package uk.gov.hmcts.reform.pcs.ccd.enforcementorder; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.ccd.sdk.type.YesOrNo; +import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity; +import uk.gov.hmcts.reform.pcs.ccd.entity.PcsCaseEntity; +import uk.gov.hmcts.reform.pcs.ccd.entity.enforcetheorder.EnforcementOrderEntity; +import uk.gov.hmcts.reform.pcs.ccd.repository.PcsCaseRepository; +import uk.gov.hmcts.reform.pcs.ccd.repository.enforcetheorder.EnforcementOrderRepository; +import uk.gov.hmcts.reform.pcs.exception.CaseNotFoundException; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Locale; +import java.util.Optional; + +import static uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction.MarkupContent.CONFIRM_EVICTION_SUMMARY_NO_DATES; +import static uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction.MarkupContent.CONFIRM_EVICTION_SUMMARY_WITH_DATES; + +@Component +@Slf4j +@AllArgsConstructor +public class EnforcementOrderMediator { + + private final PcsCaseRepository pcsCaseRepository; + private final EnforcementOrderRepository enforcementOrderRepository; + + public void handleEnforcementRequirements(long caseReference, PCSCase pcsCase) { + if (caseReference > 0 && pcsCase != null) { + getEnforcementOrder(caseReference).ifPresent(enforcementOrderEntity -> + Optional.ofNullable(enforcementOrderEntity.getBailiffDate()) + .ifPresentOrElse( + date -> prepareEvictionWithDates(pcsCase, date), + () -> prepareEvictionWithNoDates(pcsCase) + )); + } + } + + Optional getEnforcementOrder(long caseReference) { + PcsCaseEntity pcsCaseEntity = pcsCaseRepository.findByCaseReference(caseReference) + .orElseThrow(() -> new CaseNotFoundException(caseReference)); + List claims = pcsCaseEntity.getClaims(); + if (claims != null && !claims.isEmpty()) { + // At this point we do not know which Enforcement Order the Confirm Eviction is placed against. + // this to be confirmed beyond this ticket scope (HDPI-4312) + List enforcementOrderEntities = enforcementOrderRepository + .findByClaimId(claims.getFirst().getId()); + if (!enforcementOrderEntities.isEmpty()) { + return Optional.of(enforcementOrderEntities.getFirst()); + } + } + return Optional.empty(); + } + + private void prepareEvictionWithDates(PCSCase pcsCase, LocalDateTime localDateTime) { + pcsCase.setShowConfirmEvictionJourney(YesOrNo.YES); + pcsCase.setConfirmEvictionSummaryMarkup(String.format( + CONFIRM_EVICTION_SUMMARY_WITH_DATES, + formatDate(localDateTime), + getEvictionCancellationDeadline(localDateTime))); + } + + private static void prepareEvictionWithNoDates(PCSCase pcsCase) { + pcsCase.setShowConfirmEvictionJourney(YesOrNo.NO); + pcsCase.setConfirmEvictionSummaryMarkup(CONFIRM_EVICTION_SUMMARY_NO_DATES); + } + + public String formatDate(LocalDateTime localDateTime) { + DateTimeFormatter outputFormatter = DateTimeFormatter + .ofPattern("EEEE, d MMMM yyyy 'at' h:mm a", Locale.UK); + return localDateTime.format(outputFormatter); + } + + public String getEvictionCancellationDeadline(LocalDateTime localDateTime) { + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.UK); + return localDateTime.minusHours(72).format(outputFormatter); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/entity/enforcetheorder/EnforcementOrderEntity.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/entity/enforcetheorder/EnforcementOrderEntity.java index 3a90601007..a08612a90a 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/entity/enforcetheorder/EnforcementOrderEntity.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/entity/enforcetheorder/EnforcementOrderEntity.java @@ -10,13 +10,16 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; import uk.gov.hmcts.reform.pcs.ccd.domain.enforcetheorder.EnforcementOrder; import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity; +import java.time.LocalDateTime; import java.util.UUID; import static jakarta.persistence.FetchType.LAZY; @@ -25,6 +28,8 @@ @Table(name = "enf_case") @Getter @Setter +@NoArgsConstructor +@AllArgsConstructor public class EnforcementOrderEntity { @Id @@ -43,4 +48,7 @@ public class EnforcementOrderEntity { @OneToOne(mappedBy = "enforcementOrder", fetch = LAZY) private WarrantEntity warrantDetails; + @Column(name = "bailiff_date") + private LocalDateTime bailiffDate; + } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/event/EventId.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/event/EventId.java index 3a84e15878..8e48fabc23 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/event/EventId.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/event/EventId.java @@ -7,5 +7,6 @@ public enum EventId { enforceTheOrder, respondPossessionClaim, submitDefendantResponse, - createTestCase + createTestCase, + confirmEviction } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/event/confirmeviction/ConfirmEviction.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/event/confirmeviction/ConfirmEviction.java new file mode 100644 index 0000000000..7357d5fcfd --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/event/confirmeviction/ConfirmEviction.java @@ -0,0 +1,41 @@ +package uk.gov.hmcts.reform.pcs.ccd.event.confirmeviction; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.ccd.sdk.api.CCDConfig; +import uk.gov.hmcts.ccd.sdk.api.DecentralisedConfigBuilder; +import uk.gov.hmcts.ccd.sdk.api.Event; +import uk.gov.hmcts.ccd.sdk.api.EventPayload; +import uk.gov.hmcts.ccd.sdk.api.Permission; +import uk.gov.hmcts.ccd.sdk.api.callback.SubmitResponse; +import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; +import uk.gov.hmcts.reform.pcs.ccd.common.PageBuilder; +import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.domain.State; +import uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction.ConfirmEvictionConfigurer; + +import static uk.gov.hmcts.reform.pcs.ccd.event.EventId.confirmEviction; + +@Component +@AllArgsConstructor +public class ConfirmEviction implements CCDConfig { + + private final ConfirmEvictionConfigurer confirmEvictionConfigurer; + + @Override + public void configureDecentralised(DecentralisedConfigBuilder configBuilder) { + Event.EventBuilder eventBuilder = + configBuilder + .decentralisedEvent(confirmEviction.name(), this::submit) + .forAllStates() + .name("Confirm the eviction details") + .grant(Permission.CRUD, UserRole.PCS_SOLICITOR) + .showSummary(); + confirmEvictionConfigurer.configurePages(new PageBuilder(eventBuilder)); + } + + private SubmitResponse submit(EventPayload eventPayload) { + return SubmitResponse.defaultResponse(); + } + +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionConfigurer.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionConfigurer.java new file mode 100644 index 0000000000..393290c726 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionConfigurer.java @@ -0,0 +1,18 @@ +package uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.reform.pcs.ccd.common.PageBuilder; +import uk.gov.hmcts.reform.pcs.ccd.common.PageConfigurer; + +@Component +@AllArgsConstructor +public class ConfirmEvictionConfigurer implements PageConfigurer { + + @Override + public void configurePages(PageBuilder pageBuilder) { + pageBuilder + .add(new ConfirmEvictionDetailsPage()) + .add(new EvictionDatePage()); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionDetailsPage.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionDetailsPage.java new file mode 100644 index 0000000000..252ac449c1 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionDetailsPage.java @@ -0,0 +1,56 @@ +package uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction; + +import uk.gov.hmcts.reform.pcs.ccd.common.CcdPageConfiguration; +import uk.gov.hmcts.reform.pcs.ccd.common.PageBuilder; +import uk.gov.hmcts.reform.pcs.ccd.page.CcdPage; + +public class ConfirmEvictionDetailsPage implements CcdPageConfiguration, CcdPage { + + public static final String CONFIRM_EVICTION_DETAILS_CONTENT = """ +

+ The bailiff has arranged a date for the eviction and they need you to confirm if you are + available. +

+

+ They will also ask you to confirm if the person being evicted poses any risk. +

+

+ The bailiff needs this information to carry out the eviction safely. If you do not provide it, + they may not be able to complete the eviction. +

+

What you’ll need +

+

You’ll need to know:

+
    +
  • who will attend the eviction (you, or someone else)
  • +
  • if you (or they) can attend the eviction on the date suggested + by the bailiff
  • +
+

We will also ask you to:

+
    +
  • describe the person who will be evicted
  • +
  • tell us how to access the property
  • +
  • book a locksmith (this is to make sure that the person being + evicted cannot return to the property)
  • +
+

+ Once you have confirmed the eviction date, we’ll send you an email reminding you to book a + locksmith. +

+ """; + + @Override + public void addTo(PageBuilder pageBuilder) { + String pageKey = getPageKey(); + pageBuilder + .page(pageKey) + .pageLabel("Confirm the eviction details") + .label(pageKey + "-line-separator", "---") + .label(pageKey + "-content", CONFIRM_EVICTION_DETAILS_CONTENT); + } + + @Override + public String getPageKey() { + return CcdPage.derivePageKey(this.getClass()); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/EvictionDatePage.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/EvictionDatePage.java new file mode 100644 index 0000000000..beebe71a6e --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/EvictionDatePage.java @@ -0,0 +1,23 @@ +package uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction; + +import uk.gov.hmcts.reform.pcs.ccd.common.CcdPageConfiguration; +import uk.gov.hmcts.reform.pcs.ccd.common.PageBuilder; +import uk.gov.hmcts.reform.pcs.ccd.page.CcdPage; + +public class EvictionDatePage implements CcdPageConfiguration, CcdPage { + + @Override + public void addTo(PageBuilder pageBuilder) { + String pageKey = getPageKey(); + pageBuilder + .page(pageKey) + .pageLabel("The eviction date") + .label(pageKey + "-line-separator", "---"); + } + + @Override + public String getPageKey() { + return CcdPage.derivePageKey(this.getClass()); + } + +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/MarkupContent.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/MarkupContent.java new file mode 100644 index 0000000000..7eae698f3e --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/MarkupContent.java @@ -0,0 +1,61 @@ +package uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MarkupContent { + + public static String CONFIRM_EVICTION_SUMMARY_WITH_DATES = + """ +

Confirm the eviction date

+

+ The bailiff has given you an eviction date of %s. +

+

+ They need you to confirm if you are available on this date. +

+

+ You must confirm the eviction details before %s. + If you try to confirm the eviction after this + date, the bailiff will cancel your eviction. +

+

+ They will also ask you to confirm if the defendants + (the person or people being evicted) pose any risk to the + bailiff. +

+

+ The bailiff needs this information to carry out the eviction + safely. +

+

+ To confirm the eviction date, select ‘Confirm the eviction + date’ from the dropdown menu. +

+ """; + + public static String CONFIRM_EVICTION_SUMMARY_NO_DATES = + """ +

You cannot enforce the order at the moment

+

+ You cannot enforce the order at the moment (use a bailiff to evict someone). +

+

How to find out why you cannot + enforce the order +

+

To find out why you cannot enforce the order, you can:

+
    +
  • check the tab: ‘Case file view’ (you should see an order from the court, + explaining why you cannot enforce), or
  • +
  • + + contact your local court. You will need to tell them your case number + (you can find this at the top of this page). If you do not know the name of your local court, select the + ‘Money’ category and then the ‘Housing’ category to find it.
  • +
+ """; + +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/repository/enforcetheorder/EnforcementOrderRepository.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/repository/enforcetheorder/EnforcementOrderRepository.java index a7c0ce7e94..357e38d522 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/repository/enforcetheorder/EnforcementOrderRepository.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/repository/enforcetheorder/EnforcementOrderRepository.java @@ -3,8 +3,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import uk.gov.hmcts.reform.pcs.ccd.entity.enforcetheorder.EnforcementOrderEntity; +import java.util.List; import java.util.UUID; public interface EnforcementOrderRepository extends JpaRepository { - + List findByClaimId(UUID claimId); } diff --git a/src/main/resources/db/migration/V075__add_bailiff_date_enf_case.sql b/src/main/resources/db/migration/V075__add_bailiff_date_enf_case.sql new file mode 100644 index 0000000000..75e441cc17 --- /dev/null +++ b/src/main/resources/db/migration/V075__add_bailiff_date_enf_case.sql @@ -0,0 +1,2 @@ +ALTER TABLE enf_case + ADD COLUMN bailiff_date timestamp; diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java index 325c41f5f3..3b28ed7be9 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java @@ -13,6 +13,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.State; +import uk.gov.hmcts.reform.pcs.ccd.enforcementorder.EnforcementOrderMediator; import uk.gov.hmcts.reform.pcs.ccd.entity.AddressEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.DocumentEntity; @@ -96,6 +97,8 @@ class PCSCaseViewTest { private ClaimEntity claimEntity; @Mock private CaseFieldsView caseFieldsView; + @Mock + private EnforcementOrderMediator enforcementOrderMediator; private PCSCaseView underTest; @@ -108,7 +111,7 @@ void setUp() { caseTitleService, claimView, tenancyLicenceView, claimGroundsView, rentDetailsView, alternativesToPossessionView, housingActWalesView, asbProhibitedConductView, rentArrearsView, noticeOfPossessionView, - statementOfTruthView, caseFieldsView + statementOfTruthView, caseFieldsView, enforcementOrderMediator ); } @@ -345,6 +348,15 @@ void shouldSetCaseFields() { verify(caseFieldsView).setCaseFields(pcsCase); } + @Test + void shouldCallEnforcementOrderMediator() { + // When + PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); + + // Then + verify(enforcementOrderMediator).handleEnforcementRequirements(CASE_REFERENCE, pcsCase); + } + private AddressUK stubAddressEntityModelMapper(AddressEntity addressEntity) { AddressUK addressUK = mock(AddressUK.class); when(modelMapper.map(addressEntity, AddressUK.class)).thenReturn(addressUK); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/enforcementorder/EnforcementOrderMediatorTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/enforcementorder/EnforcementOrderMediatorTest.java new file mode 100644 index 0000000000..f75542a0ce --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/enforcementorder/EnforcementOrderMediatorTest.java @@ -0,0 +1,352 @@ +package uk.gov.hmcts.reform.pcs.ccd.enforcementorder; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.ccd.sdk.type.YesOrNo; +import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.domain.enforcetheorder.EnforcementOrder; +import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity; +import uk.gov.hmcts.reform.pcs.ccd.entity.PcsCaseEntity; +import uk.gov.hmcts.reform.pcs.ccd.entity.enforcetheorder.EnforcementOrderEntity; +import uk.gov.hmcts.reform.pcs.ccd.repository.PcsCaseRepository; +import uk.gov.hmcts.reform.pcs.ccd.repository.enforcetheorder.EnforcementOrderRepository; +import uk.gov.hmcts.reform.pcs.exception.CaseNotFoundException; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class EnforcementOrderMediatorTest { + + private static final long CASE_REFERENCE = 1234567890L; + + @Mock + private PcsCaseRepository pcsCaseRepository; + @Mock + private EnforcementOrderRepository enforcementOrderRepository; + + @InjectMocks + private EnforcementOrderMediator underTest; + + private PCSCase pcsCase; + + @BeforeEach + void beforeEach() { + pcsCase = PCSCase.builder() + .enforcementOrder(EnforcementOrder.builder().build()) + .build(); + } + + @Test + void shouldSetShowConfirmEvictionJourneyToYesWhenBailiffDateExists() { + // Given + long caseReference = 1234567890L; + LocalDateTime bailiffDate = LocalDateTime.parse("2026-04-15T10:00:00"); + + PcsCaseEntity pcsCaseEntity = createPcsCaseEntity(); + EnforcementOrderEntity enforcementOrderEntity = createEnforcementOrderEntity(bailiffDate); + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.of(pcsCaseEntity)); + when(enforcementOrderRepository.findByClaimId(any(UUID.class))) + .thenReturn(List.of(enforcementOrderEntity)); + + // When + underTest.handleEnforcementRequirements(caseReference, pcsCase); + + // Then + assertEquals(YesOrNo.YES, pcsCase.getShowConfirmEvictionJourney()); + assertNotNull(pcsCase.getConfirmEvictionSummaryMarkup()); + assertTrue(pcsCase.getConfirmEvictionSummaryMarkup().contains("Confirm the eviction date")); + verify(pcsCaseRepository).findByCaseReference(caseReference); + verify(enforcementOrderRepository).findByClaimId(any(UUID.class)); + } + + @Test + void shouldSetShowConfirmEvictionJourneyToNoWhenBailiffDateIsNull() { + // Given + long caseReference = 1234567890L; + PcsCaseEntity pcsCaseEntity = createPcsCaseEntity(); + EnforcementOrderEntity enforcementOrderEntity = createEnforcementOrderEntity(null); + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.of(pcsCaseEntity)); + when(enforcementOrderRepository.findByClaimId(any(UUID.class))) + .thenReturn(List.of(enforcementOrderEntity)); + + // When + underTest.handleEnforcementRequirements(caseReference, pcsCase); + + // Then + assertEquals(YesOrNo.NO, pcsCase.getShowConfirmEvictionJourney()); + assertNotNull(pcsCase.getConfirmEvictionSummaryMarkup()); + assertTrue(pcsCase.getConfirmEvictionSummaryMarkup().contains("You cannot enforce the order at the moment")); + verify(pcsCaseRepository).findByCaseReference(caseReference); + verify(enforcementOrderRepository).findByClaimId(any(UUID.class)); + } + + @Test + void shouldFormatBailiffDateCorrectlyInMarkup() { + // Given + long caseReference = 1234567890L; + LocalDateTime bailiffDate = LocalDateTime.parse("2026-05-20T14:30:00"); + + PcsCaseEntity pcsCaseEntity = createPcsCaseEntity(); + EnforcementOrderEntity enforcementOrderEntity = createEnforcementOrderEntity(bailiffDate); + + when(pcsCaseRepository.findByCaseReference(caseReference)).thenReturn(Optional.of(pcsCaseEntity)); + when(enforcementOrderRepository.findByClaimId(any(UUID.class))).thenReturn(List.of(enforcementOrderEntity)); + + // When + underTest.handleEnforcementRequirements(caseReference, pcsCase); + + // Then + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("EEEE, d MMMM yyyy", Locale.UK); + String expectedDate = bailiffDate.atZone(ZoneId.of("UTC")).format(outputFormatter); + assertTrue(pcsCase.getConfirmEvictionSummaryMarkup().contains(expectedDate)); + } + + @Test + void shouldCalculateDeadlineDateAsMinus72HoursFromBailiffDate() { + // Given + long caseReference = 1234567890L; + LocalDateTime bailiffDate = LocalDateTime.parse("2026-05-20T14:30:00"); + + PcsCaseEntity pcsCaseEntity = createPcsCaseEntity(); + EnforcementOrderEntity enforcementOrderEntity = createEnforcementOrderEntity(bailiffDate); + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.of(pcsCaseEntity)); + when(enforcementOrderRepository.findByClaimId(any(UUID.class))) + .thenReturn(List.of(enforcementOrderEntity)); + + // When + underTest.handleEnforcementRequirements(caseReference, pcsCase); + + // Then + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.UK); + String expectedDeadline = bailiffDate.atZone(ZoneId.of("UTC")).minusHours(72).format(outputFormatter); + assertTrue(pcsCase.getConfirmEvictionSummaryMarkup().contains(expectedDeadline)); + } + + @Test + void shouldNotProcessWhenCaseReferenceIsZero() { + // Given + long caseReference = 0L; + + // When + underTest.handleEnforcementRequirements(caseReference, pcsCase); + + // Then + assertNull(pcsCase.getShowConfirmEvictionJourney()); + assertNull(pcsCase.getConfirmEvictionSummaryMarkup()); + verify(pcsCaseRepository, never()).findByCaseReference(anyLong()); + } + + @Test + void shouldNotProcessWhenCaseReferenceIsNegative() { + // Given + long caseReference = -1L; + + // When + underTest.handleEnforcementRequirements(caseReference, pcsCase); + + // Then + assertNull(pcsCase.getShowConfirmEvictionJourney()); + assertNull(pcsCase.getConfirmEvictionSummaryMarkup()); + verify(pcsCaseRepository, never()).findByCaseReference(anyLong()); + } + + @Test + void shouldNotProcessWhenPcsCaseIsNull() { + // Given + long caseReference = 1234567890L; + + // When + underTest.handleEnforcementRequirements(caseReference, null); + + // Then + verify(pcsCaseRepository, never()).findByCaseReference(anyLong()); + } + + @Test + void shouldThrowCaseNotFoundExceptionWhenCaseDoesNotExist() { + // Given + long caseReference = 1234567890L; + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.empty()); + + // When & Then + assertThrows(CaseNotFoundException.class, () -> + underTest.handleEnforcementRequirements(caseReference, pcsCase) + ); + verify(pcsCaseRepository).findByCaseReference(caseReference); + } + + @Test + void shouldReturnEmptyWhenClaimsListIsNull() { + // Given + long caseReference = 1234567890L; + PcsCaseEntity pcsCaseEntity = new PcsCaseEntity(); + pcsCaseEntity.setClaims(null); + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.of(pcsCaseEntity)); + + // When + Optional result = underTest.getEnforcementOrder(caseReference); + + // Then + assertTrue(result.isEmpty()); + verify(pcsCaseRepository).findByCaseReference(caseReference); + verify(enforcementOrderRepository, never()).findByClaimId(any()); + } + + @Test + void shouldReturnEmptyWhenClaimsListIsEmpty() { + // Given + long caseReference = 1234567890L; + PcsCaseEntity pcsCaseEntity = new PcsCaseEntity(); + pcsCaseEntity.setClaims(new ArrayList<>()); + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.of(pcsCaseEntity)); + + // When + Optional result = underTest.getEnforcementOrder(caseReference); + + // Then + assertTrue(result.isEmpty()); + verify(pcsCaseRepository).findByCaseReference(caseReference); + verify(enforcementOrderRepository, never()).findByClaimId(any()); + } + + @Test + void shouldReturnEnforcementOrderWhenFound() { + // Given + long caseReference = 1234567890L; + PcsCaseEntity pcsCaseEntity = createPcsCaseEntity(); + EnforcementOrderEntity enforcementOrderEntity = createEnforcementOrderEntity(LocalDateTime.now()); + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.of(pcsCaseEntity)); + when(enforcementOrderRepository.findByClaimId(any(UUID.class))) + .thenReturn(List.of(enforcementOrderEntity)); + + // When + Optional result = underTest.getEnforcementOrder(caseReference); + + // Then + assertTrue(result.isPresent()); + assertEquals(enforcementOrderEntity, result.get()); + verify(pcsCaseRepository).findByCaseReference(caseReference); + verify(enforcementOrderRepository).findByClaimId(any(UUID.class)); + } + + @Test + void shouldReturnEmptyWhenEnforcementOrderNotFound() { + // Given + PcsCaseEntity pcsCaseEntity = createPcsCaseEntity(); + + when(pcsCaseRepository.findByCaseReference(CASE_REFERENCE)).thenReturn(Optional.of(pcsCaseEntity)); + when(enforcementOrderRepository.findByClaimId(any(UUID.class))).thenReturn(List.of()); + + // When + Optional result = underTest.getEnforcementOrder(CASE_REFERENCE); + + // Then + assertTrue(result.isEmpty()); + verify(pcsCaseRepository).findByCaseReference(CASE_REFERENCE); + verify(enforcementOrderRepository).findByClaimId(any(UUID.class)); + } + + @Test + void shouldNotSetMarkupWhenEnforcementOrderNotPresent() { + // Given + long caseReference = 1234567890L; + PcsCaseEntity pcsCaseEntity = createPcsCaseEntity(); + + when(pcsCaseRepository.findByCaseReference(caseReference)) + .thenReturn(Optional.of(pcsCaseEntity)); + when(enforcementOrderRepository.findByClaimId(any(UUID.class))).thenReturn(List.of()); + + // When + underTest.handleEnforcementRequirements(caseReference, pcsCase); + + // Then + assertNull(pcsCase.getShowConfirmEvictionJourney()); + assertNull(pcsCase.getConfirmEvictionSummaryMarkup()); + verify(pcsCaseRepository).findByCaseReference(caseReference); + verify(enforcementOrderRepository).findByClaimId(any(UUID.class)); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("formatDateArguments") + void formatDate(String testName, LocalDateTime input, String expected) { + assertThat(underTest.formatDate(input)).isEqualTo(expected); + } + + private static Stream formatDateArguments() { + return Stream.of( + Arguments.of("morning time", + LocalDateTime.of(2025, 6, 9, 9, 30), + "Monday, 9 June 2025 at 9:30 am"), + Arguments.of("afternoon time", + LocalDateTime.of(2025, 6, 9, 14, 0), + "Monday, 9 June 2025 at 2:00 pm"), + Arguments.of("midnight", + LocalDateTime.of(2025, 6, 9, 0, 0), + "Monday, 9 June 2025 at 12:00 am"), + Arguments.of("noon", + LocalDateTime.of(2025, 6, 9, 12, 0), + "Monday, 9 June 2025 at 12:00 pm"), + Arguments.of("single digit day", + LocalDateTime.of(2025, 1, 3, 8, 15), + "Friday, 3 January 2025 at 8:15 am") + ); + } + + // Helper methods + private PcsCaseEntity createPcsCaseEntity() { + PcsCaseEntity entity = new PcsCaseEntity(); + ClaimEntity claimEntity = new ClaimEntity(); + claimEntity.setId(UUID.randomUUID()); + entity.setClaims(List.of(claimEntity)); + return entity; + } + + private EnforcementOrderEntity createEnforcementOrderEntity(LocalDateTime bailiffDate) { + EnforcementOrderEntity entity = new EnforcementOrderEntity(); + entity.setId(UUID.randomUUID()); + entity.setBailiffDate(bailiffDate); + return entity; + } + +} diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/PageConfigurerHelper.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/PageConfigurerHelper.java index 1298af5944..d07d45e5fd 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/PageConfigurerHelper.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/PageConfigurerHelper.java @@ -1,22 +1,25 @@ package uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.mockito.InOrder; import uk.gov.hmcts.reform.pcs.ccd.common.CcdPageConfiguration; -import uk.gov.hmcts.reform.pcs.ccd.page.builder.SavingPageBuilder; +import uk.gov.hmcts.reform.pcs.ccd.common.PageBuilder; import java.util.concurrent.atomic.AtomicInteger; import static org.mockito.ArgumentMatchers.isA; -public class PageConfigurerHelper { +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class PageConfigurerHelper { - public static void verifyAndCount(InOrder inOrder, SavingPageBuilder pageBuilder, + public static void verifyAndCount(InOrder inOrder, PageBuilder pageBuilder, Class pageClass, AtomicInteger counter) { inOrder.verify(pageBuilder).add(isA(pageClass)); counter.incrementAndGet(); } - public static void verifyAndCount(InOrder inOrder, SavingPageBuilder pageBuilder, + public static void verifyAndCount(InOrder inOrder, PageBuilder pageBuilder, CcdPageConfiguration specificInstance, AtomicInteger counter) { inOrder.verify(pageBuilder).add(specificInstance); counter.incrementAndGet(); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionPageConfigurerTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionPageConfigurerTest.java new file mode 100644 index 0000000000..78d642dc88 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/page/enforcetheorder/confirmeviction/ConfirmEvictionPageConfigurerTest.java @@ -0,0 +1,55 @@ +package uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.confirmeviction; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.reform.pcs.ccd.common.CcdPageConfiguration; +import uk.gov.hmcts.reform.pcs.ccd.common.PageBuilder; +import uk.gov.hmcts.reform.pcs.ccd.page.BasePageTest; + +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import static uk.gov.hmcts.reform.pcs.ccd.page.enforcetheorder.PageConfigurerHelper.verifyAndCount; + +@ExtendWith(MockitoExtension.class) +class ConfirmEvictionPageConfigurerTest extends BasePageTest { + + @InjectMocks + private ConfirmEvictionConfigurer underTest; + + @Test + @SuppressWarnings("squid:S5961") + void shouldConfigurePagesInCorrectOrder() { + // Given + PageBuilder pageBuilder = mock(PageBuilder.class); + when(pageBuilder.add(any())).thenReturn(pageBuilder); + + // When + underTest.configurePages(pageBuilder); + + // Then + ArgumentCaptor pageCaptor = ArgumentCaptor.forClass(CcdPageConfiguration.class); + InOrder inOrder = inOrder(pageBuilder); + Mockito.verify(pageBuilder, Mockito.atLeastOnce()).add(pageCaptor.capture()); + AtomicInteger verificationCount = new AtomicInteger(0); + + verifyAndCount(inOrder, pageBuilder, ConfirmEvictionDetailsPage.class, verificationCount); + verifyAndCount(inOrder, pageBuilder, EvictionDatePage.class, verificationCount); + + int numberOfPages = pageCaptor.getAllValues().size(); + assertThat(verificationCount.get()).isEqualTo(numberOfPages); + + verifyNoMoreInteractions(pageBuilder); + } +}