@@ -57,6 +57,11 @@ import org.junit.jupiter.params.provider.EnumSource
5757import org.junit.jupiter.params.provider.ValueSource
5858import org.springframework.beans.factory.annotation.Autowired
5959
60+ private const val EMAIL_PERUSTAJA = " pertti@perustaja.test"
61+ private const val EMAIL_OMISTAJA = " olivia.omistaja@mail.com"
62+ private const val EMAIL_RAKENNUTTAJA = " rane.rakennuttaja@mail.com"
63+ private const val EMAIL_ASIANHOITAJA = " anssi.asianhoitaja@mail.com"
64+
6065class HankeCompletionServiceITest (
6166 @Autowired private val hankeCompletionService : HankeCompletionService ,
6267 @Autowired private val hakemusFactory : HakemusFactory ,
@@ -411,6 +416,76 @@ class HankeCompletionServiceITest(
411416 }
412417 }
413418
419+ @Nested
420+ inner class IdsForUnmodifiedDraftReminders {
421+ private fun saveHanke (
422+ status : HankeStatus = HankeStatus .DRAFT ,
423+ modifiedDaysAgo : Long = DAYS_BEFORE_COMPLETING_DRAFT - 5,
424+ modifier : HankeBuilder .() -> HankeBuilder = { this },
425+ ) =
426+ hankeFactory.builder().modifier().saveEntity(status) {
427+ it.modifiedAt = getCurrentTimeUTCAsLocalTime().minusDays(modifiedDaysAgo)
428+ }
429+
430+ @EnumSource(HankeReminder ::class , names = [" DRAFT_COMPLETION_15" , " DRAFT_COMPLETION_5" ])
431+ @ParameterizedTest
432+ fun `returns empty list when there are no hanke` (reminder : HankeReminder ) {
433+ val result = hankeCompletionService.idsForUnmodifiedDraftReminders(reminder)
434+
435+ assertThat(result).isEmpty()
436+ }
437+
438+ @EnumSource(HankeReminder ::class , names = [" DRAFT_COMPLETION_15" , " DRAFT_COMPLETION_5" ])
439+ @ParameterizedTest
440+ fun `returns only draft hanke` (reminder : HankeReminder ) {
441+ saveHanke(status = HankeStatus .COMPLETED )
442+ val draft = saveHanke()
443+ saveHanke(status = HankeStatus .PUBLIC )
444+
445+ val result = hankeCompletionService.idsForUnmodifiedDraftReminders(reminder)
446+
447+ assertThat(result).containsExactly(draft.id)
448+ }
449+
450+ @EnumSource(HankeReminder ::class , names = [" DRAFT_COMPLETION_15" , " DRAFT_COMPLETION_5" ])
451+ @ParameterizedTest
452+ fun `returns only hanke with missing area end dates` (reminder : HankeReminder ) {
453+ val noAreas = saveHanke { withNoAreas() }
454+ saveHanke {
455+ withHankealue()
456+ withHankealue(haittaLoppuPvm = ZonedDateTime .now().minusMonths(7 ))
457+ }
458+ val missingEndDate = saveHanke {
459+ withHankealue()
460+ withHankealue(haittaLoppuPvm = null )
461+ }
462+
463+ val result = hankeCompletionService.idsForUnmodifiedDraftReminders(reminder)
464+
465+ assertThat(result).containsExactlyInAnyOrder(noAreas.id, missingEndDate.id)
466+ }
467+
468+ @EnumSource(HankeReminder ::class , names = [" DRAFT_COMPLETION_15" , " DRAFT_COMPLETION_5" ])
469+ @ParameterizedTest
470+ fun `returns only hanke that haven't been modified in a long time` (
471+ reminder : HankeReminder
472+ ) {
473+ val modifiedDaysAgo =
474+ when (reminder) {
475+ HankeReminder .DRAFT_COMPLETION_15 -> DAYS_BEFORE_COMPLETING_DRAFT - 15
476+ HankeReminder .DRAFT_COMPLETION_5 -> DAYS_BEFORE_COMPLETING_DRAFT - 5
477+ else -> throw IllegalArgumentException (" Unexpected reminder $reminder " )
478+ }
479+ val onTheDay = saveHanke(modifiedDaysAgo = modifiedDaysAgo)
480+ saveHanke(modifiedDaysAgo = modifiedDaysAgo - 1 )
481+ val beforeTheDay = saveHanke(modifiedDaysAgo = modifiedDaysAgo + 1 )
482+
483+ val result = hankeCompletionService.idsForUnmodifiedDraftReminders(reminder)
484+
485+ assertThat(result).containsExactly(beforeTheDay.id, onTheDay.id)
486+ }
487+ }
488+
414489 @Nested
415490 inner class IdsForDraftsToComplete {
416491 private fun saveHanke (
@@ -602,10 +677,10 @@ class HankeCompletionServiceITest(
602677 assertThat(recipients).hasSize(4 )
603678 assertThat(recipients)
604679 .containsExactlyInAnyOrder(
605- " pertti@perustaja.test " ,
606- " olivia.omistaja@mail.com " ,
607- " rane.rakennuttaja@mail.com " ,
608- " anssi.asianhoitaja@mail.com " ,
680+ EMAIL_PERUSTAJA ,
681+ EMAIL_OMISTAJA ,
682+ EMAIL_RAKENNUTTAJA ,
683+ EMAIL_ASIANHOITAJA ,
609684 )
610685 val email = emails.first()
611686 assertThat(email.subject)
@@ -731,11 +806,7 @@ class HankeCompletionServiceITest(
731806 val recipients = greenMail.receivedMessages.map { it.allRecipients.single().toString() }
732807 assertThat(recipients).hasSize(3 )
733808 assertThat(recipients)
734- .containsExactlyInAnyOrder(
735- " pertti@perustaja.test" ,
736- " omistaja@test" ,
737- " toteuttaja@test" ,
738- )
809+ .containsExactlyInAnyOrder(EMAIL_PERUSTAJA , " omistaja@test" , " toteuttaja@test" )
739810 }
740811
741812 @Test
@@ -841,7 +912,7 @@ class HankeCompletionServiceITest(
841912 assertThat(updatedHanke.sentReminders).containsExactly(HankeReminder .COMPLETION_5 )
842913 val email = greenMail.firstReceivedMessage()
843914 assertThat(email.allRecipients).hasSize(1 )
844- assertThat(email.allRecipients[0 ].toString()).isEqualTo(" pertti@perustaja.test " )
915+ assertThat(email.allRecipients[0 ].toString()).isEqualTo(EMAIL_PERUSTAJA )
845916 assertThat(email.subject)
846917 .isEqualTo(
847918 " Haitaton: Hankkeesi ${hanke.hankeTunnus} päättymispäivä lähenee " +
@@ -872,7 +943,7 @@ class HankeCompletionServiceITest(
872943 assertThat(updatedHanke.sentReminders).containsExactly(HankeReminder .COMPLETION_5 )
873944 val email = greenMail.firstReceivedMessage()
874945 assertThat(email.allRecipients).hasSize(1 )
875- assertThat(email.allRecipients[0 ].toString()).isEqualTo(" pertti@perustaja.test " )
946+ assertThat(email.allRecipients[0 ].toString()).isEqualTo(EMAIL_PERUSTAJA )
876947 assertThat(email.subject)
877948 .isEqualTo(
878949 " Haitaton: Hankkeesi ${hanke.hankeTunnus} päättymispäivä lähenee " +
@@ -1009,7 +1080,7 @@ class HankeCompletionServiceITest(
10091080 assertThat(updatedHanke.sentReminders).containsExactly(HankeReminder .COMPLETION_14 )
10101081 val email = greenMail.firstReceivedMessage()
10111082 assertThat(email.allRecipients).hasSize(1 )
1012- assertThat(email.allRecipients[0 ].toString()).isEqualTo(" pertti@perustaja.test " )
1083+ assertThat(email.allRecipients[0 ].toString()).isEqualTo(EMAIL_PERUSTAJA )
10131084 assertThat(email.subject)
10141085 .isEqualTo(
10151086 " Haitaton: Hankkeesi ${hanke.hankeTunnus} päättymispäivä lähenee " +
@@ -1043,7 +1114,7 @@ class HankeCompletionServiceITest(
10431114 assertThat(updatedHanke.sentReminders).containsExactly(HankeReminder .COMPLETION_14 )
10441115 val email = greenMail.firstReceivedMessage()
10451116 assertThat(email.allRecipients).hasSize(1 )
1046- assertThat(email.allRecipients[0 ].toString()).isEqualTo(" pertti@perustaja.test " )
1117+ assertThat(email.allRecipients[0 ].toString()).isEqualTo(EMAIL_PERUSTAJA )
10471118 assertThat(email.subject)
10481119 .isEqualTo(
10491120 " Haitaton: Hankkeesi ${hanke.hankeTunnus} päättymispäivä lähenee " +
@@ -1292,7 +1363,7 @@ class HankeCompletionServiceITest(
12921363 assertThat(updatedHanke.sentReminders).containsExactly(HankeReminder .DELETION_5 )
12931364 val email = greenMail.firstReceivedMessage()
12941365 assertThat(email.allRecipients).hasSize(1 )
1295- assertThat(email.allRecipients[0 ].toString()).isEqualTo(" pertti@perustaja.test " )
1366+ assertThat(email.allRecipients[0 ].toString()).isEqualTo(EMAIL_PERUSTAJA )
12961367 assertThat(email.subject)
12971368 .isEqualTo(
12981369 " Haitaton: Hankkeesi ${hanke.hankeTunnus} poistetaan järjestelmästä " +
@@ -1356,11 +1427,7 @@ class HankeCompletionServiceITest(
13561427 val recipients = greenMail.receivedMessages.map { it.allRecipients.single().toString() }
13571428 assertThat(recipients).hasSize(3 )
13581429 assertThat(recipients)
1359- .containsExactlyInAnyOrder(
1360- " pertti@perustaja.test" ,
1361- " omistaja@test" ,
1362- " toteuttaja@test" ,
1363- )
1430+ .containsExactlyInAnyOrder(EMAIL_PERUSTAJA , " omistaja@test" , " toteuttaja@test" )
13641431 }
13651432 }
13661433
@@ -1477,10 +1544,10 @@ class HankeCompletionServiceITest(
14771544 assertThat(recipients).hasSize(4 )
14781545 assertThat(recipients)
14791546 .containsExactlyInAnyOrder(
1480- " pertti@perustaja.test " ,
1481- " olivia.omistaja@mail.com " ,
1482- " rane.rakennuttaja@mail.com " ,
1483- " anssi.asianhoitaja@mail.com " ,
1547+ EMAIL_PERUSTAJA ,
1548+ EMAIL_OMISTAJA ,
1549+ EMAIL_RAKENNUTTAJA ,
1550+ EMAIL_ASIANHOITAJA ,
14841551 )
14851552 val email = emails.first()
14861553 assertThat(email.subject)
@@ -1496,6 +1563,131 @@ class HankeCompletionServiceITest(
14961563 }
14971564 }
14981565
1566+ @Nested
1567+ inner class SendUnmodifiedDraftReminderIfNecessary {
1568+ @Test
1569+ fun `does nothing when hanke has already been sent this reminder` () {
1570+ val hanke =
1571+ hankeFactory.builder().saveEntity(HankeStatus .DRAFT ) {
1572+ it.sentReminders + = HankeReminder .DRAFT_COMPLETION_15
1573+ }
1574+
1575+ hankeCompletionService.sendUnmodifiedDraftReminderIfNecessary(
1576+ hanke.id,
1577+ HankeReminder .DRAFT_COMPLETION_15 ,
1578+ )
1579+
1580+ assertThat(greenMail.receivedMessages).isEmpty()
1581+ val result = hankeRepository.getReferenceById(hanke.id)
1582+ assertThat(result.sentReminders).containsExactly(HankeReminder .DRAFT_COMPLETION_15 )
1583+ }
1584+
1585+ @Test
1586+ fun `marks reminder as sent and sends emails for DRAFT_COMPLETION_15` () {
1587+ val hanke =
1588+ hankeFactory.builder().withNoAreas().saveWithYhteystiedot {
1589+ omistaja(Kayttooikeustaso .KAIKKI_OIKEUDET )
1590+ rakennuttaja(Kayttooikeustaso .KAIKKIEN_MUOKKAUS )
1591+ toteuttaja(Kayttooikeustaso .KATSELUOIKEUS )
1592+ }
1593+ hanke.status = HankeStatus .DRAFT
1594+ hankeRepository.save(hanke)
1595+
1596+ hankeCompletionService.sendUnmodifiedDraftReminderIfNecessary(
1597+ hanke.id,
1598+ HankeReminder .DRAFT_COMPLETION_15 ,
1599+ )
1600+
1601+ val result = hankeRepository.getReferenceById(hanke.id)
1602+ assertThat(result.sentReminders).containsExactly(HankeReminder .DRAFT_COMPLETION_15 )
1603+
1604+ val emails = greenMail.receivedMessages
1605+ assertThat(emails).hasSize(3 )
1606+ val recipients = emails.map { it.allRecipients.single().toString() }
1607+ assertThat(recipients)
1608+ .containsExactlyInAnyOrder(EMAIL_PERUSTAJA , EMAIL_OMISTAJA , EMAIL_RAKENNUTTAJA )
1609+
1610+ val email = emails.first()
1611+ assertThat(email.subject)
1612+ .contains(
1613+ " Haitaton: Luonnos-tilainen hankkeesi ${hanke.hankeTunnus} on ollut pitkään muokkaamattomana"
1614+ )
1615+ assertThat(email.textBody())
1616+ .contains(
1617+ " Hankkeesi ${hanke.nimi} (${hanke.hankeTunnus} ) on luonnos-tilassa" ,
1618+ " 165 vuorokauteen" ,
1619+ " 180 vuorokautta" ,
1620+ )
1621+ }
1622+
1623+ @Test
1624+ fun `marks reminder as sent and sends emails for DRAFT_COMPLETION_5` () {
1625+ val hanke =
1626+ hankeFactory.builder().withNoAreas().saveWithYhteystiedot {
1627+ omistaja(Kayttooikeustaso .KAIKKI_OIKEUDET )
1628+ rakennuttaja(Kayttooikeustaso .KAIKKIEN_MUOKKAUS )
1629+ }
1630+ hanke.status = HankeStatus .DRAFT
1631+ hankeRepository.save(hanke)
1632+
1633+ hankeCompletionService.sendUnmodifiedDraftReminderIfNecessary(
1634+ hanke.id,
1635+ HankeReminder .DRAFT_COMPLETION_5 ,
1636+ )
1637+
1638+ val result = hankeRepository.getReferenceById(hanke.id)
1639+ assertThat(result.sentReminders).containsExactly(HankeReminder .DRAFT_COMPLETION_5 )
1640+
1641+ val emails = greenMail.receivedMessages
1642+ assertThat(emails).hasSize(3 )
1643+ val recipients = emails.map { it.allRecipients.single().toString() }
1644+ assertThat(recipients)
1645+ .containsExactlyInAnyOrder(EMAIL_PERUSTAJA , EMAIL_OMISTAJA , EMAIL_RAKENNUTTAJA )
1646+
1647+ val email = emails.first()
1648+ assertThat(email.subject)
1649+ .contains(
1650+ " Haitaton: Luonnos-tilainen hankkeesi ${hanke.hankeTunnus} on ollut pitkään muokkaamattomana"
1651+ )
1652+ assertThat(email.textBody())
1653+ .contains(
1654+ " Hankkeesi ${hanke.nimi} (${hanke.hankeTunnus} ) on luonnos-tilassa" ,
1655+ " 175 vuorokauteen" ,
1656+ " 180 vuorokautta" ,
1657+ )
1658+ }
1659+
1660+ @Test
1661+ fun `sends emails only to users with EDIT permissions` () {
1662+ val hanke =
1663+ hankeFactory.builder().withNoAreas().saveWithYhteystiedot {
1664+ omistaja(Kayttooikeustaso .KAIKKI_OIKEUDET )
1665+ rakennuttaja(Kayttooikeustaso .KAIKKIEN_MUOKKAUS )
1666+ toteuttaja(Kayttooikeustaso .KATSELUOIKEUS )
1667+ muuYhteystieto(Kayttooikeustaso .HANKEMUOKKAUS )
1668+ toteuttaja(Kayttooikeustaso .HAKEMUSASIOINTI )
1669+ }
1670+ hanke.status = HankeStatus .DRAFT
1671+ hankeRepository.save(hanke)
1672+
1673+ hankeCompletionService.sendUnmodifiedDraftReminderIfNecessary(
1674+ hanke.id,
1675+ HankeReminder .DRAFT_COMPLETION_15 ,
1676+ )
1677+
1678+ val emails = greenMail.receivedMessages
1679+ val recipients = emails.map { it.allRecipients.single().toString() }
1680+ assertThat(recipients).hasSize(4 )
1681+ assertThat(recipients)
1682+ .containsExactlyInAnyOrder(
1683+ EMAIL_OMISTAJA ,
1684+ EMAIL_RAKENNUTTAJA ,
1685+ EMAIL_ASIANHOITAJA ,
1686+ EMAIL_PERUSTAJA ,
1687+ )
1688+ }
1689+ }
1690+
14991691 companion object {
15001692
15011693 @JvmField
0 commit comments