From 63f030cc9214589ccba115c603c3262e0d49f091 Mon Sep 17 00:00:00 2001 From: samyou-softwire <108681823+samyou-softwire@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:41:33 +0100 Subject: [PATCH 1/5] PDJB-1425: Add name & email to org user --- .../database/entity/OrganisationLandlordUser.kt | 16 +++++++++++++++- .../stepConfig/CancelInvitationStepConfig.kt | 11 ++++------- .../services/LandlordRegistrationService.kt | 7 ++++++- .../services/OrganisationLandlordUserService.kt | 7 ++++++- src/main/resources/data-integration.sql | 4 ++-- src/main/resources/data-local.sql | 4 ++-- ...rganisation_landlord_user_contact_details.sql | 13 +++++++++++++ 7 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 src/main/resources/db/migrations/V1_46_0__add_organisation_landlord_user_contact_details.sql diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlordUser.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlordUser.kt index 57ec93f143..8c33bbbf60 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlordUser.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlordUser.kt @@ -1,5 +1,6 @@ package uk.gov.communities.prsdb.webapp.database.entity +import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType @@ -27,9 +28,22 @@ class OrganisationLandlordUser() : AuditableEntity() { @JoinColumn(name = "subject_identifier", nullable = false) lateinit var baseUser: PrsdbUser - constructor(organisationLandlord: OrganisationLandlord, baseUser: PrsdbUser) : this() { + @Column(nullable = false) + lateinit var name: String + @Column(nullable = false) + lateinit var email: String + + constructor( + organisationLandlord: OrganisationLandlord, + baseUser: PrsdbUser, + name: String, + email: String, + ) : this() { this.organisationLandlord = organisationLandlord this.baseUser = baseUser + this.name = name + this.email = email + organisationLandlord.addOrganisationLandlordUser(this) } } diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfig.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfig.kt index aa5ea97bf7..85207d7dce 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfig.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfig.kt @@ -1,7 +1,6 @@ package uk.gov.communities.prsdb.webapp.journeys.cancelJointLandlordInvitation.stepConfig import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.JourneyFrameworkComponent -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.journeys.AbstractInternalStepConfig import uk.gov.communities.prsdb.webapp.journeys.Destination import uk.gov.communities.prsdb.webapp.journeys.JourneyStep @@ -51,11 +50,10 @@ class CancelInvitationStepConfig( // Email the canceller // TODO: PDJB-1274: Update emails to account for org landlord - check(cancellerLandlord is IndividualLandlord) cancellerEmailSender.sendEmail( - cancellerLandlord.email, + cancellerLandlord.contactEmail, JointLandlordInvitationCancellationCancellerEmail( - recipientName = cancellerLandlord.name, + recipientName = cancellerLandlord.contactName, invitedEmail = state.invitedEmail, propertyAddress = propertyAddress, propertyRecordUrl = propertyRecordUrl, @@ -67,11 +65,10 @@ class CancelInvitationStepConfig( .filterNot { cancellerLandlord.id == it.id } // TODO: PDJB-1274: Update emails to account for org landlord .forEach { - check(it is IndividualLandlord) otherLandlordEmailSender.sendEmail( - it.email, + it.contactEmail, JointLandlordInvitationCancellationOtherLandlordEmail( - recipientName = it.name, + recipientName = it.contactName, invitedEmail = state.invitedEmail, propertyAddress = propertyAddress, propertyRecordUrl = propertyRecordUrl, diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt index dee9b40406..ab4c522e84 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt @@ -115,7 +115,12 @@ class LandlordRegistrationService( registrantPhoneNumber = organisationRegistrantPhoneNumber, ) - organisationLandlordUserService.createOrganisationLandlordUser(landlord, baseUser) + organisationLandlordUserService.createOrganisationLandlordUser( + landlord, + baseUser, + organisationRegistrantName, + organisationRegistrantEmail, + ) if (!organisationHasCompanyNumber) { organisationGoverningBodyMemberService.createGoverningBodyMembers(landlord, organisationGoverningBodyMembers) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserService.kt index 1d76e7eee0..d09a69194c 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserService.kt @@ -15,5 +15,10 @@ class OrganisationLandlordUserService( fun createOrganisationLandlordUser( organisationLandlord: OrganisationLandlord, baseUser: PrsdbUser, - ): OrganisationLandlordUser = organisationLandlordUserRepository.save(OrganisationLandlordUser(organisationLandlord, baseUser)) + name: String, + email: String, + ): OrganisationLandlordUser = + organisationLandlordUserRepository.save( + OrganisationLandlordUser(organisationLandlord, baseUser, name, email), + ) } diff --git a/src/main/resources/data-integration.sql b/src/main/resources/data-integration.sql index d411f8b091..fa6b234489 100644 --- a/src/main/resources/data-integration.sql +++ b/src/main/resources/data-integration.sql @@ -237,8 +237,8 @@ VALUES (11, 900, 1, '2026-07-30 00:00:00+00', SELECT setval(pg_get_serial_sequence('landlord', 'id'), (SELECT MAX(id) FROM landlord)); -INSERT INTO organisation_landlord_user (id, organisation_landlord_id, subject_identifier, created_date) -VALUES (1, 11, 'urn:fdc:gov.uk:2022:OJhyoHBpqAWPIqCCe_n9eVA4HGvFfgXCQMHSAsKSiRw', '2026-07-30 00:00:00+00') ON CONFLICT DO NOTHING; +INSERT INTO organisation_landlord_user (id, organisation_landlord_id, subject_identifier, name, email, created_date) +VALUES (1, 11, 'urn:fdc:gov.uk:2022:OJhyoHBpqAWPIqCCe_n9eVA4HGvFfgXCQMHSAsKSiRw', 'Test Registrant', 'registrant@example.com', '2026-07-30 00:00:00+00') ON CONFLICT DO NOTHING; SELECT setval(pg_get_serial_sequence('organisation_landlord_user', 'id'), (SELECT MAX(id) FROM organisation_landlord_user)); diff --git a/src/main/resources/data-local.sql b/src/main/resources/data-local.sql index 2429241e07..f9a533b719 100644 --- a/src/main/resources/data-local.sql +++ b/src/main/resources/data-local.sql @@ -284,8 +284,8 @@ VALUES (36, '07/23/26', '07/23/26', 81, 1, 'Local Organisation Landlord', 5, 'local-registrant@example.com', '07111111112', true, false, false, '12345678', 'Local Main Contact', 'local-main-contact@example.com', '07111111113'); -INSERT INTO organisation_landlord_user (organisation_landlord_id, subject_identifier, created_date) -VALUES (36, 'urn:fdc:gov.uk:2022:ORG01', '07/23/26'); +INSERT INTO organisation_landlord_user (organisation_landlord_id, subject_identifier, name, email, created_date) +VALUES (36, 'urn:fdc:gov.uk:2022:ORG01', 'Local Registrant', 'local-registrant@example.com', '07/23/26'); SELECT setval(pg_get_serial_sequence('landlord', 'id'), (SELECT MAX(id) FROM landlord)); diff --git a/src/main/resources/db/migrations/V1_46_0__add_organisation_landlord_user_contact_details.sql b/src/main/resources/db/migrations/V1_46_0__add_organisation_landlord_user_contact_details.sql new file mode 100644 index 0000000000..031185dabb --- /dev/null +++ b/src/main/resources/db/migrations/V1_46_0__add_organisation_landlord_user_contact_details.sql @@ -0,0 +1,13 @@ +ALTER TABLE organisation_landlord_user + ADD COLUMN name VARCHAR(255), + ADD COLUMN email VARCHAR(255); + +UPDATE organisation_landlord_user AS organisation_user +SET name = landlord.organisation_registrant_name, + email = landlord.organisation_registrant_email +FROM landlord +WHERE landlord.id = organisation_user.organisation_landlord_id; + +ALTER TABLE organisation_landlord_user + ALTER COLUMN name SET NOT NULL, + ALTER COLUMN email SET NOT NULL; From 6f6bdebcd35fe38aacc32d1ca7e93bdb092df6e8 Mon Sep 17 00:00:00 2001 From: samyou-softwire <108681823+samyou-softwire@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:47:17 +0100 Subject: [PATCH 2/5] PDJB-1425: Add temp email & name methods to landlords --- .../database/entity/IndividualLandlord.kt | 8 ++++++++ .../prsdb/webapp/database/entity/Landlord.kt | 7 +++++++ .../database/entity/OrganisationLandlord.kt | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/IndividualLandlord.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/IndividualLandlord.kt index bc5e14f21b..428d84ea05 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/IndividualLandlord.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/IndividualLandlord.kt @@ -27,6 +27,14 @@ class IndividualLandlord() : Landlord() { override val displayEmail: String get() = email + @get:Transient + override val contactName: String + get() = name + + @get:Transient + override val contactEmail: String + get() = email + @OneToOne @JoinColumn(name = "individual_subject_identifier", unique = true) lateinit var baseUser: PrsdbUser diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/Landlord.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/Landlord.kt index 37d3bd045b..298bce97bb 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/Landlord.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/Landlord.kt @@ -28,6 +28,13 @@ abstract class Landlord : ModifiableAuditableEntity() { @get:Transient abstract val displayEmail: String + @get:Transient + abstract val contactName: String + + // TODO PDJB-1274: This method is temporary - a landlord will soon not have a single email + @get:Transient + abstract val contactEmail: String + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) open val id: Long = 0 diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlord.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlord.kt index 6759788e14..dec12632da 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlord.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/database/entity/OrganisationLandlord.kt @@ -3,8 +3,10 @@ package uk.gov.communities.prsdb.webapp.database.entity import jakarta.persistence.Column import jakarta.persistence.DiscriminatorValue import jakarta.persistence.Entity +import jakarta.persistence.FetchType import jakarta.persistence.JoinColumn import jakarta.persistence.ManyToOne +import jakarta.persistence.OneToMany import jakarta.persistence.Transient import uk.gov.communities.prsdb.webapp.constants.enums.CharityRegulator import uk.gov.communities.prsdb.webapp.constants.enums.LandlordType @@ -25,6 +27,16 @@ class OrganisationLandlord() : Landlord() { override val displayEmail: String get() = email + @get:Transient + override val contactName: String + // TODO PDJB-1274: The single-user assumption must be removed to support multiple organisation users. + get() = organisationLandlordUsers.single().name + + @get:Transient + override val contactEmail: String + // TODO PDJB-1274: The single-user assumption must be removed to support multiple organisation users. + get() = organisationLandlordUsers.single().email + @Column(name = "organisation_landlord_name") lateinit var name: String @@ -93,6 +105,13 @@ class OrganisationLandlord() : Landlord() { @Column(name = "organisation_main_contact_phone") lateinit var mainContactPhone: String + @OneToMany(mappedBy = "organisationLandlord", fetch = FetchType.EAGER) + private val organisationLandlordUsers: MutableSet = mutableSetOf() + + internal fun addOrganisationLandlordUser(organisationLandlordUser: OrganisationLandlordUser) { + organisationLandlordUsers.add(organisationLandlordUser) + } + constructor( registrationNumber: RegistrationNumber, name: String, From 6af69f6e9f975e3fd3f0104609f9c3e9d073dfb8 Mon Sep 17 00:00:00 2001 From: samyou-softwire <108681823+samyou-softwire@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:52:24 +0100 Subject: [PATCH 3/5] PDJB-1425: Rename LandlordUpdateModel to Individual... --- ...el.kt => IndividualLandlordUpdateModel.kt} | 2 +- .../prsdb/webapp/services/LandlordService.kt | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) rename src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/updateModels/{LandlordUpdateModel.kt => IndividualLandlordUpdateModel.kt} (89%) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/updateModels/LandlordUpdateModel.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/updateModels/IndividualLandlordUpdateModel.kt similarity index 89% rename from src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/updateModels/LandlordUpdateModel.kt rename to src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/updateModels/IndividualLandlordUpdateModel.kt index b8f2390424..8b587ddddb 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/updateModels/LandlordUpdateModel.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/models/dataModels/updateModels/IndividualLandlordUpdateModel.kt @@ -3,7 +3,7 @@ package uk.gov.communities.prsdb.webapp.models.dataModels.updateModels import uk.gov.communities.prsdb.webapp.models.dataModels.AddressDataModel import java.time.LocalDate -data class LandlordUpdateModel( +data class IndividualLandlordUpdateModel( val email: String? = null, val name: String? = null, val phoneNumber: String? = null, diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt index 4eb72aaea5..70bf97a252 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt @@ -19,7 +19,7 @@ import uk.gov.communities.prsdb.webapp.exceptions.RepositoryQueryTimeoutExceptio import uk.gov.communities.prsdb.webapp.helpers.extensions.StringExtensions.Companion.toNormalizedEmail import uk.gov.communities.prsdb.webapp.models.dataModels.AddressDataModel import uk.gov.communities.prsdb.webapp.models.dataModels.RegistrationNumberDataModel -import uk.gov.communities.prsdb.webapp.models.dataModels.updateModels.LandlordUpdateModel +import uk.gov.communities.prsdb.webapp.models.dataModels.updateModels.IndividualLandlordUpdateModel import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.LandlordUpdateConfirmation import uk.gov.communities.prsdb.webapp.models.viewModels.searchResultModels.LandlordSearchResultViewModel import java.time.LocalDate @@ -135,8 +135,8 @@ class LandlordService( } @Transactional - fun updateLandlordForUser( - landlordUpdate: LandlordUpdateModel, + fun updateIndividualLandlordForUser( + landlordUpdate: IndividualLandlordUpdateModel, checkUpdateIsValid: () -> Unit, ): Landlord { checkUpdateIsValid() @@ -164,36 +164,36 @@ class LandlordService( @Transactional fun updateLandlordEmail(email: String) { - updateLandlordForUser( - LandlordUpdateModel(email = email), + updateIndividualLandlordForUser( + IndividualLandlordUpdateModel(email = email), ) {} } @Transactional fun updateLandlordPhoneNumber(phoneNumber: String) { - updateLandlordForUser( - LandlordUpdateModel(phoneNumber = phoneNumber), + updateIndividualLandlordForUser( + IndividualLandlordUpdateModel(phoneNumber = phoneNumber), ) {} } @Transactional fun updateLandlordName(name: String) { - updateLandlordForUser( - LandlordUpdateModel(name = name), + updateIndividualLandlordForUser( + IndividualLandlordUpdateModel(name = name), ) {} } @Transactional fun updateLandlordAddress(address: AddressDataModel) { - updateLandlordForUser( - LandlordUpdateModel(address = address), + updateIndividualLandlordForUser( + IndividualLandlordUpdateModel(address = address), ) {} } @Transactional fun updateLandlordDateOfBirth(dateOfBirth: LocalDate) { - updateLandlordForUser( - LandlordUpdateModel( + updateIndividualLandlordForUser( + IndividualLandlordUpdateModel( email = null, name = null, phoneNumber = null, @@ -238,7 +238,7 @@ class LandlordService( } private fun sendUpdateConfirmationEmail( - landlordUpdate: LandlordUpdateModel, + landlordUpdate: IndividualLandlordUpdateModel, landlord: IndividualLandlord, oldEmail: String, ) { From fd8e453d71a33d86bbc6124eb142c1a20edffaef Mon Sep 17 00:00:00 2001 From: samyou-softwire <108681823+samyou-softwire@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:55:20 +0100 Subject: [PATCH 4/5] PDJB-1425: Use shared props to send emails --- ...PropertiesReminderTaskApplicationRunner.kt | 10 ++--- ...ouAreALandlordForThisPropertyStepConfig.kt | 13 +++--- .../steps/SendRejectionEmailsStepConfig.kt | 6 +-- .../stepConfig/DeregisterStepConfig.kt | 4 +- .../stepConfig/ConfirmStepConfig.kt | 9 ++-- .../PropertyRegistrationJourneyFactory.kt | 7 +-- .../InviteJointLandlordJourneyFactory.kt | 3 +- .../CompleteSwitchToIndividualStepConfig.kt | 6 +-- ...intLandlordInvitationExpiryEmailService.kt | 6 +-- .../JointLandlordInvitationService.kt | 23 ++++------ ...ntLandlordOtherLandlordLeftEmailService.kt | 9 ++-- .../services/LandlordRegistrationService.kt | 3 +- .../prsdb/webapp/services/LandlordService.kt | 2 +- .../services/PropertyComplianceService.kt | 45 +++++++++---------- .../services/PropertyRegistrationService.kt | 6 +-- .../services/PropertyUpdateEmailService.kt | 9 ++-- .../SwapToIndividualNudgeEmailService.kt | 6 +-- .../services/VirusNotificationEmailHandler.kt | 4 +- 18 files changed, 66 insertions(+), 105 deletions(-) diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/application/IncompletePropertiesReminderTaskApplicationRunner.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/application/IncompletePropertiesReminderTaskApplicationRunner.kt index 3f08de1e4b..9ed0506c0c 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/application/IncompletePropertiesReminderTaskApplicationRunner.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/application/IncompletePropertiesReminderTaskApplicationRunner.kt @@ -10,7 +10,6 @@ import org.springframework.context.ApplicationContext import uk.gov.communities.prsdb.webapp.annotations.taskAnnotations.PrsdbScheduledTask import uk.gov.communities.prsdb.webapp.annotations.taskAnnotations.PrsdbTaskService import uk.gov.communities.prsdb.webapp.constants.INCOMPLETE_PROPERTY_AGE_WHEN_REMINDER_EMAIL_DUE_IN_DAYS -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.exceptions.PersistentEmailSendException import uk.gov.communities.prsdb.webapp.exceptions.TrackEmailSentException import uk.gov.communities.prsdb.webapp.exceptions.TransientEmailSentException @@ -56,17 +55,18 @@ class IncompletePropertiesReminderTaskLogic( LocalDate.now().minusDays(INCOMPLETE_PROPERTY_AGE_WHEN_REMINDER_EMAIL_DUE_IN_DAYS.toLong()), ) - val pagesOfProperties = incompletePropertiesService.getNumberOfPagesOfIncompletePropertiesOlderThanDate(cutoffDate) + val pagesOfProperties = + incompletePropertiesService.getNumberOfPagesOfIncompletePropertiesOlderThanDate(cutoffDate) for (page in 0.. // TODO: PDJB-1274: Update emails to account for org landlord val landlord = property.landlord - check(landlord is IndividualLandlord) try { emailSender.sendEmail( - landlord.email, + landlord.contactEmail, IncompletePropertyReminderEmail( singleLineAddress = property.savedJourneyState.getPropertyRegistrationSingleLineAddress(), diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfig.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfig.kt index 4742719564..9bba490132 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfig.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfig.kt @@ -1,7 +1,6 @@ package uk.gov.communities.prsdb.webapp.journeys.acceptOrRejectJointLandlordInvitation.steps import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.JourneyFrameworkComponent -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.Landlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership import uk.gov.communities.prsdb.webapp.journeys.AbstractRequestableStepConfig @@ -85,11 +84,10 @@ class ConfirmYouAreALandlordForThisPropertyStepConfig( RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber).toString() // TODO: PDJB-1274: Update emails to account for org landlord - check(acceptingLandlord is IndividualLandlord) acceptedEmailSender.sendEmail( - acceptingLandlord.email, + acceptingLandlord.contactEmail, JointLandlordInvitationAcceptedEmail( - recipientName = acceptingLandlord.name, + recipientName = acceptingLandlord.contactName, propertyAddress = propertyAddress, propertyRecordUrl = propertyRecordUrl, propertyRegistrationNumber = propertyRegistrationNumber, @@ -100,12 +98,11 @@ class ConfirmYouAreALandlordForThisPropertyStepConfig( .filter { it.id != acceptingLandlord.id } // TODO: PDJB-1274: Update emails to account for org landlord .forEach { landlord -> - check(landlord is IndividualLandlord) otherLandlordEmailSender.sendEmail( - landlord.email, + landlord.contactEmail, JointLandlordInvitationAcceptedOtherLandlordEmail( - recipientName = landlord.name, - inviteeName = acceptingLandlord.name, + recipientName = landlord.contactName, + inviteeName = acceptingLandlord.displayName, propertyAddress = propertyAddress, propertyRecordUrl = propertyRecordUrl, ), diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfig.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfig.kt index c341ef7f9f..65f2df2e33 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfig.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfig.kt @@ -1,7 +1,6 @@ package uk.gov.communities.prsdb.webapp.journeys.acceptOrRejectJointLandlordInvitation.steps import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.JourneyFrameworkComponent -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.journeys.AbstractInternalStepConfig import uk.gov.communities.prsdb.webapp.journeys.JourneyStep import uk.gov.communities.prsdb.webapp.journeys.acceptOrRejectJointLandlordInvitation.AcceptOrRejectJointLandlordInvitationJourneyState @@ -29,11 +28,10 @@ class SendRejectionEmailsStepConfig( // TODO: PDJB-1274: Update emails to account for org landlord invitation.registeredOwnership.landlords.forEach { landlord -> - check(landlord is IndividualLandlord) rejectionEmailSender.sendEmail( - landlord.email, + landlord.contactEmail, JointLandlordInvitationRejectionEmail( - recipientName = landlord.name, + recipientName = landlord.contactName, inviteeEmail = invitation.invitedEmail, propertyAddress = propertyAddress, propertyRecordUrl = propertyRecordUrl, diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfig.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfig.kt index 97f7487a5c..a198a623a3 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfig.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfig.kt @@ -2,7 +2,6 @@ package uk.gov.communities.prsdb.webapp.journeys.landlordDeregistration.stepConf import org.springframework.security.core.context.SecurityContextHolder import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.JourneyFrameworkComponent -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.journeys.AbstractInternalStepConfig import uk.gov.communities.prsdb.webapp.journeys.Destination import uk.gov.communities.prsdb.webapp.journeys.JourneyStep @@ -40,8 +39,7 @@ class DeregisterStepConfig( landlordDeregistrationService.addLandlordHadActivePropertiesToSession(landlordHadActiveSoloProperties) // TODO: PDJB-1274: Update emails to account for org landlord - check(landlord is IndividualLandlord) - val landlordEmailAddress = landlord.email + val landlordEmailAddress = landlord.contactEmail if (landlordHadActiveSoloProperties) { // TODO PDJB-311: This email does not address properties that are not deleted diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfig.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfig.kt index 8b8c07631c..ca1a08b399 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfig.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfig.kt @@ -2,7 +2,6 @@ package uk.gov.communities.prsdb.webapp.journeys.propertyDeregistration.stepConf import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.JourneyFrameworkComponent import uk.gov.communities.prsdb.webapp.controllers.PropertyDetailsController -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.journeys.AbstractRequestableStepConfig import uk.gov.communities.prsdb.webapp.journeys.Destination import uk.gov.communities.prsdb.webapp.journeys.JourneyStep.RequestableStep @@ -58,8 +57,7 @@ class ConfirmStepConfig( // TODO: PDJB-1274: Update emails to account for org landlord val landlordContacts = propertyOwnership.landlords.map { landlord -> - check(landlord is IndividualLandlord) - landlord.name to landlord.email + landlord.contactName to landlord.contactEmail } val cancelledInvitationEmailAddresses = jointLandlordInvitationService.getPendingInvitations(propertyOwnership).map { it.invitedEmail } @@ -67,7 +65,10 @@ class ConfirmStepConfig( val multiLineAddress = propertyOwnership.address.toMultiLineAddress() propertyDeregistrationService.deregisterProperty(state.propertyOwnershipId) - propertyDeregistrationService.addDeregisteredPropertyOwnershipIdToSession(state.propertyOwnershipId, singleLineAddress) + propertyDeregistrationService.addDeregisteredPropertyOwnershipIdToSession( + state.propertyOwnershipId, + singleLineAddress, + ) landlordContacts.forEach { (landlordName, landlordEmail) -> confirmationEmailSender.sendEmail( diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/PropertyRegistrationJourneyFactory.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/PropertyRegistrationJourneyFactory.kt index 09b3fd065e..7286f77763 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/PropertyRegistrationJourneyFactory.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/PropertyRegistrationJourneyFactory.kt @@ -9,7 +9,6 @@ import uk.gov.communities.prsdb.webapp.constants.CONFIRMATION_PATH_SEGMENT import uk.gov.communities.prsdb.webapp.constants.PROPERTY_REGISTRATION_RESTRUCTURE_AND_SKIPPING import uk.gov.communities.prsdb.webapp.constants.TASK_LIST_PATH_SEGMENT import uk.gov.communities.prsdb.webapp.controllers.RegisterPropertyController.Companion.PROPERTY_REGISTRATION_ROUTE -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.exceptions.PrsdbWebException import uk.gov.communities.prsdb.webapp.journeys.AbstractJourneyState import uk.gov.communities.prsdb.webapp.journeys.AndParents @@ -645,11 +644,7 @@ class PropertyRegistrationJourney( override val loggedInLandlordEmail: String? // TODO: PDJB-1274: Update emails to account for org landlord - get() { - val landlord = userToLandlordService.getCurrentLandlordForUser() - check(landlord is IndividualLandlord) - return landlord.email - } + get() = userToLandlordService.getCurrentLandlordForUser().contactEmail companion object { fun generateSeedForUser(user: Principal): String = "Prop reg journey for user ${user.name} at time ${System.currentTimeMillis()}" diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/update/inviteJointLandlord/InviteJointLandlordJourneyFactory.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/update/inviteJointLandlord/InviteJointLandlordJourneyFactory.kt index 8a84c6e084..fd3ed38115 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/update/inviteJointLandlord/InviteJointLandlordJourneyFactory.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyRegistration/update/inviteJointLandlord/InviteJointLandlordJourneyFactory.kt @@ -7,7 +7,6 @@ import uk.gov.communities.prsdb.webapp.constants.CONFIRMATION_PATH_SEGMENT import uk.gov.communities.prsdb.webapp.constants.LANDLORD_DETAILS_FRAGMENT import uk.gov.communities.prsdb.webapp.controllers.InviteJointLandlordController import uk.gov.communities.prsdb.webapp.controllers.PropertyDetailsController -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.exceptions.PrsdbWebException import uk.gov.communities.prsdb.webapp.journeys.AbstractPropertyOwnershipUpdateJourneyState import uk.gov.communities.prsdb.webapp.journeys.Destination @@ -186,7 +185,7 @@ class InviteJointLandlordJourney( // TODO: PDJB-1274: Update emails to account for org landlord override val existingLandlordEmails: List - get() = propertyOwnershipService.getPropertyOwnership(propertyId).landlords.map { (it as IndividualLandlord).email } + get() = propertyOwnershipService.getPropertyOwnership(propertyId).landlords.map { it.contactEmail } } interface InviteJointLandlordJourneyState : diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfig.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfig.kt index 43845398f8..9a3fd0b45a 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfig.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfig.kt @@ -4,7 +4,6 @@ import jakarta.servlet.http.HttpSession import jakarta.transaction.Transactional import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.JourneyFrameworkComponent import uk.gov.communities.prsdb.webapp.constants.SWITCHED_TO_INDIVIDUAL_PROPERTY_ID -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.exceptions.PrsdbWebException import uk.gov.communities.prsdb.webapp.journeys.AbstractInternalStepConfig import uk.gov.communities.prsdb.webapp.journeys.Destination @@ -44,10 +43,9 @@ class CompleteSwitchToIndividualStepConfig( // TODO: PDJB-1274: Update emails to account for org landlord val landlord = propertyOwnership.landlords.first() - check(landlord is IndividualLandlord) switchToIndividualConfirmationEmailSender.sendEmail( - landlord.email, - SwitchToIndividualConfirmationEmail(landlordName = landlord.name, propertyAddress = propertyAddress), + landlord.contactEmail, + SwitchToIndividualConfirmationEmail(landlordName = landlord.contactName, propertyAddress = propertyAddress), ) for (invitation in pendingInvitations) { diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailService.kt index 5011a782f3..ac9ed0a910 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailService.kt @@ -3,7 +3,6 @@ package uk.gov.communities.prsdb.webapp.services import uk.gov.communities.prsdb.webapp.annotations.taskAnnotations.PrsdbTaskService import uk.gov.communities.prsdb.webapp.constants.JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS import uk.gov.communities.prsdb.webapp.constants.enums.JointLandlordInvitationStatus -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.JointLandlordInvitation import uk.gov.communities.prsdb.webapp.database.repository.JointLandlordInvitationRepository import uk.gov.communities.prsdb.webapp.exceptions.PersistentEmailSendException @@ -48,11 +47,10 @@ class JointLandlordInvitationExpiryEmailService( // TODO: PDJB-1274: Update emails to account for org landlord propertyOwnership.landlords.forEach { recipient -> - check(recipient is IndividualLandlord) expiryEmailNotificationService.sendEmail( - recipient.email, + recipient.contactEmail, JointLandlordInvitationExpiryEmail( - recipientName = recipient.name, + recipientName = recipient.contactName, invitedEmail = invitation.invitedEmail, propertyAddress = propertyAddress, propertyRecordUri = propertyRecordUri, diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationService.kt index 983d14108f..59d2c28025 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationService.kt @@ -63,20 +63,15 @@ class JointLandlordInvitationService( invitingLandlord: Landlord, ) { // TODO: PDJB-1274: Update emails to account for org landlord - check(invitingLandlord is IndividualLandlord) - val senderName = invitingLandlord.name + val senderName = invitingLandlord.displayName + val senderContactName = invitingLandlord.contactName val propertyAddress = propertyOwnership.address.toMultiLineAddress() // Re-check against the current state of the database when finishing the journey. The form-level checks happen // when an email is submitted, so without this a concurrent journey could invite the same email twice. val alreadyInvitedEmails = getExistingInvitedEmails(propertyOwnership.id) // TODO: PDJB-1279: Update joint landlord flow to account for org landlords - val registeredLandlords = - propertyOwnership.landlords.map { landlord -> - check(landlord is IndividualLandlord) - landlord - } - val existingLandlordEmails = registeredLandlords.map { it.email } + val existingLandlordEmails = propertyOwnership.landlords.map { it.contactEmail } val emailsToInvite = jointLandlordEmails.filter { candidateEmail -> !alreadyInvitedEmails.containsEmail(candidateEmail) && @@ -89,7 +84,7 @@ class JointLandlordInvitationService( // Save the invitation before sending the email so the link in the email always resolves to a real token. // If the email fails to send, delete the invitation again so we don't leave an orphaned record behind. - val invitation = JointLandlordInvitation(token, email, propertyOwnership, invitingLandlord.name) + val invitation = JointLandlordInvitation(token, email, propertyOwnership, senderName) invitationRepository.save(invitation) try { @@ -110,21 +105,21 @@ class JointLandlordInvitationService( if (emailsToInvite.isNotEmpty()) { val propertyRecordUrl = absoluteUrlProvider.buildPropertyDetailsUri(propertyOwnership.id).toString() confirmationEmailSender.sendEmail( - invitingLandlord.email, + invitingLandlord.contactEmail, JointLandlordInvitationConfirmationEmail( - senderName = senderName, + senderName = senderContactName, propertyAddress = propertyAddress, jointLandlordEmails = emailsToInvite, propertyRecordUrl = propertyRecordUrl, ), ) - val existingJointLandlords = registeredLandlords.filter { it.id != invitingLandlord.id } + val existingJointLandlords = propertyOwnership.landlords.filter { it.id != invitingLandlord.id } existingJointLandlords.forEach { landlord -> notifyExistingEmailSender.sendEmail( - landlord.email, + landlord.contactEmail, JointLandlordInvitationNotifyExistingEmail( - recipientName = landlord.name, + recipientName = landlord.contactName, propertyAddress = propertyAddress, jointLandlordEmails = emailsToInvite, propertyRecordUrl = propertyRecordUrl, diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailService.kt index 68e7921d33..7503b181b6 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailService.kt @@ -1,7 +1,6 @@ package uk.gov.communities.prsdb.webapp.services import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.PrsdbWebService -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.Landlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.JointLandlordOtherLandlordLeftNotification @@ -16,14 +15,12 @@ class JointLandlordOtherLandlordLeftEmailService( previousLandlord: Landlord, ) { // TODO: PDJB-1274: Update emails to account for org landlord - check(previousLandlord is IndividualLandlord) propertyOwnership.landlords.forEach { otherLandlord -> - check(otherLandlord is IndividualLandlord) otherLandlordLeftEmailService.sendEmail( - otherLandlord.email, + otherLandlord.contactEmail, JointLandlordOtherLandlordLeftNotification( - leavingLandlord = previousLandlord.name, - notifiedLandlord = otherLandlord.name, + leavingLandlord = previousLandlord.displayName, + notifiedLandlord = otherLandlord.contactName, address = propertyOwnership.address.toMultiLineAddress(), propertyRecordUrl = absoluteUrlProvider.buildPropertyDetailsUri(propertyOwnership.id).toString(), ), diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt index ab4c522e84..d3c9e84d78 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationService.kt @@ -133,9 +133,8 @@ class LandlordRegistrationService( private fun sendRegistrationConfirmationEmail(landlord: Landlord) { // TODO: PDJB-1274: Update emails to account for org landlord - check(landlord is IndividualLandlord) registrationConfirmationSender.sendEmail( - landlord.email, + landlord.contactEmail, LandlordRegistrationConfirmationEmail( RegistrationNumberDataModel.fromRegistrationNumber(landlord.registrationNumber).toString(), absoluteUrlProvider.buildLandlordDashboardUri().toString(), diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt index 70bf97a252..3b2e03caea 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordService.kt @@ -142,7 +142,6 @@ class LandlordService( checkUpdateIsValid() val landlordEntity = userToLandlordService.getCurrentLandlordForUser() check(landlordEntity is IndividualLandlord) - // TODO: PDJB-1274: Update emails to account for org landlord val existingEmail = landlordEntity.email @@ -242,6 +241,7 @@ class LandlordService( landlord: IndividualLandlord, oldEmail: String, ) { + // TODO: PDJB-1274: Update emails to account for org landlord val updatedDetail = when { landlordUpdate.name != null -> "name" diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceService.kt index 410b0b1029..bb8d85fac0 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceService.kt @@ -11,7 +11,6 @@ import uk.gov.communities.prsdb.webapp.constants.PROVIDE_LATER_DEADLINE_DAYS import uk.gov.communities.prsdb.webapp.constants.enums.CertificateType import uk.gov.communities.prsdb.webapp.constants.enums.EpcExemptionReason import uk.gov.communities.prsdb.webapp.constants.enums.MeesExemptionReason -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.Landlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyCompliance import uk.gov.communities.prsdb.webapp.database.repository.FileUploadRepository @@ -367,11 +366,10 @@ class PropertyComplianceService( ) // TODO: PDJB-1274: Update emails to account for org landlord - check(landlord is IndividualLandlord) complianceUpdateConfirmationSender.sendEmail( - landlord.email, + landlord.contactEmail, ComplianceUpdateConfirmationEmail( - landlordName = landlord.name, + landlordName = landlord.contactName, multiLineAddress = propertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber), dashboardUrl = absoluteUrlProvider.buildLandlordDashboardUri(), @@ -387,27 +385,24 @@ class PropertyComplianceService( val otherLandlords = propertyOwnership.landlords.filter { it.id != currentLandlord.id } // TODO: PDJB-1274: Update emails to account for org landlord - otherLandlords - .map { landlord -> - landlord as IndividualLandlord - }.forEach { otherLandlord -> - complianceUpdateConfirmationSender.sendEmail( - otherLandlord.email, - ComplianceUpdateConfirmationEmail( - landlordName = otherLandlord.name, - multiLineAddress = propertyOwnership.address.toMultiLineAddress(), - registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber), - dashboardUrl = absoluteUrlProvider.buildLandlordDashboardUri(), - newCertificateUrl = absoluteUrlProvider.buildComplianceInformationUri(propertyOwnership.id), - complianceUpdateType = updateType, - certificateType = certificateType, - certificateTypeLabel = certificateTypeLabel, - expiryDate = formattedExpiryDate, - deadlineDate = formattedDeadlineDate, - isJointLandlord = true, - ), - ) - } + otherLandlords.forEach { otherLandlord -> + complianceUpdateConfirmationSender.sendEmail( + otherLandlord.contactEmail, + ComplianceUpdateConfirmationEmail( + landlordName = otherLandlord.contactName, + multiLineAddress = propertyOwnership.address.toMultiLineAddress(), + registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber), + dashboardUrl = absoluteUrlProvider.buildLandlordDashboardUri(), + newCertificateUrl = absoluteUrlProvider.buildComplianceInformationUri(propertyOwnership.id), + complianceUpdateType = updateType, + certificateType = certificateType, + certificateTypeLabel = certificateTypeLabel, + expiryDate = formattedExpiryDate, + deadlineDate = formattedDeadlineDate, + isJointLandlord = true, + ), + ) + } } private fun throwErrorIfLastModifiedDatesConflict( diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationService.kt index ddbf7455cf..c6cea4bdd3 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationService.kt @@ -11,7 +11,6 @@ import uk.gov.communities.prsdb.webapp.constants.enums.MeesExemptionReason import uk.gov.communities.prsdb.webapp.constants.enums.OwnershipType import uk.gov.communities.prsdb.webapp.constants.enums.PropertyType import uk.gov.communities.prsdb.webapp.constants.enums.RentFrequency -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.Landlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership import uk.gov.communities.prsdb.webapp.database.repository.PropertyOwnershipRepository @@ -179,11 +178,10 @@ class PropertyRegistrationService( jointLandlordEmails: List?, ) { // TODO: PDJB-1274: Update emails to account for org landlord - check(landlord is IndividualLandlord) confirmationEmailSender.sendEmail( - landlord.email, + landlord.contactEmail, PropertyRegistrationConfirmationEmail( - RegistrationNumberDataModel.Companion + RegistrationNumberDataModel .fromRegistrationNumber(propertyOwnership.registrationNumber) .toString(), addressModel.singleLineAddress, diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailService.kt index 1c1233d9a4..d40bceea96 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailService.kt @@ -1,7 +1,6 @@ package uk.gov.communities.prsdb.webapp.services import uk.gov.communities.prsdb.webapp.annotations.webAnnotations.PrsdbWebService -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.models.dataModels.RegistrationNumberDataModel import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.JointLandlordPropertyUpdateNotificationEmail import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.PropertyUpdateConfirmation @@ -24,9 +23,8 @@ class PropertyUpdateEmailService( RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber).toString() // TODO: PDJB-1274: Update emails to account for org landlord - check(actingLandlord is IndividualLandlord) confirmationEmailService.sendEmail( - actingLandlord.email, + actingLandlord.contactEmail, PropertyUpdateConfirmation( singleLineAddress = propertyOwnership.address.singleLineAddress, registrationNumber = registrationNumber, @@ -40,11 +38,10 @@ class PropertyUpdateEmailService( val propertyRecordUrl = absoluteUrlProvider.buildPropertyDetailsUri(propertyOwnership.id).toString() // TODO: PDJB-1274: Update emails to account for org landlord otherLandlords.forEach { landlord -> - check(landlord is IndividualLandlord) notificationEmailService.sendEmail( - landlord.email, + landlord.contactEmail, JointLandlordPropertyUpdateNotificationEmail( - recipientName = landlord.name, + recipientName = landlord.contactName, propertyAddress = propertyOwnership.address.toMultiLineAddress(), updatedBullets = updatedBullets, propertyRecordUrl = propertyRecordUrl, diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailService.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailService.kt index 2f345b4eb4..153d6fd541 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailService.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailService.kt @@ -2,7 +2,6 @@ package uk.gov.communities.prsdb.webapp.services import org.springframework.stereotype.Service import uk.gov.communities.prsdb.webapp.constants.enums.JointLandlordInvitationStatus -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership import uk.gov.communities.prsdb.webapp.database.repository.JointLandlordInvitationRepository import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.SwapToIndividualNudgeEmail @@ -28,14 +27,13 @@ class SwapToIndividualNudgeEmailService( // TODO: PDJB-1274: Update emails to account for org landlord val soleLandlord = propertyOwnership.landlords.single() - check(soleLandlord is IndividualLandlord) val propertyAddress = propertyOwnership.address.toMultiLineAddress() val propertyRecordUrl = absoluteUrlProvider.buildPropertyDetailsUri(propertyOwnership.id).toString() nudgeEmailNotificationService.sendEmail( - soleLandlord.email, + soleLandlord.contactEmail, SwapToIndividualNudgeEmail( - recipientName = soleLandlord.name, + recipientName = soleLandlord.contactName, propertyAddress = propertyAddress, propertyRecordUrl = propertyRecordUrl, ), diff --git a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandler.kt b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandler.kt index 52184fd97f..2ba42a3593 100644 --- a/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandler.kt +++ b/src/main/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandler.kt @@ -4,7 +4,6 @@ import kotlinx.serialization.json.Json import org.springframework.beans.factory.annotation.Value import uk.gov.communities.prsdb.webapp.annotations.taskAnnotations.PrsdbTaskService import uk.gov.communities.prsdb.webapp.constants.enums.CertificateType -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership import uk.gov.communities.prsdb.webapp.database.entity.VirusScanCallback import uk.gov.communities.prsdb.webapp.database.repository.PropertyOwnershipRepository @@ -44,8 +43,7 @@ class VirusNotificationEmailHandler( } else { // TODO: PDJB-1274: Update emails to account for org landlord ownership.landlords.forEach { landlord -> - check(landlord is IndividualLandlord) - emailNotificationService.sendEmail(landlord.email, email) + emailNotificationService.sendEmail(landlord.contactEmail, email) } } } From 09589bb9189f54f5e13b4a481461c3c49afc204f Mon Sep 17 00:00:00 2001 From: samyou-softwire <108681823+samyou-softwire@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:55:43 +0100 Subject: [PATCH 5/5] PDJB-1425: Update tests --- ...ALandlordForThisPropertyStepConfigTests.kt | 94 +++++-- .../SendRejectionEmailsStepConfigTests.kt | 95 ++++---- .../CancelInvitationStepConfigTests.kt | 59 ++++- .../stepConfig/DeregisterStepConfigTests.kt | 27 ++ .../stepConfig/ConfirmStepConfigTests.kt | 38 ++- .../InviteJointLandlordStepConfigTests.kt | 10 +- ...mpleteSwitchToIndividualStepConfigTests.kt | 42 +++- .../InviteJointLandlordsFormModelTests.kt | 34 ++- ...rtyDetailsLandlordViewModelBuilderTests.kt | 18 +- ...rtiesReminderTaskApplicationRunnerTests.kt | 61 ++++- ...ndlordInvitationExpiryEmailServiceTests.kt | 67 ++++- .../JointLandlordInvitationServiceTests.kt | 184 ++++++++++++-- ...dlordOtherLandlordLeftEmailServiceTests.kt | 38 ++- .../LandlordRegistrationServiceTests.kt | 18 +- .../webapp/services/LandlordServiceTests.kt | 36 +-- .../OrganisationLandlordUserServiceTests.kt | 14 +- .../PropertyComplianceServiceTests.kt | 230 ++++++++++++++---- .../PropertyRegistrationServiceTests.kt | 77 ++++++ .../PropertyUpdateEmailServiceTests.kt | 64 ++++- .../SwapToIndividualNudgeEmailServiceTests.kt | 48 +++- .../services/UserToLandlordServiceTests.kt | 2 +- .../VirusNotificationEmailHandlerTests.kt | 45 ++++ .../mockObjects/MockLandlordData.kt | 8 + 23 files changed, 1114 insertions(+), 195 deletions(-) diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfigTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfigTests.kt index dddce43faf..9ef045f168 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfigTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/ConfirmYouAreALandlordForThisPropertyStepConfigTests.kt @@ -8,7 +8,6 @@ import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import org.mockito.Mock -import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoInteractions import org.mockito.junit.jupiter.MockitoExtension @@ -16,11 +15,10 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.whenever -import org.springframework.security.core.Authentication -import org.springframework.security.core.context.SecurityContext import org.springframework.security.core.context.SecurityContextHolder import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.database.entity.JointLandlordInvitation +import uk.gov.communities.prsdb.webapp.database.entity.Landlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership import uk.gov.communities.prsdb.webapp.journeys.acceptOrRejectJointLandlordInvitation.AcceptOrRejectJointLandlordInvitationJourneyState import uk.gov.communities.prsdb.webapp.models.dataModels.RegistrationNumberDataModel @@ -186,9 +184,41 @@ class ConfirmYouAreALandlordForThisPropertyStepConfigTests { // Assert val emailCaptor = argumentCaptor() - verify(mockAcceptedEmailSender).sendEmail(eq(landlord.email), emailCaptor.capture()) + verify(mockAcceptedEmailSender).sendEmail(eq(landlord.contactEmail), emailCaptor.capture()) val email = emailCaptor.firstValue - assertEquals(landlord.name, email.recipientName) + assertEquals(landlord.contactName, email.recipientName) + assertEquals(propertyOwnership.address.toMultiLineAddress(), email.propertyAddress) + assertEquals(expectedPropertyUrl, email.propertyRecordUrl) + assertEquals( + RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber).toString(), + email.propertyRegistrationNumber, + ) + } + + @Test + fun `afterStepDataIsAdded sends accepted email to org accepting landlord using contact details when token is valid`() { + // Arrange + val stepConfig = setupStepConfig() + val acceptingLandlord = + MockLandlordData.createOrgLandlord( + baseUser = MockLandlordData.createPrsdbUser(baseUserId), + name = "Accepting Estates Ltd", + registrantName = "Alicia Contact", + registrantEmail = "alicia@example.com", + ) + val propertyOwnership = MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(acceptingLandlord)) + val invitation = MockJointLandlordData.createJointLandlordInvitation(propertyOwnership = propertyOwnership) + val expectedPropertyUrl = "https://example.com/property" + setupValidTokenWithLandlordAndOwnership(acceptingLandlord, propertyOwnership, invitation) + + // Act + stepConfig.afterStepDataIsAdded(mockState) + + // Assert + val emailCaptor = argumentCaptor() + verify(mockAcceptedEmailSender).sendEmail(eq(acceptingLandlord.contactEmail), emailCaptor.capture()) + val email = emailCaptor.firstValue + assertEquals(acceptingLandlord.contactName, email.recipientName) assertEquals(propertyOwnership.address.toMultiLineAddress(), email.propertyAddress) assertEquals(expectedPropertyUrl, email.propertyRecordUrl) assertEquals( @@ -221,10 +251,46 @@ class ConfirmYouAreALandlordForThisPropertyStepConfigTests { // Assert val emailCaptor = argumentCaptor() - verify(mockOtherLandlordEmailSender).sendEmail(eq(otherLandlord.email), emailCaptor.capture()) + verify(mockOtherLandlordEmailSender).sendEmail(eq(otherLandlord.contactEmail), emailCaptor.capture()) + val email = emailCaptor.firstValue + assertEquals(otherLandlord.contactName, email.recipientName) + assertEquals(acceptingLandlord.displayName, email.inviteeName) + assertEquals(propertyOwnership.address.toMultiLineAddress(), email.propertyAddress) + assertEquals(expectedPropertyUrl, email.propertyRecordUrl) + } + + @Test + fun `afterStepDataIsAdded sends org other email using contact details and accepting landlord display name when token is valid`() { + // Arrange + val stepConfig = setupStepConfig() + val acceptingLandlord = + MockLandlordData.createOrgLandlord( + baseUser = MockLandlordData.createPrsdbUser(baseUserId), + name = "Accepting Estates Ltd", + registrantName = "Alicia Contact", + registrantEmail = "alicia@example.com", + ) + val otherLandlord = + MockLandlordData.createOrgLandlord( + baseUser = MockLandlordData.createPrsdbUser("other-user"), + name = "Other Estates Ltd", + registrantName = "Oliver Contact", + registrantEmail = "oliver@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(acceptingLandlord, otherLandlord)) + setupValidTokenWithLandlordAndOwnership(acceptingLandlord, propertyOwnership) + val expectedPropertyUrl = "https://example.com/property" + + // Act + stepConfig.afterStepDataIsAdded(mockState) + + // Assert + val emailCaptor = argumentCaptor() + verify(mockOtherLandlordEmailSender).sendEmail(eq(otherLandlord.contactEmail), emailCaptor.capture()) val email = emailCaptor.firstValue - assertEquals(otherLandlord.name, email.recipientName) - assertEquals(acceptingLandlord.name, email.inviteeName) + assertEquals(otherLandlord.contactName, email.recipientName) + assertEquals(acceptingLandlord.displayName, email.inviteeName) assertEquals(propertyOwnership.address.toMultiLineAddress(), email.propertyAddress) assertEquals(expectedPropertyUrl, email.propertyRecordUrl) } @@ -297,20 +363,12 @@ class ConfirmYouAreALandlordForThisPropertyStepConfigTests { } private fun setupValidTokenWithLandlordAndOwnership( - acceptingLandlord: IndividualLandlord, + acceptingLandlord: Landlord, propertyOwnership: PropertyOwnership, + invitation: JointLandlordInvitation = MockJointLandlordData.createJointLandlordInvitation(propertyOwnership = propertyOwnership), ) { - val invitation = MockJointLandlordData.createJointLandlordInvitation(propertyOwnership = propertyOwnership) setupValidTokenWithInvitation(invitation) whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(acceptingLandlord) whenever(mockAbsoluteUrlProvider.buildPropertyDetailsUri(any())).thenReturn(URI("https://example.com/property")) } - - private fun setMockPrincipal(name: String) { - val authentication = mock() - whenever(authentication.name).thenReturn(name) - val context = mock() - whenever(context.authentication).thenReturn(authentication) - SecurityContextHolder.setContext(context) - } } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfigTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfigTests.kt index c72614fb25..345a4d319b 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfigTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/acceptOrRejectJointLandlordInvitation/steps/SendRejectionEmailsStepConfigTests.kt @@ -3,20 +3,17 @@ package uk.gov.communities.prsdb.webapp.journeys.acceptOrRejectJointLandlordInvi import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mock -import org.mockito.Mockito.mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.eq import org.mockito.kotlin.verify import org.mockito.kotlin.whenever -import uk.gov.communities.prsdb.webapp.database.entity.Address -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord -import uk.gov.communities.prsdb.webapp.database.entity.JointLandlordInvitation -import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership import uk.gov.communities.prsdb.webapp.journeys.acceptOrRejectJointLandlordInvitation.AcceptOrRejectJointLandlordInvitationJourneyState import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.JointLandlordInvitationRejectionEmail import uk.gov.communities.prsdb.webapp.services.AbsoluteUrlProvider import uk.gov.communities.prsdb.webapp.services.EmailNotificationService import uk.gov.communities.prsdb.webapp.services.JointLandlordInvitationService +import uk.gov.communities.prsdb.webapp.testHelpers.mockObjects.MockJointLandlordData +import uk.gov.communities.prsdb.webapp.testHelpers.mockObjects.MockLandlordData import java.net.URI @ExtendWith(MockitoExtension::class) @@ -36,29 +33,33 @@ class SendRejectionEmailsStepConfigTests { private val journeyId = "test-journey-id" @Test - fun `afterStepIsReached sends rejection email to all landlords`() { + fun `afterStepIsReached sends rejection email to each landlord using contact details`() { // Arrange val stepConfig = setupStepConfig() - - val landlord1 = mock() - whenever(landlord1.name).thenReturn("Lois Lane") - whenever(landlord1.email).thenReturn("lois@example.com") - - val landlord2 = mock() - whenever(landlord2.name).thenReturn("Clark Kent") - whenever(landlord2.email).thenReturn("clark@example.com") - - val mockAddress = mock
() - whenever(mockAddress.toMultiLineAddress()).thenReturn("Flat 1\n11 Elm Drive\nLondon\nNW8 2DK") - - val mockPropertyOwnership = mock() - whenever(mockPropertyOwnership.address).thenReturn(mockAddress) - whenever(mockPropertyOwnership.landlords).thenReturn(mutableSetOf(landlord1, landlord2)) - whenever(mockPropertyOwnership.id).thenReturn(42L) - - val invitation = mock() - whenever(invitation.registeredOwnership).thenReturn(mockPropertyOwnership) - whenever(invitation.invitedEmail).thenReturn("invitee@example.com") + val address = MockLandlordData.createAddress("Flat 1, 11 Elm Drive, London, NW8 2DK") + val propertyAddress = address.toMultiLineAddress() + val individualLandlord = + MockLandlordData.createIndividualLandlord( + name = "Lois Lane", + email = "lois@example.com", + ) + val organisationLandlord = + MockLandlordData.createOrgLandlord( + name = "Clark Properties Ltd", + registrantName = "Clark Kent", + registrantEmail = "clark@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership( + id = 42L, + address = address, + landlords = mutableSetOf(individualLandlord, organisationLandlord), + ) + val invitation = + MockJointLandlordData.createJointLandlordInvitation( + email = "invitee@example.com", + propertyOwnership = propertyOwnership, + ) whenever(mockState.journeyId).thenReturn(journeyId) whenever(mockInvitationService.getInvitationForJourney(journeyId)).thenReturn(invitation) @@ -69,23 +70,23 @@ class SendRejectionEmailsStepConfigTests { // Assert verify(mockRejectionEmailSender).sendEmail( - eq("lois@example.com"), + eq(individualLandlord.contactEmail), eq( JointLandlordInvitationRejectionEmail( - recipientName = "Lois Lane", + recipientName = individualLandlord.contactName, inviteeEmail = "invitee@example.com", - propertyAddress = "Flat 1\n11 Elm Drive\nLondon\nNW8 2DK", + propertyAddress = propertyAddress, propertyRecordUrl = "http://localhost/property/42", ), ), ) verify(mockRejectionEmailSender).sendEmail( - eq("clark@example.com"), + eq(organisationLandlord.contactEmail), eq( JointLandlordInvitationRejectionEmail( - recipientName = "Clark Kent", + recipientName = organisationLandlord.contactName, inviteeEmail = "invitee@example.com", - propertyAddress = "Flat 1\n11 Elm Drive\nLondon\nNW8 2DK", + propertyAddress = propertyAddress, propertyRecordUrl = "http://localhost/property/42", ), ), @@ -96,22 +97,16 @@ class SendRejectionEmailsStepConfigTests { fun `afterStepIsReached stores rejection property address in session`() { // Arrange val stepConfig = setupStepConfig() - - val mockAddress = mock
() - whenever(mockAddress.toMultiLineAddress()).thenReturn("Flat 1\n11 Elm Drive\nLondon\nNW8 2DK") - - val landlord = mock() - whenever(landlord.name).thenReturn("Lois Lane") - whenever(landlord.email).thenReturn("lois@example.com") - - val mockPropertyOwnership = mock() - whenever(mockPropertyOwnership.address).thenReturn(mockAddress) - whenever(mockPropertyOwnership.landlords).thenReturn(mutableSetOf(landlord)) - whenever(mockPropertyOwnership.id).thenReturn(42L) - - val invitation = mock() - whenever(invitation.registeredOwnership).thenReturn(mockPropertyOwnership) - whenever(invitation.invitedEmail).thenReturn("invitee@example.com") + val address = MockLandlordData.createAddress("Flat 1, 11 Elm Drive, London, NW8 2DK") + val propertyAddress = address.toMultiLineAddress() + val landlord = MockLandlordData.createOrgLandlord() + val propertyOwnership = + MockLandlordData.createPropertyOwnership( + id = 42L, + address = address, + landlords = mutableSetOf(landlord), + ) + val invitation = MockJointLandlordData.createJointLandlordInvitation(propertyOwnership = propertyOwnership) whenever(mockState.journeyId).thenReturn(journeyId) whenever(mockInvitationService.getInvitationForJourney(journeyId)).thenReturn(invitation) @@ -121,9 +116,7 @@ class SendRejectionEmailsStepConfigTests { stepConfig.afterStepIsReached(mockState) // Assert - verify(mockInvitationService).addRejectedPropertyAddressToSession( - "Flat 1\n11 Elm Drive\nLondon\nNW8 2DK", - ) + verify(mockInvitationService).addRejectedPropertyAddressToSession(propertyAddress) } private fun setupStepConfig() = diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfigTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfigTests.kt index 16bd1e7d09..a747c5aa54 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfigTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/cancelJointLandlordInvitation/stepConfig/CancelInvitationStepConfigTests.kt @@ -6,12 +6,14 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.springframework.security.core.context.SecurityContextHolder import org.springframework.test.util.ReflectionTestUtils +import uk.gov.communities.prsdb.webapp.database.entity.Landlord import uk.gov.communities.prsdb.webapp.journeys.Destination import uk.gov.communities.prsdb.webapp.journeys.cancelJointLandlordInvitation.CancelJointLandlordInvitationJourneyState import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.JointLandlordInvitationCancellationCancellerEmail @@ -25,6 +27,7 @@ import uk.gov.communities.prsdb.webapp.services.UserToLandlordService import uk.gov.communities.prsdb.webapp.testHelpers.mockObjects.MockJointLandlordData import uk.gov.communities.prsdb.webapp.testHelpers.mockObjects.MockLandlordData import java.net.URI +import kotlin.test.assertEquals @ExtendWith(MockitoExtension::class) class CancelInvitationStepConfigTests { @@ -52,7 +55,6 @@ class CancelInvitationStepConfigTests { @Mock lateinit var mockState: CancelJointLandlordInvitationJourneyState - private val baseUserId = "test-user-id" private val invitedEmail = "invitee@example.com" private val cancellerEmail = "canceller@example.com" private val cancellerName = "Canceller Name" @@ -92,6 +94,25 @@ class CancelInvitationStepConfigTests { ) } + @Test + fun `afterStepIsReached sends confirmation email using organisation canceller contact details`() { + val stepConfig = setupStepConfig() + val cancellerLandlord = + MockLandlordData.createOrgLandlord( + name = "Canceller Organisation", + email = "organisation@example.com", + registrantName = "Canceller Contact", + registrantEmail = "org-contact@example.com", + ) + setupMocks(includeOtherLandlord = false, cancellerLandlord = cancellerLandlord) + val emailCaptor = argumentCaptor() + + stepConfig.afterStepIsReached(mockState) + + verify(mockCancellerEmailSender).sendEmail(eq(cancellerLandlord.contactEmail), emailCaptor.capture()) + assertEquals(cancellerLandlord.contactName, emailCaptor.firstValue.recipientName) + } + @Test fun `afterStepIsReached sends notification email to other landlords`() { val stepConfig = setupStepConfig() @@ -105,6 +126,25 @@ class CancelInvitationStepConfigTests { ) } + @Test + fun `afterStepIsReached sends notification email using organisation other landlord contact details`() { + val stepConfig = setupStepConfig() + val otherLandlord = + MockLandlordData.createOrgLandlord( + name = "Other Organisation", + email = "other-organisation@example.com", + registrantName = "Other Contact", + registrantEmail = "other-contact@example.com", + ) + setupMocks(otherLandlord = otherLandlord) + val emailCaptor = argumentCaptor() + + stepConfig.afterStepIsReached(mockState) + + verify(mockOtherLandlordEmailSender).sendEmail(eq(otherLandlord.contactEmail), emailCaptor.capture()) + assertEquals(otherLandlord.contactName, emailCaptor.firstValue.recipientName) + } + @Test fun `afterStepIsReached does not send other landlord email to canceller`() { val stepConfig = setupStepConfig() @@ -160,8 +200,19 @@ class CancelInvitationStepConfigTests { verify(mockState).deleteJourney() } - private fun setupMocks(includeOtherLandlord: Boolean = true): uk.gov.communities.prsdb.webapp.database.entity.JointLandlordInvitation { - val cancellerLandlord = MockLandlordData.createIndividualLandlord(name = cancellerName, email = cancellerEmail) + private fun setupMocks( + includeOtherLandlord: Boolean = true, + cancellerLandlord: Landlord = + MockLandlordData.createIndividualLandlord( + name = cancellerName, + email = cancellerEmail, + ), + otherLandlord: Landlord = + MockLandlordData.createIndividualLandlord( + name = otherLandlordName, + email = otherLandlordEmail, + ), + ): uk.gov.communities.prsdb.webapp.database.entity.JointLandlordInvitation { ReflectionTestUtils.setField(cancellerLandlord, "id", 1L) val propertyOwnership = @@ -171,8 +222,6 @@ class CancelInvitationStepConfigTests { ) if (includeOtherLandlord) { - val otherLandlord = - MockLandlordData.createIndividualLandlord(name = otherLandlordName, email = otherLandlordEmail) ReflectionTestUtils.setField(otherLandlord, "id", 2L) propertyOwnership.addLandlord(otherLandlord) } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfigTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfigTests.kt index 9e1ed63f91..26ea52bf83 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfigTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/landlordDeregistration/stepConfig/DeregisterStepConfigTests.kt @@ -103,6 +103,33 @@ class DeregisterStepConfigTests { ) } + @Test + fun `afterStepIsReached sends with-properties confirmation email to organisation sole user contact email`() { + val stepConfig = setupStepConfig() + JourneyTestHelper.setMockUser(baseUserId) + val organisationDisplayEmail = "organisation@example.com" + val organisationContactEmail = "sole-user@example.com" + val property = MockLandlordData.createPropertyOwnership() + val landlord = + MockLandlordData.createOrgLandlord( + email = organisationDisplayEmail, + registrantEmail = organisationContactEmail, + propertyOwnerships = setOf(property), + ) + whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(landlord) + + stepConfig.afterStepIsReached(mockState) + + verify(mockConfirmationWithPropertiesEmailSender).sendEmail( + eq(organisationContactEmail), + any(), + ) + verify(mockConfirmationWithPropertiesEmailSender, never()).sendEmail( + eq(organisationDisplayEmail), + any(), + ) + } + @Test fun `afterStepIsReached sets session marker to false when landlord has no properties`() { val stepConfig = setupStepConfig() diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfigTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfigTests.kt index 0fef576a16..e82ae4468d 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfigTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/propertyDeregistration/stepConfig/ConfirmStepConfigTests.kt @@ -72,7 +72,10 @@ class ConfirmStepConfigTests { stepConfig.afterStepDataIsAdded(mockState) - verify(mockPropertyDeregistrationService).addDeregisteredPropertyOwnershipIdToSession(propertyOwnershipId, propertyAddress) + verify(mockPropertyDeregistrationService).addDeregisteredPropertyOwnershipIdToSession( + propertyOwnershipId, + propertyAddress, + ) } @Test @@ -85,7 +88,38 @@ class ConfirmStepConfigTests { stepConfig.afterStepDataIsAdded(mockState) - verify(mockConfirmationEmailSender).sendEmail(eq("james@example.com"), any()) + verify(mockConfirmationEmailSender).sendEmail( + eq("james@example.com"), + any(), + ) + } + + @Test + fun `afterStepDataIsAdded sends confirmation email to organisation sole user contact details`() { + val stepConfig = setupStepConfig() + val organisationDisplayEmail = "organisation@example.com" + val organisationContactEmail = "sole-user@example.com" + val organisationContactName = "Sole User" + val organisationLandlord = + MockLandlordData.createOrgLandlord( + email = organisationDisplayEmail, + registrantName = organisationContactName, + registrantEmail = organisationContactEmail, + ) + whenever(mockState.propertyOwnershipId).thenReturn(propertyOwnershipId) + whenever(mockPropertyOwnershipService.getPropertyOwnership(propertyOwnershipId)) + .thenReturn(MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(organisationLandlord))) + + stepConfig.afterStepDataIsAdded(mockState) + + verify(mockConfirmationEmailSender).sendEmail( + eq(organisationContactEmail), + argThat { this.landlordName == organisationContactName }, + ) + verify(mockConfirmationEmailSender, never()).sendEmail( + eq(organisationDisplayEmail), + any(), + ) } @Test diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/shared/inviteJointLandlord/InviteJointLandlordStepConfigTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/shared/inviteJointLandlord/InviteJointLandlordStepConfigTests.kt index 79ad5fd986..6035ef3b25 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/shared/inviteJointLandlord/InviteJointLandlordStepConfigTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/shared/inviteJointLandlord/InviteJointLandlordStepConfigTests.kt @@ -97,15 +97,15 @@ class InviteJointLandlordStepConfigTests { } @Test - fun `enrichSubmittedDataBeforeValidation includes both session and existing invited emails`() { + fun `enrichSubmittedDataBeforeValidation includes organisation contact emails from dependencies`() { val stepConfig = InviteJointLandlordStepConfig(urlParameterService) stepConfig.routeSegment = InviteJointLandlordStep.INVITE_ANOTHER_ROUTE_SEGMENT stepConfig.validator = AlwaysTrueValidator() whenever(mockJourneyState.invitedJointLandlords).thenReturn(listOf("session@example.com")) whenever(mockJourneyState.dependencies).thenReturn(mockDependencies) whenever(mockDependencies.existingInvitedEmails).thenReturn(listOf("existing@example.com")) - whenever(mockDependencies.existingLandlordEmails).thenReturn(listOf("landlord@example.com")) - whenever(mockDependencies.loggedInLandlordEmail).thenReturn("me@example.com") + whenever(mockDependencies.existingLandlordEmails).thenReturn(listOf("sole-user@example.com")) + whenever(mockDependencies.loggedInLandlordEmail).thenReturn("sole-user@example.com") whenever(urlParameterService.getParameterOrNull()).thenReturn(null) val result = stepConfig.enrichSubmittedDataBeforeValidation(mockJourneyState, emptyMap()) @@ -115,8 +115,8 @@ class InviteJointLandlordStepConfigTests { assertEquals(listOf("session@example.com", "existing@example.com"), invitedAddresses) @Suppress("UNCHECKED_CAST") val landlordEmails = result["existingLandlordEmails"] as List - assertEquals(listOf("landlord@example.com"), landlordEmails) - assertEquals("me@example.com", result["loggedInLandlordEmail"]) + assertEquals(listOf("sole-user@example.com"), landlordEmails) + assertEquals("sole-user@example.com", result["loggedInLandlordEmail"]) } private fun setupStepConfig(): InviteJointLandlordStepConfig { diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfigTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfigTests.kt index 2bb0b64b5a..ef95aab551 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfigTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/journeys/switchToIndividual/stepConfig/CompleteSwitchToIndividualStepConfigTests.kt @@ -8,11 +8,11 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import uk.gov.communities.prsdb.webapp.constants.SWITCHED_TO_INDIVIDUAL_PROPERTY_ID -import uk.gov.communities.prsdb.webapp.database.entity.IndividualLandlord import uk.gov.communities.prsdb.webapp.exceptions.PrsdbWebException import uk.gov.communities.prsdb.webapp.journeys.shared.Complete import uk.gov.communities.prsdb.webapp.journeys.switchToIndividual.SwitchToIndividualJourneyState @@ -153,10 +153,11 @@ class CompleteSwitchToIndividualStepConfigTests { } @Test - fun `afterStepIsReached sends confirmation email to the landlord`() { + fun `afterStepIsReached sends confirmation email to the landlord contact details`() { val stepConfig = setupStepConfig() val propertyOwnershipId = 1L val propertyOwnership = MockLandlordData.createPropertyOwnership(id = propertyOwnershipId) + val emailCaptor = argumentCaptor() whenever(mockState.propertyOwnershipId).thenReturn(propertyOwnershipId) whenever(mockPropertyOwnershipService.getPropertyOwnership(propertyOwnershipId)).thenReturn(propertyOwnership) whenever(mockJointLandlordInvitationService.getPendingInvitations(propertyOwnership)) @@ -164,9 +165,42 @@ class CompleteSwitchToIndividualStepConfigTests { stepConfig.afterStepIsReached(mockState) + val landlord = propertyOwnership.landlords.first() verify(mockSwitchToIndividualConfirmationEmailSender).sendEmail( - eq((propertyOwnership.landlords.first() as IndividualLandlord).email), - any(), + eq(landlord.contactEmail), + emailCaptor.capture(), ) + assertEquals(landlord.contactName, emailCaptor.firstValue.landlordName) + } + + @Test + fun `afterStepIsReached sends confirmation email using organisation landlord contact details`() { + val stepConfig = setupStepConfig() + val propertyOwnershipId = 1L + val landlord = + MockLandlordData.createOrgLandlord( + name = "Example Organisation", + email = "organisation@example.com", + registrantName = "Alex Contact", + registrantEmail = "alex.contact@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership( + id = propertyOwnershipId, + landlords = mutableSetOf(landlord), + ) + val emailCaptor = argumentCaptor() + whenever(mockState.propertyOwnershipId).thenReturn(propertyOwnershipId) + whenever(mockPropertyOwnershipService.getPropertyOwnership(propertyOwnershipId)).thenReturn(propertyOwnership) + whenever(mockJointLandlordInvitationService.getPendingInvitations(propertyOwnership)) + .thenReturn(emptyList()) + + stepConfig.afterStepIsReached(mockState) + + verify(mockSwitchToIndividualConfirmationEmailSender).sendEmail( + eq(landlord.contactEmail), + emailCaptor.capture(), + ) + assertEquals(landlord.contactName, emailCaptor.firstValue.landlordName) } } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/requestModels/formModels/InviteJointLandlordsFormModelTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/requestModels/formModels/InviteJointLandlordsFormModelTests.kt index 4a53252008..b831be9060 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/requestModels/formModels/InviteJointLandlordsFormModelTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/requestModels/formModels/InviteJointLandlordsFormModelTests.kt @@ -64,16 +64,27 @@ class InviteJointLandlordsFormModelTests { } @Test - fun `a user cannot invite an email that is already a joint landlord on the property`() { + fun `a user cannot invite an organisation landlord contact email that is already on the property`() { val formModel = InviteJointLandlordsFormModel().apply { - existingLandlordEmails = mutableListOf("landlord@example.com") - emailAddress = "landlord@example.com" + existingLandlordEmails = mutableListOf("sole-user@example.com") + emailAddress = "sole-user@example.com" } assertFalse(formModel.isEmailNotAlreadyOnProperty()) } + @Test + fun `a user can invite an organisation display email when only the contact email is already on the property`() { + val formModel = + InviteJointLandlordsFormModel().apply { + existingLandlordEmails = mutableListOf("sole-user@example.com") + emailAddress = "organisation@example.com" + } + + assertTrue(formModel.isEmailNotAlreadyOnProperty()) + } + @Test fun `a user can invite an email that is not already a joint landlord on the property`() { val formModel = @@ -86,16 +97,27 @@ class InviteJointLandlordsFormModelTests { } @Test - fun `a user cannot invite their own logged-in email address`() { + fun `a user cannot invite their own organisation contact email address`() { val formModel = InviteJointLandlordsFormModel().apply { - loggedInLandlordEmail = "me@example.com" - emailAddress = "me@example.com" + loggedInLandlordEmail = "sole-user@example.com" + emailAddress = "sole-user@example.com" } assertFalse(formModel.isEmailNotLoggedInLandlord()) } + @Test + fun `a user can invite an organisation display email when their logged-in email is the contact email`() { + val formModel = + InviteJointLandlordsFormModel().apply { + loggedInLandlordEmail = "sole-user@example.com" + emailAddress = "organisation@example.com" + } + + assertTrue(formModel.isEmailNotLoggedInLandlord()) + } + @Test fun `a user can invite an email that is not their own logged-in email address`() { val formModel = diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/viewModels/summaryModels/PropertyDetailsLandlordViewModelBuilderTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/viewModels/summaryModels/PropertyDetailsLandlordViewModelBuilderTests.kt index dc725210f4..9d9bea6112 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/viewModels/summaryModels/PropertyDetailsLandlordViewModelBuilderTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/models/viewModels/summaryModels/PropertyDetailsLandlordViewModelBuilderTests.kt @@ -1,6 +1,7 @@ package uk.gov.communities.prsdb.webapp.models.viewModels.summaryModels import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotEquals import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import uk.gov.communities.prsdb.webapp.constants.enums.RegistrationNumberType @@ -22,7 +23,8 @@ class PropertyDetailsLandlordViewModelBuilderTests { @Test fun `with single landlord returns one card with LRN and email`() { // Arrange, Act - val cards = PropertyDetailsLandlordViewModelBuilder.buildSummaryCards(setOf(loggedInLandlord), loggedInLandlord, 1L) + val cards = + PropertyDetailsLandlordViewModelBuilder.buildSummaryCards(setOf(loggedInLandlord), loggedInLandlord, 1L) // Assert val lrnValue = cards[0].summaryList[0].fieldValue @@ -65,19 +67,24 @@ class PropertyDetailsLandlordViewModelBuilderTests { @Test fun `with org landlord as current landlord uses org card title`() { + val orgDisplayEmail = "info@acme.com" + val soleUserContactEmail = "owner@acme.com" val orgLandlord = MockLandlordData.createOrgLandlord( name = "ACME Properties Ltd", - email = "info@acme.com", + email = orgDisplayEmail, + registrantEmail = soleUserContactEmail, registrationNumber = RegistrationNumber(RegistrationNumberType.LANDLORD, 5678L), ) val cards = PropertyDetailsLandlordViewModelBuilder.buildSummaryCards(setOf(orgLandlord), orgLandlord, 1L) + val displayedEmail = cards[0].summaryList[1].fieldValue assertEquals(1, cards.size) assertEquals("propertyDetails.landlordDetails.registeredLandlords.currentOrgCardTitle", cards[0].title) assertEquals("ACME Properties Ltd", cards[0].cardNumber) - assertEquals("info@acme.com", cards[0].summaryList[1].fieldValue) + assertEquals(orgDisplayEmail, displayedEmail) + assertNotEquals(soleUserContactEmail, displayedEmail) } @Test @@ -159,7 +166,10 @@ class PropertyDetailsLandlordViewModelBuilderTests { val card = cards.single() assertEquals(1, card.actions!!.size) - assertEquals("propertyDetails.landlordDetails.registeredLandlords.viewLandlordRecord", card.actions!![0].text) + assertEquals( + "propertyDetails.landlordDetails.registeredLandlords.viewLandlordRecord", + card.actions!![0].text, + ) assertEquals("/local-council/landlord-details/${landlord.id}", card.actions!![0].url) assertEquals(true, card.actions!![0].opensInNewTab) } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/scheduledTaskRunners/IncompletePropertiesReminderTaskApplicationRunnerTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/scheduledTaskRunners/IncompletePropertiesReminderTaskApplicationRunnerTests.kt index c10c87ac97..6047b8ee31 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/scheduledTaskRunners/IncompletePropertiesReminderTaskApplicationRunnerTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/scheduledTaskRunners/IncompletePropertiesReminderTaskApplicationRunnerTests.kt @@ -74,6 +74,59 @@ class IncompletePropertiesReminderTaskApplicationRunnerTests { verify(emailSender).sendEmail(emailAddress2, reminderEmail2) } + @Test + fun `sendIncompletePropertyReminders sends organisation landlord reminder to contact email rather than display email`() { + // Arrange + val displayEmail = "organisation@example.com" + val contactEmail = "sole-user@example.com" + val propertyAddress = "Organisation Address" + val createdDate = + DateTimeHelper.getJavaInstantFromLocalDate( + LocalDate.now().minusDays(INCOMPLETE_PROPERTY_AGE_WHEN_REMINDER_EMAIL_DUE_IN_DAYS.toLong()), + ) + val savedJourneyState = + MockSavedJourneyStateData.createSavedJourneyState( + serializedState = MockSavedJourneyStateData.createSerialisedStateWithSingleLineAddress(propertyAddress), + createdDate = createdDate, + entityId = 3L, + ) + val expectedEmail = + IncompletePropertyReminderEmail( + singleLineAddress = propertyAddress, + daysToComplete = 7, + prsdUrl = mockPrsdUrl, + ) + val reminderCutoffDate = + DateTimeHelper.getJavaInstantFromLocalDate( + LocalDate.now().minusDays(INCOMPLETE_PROPERTY_AGE_WHEN_REMINDER_EMAIL_DUE_IN_DAYS.toLong()), + ) + + whenever(incompletePropertiesService.getNumberOfPagesOfIncompletePropertiesOlderThanDate(reminderCutoffDate)).thenReturn( + 1, + ) + whenever(incompletePropertiesService.getIncompletePropertiesDueReminderPage(reminderCutoffDate, 0)) + .thenReturn( + listOf( + LandlordIncompleteProperties( + landlord = + MockLandlordData.createOrgLandlord( + email = displayEmail, + registrantEmail = contactEmail, + mainContactEmail = "main-contact@example.com", + ), + savedJourneyState = savedJourneyState, + ), + ), + ) + + // Act + taskLogic.sendIncompletePropertyReminders() + + // Assert + verify(emailSender).sendEmail(contactEmail, expectedEmail) + verify(emailSender, never()).sendEmail(displayEmail, expectedEmail) + } + @Test fun `sendIncompletePropertyReminders still attempts other sends when one email fails, and completes task`() { // Arrange @@ -235,7 +288,9 @@ class IncompletePropertiesReminderTaskApplicationRunnerTests { LocalDate.now().minusDays(INCOMPLETE_PROPERTY_AGE_WHEN_REMINDER_EMAIL_DUE_IN_DAYS.toLong()), ) - whenever(incompletePropertiesService.getNumberOfPagesOfIncompletePropertiesOlderThanDate(reminderCutoffDate)).thenReturn(1) + whenever(incompletePropertiesService.getNumberOfPagesOfIncompletePropertiesOlderThanDate(reminderCutoffDate)).thenReturn( + 1, + ) whenever(incompletePropertiesService.getIncompletePropertiesDueReminderPage(reminderCutoffDate)) .thenReturn( @@ -258,7 +313,9 @@ class IncompletePropertiesReminderTaskApplicationRunnerTests { LocalDate.now().minusDays(INCOMPLETE_PROPERTY_AGE_WHEN_REMINDER_EMAIL_DUE_IN_DAYS.toLong()), ) - whenever(incompletePropertiesService.getNumberOfPagesOfIncompletePropertiesOlderThanDate(reminderCutoffDate)).thenReturn(2) + whenever(incompletePropertiesService.getNumberOfPagesOfIncompletePropertiesOlderThanDate(reminderCutoffDate)).thenReturn( + 2, + ) whenever(incompletePropertiesService.getIncompletePropertiesDueReminderPage(reminderCutoffDate, 0)) .thenReturn( diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailServiceTests.kt index 103e0f9459..4792c67049 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationExpiryEmailServiceTests.kt @@ -51,7 +51,8 @@ class JointLandlordInvitationExpiryEmailServiceTests { fun `sendExpiryEmailsForExpiredInvitations sends expiry email to the primary landlord for each expired invitation`() { val primaryLandlord = MockLandlordData.createIndividualLandlord(name = "Lois", email = "lois@example.com") val address = MockLandlordData.createAddress(singleLineAddress = "Flat 1, 11 Elm Drive, London, NW8 2DK") - val propertyOwnership = MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(primaryLandlord), address = address) + val propertyOwnership = + MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(primaryLandlord), address = address) val invitation = MockJointLandlordData.createJointLandlordInvitation( email = "very-real-email@example.com", @@ -78,13 +79,59 @@ class JointLandlordInvitationExpiryEmailServiceTests { assertEquals(28, sentEmail.expiryDays) } + @Test + fun `sendExpiryEmailsForExpiredInvitations sends email to organisation landlord contact details`() { + val organisationLandlord = + MockLandlordData.createOrgLandlord( + name = "Acme Property Ltd", + email = "info@acme.example.com", + registrantName = "Alice Agent", + registrantEmail = "alice.agent@example.com", + ) + val propertyOwnership = MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(organisationLandlord)) + val invitation = + MockJointLandlordData.createJointLandlordInvitation( + email = "very-real-email@example.com", + propertyOwnership = propertyOwnership, + createdDate = expiredCreatedDate, + ) + val propertyRecordUri = URI("https://example.com/landlord/property/1") + + whenever(mockJointLandlordInvitationRepository.findAllByInvitationExpiredEmailSentFalse()) + .thenReturn(listOf(invitation)) + whenever(mockAbsoluteUrlProvider.buildPropertyDetailsUri(any())) + .thenReturn(propertyRecordUri) + + expiryService.sendExpiryEmailsForExpiredInvitations() + + val emailModelCaptor = argumentCaptor() + verify(mockExpiryEmailNotificationService).sendEmail(eq("alice.agent@example.com"), emailModelCaptor.capture()) + + val sentEmail = emailModelCaptor.firstValue + assertEquals("Alice Agent", sentEmail.recipientName) + assertEquals("very-real-email@example.com", sentEmail.invitedEmail) + assertEquals(propertyRecordUri, sentEmail.propertyRecordUri) + } + @Test fun `sendExpiryEmailsForExpiredInvitations sends one email per expired invitation`() { val invitations = listOf( - MockJointLandlordData.createJointLandlordInvitation(id = 1, email = "first@example.com", createdDate = expiredCreatedDate), - MockJointLandlordData.createJointLandlordInvitation(id = 2, email = "second@example.com", createdDate = expiredCreatedDate), - MockJointLandlordData.createJointLandlordInvitation(id = 3, email = "third@example.com", createdDate = expiredCreatedDate), + MockJointLandlordData.createJointLandlordInvitation( + id = 1, + email = "first@example.com", + createdDate = expiredCreatedDate, + ), + MockJointLandlordData.createJointLandlordInvitation( + id = 2, + email = "second@example.com", + createdDate = expiredCreatedDate, + ), + MockJointLandlordData.createJointLandlordInvitation( + id = 3, + email = "third@example.com", + createdDate = expiredCreatedDate, + ), ) whenever(mockJointLandlordInvitationRepository.findAllByInvitationExpiredEmailSentFalse()) @@ -101,8 +148,16 @@ class JointLandlordInvitationExpiryEmailServiceTests { fun `sendExpiryEmailsForExpiredInvitations marks when expiry email is sent and saves it after sending the email`() { val invitations = listOf( - MockJointLandlordData.createJointLandlordInvitation(id = 1, email = "first@example.com", createdDate = expiredCreatedDate), - MockJointLandlordData.createJointLandlordInvitation(id = 2, email = "second@example.com", createdDate = expiredCreatedDate), + MockJointLandlordData.createJointLandlordInvitation( + id = 1, + email = "first@example.com", + createdDate = expiredCreatedDate, + ), + MockJointLandlordData.createJointLandlordInvitation( + id = 2, + email = "second@example.com", + createdDate = expiredCreatedDate, + ), ) whenever(mockJointLandlordInvitationRepository.findAllByInvitationExpiredEmailSentFalse()) diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationServiceTests.kt index 98b70f0ce9..66e513b2de 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordInvitationServiceTests.kt @@ -93,7 +93,10 @@ class JointLandlordInvitationServiceTests { MockJointLandlordData.createJointLandlordInvitation( id = 456L, propertyOwnership = propertyOwnership, - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), ) whenever(mockJointLandlordInvitationRepository.findByRegisteredOwnership(propertyOwnership)) @@ -166,13 +169,19 @@ class JointLandlordInvitationServiceTests { MockJointLandlordData.createJointLandlordInvitation( id = 1L, propertyOwnership = propertyOwnership, - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 32).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 32).toLong(), ChronoUnit.DAYS), ) val newerExpired = MockJointLandlordData.createJointLandlordInvitation( id = 2L, propertyOwnership = propertyOwnership, - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 2).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 2).toLong(), ChronoUnit.DAYS), ) whenever(mockJointLandlordInvitationRepository.findByRegisteredOwnership(propertyOwnership)) @@ -192,13 +201,19 @@ class JointLandlordInvitationServiceTests { MockJointLandlordData.createJointLandlordInvitation( id = 1L, propertyOwnership = propertyOwnership, - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), ) val hiddenExpiredInvitation = MockJointLandlordData.createJointLandlordInvitation( id = 2L, propertyOwnership = propertyOwnership, - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), isHidden = true, ) @@ -286,6 +301,30 @@ class JointLandlordInvitationServiceTests { assertEquals(mockUri, emailModelCaptor.firstValue.invitationUri) } + @Test + fun `sendInvitationEmails uses organisation display name in invitation emails`() { + val jointLandlordEmails = listOf("landlord1@example.com") + val landlord = + MockLandlordData.createOrgLandlord( + name = "Acme Lettings Ltd", + registrantName = "Alex Contact", + registrantEmail = "alex.contact@example.com", + ) + val propertyOwnership = MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(landlord)) + val mockUri = URI("https://example.com/invite/test-token") + + whenever(mockAbsoluteUrlProvider.buildJointLandlordInvitationUri(any())) + .thenReturn(mockUri) + + invitationService.sendInvitationEmails(jointLandlordEmails, propertyOwnership, landlord) + + val emailModelCaptor = argumentCaptor() + verify(mockInvitationEmailSender) + .sendEmail(eq("landlord1@example.com"), emailModelCaptor.capture()) + + assertEquals("Acme Lettings Ltd", emailModelCaptor.firstValue.senderName) + } + @Test fun `sendInvitationEmails creates unique tokens for each invitation`() { val jointLandlordEmails = listOf("landlord1@example.com", "landlord2@example.com") @@ -327,6 +366,29 @@ class JointLandlordInvitationServiceTests { verify(mockConfirmationEmailSender).sendEmail(eq(invitingLandlord.email), any()) } + @Test + fun `sendInvitationEmails sends confirmation email to organisation landlord contact details`() { + val jointLandlordEmails = listOf("landlord1@example.com") + val landlord = + MockLandlordData.createOrgLandlord( + name = "Acme Lettings Ltd", + registrantName = "Alex Contact", + registrantEmail = "alex.contact@example.com", + ) + val propertyOwnership = MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(landlord)) + val mockUri = URI("https://example.com/invite/test-token") + + whenever(mockAbsoluteUrlProvider.buildJointLandlordInvitationUri(any())) + .thenReturn(mockUri) + + invitationService.sendInvitationEmails(jointLandlordEmails, propertyOwnership, landlord) + + val emailModelCaptor = argumentCaptor() + verify(mockConfirmationEmailSender).sendEmail(eq("alex.contact@example.com"), emailModelCaptor.capture()) + + assertEquals("Alex Contact", emailModelCaptor.firstValue.senderName) + } + @Test fun `sendInvitationEmails does not send confirmation email when list is empty`() { val propertyOwnership = MockLandlordData.createPropertyOwnership() @@ -398,7 +460,8 @@ class JointLandlordInvitationServiceTests { @Test fun `sendInvitationEmails sends notify-existing email to other landlords on property`() { val jointLandlordEmails = listOf("new@example.com") - val existingLandlord = MockLandlordData.createIndividualLandlord(name = "Existing", email = "existing@example.com") + val existingLandlord = + MockLandlordData.createIndividualLandlord(name = "Existing", email = "existing@example.com") ReflectionTestUtils.setField(existingLandlord, "id", 2L) ReflectionTestUtils.setField(invitingLandlord, "id", 1L) val propertyOwnership = @@ -416,11 +479,43 @@ class JointLandlordInvitationServiceTests { assertEquals(listOf("new@example.com"), emailModelCaptor.firstValue.jointLandlordEmails) } + @Test + fun `sendInvitationEmails uses organisation contact details for notify-existing emails`() { + val jointLandlordEmails = listOf("new@example.com") + val existingLandlord = + MockLandlordData.createOrgLandlord( + name = "Existing Organisation", + registrantName = "Existing Contact", + registrantEmail = "existing.contact@example.com", + ) + ReflectionTestUtils.setField(existingLandlord, "id", 2L) + ReflectionTestUtils.setField(invitingLandlord, "id", 1L) + val propertyOwnership = + MockLandlordData.createPropertyOwnership( + id = 123L, + landlords = mutableSetOf(invitingLandlord, existingLandlord), + ) + val mockUri = URI("https://example.com/invite/test-token") + + whenever(mockAbsoluteUrlProvider.buildJointLandlordInvitationUri(any())).thenReturn(mockUri) + + invitationService.sendInvitationEmails(jointLandlordEmails, propertyOwnership, invitingLandlord) + + val emailModelCaptor = argumentCaptor() + verify(mockNotifyExistingEmailSender).sendEmail( + eq("existing.contact@example.com"), + emailModelCaptor.capture(), + ) + assertEquals("Existing Contact", emailModelCaptor.firstValue.recipientName) + assertEquals(listOf("new@example.com"), emailModelCaptor.firstValue.jointLandlordEmails) + } + @Test fun `sendInvitationEmails does not send notify-existing email to inviting landlord`() { val jointLandlordEmails = listOf("new@example.com") ReflectionTestUtils.setField(invitingLandlord, "id", 1L) - val propertyOwnership = MockLandlordData.createPropertyOwnership(id = 123L, landlords = mutableSetOf(invitingLandlord)) + val propertyOwnership = + MockLandlordData.createPropertyOwnership(id = 123L, landlords = mutableSetOf(invitingLandlord)) val mockUri = URI("https://example.com/invite/test-token") whenever(mockAbsoluteUrlProvider.buildJointLandlordInvitationUri(any())).thenReturn(mockUri) @@ -509,6 +604,31 @@ class JointLandlordInvitationServiceTests { verify(mockJointLandlordInvitationRepository, times(1)).save(any()) } + @Test + fun `sendInvitationEmails skips emails matching an organisation landlord contact email`() { + val existingLandlord = + MockLandlordData.createOrgLandlord( + email = "organisation@example.com", + registrantEmail = "existing.contact@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership( + id = 123L, + landlords = mutableSetOf(invitingLandlord, existingLandlord), + ) + val jointLandlordEmails = listOf("Existing.Contact@Example.com", "new@example.com") + val mockUri = URI("https://example.com/invite/test-token") + + whenever(mockAbsoluteUrlProvider.buildJointLandlordInvitationUri(any())).thenReturn(mockUri) + + invitationService.sendInvitationEmails(jointLandlordEmails, propertyOwnership, invitingLandlord) + + val emailCaptor = argumentCaptor() + verify(mockInvitationEmailSender, times(1)).sendEmail(emailCaptor.capture(), any()) + assertEquals(listOf("new@example.com"), emailCaptor.allValues) + verify(mockJointLandlordInvitationRepository, times(1)).save(any()) + } + @Test fun `sendInvitationEmails skips emails already invited on the property ignoring case`() { val jointLandlordEmails = listOf("Already.Invited@Example.com", "new@example.com") @@ -672,7 +792,8 @@ class JointLandlordInvitationServiceTests { @Test fun `clearJourneyIdInvitationTokenPairsForTokenFromSession removes all pairs with matching token`() { // Arrange - val pairs = mutableListOf(Pair("journey1", "token1"), Pair("journey2", "token1"), Pair("journey3", "token2")) + val pairs = + mutableListOf(Pair("journey1", "token1"), Pair("journey2", "token1"), Pair("journey3", "token2")) whenever(mockHttpSession.getAttribute(JOINT_LANDLORD_INVITATION_TOKEN_WITH_ACCEPTANCE_JOURNEY_IDS)) .thenReturn(pairs) @@ -715,7 +836,9 @@ class JointLandlordInvitationServiceTests { @Test fun `getTokenIsValid returns true when token is a valid unexpired invitation`() { val mockInvitation = mock() - whenever(mockJointLandlordInvitationRepository.findByToken(UUID.fromString(validToken))).thenReturn(mockInvitation) + whenever(mockJointLandlordInvitationRepository.findByToken(UUID.fromString(validToken))).thenReturn( + mockInvitation, + ) whenever(mockInvitation.status).thenReturn(JointLandlordInvitationStatus.PENDING) assertTrue(invitationService.getTokenIsValid(validToken)) @@ -736,7 +859,9 @@ class JointLandlordInvitationServiceTests { @Test fun `getTokenIsValid returns false when invitation has expired`() { val mockInvitation = mock() - whenever(mockJointLandlordInvitationRepository.findByToken(UUID.fromString(validToken))).thenReturn(mockInvitation) + whenever(mockJointLandlordInvitationRepository.findByToken(UUID.fromString(validToken))).thenReturn( + mockInvitation, + ) whenever(mockInvitation.status).thenReturn(JointLandlordInvitationStatus.EXPIRED) assertFalse(invitationService.getTokenIsValid(validToken)) @@ -745,7 +870,9 @@ class JointLandlordInvitationServiceTests { @Test fun `getTokenIsValid returns false when invitation has been hidden`() { val mockInvitation = mock() - whenever(mockJointLandlordInvitationRepository.findByToken(UUID.fromString(validToken))).thenReturn(mockInvitation) + whenever(mockJointLandlordInvitationRepository.findByToken(UUID.fromString(validToken))).thenReturn( + mockInvitation, + ) whenever(mockInvitation.status).thenReturn(JointLandlordInvitationStatus.HIDDEN) assertFalse(invitationService.getTokenIsValid(validToken)) @@ -761,7 +888,10 @@ class JointLandlordInvitationServiceTests { MockJointLandlordData.createJointLandlordInvitation( id = 1L, propertyOwnership = propertyOwnership, - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), ) whenever(mockJointLandlordInvitationRepository.findById(1L)) @@ -795,7 +925,10 @@ class JointLandlordInvitationServiceTests { MockJointLandlordData.createJointLandlordInvitation( id = 1L, propertyOwnership = propertyOwnership, - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), ) whenever(mockJointLandlordInvitationRepository.findById(1L)) @@ -847,7 +980,10 @@ class JointLandlordInvitationServiceTests { val expiredInvitation = MockJointLandlordData.createJointLandlordInvitation( email = "expired@example.com", - createdDate = Instant.now().minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), + createdDate = + Instant + .now() + .minus((JOINT_LANDLORD_INVITATION_LIFETIME_IN_DAYS + 1).toLong(), ChronoUnit.DAYS), ) val hiddenInvitation = MockJointLandlordData.createJointLandlordInvitation( @@ -986,7 +1122,9 @@ class JointLandlordInvitationServiceTests { val propertyOwnership = MockLandlordData.createPropertyOwnership() val invitation = MockJointLandlordData.createJointLandlordInvitation(propertyOwnership = propertyOwnership) whenever(mockJointLandlordInvitationRepository.findById(invitation.id)).thenReturn(Optional.of(invitation)) - whenever(mockPropertyOwnershipService.getCurrentUserIsAuthorizedToEditRecord(propertyOwnership.id)).thenReturn(true) + whenever(mockPropertyOwnershipService.getCurrentUserIsAuthorizedToEditRecord(propertyOwnership.id)).thenReturn( + true, + ) val result = invitationService.getPendingInvitationIfAuthorizedLandlord(invitation.id) @@ -1017,7 +1155,9 @@ class JointLandlordInvitationServiceTests { val propertyOwnership = MockLandlordData.createPropertyOwnership() val invitation = MockJointLandlordData.createJointLandlordInvitation(propertyOwnership = propertyOwnership) whenever(mockJointLandlordInvitationRepository.findById(invitation.id)).thenReturn(Optional.of(invitation)) - whenever(mockPropertyOwnershipService.getCurrentUserIsAuthorizedToEditRecord(propertyOwnership.id)).thenReturn(false) + whenever(mockPropertyOwnershipService.getCurrentUserIsAuthorizedToEditRecord(propertyOwnership.id)).thenReturn( + false, + ) val exception = assertThrows { @@ -1152,7 +1292,10 @@ class JointLandlordInvitationServiceTests { invitationService.storeLastAcceptedPropertyInSession(address, propertyOwnershipId) - verify(mockHttpSession).setAttribute(ACCEPTED_JOINT_LANDLORD_PROPERTY_DETAILS, Pair(address, propertyOwnershipId)) + verify(mockHttpSession).setAttribute( + ACCEPTED_JOINT_LANDLORD_PROPERTY_DETAILS, + Pair(address, propertyOwnershipId), + ) } } @@ -1162,7 +1305,12 @@ class JointLandlordInvitationServiceTests { fun `getLastAcceptedPropertyFromSession returns pair when present`() { val address = "1 Test Street\nTest Town\nAB1 2CD" val propertyOwnershipId = 42L - whenever(mockHttpSession.getAttribute(ACCEPTED_JOINT_LANDLORD_PROPERTY_DETAILS)).thenReturn(Pair(address, propertyOwnershipId)) + whenever(mockHttpSession.getAttribute(ACCEPTED_JOINT_LANDLORD_PROPERTY_DETAILS)).thenReturn( + Pair( + address, + propertyOwnershipId, + ), + ) val result = invitationService.getLastAcceptedPropertyFromSession() diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailServiceTests.kt index 9051368bdb..5e7609bb3d 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/JointLandlordOtherLandlordLeftEmailServiceTests.kt @@ -35,7 +35,8 @@ class JointLandlordOtherLandlordLeftEmailServiceTests { val address = MockLandlordData.createAddress(singleLineAddress = "10 High Street, London, SW1A 1AA") val previousLandlord = MockLandlordData.createIndividualLandlord(name = "Alice", email = "alice@example.com") val remainingLandlordOne = MockLandlordData.createIndividualLandlord(name = "Bob", email = "bob@example.com") - val remainingLandlordTwo = MockLandlordData.createIndividualLandlord(name = "Carol", email = "carol@example.com") + val remainingLandlordTwo = + MockLandlordData.createIndividualLandlord(name = "Carol", email = "carol@example.com") val propertyOwnership = MockLandlordData.createPropertyOwnership( id = 7, @@ -62,6 +63,41 @@ class JointLandlordOtherLandlordLeftEmailServiceTests { assertEquals(propertyRecordUri.toString(), carolEmail.propertyRecordUrl) } + @Test + fun `sendNotificationToRemainingLandlords uses organisation display and contact details in emails`() { + val address = MockLandlordData.createAddress(singleLineAddress = "10 High Street, London, SW1A 1AA") + val previousLandlord = + MockLandlordData.createOrgLandlord( + name = "Leaving Organisation", + registrantName = "Leaving Contact", + registrantEmail = "leaving.contact@example.com", + ) + val remainingLandlord = + MockLandlordData.createOrgLandlord( + name = "Remaining Organisation", + registrantName = "Remaining Contact", + registrantEmail = "remaining.contact@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership( + id = 7, + landlords = mutableSetOf(remainingLandlord), + address = address, + ) + val propertyRecordUri = URI("https://example.com/landlord/property/7") + whenever(mockAbsoluteUrlProvider.buildPropertyDetailsUri(7)).thenReturn(propertyRecordUri) + + emailService.sendNotificationToRemainingLandlords(propertyOwnership, previousLandlord) + + val emailCaptor = argumentCaptor() + verify(mockNotificationEmailService).sendEmail(eq("remaining.contact@example.com"), emailCaptor.capture()) + + assertEquals("Leaving Organisation", emailCaptor.firstValue.leavingLandlord) + assertEquals("Remaining Contact", emailCaptor.firstValue.notifiedLandlord) + assertEquals(address.toMultiLineAddress(), emailCaptor.firstValue.address) + assertEquals(propertyRecordUri.toString(), emailCaptor.firstValue.propertyRecordUrl) + } + @Test fun `sendNotificationToRemainingLandlords sends no emails when there are no remaining landlords`() { val previousLandlord = MockLandlordData.createIndividualLandlord(name = "Alice", email = "alice@example.com") diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationServiceTests.kt index a35da20b32..72181b5f34 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordRegistrationServiceTests.kt @@ -197,7 +197,16 @@ class LandlordRegistrationServiceTests { fun stubIndividualLandlord() { whenever( mockLandlordService.createIndividualLandlord( - any(), any(), any(), any(), any(), any(), any(), any(), anyOrNull(), anyOrNull(), + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any(), + anyOrNull(), + anyOrNull(), ), ).thenReturn(individualLandlord) whenever(mockAbsoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(dashboardUri) @@ -450,7 +459,12 @@ class LandlordRegistrationServiceTests { fun `registerOrganisationLandlord creates an OrganisationLandlordUser`() { registerOrganisationLandlord() - verify(mockOrganisationLandlordUserService).createOrganisationLandlordUser(any(), eq(baseUser)) + verify(mockOrganisationLandlordUserService).createOrganisationLandlordUser( + any(), + eq(baseUser), + eq("Alice"), + eq("alice@test.com"), + ) } } } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordServiceTests.kt index f76ccd08d6..7731eb0625 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/LandlordServiceTests.kt @@ -39,7 +39,7 @@ import uk.gov.communities.prsdb.webapp.exceptions.RepositoryQueryTimeoutExceptio import uk.gov.communities.prsdb.webapp.models.dataModels.AddressDataModel import uk.gov.communities.prsdb.webapp.models.dataModels.LandlordSearchResultDataModel import uk.gov.communities.prsdb.webapp.models.dataModels.RegistrationNumberDataModel -import uk.gov.communities.prsdb.webapp.models.dataModels.updateModels.LandlordUpdateModel +import uk.gov.communities.prsdb.webapp.models.dataModels.updateModels.IndividualLandlordUpdateModel import uk.gov.communities.prsdb.webapp.models.viewModels.emailModels.LandlordUpdateConfirmation import uk.gov.communities.prsdb.webapp.models.viewModels.searchResultModels.LandlordSearchResultViewModel import uk.gov.communities.prsdb.webapp.testHelpers.mockObjects.MockLandlordData.Companion.createAddress @@ -479,12 +479,12 @@ class LandlordServiceTests { phoneNumber = originalPhoneNumber, dateOfBirth = originalDateOfBirth, ) - val updateModel = LandlordUpdateModel(null, null, null, null, null) + val updateModel = IndividualLandlordUpdateModel(null, null, null, null, null) whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(landlordEntity) // Act - landlordService.updateLandlordForUser(updateModel) {} + landlordService.updateIndividualLandlordForUser(updateModel) {} // Assert assertEquals(originalName, landlordEntity.name) @@ -506,7 +506,7 @@ class LandlordServiceTests { ) val newAddress = createAddress("new address") val updateModel = - LandlordUpdateModel( + IndividualLandlordUpdateModel( "newEmail", "newName", "new phone number", @@ -519,7 +519,7 @@ class LandlordServiceTests { whenever(absoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(URI("example.com/landlord-dashboard")) // Act - landlordService.updateLandlordForUser(updateModel) {} + landlordService.updateIndividualLandlordForUser(updateModel) {} // Assert assertEquals(updateModel.name, landlordEntity.name) @@ -550,7 +550,7 @@ class LandlordServiceTests { @ParameterizedTest @MethodSource("getUpdateAndExpectedEmailPairs") fun `when a landlord is updated, a corresponding email is sent to each relevant email`( - updateModel: LandlordUpdateModel, + updateModel: IndividualLandlordUpdateModel, expectedDetail: String, ) { // Arrange @@ -572,7 +572,7 @@ class LandlordServiceTests { whenever(absoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(dashboardUrl) // Act - landlordService.updateLandlordForUser(updateModel) {} + landlordService.updateIndividualLandlordForUser(updateModel) {} // Assert val expectedEmailModel = @@ -608,12 +608,12 @@ class LandlordServiceTests { address = createAddress("original address"), dateOfBirth = LocalDate.of(1991, 1, 1), ) - val updateModel = LandlordUpdateModel(newCasingEmailAddress, null, null, null, null) + val updateModel = IndividualLandlordUpdateModel(newCasingEmailAddress, null, null, null, null) whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(landlordEntity) whenever(absoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(URI("example.com/landlord-dashboard")) // Act - val updatedLandlord = landlordService.updateLandlordForUser(updateModel) {} + val updatedLandlord = landlordService.updateIndividualLandlordForUser(updateModel) {} // Assert assertEquals(newCasingEmailAddress, (updatedLandlord as IndividualLandlord).email) @@ -637,7 +637,7 @@ class LandlordServiceTests { ) val newAddress = createAddress("new address") val updateModel = - LandlordUpdateModel( + IndividualLandlordUpdateModel( "newEmail", "newName", "new phone number", @@ -647,7 +647,7 @@ class LandlordServiceTests { // Act try { - landlordService.updateLandlordForUser(updateModel) { throw Exception("Invalid update") } + landlordService.updateIndividualLandlordForUser(updateModel) { throw Exception("Invalid update") } } catch (_: Exception) { // Expected exception, do nothing } @@ -660,8 +660,8 @@ class LandlordServiceTests { } @Test - fun `updateLandlordForUser is annotated with @Transactional`() { - assertTrue(landlordService::updateLandlordForUser.hasAnnotation()) + fun `updateIndividualLandlordForUser is annotated with @Transactional`() { + assertTrue(landlordService::updateIndividualLandlordForUser.hasAnnotation()) } companion object { @@ -669,7 +669,7 @@ class LandlordServiceTests { fun getUpdateAndExpectedEmailPairs() = listOf( Arguments.of( - LandlordUpdateModel( + IndividualLandlordUpdateModel( "newEmail", null, null, @@ -679,7 +679,7 @@ class LandlordServiceTests { "email address", ), Arguments.of( - LandlordUpdateModel( + IndividualLandlordUpdateModel( null, "newName", null, @@ -689,7 +689,7 @@ class LandlordServiceTests { "name", ), Arguments.of( - LandlordUpdateModel( + IndividualLandlordUpdateModel( null, null, "new phone number", @@ -699,7 +699,7 @@ class LandlordServiceTests { "telephone number", ), Arguments.of( - LandlordUpdateModel( + IndividualLandlordUpdateModel( null, null, null, @@ -709,7 +709,7 @@ class LandlordServiceTests { "contact address", ), Arguments.of( - LandlordUpdateModel( + IndividualLandlordUpdateModel( null, null, null, diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserServiceTests.kt index fa96000101..13bceab90f 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/OrganisationLandlordUserServiceTests.kt @@ -27,13 +27,21 @@ class OrganisationLandlordUserServiceTests { private lateinit var mockOrganisationLandlord: OrganisationLandlord @Test - fun `createOrganisationLandlordUser saves and returns an OrganisationLandlordUser linking landlord to user`() { + fun `createOrganisationLandlordUser saves and returns an OrganisationLandlordUser linking landlord to user with contact details`() { val baseUser = PrsdbUser("user-123") + val name = "Alice Registrant" + val email = "alice@example.com" whenever(mockOrganisationLandlordUserRepository.save(any())) .thenAnswer { it.arguments[0] } - val result = organisationLandlordUserService.createOrganisationLandlordUser(mockOrganisationLandlord, baseUser) + val result = + organisationLandlordUserService.createOrganisationLandlordUser( + mockOrganisationLandlord, + baseUser, + name, + email, + ) val captor = captor() verify(mockOrganisationLandlordUserRepository).save(captor.capture()) @@ -41,6 +49,8 @@ class OrganisationLandlordUserServiceTests { val saved = captor.value assertEquals(mockOrganisationLandlord, saved.organisationLandlord) assertEquals(baseUser, saved.baseUser) + assertEquals(name, saved.name) + assertEquals(email, saved.email) assertEquals(result, saved) } } diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceServiceTests.kt index 53b15b12a0..3121c7046a 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyComplianceServiceTests.kt @@ -33,6 +33,7 @@ import uk.gov.communities.prsdb.webapp.constants.enums.FurnishedStatus import uk.gov.communities.prsdb.webapp.constants.enums.MeesExemptionReason import uk.gov.communities.prsdb.webapp.constants.enums.RentFrequency import uk.gov.communities.prsdb.webapp.database.entity.FileUpload +import uk.gov.communities.prsdb.webapp.database.entity.Landlord import uk.gov.communities.prsdb.webapp.database.entity.PropertyCompliance import uk.gov.communities.prsdb.webapp.database.repository.FileUploadRepository import uk.gov.communities.prsdb.webapp.database.repository.PropertyComplianceRepository @@ -86,7 +87,8 @@ class PropertyComplianceServiceTests { MockLandlordData.createIndividualLandlord( baseUser = MockLandlordData.createPrsdbUser(loggedInBaseUserId), ) - private val mockPropertyOwnership = MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(mockLoggedInLandlord)) + private val mockPropertyOwnership = + MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(mockLoggedInLandlord)) private val dateFormatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.UK) private fun createComplianceWithLastModifiedDate(lastModifiedDate: Instant = initialLastModifiedDate): PropertyCompliance { @@ -98,7 +100,9 @@ class PropertyComplianceServiceTests { @BeforeEach fun setup() { - lenient().`when`(mockAbsoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(URI("https://test.example.com")) + lenient() + .`when`(mockAbsoluteUrlProvider.buildLandlordDashboardUri()) + .thenReturn(URI("https://test.example.com")) lenient() .`when`( mockAbsoluteUrlProvider.buildComplianceInformationUri(any()), @@ -110,8 +114,8 @@ class PropertyComplianceServiceTests { SecurityContextHolder.clearContext() } - private fun setMockPrincipal() { - whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(mockLoggedInLandlord) + private fun setMockPrincipal(landlord: Landlord = mockLoggedInLandlord) { + whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(landlord) } @Test @@ -463,8 +467,16 @@ class PropertyComplianceServiceTests { electricalCertType = CertificateType.Eicr, ) - verify(mockVirusScanCallbackService).updateCallbacksToOwner(10L, mockPropertyOwnership.id, CertificateType.GasSafetyCert) - verify(mockVirusScanCallbackService).updateCallbacksToOwner(20L, mockPropertyOwnership.id, CertificateType.Eicr) + verify(mockVirusScanCallbackService).updateCallbacksToOwner( + 10L, + mockPropertyOwnership.id, + CertificateType.GasSafetyCert, + ) + verify(mockVirusScanCallbackService).updateCallbacksToOwner( + 20L, + mockPropertyOwnership.id, + CertificateType.Eicr, + ) } @Test @@ -623,7 +635,11 @@ class PropertyComplianceServiceTests { gasSafetyCertUploadIds = listOf(10L), ) - verify(mockVirusScanCallbackService).updateCallbacksToOwner(10L, propertyOwnershipId, CertificateType.GasSafetyCert) + verify(mockVirusScanCallbackService).updateCallbacksToOwner( + 10L, + propertyOwnershipId, + CertificateType.GasSafetyCert, + ) } @Test @@ -646,7 +662,11 @@ class PropertyComplianceServiceTests { gasSafetyCertUploadIds = listOf(10L), ) - verify(mockVirusScanCallbackService, never()).updateCallbacksToOwner(any(), any(), eq(CertificateType.Eicr)) + verify(mockVirusScanCallbackService, never()).updateCallbacksToOwner( + any(), + any(), + eq(CertificateType.Eicr), + ) } @Test @@ -721,10 +741,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -738,6 +758,60 @@ class PropertyComplianceServiceTests { ) } + @Test + fun `sends a gas safety confirmation email to an organisation acting landlord contact details`() { + val loggedInLandlord = + MockLandlordData.createOrgLandlord( + baseUser = MockLandlordData.createPrsdbUser(loggedInBaseUserId), + registrantName = "Org Contact", + registrantEmail = "org.contact@example.com", + ) + val otherLandlord = + MockLandlordData.createIndividualLandlord( + baseUser = MockLandlordData.createPrsdbUser("other-base-user-id"), + email = "other@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(loggedInLandlord, otherLandlord)) + setMockPrincipal(loggedInLandlord) + val gasUpload = FileUpload(FileUploadStatus.QUARANTINED, "gas-1", "pdf", "etag1", "v1") + val compliance = MockPropertyComplianceData.createPropertyCompliance(propertyOwnership = propertyOwnership) + ReflectionTestUtils.setField(compliance, "createdDate", Instant.EPOCH) + ReflectionTestUtils.setField(compliance, "lastModifiedDate", initialLastModifiedDate) + val issueDate = LocalDate.now() + + whenever(mockPropertyComplianceRepository.findByPropertyOwnership_Id(propertyOwnershipId)) + .thenReturn(compliance) + whenever(mockPropertyComplianceRepository.save(any())) + .thenAnswer { it.arguments[0] } + whenever(fileUploadRepository.getReferenceById(10L)).thenReturn(gasUpload) + + propertyComplianceService.updateGasSafety( + propertyOwnershipId = propertyOwnershipId, + initialLastModifiedDate = initialLastModifiedDate, + hasGasSupply = true, + gasSafetyCertIssueDate = issueDate, + gasSafetyCertUploadIds = listOf(10L), + ) + + verify(mockComplianceUpdateConfirmationSender).sendEmail( + eq(loggedInLandlord.contactEmail), + eq( + ComplianceUpdateConfirmationEmail( + landlordName = loggedInLandlord.contactName, + multiLineAddress = propertyOwnership.address.toMultiLineAddress(), + registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber), + dashboardUrl = URI("https://test.example.com"), + newCertificateUrl = URI("https://test.example.com/compliance"), + complianceUpdateType = ComplianceUpdateConfirmationEmail.UpdateType.CERTIFICATE_ADDED, + certificateType = "gas safety certificate", + certificateTypeLabel = "Gas safety certificate", + expiryDate = issueDate.plusYears(1).format(dateFormatter), + ), + ), + ) + } + @Test fun `notifies other landlords with joint landlord email and does not send them the confirmation email`() { val otherLandlord = @@ -770,10 +844,60 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(otherLandlord.email), + eq(otherLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = otherLandlord.name, + landlordName = otherLandlord.contactName, + multiLineAddress = propertyOwnership.address.toMultiLineAddress(), + registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber), + dashboardUrl = URI("https://test.example.com"), + newCertificateUrl = URI("https://test.example.com/compliance"), + complianceUpdateType = ComplianceUpdateConfirmationEmail.UpdateType.CERTIFICATE_ADDED, + certificateType = "gas safety certificate", + certificateTypeLabel = "Gas safety certificate", + expiryDate = issueDate.plusYears(1).format(dateFormatter), + isJointLandlord = true, + ), + ), + ) + } + + @Test + fun `notifies an organisation joint landlord using contact details`() { + val otherLandlord = + MockLandlordData.createOrgLandlord( + baseUser = MockLandlordData.createPrsdbUser("other-base-user-id"), + registrantName = "Other Contact", + registrantEmail = "other.contact@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership(landlords = mutableSetOf(mockLoggedInLandlord, otherLandlord)) + setMockPrincipal() + val gasUpload = FileUpload(FileUploadStatus.QUARANTINED, "gas-1", "pdf", "etag1", "v1") + val compliance = MockPropertyComplianceData.createPropertyCompliance(propertyOwnership = propertyOwnership) + ReflectionTestUtils.setField(compliance, "createdDate", Instant.EPOCH) + ReflectionTestUtils.setField(compliance, "lastModifiedDate", initialLastModifiedDate) + val issueDate = LocalDate.now() + + whenever(mockPropertyComplianceRepository.findByPropertyOwnership_Id(propertyOwnershipId)) + .thenReturn(compliance) + whenever(mockPropertyComplianceRepository.save(any())) + .thenAnswer { it.arguments[0] } + whenever(fileUploadRepository.getReferenceById(10L)).thenReturn(gasUpload) + + propertyComplianceService.updateGasSafety( + propertyOwnershipId = propertyOwnershipId, + initialLastModifiedDate = initialLastModifiedDate, + hasGasSupply = true, + gasSafetyCertIssueDate = issueDate, + gasSafetyCertUploadIds = listOf(10L), + ) + + verify(mockComplianceUpdateConfirmationSender).sendEmail( + eq(otherLandlord.contactEmail), + eq( + ComplianceUpdateConfirmationEmail( + landlordName = otherLandlord.contactName, multiLineAddress = propertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -820,10 +944,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(otherLandlord.email), + eq(otherLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = otherLandlord.name, + landlordName = otherLandlord.contactName, multiLineAddress = propertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(propertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -859,10 +983,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -901,10 +1025,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = occupiedPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber( @@ -915,7 +1039,11 @@ class PropertyComplianceServiceTests { complianceUpdateType = ComplianceUpdateConfirmationEmail.UpdateType.EXPIRED_CERTIFICATE_OCCUPIED, certificateType = "gas safety certificate", certificateTypeLabel = "Gas safety certificate", - deadlineDate = LocalDate.now().plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()).format(dateFormatter), + deadlineDate = + LocalDate + .now() + .plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()) + .format(dateFormatter), ), ), ) @@ -941,10 +1069,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -981,10 +1109,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = occupiedPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber( @@ -995,7 +1123,11 @@ class PropertyComplianceServiceTests { complianceUpdateType = ComplianceUpdateConfirmationEmail.UpdateType.EXPIRED_CERTIFICATE_OCCUPIED, certificateType = "gas safety certificate", certificateTypeLabel = "Gas safety certificate", - deadlineDate = LocalDate.now().plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()).format(dateFormatter), + deadlineDate = + LocalDate + .now() + .plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()) + .format(dateFormatter), ), ), ) @@ -1119,7 +1251,11 @@ class PropertyComplianceServiceTests { electricalSafetyCertUploadIds = listOf(10L), ) - verify(mockVirusScanCallbackService, never()).updateCallbacksToOwner(any(), any(), eq(CertificateType.GasSafetyCert)) + verify(mockVirusScanCallbackService, never()).updateCallbacksToOwner( + any(), + any(), + eq(CertificateType.GasSafetyCert), + ) } @Test @@ -1218,10 +1354,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -1257,10 +1393,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -1299,10 +1435,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = occupiedPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber( @@ -1313,7 +1449,11 @@ class PropertyComplianceServiceTests { complianceUpdateType = ComplianceUpdateConfirmationEmail.UpdateType.EXPIRED_CERTIFICATE_OCCUPIED, certificateType = "electrical safety certificate", certificateTypeLabel = "Electrical safety certificate (EICR)", - deadlineDate = LocalDate.now().plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()).format(dateFormatter), + deadlineDate = + LocalDate + .now() + .plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()) + .format(dateFormatter), ), ), ) @@ -1339,10 +1479,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -1379,10 +1519,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = occupiedPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber( @@ -1393,7 +1533,11 @@ class PropertyComplianceServiceTests { complianceUpdateType = ComplianceUpdateConfirmationEmail.UpdateType.EXPIRED_CERTIFICATE_OCCUPIED, certificateType = "electrical safety certificate", certificateTypeLabel = "Electrical safety certificate (EICR)", - deadlineDate = LocalDate.now().plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()).format(dateFormatter), + deadlineDate = + LocalDate + .now() + .plusDays(PROVIDE_LATER_DEADLINE_DAYS.toLong()) + .format(dateFormatter), ), ), ) @@ -1580,10 +1724,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -1617,10 +1761,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = mockPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber(mockPropertyOwnership.registrationNumber), dashboardUrl = URI("https://test.example.com"), @@ -1657,10 +1801,10 @@ class PropertyComplianceServiceTests { ) verify(mockComplianceUpdateConfirmationSender).sendEmail( - eq(mockLoggedInLandlord.email), + eq(mockLoggedInLandlord.contactEmail), eq( ComplianceUpdateConfirmationEmail( - landlordName = mockLoggedInLandlord.name, + landlordName = mockLoggedInLandlord.contactName, multiLineAddress = occupiedPropertyOwnership.address.toMultiLineAddress(), registrationNumber = RegistrationNumberDataModel.fromRegistrationNumber( diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationServiceTests.kt index 5da3caa85c..7e01991f28 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyRegistrationServiceTests.kt @@ -315,6 +315,83 @@ class PropertyRegistrationServiceTests { ) } + @Test + fun `registerProperty sends a confirmation email to an organisation landlord contact email`() { + // Arrange + val landlord = + MockLandlordData.createOrgLandlord( + email = "organisation@example.com", + registrantEmail = "contact@example.com", + ) + val registrationNumber = RegistrationNumber(RegistrationNumberType.PROPERTY, 2468) + + val expectedPropertyOwnership = + MockLandlordData.createPropertyOwnership( + landlords = mutableSetOf(landlord), + registrationNumber = registrationNumber, + ) + + whenever(mockAddressService.findOrCreateAddress(any())).thenReturn(expectedPropertyOwnership.address) + whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(landlord) + whenever(mockLicenseService.createLicense(any(), any())).thenReturn(expectedPropertyOwnership.license) + whenever( + mockPropertyOwnershipService.createPropertyOwnership( + ownershipType = any(), + isOccupied = any(), + numberOfHouseholds = any(), + numberOfPeople = any(), + landlords = any(), + propertyBuildType = any(), + address = any(), + license = anyOrNull(), + isActive = any(), + numBedrooms = anyOrNull(), + billsIncludedList = anyOrNull(), + customBillsIncluded = anyOrNull(), + furnishedStatus = anyOrNull(), + rentFrequency = anyOrNull(), + customRentFrequency = anyOrNull(), + rentAmount = anyOrNull(), + customPropertyType = anyOrNull(), + markedJointLandlord = any(), + ), + ).thenReturn(expectedPropertyOwnership) + + val dashboardUri = URI("https:gov.uk") + whenever(mockAbsoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(dashboardUri) + + // Act + propertyRegistrationService.registerProperty( + AddressDataModel.fromAddress(expectedPropertyOwnership.address), + PropertyType.DETACHED_HOUSE, + LicensingType.SELECTIVE_LICENCE, + "Licence", + OwnershipType.FREEHOLD, + true, + 2, + 1, + null, + null, + null, + null, + RentFrequency.MONTHLY, + null, + 123.toBigDecimal(), + null, + ) + + // Assert + verify(mockConfirmationEmailSender).sendEmail( + eq("contact@example.com"), + argThat { email -> + email.prn == RegistrationNumberDataModel.fromRegistrationNumber(registrationNumber).toString() && + email.singleLineAddress == expectedPropertyOwnership.address.singleLineAddress && + email.prsdUrl == dashboardUri.toString() && + email.isOccupied == (expectedPropertyOwnership.currentNumTenants > 0) + }, + ) + } + @Test fun `registerProperty sends a confirmation email and caches the registration number when it registers the property`() { // Arrange diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailServiceTests.kt index 039f392fde..73f7d2ab83 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/PropertyUpdateEmailServiceTests.kt @@ -84,7 +84,7 @@ class PropertyUpdateEmailServiceTests { notifier.sendUpdateEmails(propertyId, bullets) verify(mockConfirmationEmailService).sendEmail( - eq("actor@example.com"), + eq(actor.contactEmail), argThat { this.updatedBullets == bullets }, ) } @@ -108,12 +108,68 @@ class PropertyUpdateEmailServiceTests { notifier.sendUpdateEmails(propertyId, bullets) verify(mockNotificationEmailService).sendEmail( - eq("other@example.com"), + eq(other.contactEmail), argThat { - this.recipientName == "Lois" && this.updatedBullets == bullets && this.propertyRecordUrl == "http://property" + this.recipientName == other.contactName && this.updatedBullets == bullets && + this.propertyRecordUrl == "http://property" + }, + ) + verify(mockNotificationEmailService, never()).sendEmail(eq(actor.contactEmail), any()) + } + + @Test + fun `sendUpdateEmails sends the confirmation to an organisation acting landlord contact email`() { + val baseUserId = "acting-user" + val actor = + MockLandlordData.createOrgLandlord( + baseUser = MockLandlordData.createPrsdbUser(baseUserId), + registrantEmail = "org.contact@example.com", + ) + val other = MockLandlordData.createIndividualLandlord(email = "other@example.com") + val propertyOwnership = + MockLandlordData.createPropertyOwnership(id = propertyId, landlords = mutableSetOf(actor, other)) + whenever(mockPropertyOwnershipService.getPropertyOwnership(propertyId)).thenReturn(propertyOwnership) + whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(actor) + whenever(mockAbsoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(URI("http://dashboard")) + whenever(mockAbsoluteUrlProvider.buildPropertyDetailsUri(propertyId)).thenReturn(URI("http://property")) + + notifier.sendUpdateEmails(propertyId, bullets) + + verify(mockConfirmationEmailService).sendEmail( + eq(actor.contactEmail), + argThat { this.updatedBullets == bullets }, + ) + } + + @Test + fun `sendUpdateEmails notifies an organisation landlord using contact details`() { + val baseUserId = "acting-user" + val actor = + MockLandlordData.createIndividualLandlord( + baseUser = MockLandlordData.createPrsdbUser(baseUserId), + email = "actor@example.com", + ) + val other = + MockLandlordData.createOrgLandlord( + registrantName = "Olive Contact", + registrantEmail = "olive@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership(id = propertyId, landlords = mutableSetOf(actor, other)) + whenever(mockPropertyOwnershipService.getPropertyOwnership(propertyId)).thenReturn(propertyOwnership) + whenever(mockUserToLandlordService.getCurrentLandlordForUser()).thenReturn(actor) + whenever(mockAbsoluteUrlProvider.buildLandlordDashboardUri()).thenReturn(URI("http://dashboard")) + whenever(mockAbsoluteUrlProvider.buildPropertyDetailsUri(propertyId)).thenReturn(URI("http://property")) + + notifier.sendUpdateEmails(propertyId, bullets) + + verify(mockNotificationEmailService).sendEmail( + eq(other.contactEmail), + argThat { + this.recipientName == other.contactName && this.updatedBullets == bullets && + this.propertyRecordUrl == "http://property" }, ) - verify(mockNotificationEmailService, never()).sendEmail(eq("actor@example.com"), any()) } @Test diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailServiceTests.kt index 757090b51d..e28a5eeb81 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/SwapToIndividualNudgeEmailServiceTests.kt @@ -38,11 +38,16 @@ class SwapToIndividualNudgeEmailServiceTests { @Test fun `sendNudgeEmailIfApplicable sends email when property is marked joint with sole landlord and no pending invitations`() { - val landlord = MockLandlordData.createIndividualLandlord(name = "Alice", email = "alice@example.com") val address = MockLandlordData.createAddress(singleLineAddress = "10 High Street, London, SW1A 1AA") val propertyOwnership = MockLandlordData.createPropertyOwnership( - landlords = mutableSetOf(MockLandlordData.createIndividualLandlord(name = "Alice", email = "alice@example.com")), + landlords = + mutableSetOf( + MockLandlordData.createIndividualLandlord( + name = "Alice", + email = "alice@example.com", + ), + ), address = address, markedJointLandlord = true, ) @@ -64,6 +69,37 @@ class SwapToIndividualNudgeEmailServiceTests { assertEquals(propertyRecordUri.toString(), sentEmail.propertyRecordUrl) } + @Test + fun `sendNudgeEmailIfApplicable sends email to organisation landlord contact details when sole landlord is an organisation`() { + val organisationLandlord = + MockLandlordData.createOrgLandlord( + name = "Acme Property Ltd", + email = "info@acme.example.com", + registrantName = "Alice Agent", + registrantEmail = "alice.agent@example.com", + ) + val propertyOwnership = + MockLandlordData.createPropertyOwnership( + landlords = mutableSetOf(organisationLandlord), + markedJointLandlord = true, + ) + val propertyRecordUri = URI("https://example.com/landlord/property/1") + + whenever(mockInvitationRepository.findByRegisteredOwnership(propertyOwnership)) + .thenReturn(emptyList()) + whenever(mockAbsoluteUrlProvider.buildPropertyDetailsUri(any())) + .thenReturn(propertyRecordUri) + + nudgeService.sendNudgeEmailIfApplicable(propertyOwnership) + + val emailCaptor = argumentCaptor() + verify(mockNudgeEmailNotificationService).sendEmail(eq("alice.agent@example.com"), emailCaptor.capture()) + + val sentEmail = emailCaptor.firstValue + assertEquals("Alice Agent", sentEmail.recipientName) + assertEquals(propertyRecordUri.toString(), sentEmail.propertyRecordUrl) + } + @Test fun `sendNudgeEmailIfApplicable does not send email when property is not marked as joint`() { val propertyOwnership = @@ -137,7 +173,13 @@ class SwapToIndividualNudgeEmailServiceTests { fun `sendNudgeEmailIfApplicable sends email when only processed expired invitations exist`() { val propertyOwnership = MockLandlordData.createPropertyOwnership( - landlords = mutableSetOf(MockLandlordData.createIndividualLandlord(name = "Bob", email = "bob@example.com")), + landlords = + mutableSetOf( + MockLandlordData.createIndividualLandlord( + name = "Bob", + email = "bob@example.com", + ), + ), markedJointLandlord = true, ) val expiredInvitation = diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserToLandlordServiceTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserToLandlordServiceTests.kt index e3e1059f94..5eadf8550a 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserToLandlordServiceTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/UserToLandlordServiceTests.kt @@ -56,7 +56,7 @@ class UserToLandlordServiceTests { whenever(individualLandlordRepository.findByBaseUser_Id(baseUserId)).thenReturn(null) whenever(organisationLandlordUserRepository.findByBaseUser_Id(baseUserId)).thenReturn( listOf( - OrganisationLandlordUser(landlord, baseUser), + OrganisationLandlordUser(landlord, baseUser, "Alice Registrant", "alice@example.com"), ), ) diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandlerTests.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandlerTests.kt index b0225920a9..4ed6772487 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandlerTests.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/services/VirusNotificationEmailHandlerTests.kt @@ -4,10 +4,12 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mockito.mock import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -113,6 +115,49 @@ class VirusNotificationEmailHandlerTests { assertEmailSentToAddress(landlordEmails, expectedEmail) } + @Test + fun `handleCallback for owner email sends organisation landlord email to contact email rather than display email`() { + // Arrange + val displayEmail = "organisation@example.com" + val contactEmail = "sole-user@example.com" + val ownership = + MockLandlordData.createPropertyOwnership( + landlords = + mutableSetOf( + MockLandlordData.createOrgLandlord( + email = displayEmail, + registrantEmail = contactEmail, + mainContactEmail = "main-contact@example.com", + ), + ), + address = MockLandlordData.createAddress(singleLineAddress = "123 Main St, Anytown"), + registrationNumber = RegistrationNumber(RegistrationNumberType.PROPERTY, 37L), + ) + val complianceUri = URI("http://example.com/compliance/1") + whenever(absoluteUrlProvider.buildComplianceInformationUri(ownership.id)).thenReturn(complianceUri) + whenever(propertyOwnershipRepository.findByIdAndIsActiveTrue(ownership.id)).thenReturn(ownership) + val expectedEmail = + VirusScanUnsuccessfulEmail( + "A gas safety certificate", + "gas safety certificate", + "gas safety certificate", + "123 Main St, Anytown", + RegistrationNumberDataModel.fromRegistrationNumber(ownership.registrationNumber).toString(), + complianceUri, + ) + + // Act + val callbackData = EmailNotificationData.OwnerEmailNotification(ownership.id, CertificateType.GasSafetyCert) + val encodedCallbackData = Json.encodeToString(callbackData) + virusNotificationEmailHandler.handleCallback( + VirusScanCallback(mock(), encodedCallbackData), + ) + + // Assert + verify(emailNotificationService).sendEmail(contactEmail, expectedEmail) + verify(emailNotificationService, never()).sendEmail(displayEmail, expectedEmail) + } + private fun arrangeOwnedPropertyUploadCallback( subjectCertificateType: String, headingCertificateType: String, diff --git a/src/test/kotlin/uk/gov/communities/prsdb/webapp/testHelpers/mockObjects/MockLandlordData.kt b/src/test/kotlin/uk/gov/communities/prsdb/webapp/testHelpers/mockObjects/MockLandlordData.kt index 67460d67c8..b1fa4ed6d9 100644 --- a/src/test/kotlin/uk/gov/communities/prsdb/webapp/testHelpers/mockObjects/MockLandlordData.kt +++ b/src/test/kotlin/uk/gov/communities/prsdb/webapp/testHelpers/mockObjects/MockLandlordData.kt @@ -15,6 +15,7 @@ import uk.gov.communities.prsdb.webapp.database.entity.LandlordIncompletePropert import uk.gov.communities.prsdb.webapp.database.entity.License import uk.gov.communities.prsdb.webapp.database.entity.LocalCouncil import uk.gov.communities.prsdb.webapp.database.entity.OrganisationLandlord +import uk.gov.communities.prsdb.webapp.database.entity.OrganisationLandlordUser import uk.gov.communities.prsdb.webapp.database.entity.OwnershipLink import uk.gov.communities.prsdb.webapp.database.entity.Passcode import uk.gov.communities.prsdb.webapp.database.entity.PropertyOwnership @@ -96,6 +97,7 @@ class MockLandlordData { } fun createOrgLandlord( + baseUser: PrsdbUser = createPrsdbUser(), name: String = "Organisation landlord", address: Address = createAddress(), email: String = "organisation@example.com", @@ -148,6 +150,12 @@ class MockLandlordData { mainContactEmail = mainContactEmail, mainContactPhone = mainContactPhoneNumber, ) + OrganisationLandlordUser( + organisationLandlord = landlord, + baseUser = baseUser, + name = registrantName, + email = registrantEmail, + ) ReflectionTestUtils.setField(landlord, "createdDate", createdDate) ReflectionTestUtils.setField(