Skip to content

Commit

Permalink
BST-112068 Add page 'Occupier Detail'
Browse files Browse the repository at this point in the history
  • Loading branch information
pangiole committed Nov 20, 2024
1 parent 858e0f6 commit ac3f1a6
Show file tree
Hide file tree
Showing 34 changed files with 986 additions and 213 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ class CompletedLettingsController @Inject (
hasCompletedLettings <- lettingHistory.hasCompletedLettings
yield freshForm.fill(hasCompletedLettings)

Ok(theView(filledForm.getOrElse(freshForm), previousRentPeriod, backLinkUrl))
Ok(theView(filledForm.getOrElse(freshForm), previousRentalPeriod, backLinkUrl))
}

def submit: Action[AnyContent] = (Action andThen sessionRefiner).async { implicit request =>
continueOrSaveAsDraft[AnswersYesNo](
theForm,
theFormWithErrors => successful(BadRequest(theView(theFormWithErrors, previousRentPeriod, backLinkUrl))),
theFormWithErrors => successful(BadRequest(theView(theFormWithErrors, previousRentalPeriod, backLinkUrl))),
hasCompletedLettings =>
given Session = request.sessionData
for updatedSession <- repository.saveOrUpdateSession(withCompletedLettings(hasCompletedLettings))
yield navigator.redirect(fromPage = CompletedLettingsPageId, updatedSession)
for savedSession <- repository.saveOrUpdateSession(withCompletedLettings(hasCompletedLettings))
yield navigator.redirect(currentPage = CompletedLettingsPageId, savedSession)
)
}

Expand Down
77 changes: 77 additions & 0 deletions app/controllers/lettingHistory/OccupierDetailController.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2024 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package controllers.lettingHistory

import actions.{SessionRequest, WithSessionRefiner}
import controllers.FORDataCaptureController
import form.lettingHistory.OccupierDetailForm.theForm
import models.Session
import models.submissions.lettingHistory.LettingHistory.byAddingOccupierNameAndAddress
import models.submissions.lettingHistory.OccupierDetail
import navigation.LettingHistoryNavigator
import navigation.identifiers.OccupierDetailPageId
import play.api.i18n.I18nSupport
import play.api.mvc.{Action, AnyContent, MessagesControllerComponents}
import repositories.SessionRepo
import views.html.lettingHistory.occupierDetail as OccupierDetailView

import javax.inject.{Inject, Named}
import scala.concurrent.ExecutionContext
import scala.concurrent.Future.successful

class OccupierDetailController @Inject (
mcc: MessagesControllerComponents,
navigator: LettingHistoryNavigator,
theView: OccupierDetailView,
sessionRefiner: WithSessionRefiner,
@Named("session") repository: SessionRepo
)(using ec: ExecutionContext)
extends FORDataCaptureController(mcc)
with WelshJourneySupport
with I18nSupport:

def show(maybeIndex: Option[Int] = None): Action[AnyContent] = (Action andThen sessionRefiner).apply {
implicit request =>
val completedLettings = (
for lettingHistory <- request.sessionData.lettingHistory.toList
yield lettingHistory.completedLettings
).flatten

val freshForm = theForm
val filledForm =
for
index <- maybeIndex
occupierDetail <- completedLettings.lift(index)
yield freshForm.fill(occupierDetail)

Ok(theView(filledForm.getOrElse(freshForm), previousRentalPeriod, backLinkUrl))
}

def submit: Action[AnyContent] = (Action andThen sessionRefiner).async { implicit request =>
continueOrSaveAsDraft[OccupierDetail](
theForm,
theFormWithErrors => successful(BadRequest(theView(theFormWithErrors, previousRentalPeriod, backLinkUrl))),
occupierDetail =>
given Session = request.sessionData
val updatedSession = byAddingOccupierNameAndAddress(occupierDetail.name, occupierDetail.address)
for savedSession <- repository.saveOrUpdateSession(updatedSession)
yield navigator.redirect(currentPage = OccupierDetailPageId, savedSession)
)
}

private def backLinkUrl(using request: SessionRequest[AnyContent]): Option[String] =
navigator.backLinkUrl(ofPage = OccupierDetailPageId)
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ class PermanentResidentsController @Inject() (
theFormWithErrors => successful(BadRequest(theView(theFormWithErrors, backLinkUrl))),
hasPermanentResidents =>
given Session = request.sessionData
for updatedSession <- repository.saveOrUpdateSession(withPermanentResidents(hasPermanentResidents))
yield navigator.redirect(fromPage = PermanentResidentsPageId, updatedSession)
for savedSession <- repository.saveOrUpdateSession(withPermanentResidents(hasPermanentResidents))
yield navigator.redirect(currentPage = PermanentResidentsPageId, savedSession)
)
}

Expand Down
27 changes: 16 additions & 11 deletions app/controllers/lettingHistory/ResidentDetailController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,21 @@ class ResidentDetailController @Inject() (
extends FORDataCaptureController(mcc)
with I18nSupport:

def show(index: Option[Int] = None): Action[AnyContent] = (Action andThen sessionRefiner).apply { implicit request =>
val freshForm = theForm
val filledForm =
for
idx <- index
lettingHistory <- request.sessionData.lettingHistory
residentDetail <- lettingHistory.permanentResidents.lift(idx)
yield freshForm.fill(residentDetail)
def show(maybeIndex: Option[Int] = None): Action[AnyContent] = (Action andThen sessionRefiner).apply {
implicit request =>
val permanentResidents = (
for lettingHistory <- request.sessionData.lettingHistory.toList
yield lettingHistory.permanentResidents
).flatten

Ok(theView(filledForm.getOrElse(freshForm), backLinkUrl))
val freshForm = theForm
val filledForm =
for
index <- maybeIndex
residentDetail <- permanentResidents.lift(index)
yield freshForm.fill(residentDetail)

Ok(theView(filledForm.getOrElse(freshForm), backLinkUrl))
}

def submit: Action[AnyContent] = (Action andThen sessionRefiner).async { implicit request =>
Expand All @@ -61,8 +66,8 @@ class ResidentDetailController @Inject() (
theFormWithErrors => successful(BadRequest(theView(theFormWithErrors, backLinkUrl))),
residentDetail =>
given Session = request.sessionData
for updatedSession <- repository.saveOrUpdateSession(byAddingPermanentResident(residentDetail))
yield navigator.redirect(fromPage = ResidentDetailPageId, updatedSession)
for savedSession <- repository.saveOrUpdateSession(byAddingPermanentResident(residentDetail))
yield navigator.redirect(currentPage = ResidentDetailPageId, savedSession)
)
}

Expand Down
34 changes: 19 additions & 15 deletions app/controllers/lettingHistory/ResidentListController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import form.confirmableActionForm.confirmableActionForm as theRemoveConfirmation
import form.lettingHistory.ResidentListForm.theForm as theListForm
import models.Session
import models.submissions.common.{AnswerYes, AnswersYesNo}
import models.submissions.lettingHistory.LettingHistory.byRemovingPermanentResidentAt
import models.submissions.lettingHistory.LettingHistory.{byRemovingPermanentResidentAt, permanentResidents}
import models.submissions.lettingHistory.{LettingHistory, ResidentDetail}
import navigation.LettingHistoryNavigator
import navigation.identifiers.ResidentListPageId
import navigation.identifiers.{ResidentListPageId, ResidentRemovePageId}
import play.api.data.Form
import play.api.i18n.I18nSupport
import play.api.mvc.{Action, AnyContent, MessagesControllerComponents, Result}
Expand All @@ -49,30 +49,34 @@ class ResidentListController @Inject() (
with I18nSupport:

def show: Action[AnyContent] = (Action andThen sessionRefiner).apply { implicit request =>
Ok(theListView(theListForm, backLinkUrl, LettingHistory.permanentResidents(request.sessionData)))
Ok(theListView(theListForm, permanentResidents(request.sessionData), backLinkUrl))
}

def remove(index: Int): Action[AnyContent] = (Action andThen sessionRefiner).async { implicit request =>
this.foldResidentDetailAt(index) { residentialDetail =>
withResidentDetailAt(index) { residentialDetail =>
successful(Ok(renderTheConfirmationViewWith(theRemoveConfirmationForm, residentialDetail, index)))
}
}

def performRemove(index: Int): Action[AnyContent] = (Action andThen sessionRefiner).async { implicit request =>
this.foldResidentDetailAt(index) { residentialDetail =>
withResidentDetailAt(index) { residentialDetail =>
theRemoveConfirmationForm
.bindFromRequest()
.fold(
formWithErrors =>
successful(BadRequest(renderTheConfirmationViewWith(formWithErrors, residentialDetail, index))),
answer =>
if answer == AnswerYes then
given Session = request.sessionData
for updatedSession <- repository.saveOrUpdateSession(byRemovingPermanentResidentAt(index))
yield Redirect(routes.ResidentListController.show)
else
// AnswerNo
successful(Redirect(routes.ResidentListController.show))
val eventuallySavedSession =
if answer == AnswerYes then
given Session = request.sessionData
for savedSession <- repository.saveOrUpdateSession(byRemovingPermanentResidentAt(index))
yield savedSession
else
// AnswerNo
successful(request.sessionData)

for savedSession <- eventuallySavedSession
yield navigator.redirect(currentPage = ResidentRemovePageId, savedSession)
)
}
}
Expand All @@ -83,21 +87,21 @@ class ResidentListController @Inject() (
theFormWithErrors =>
successful(
BadRequest(
theListView(theFormWithErrors, backLinkUrl, LettingHistory.permanentResidents(request.sessionData))
theListView(theFormWithErrors, permanentResidents(request.sessionData), backLinkUrl)
)
),
hasMoreResidents =>
successful(
navigator.redirect(
fromPage = ResidentListPageId,
currentPage = ResidentListPageId,
updatedSession = request.sessionData,
navigationData = Map("hasMoreResidents" -> hasMoreResidents.toString)
)
)
)
}

private def foldResidentDetailAt(
private def withResidentDetailAt(
index: Int
)(func: ResidentDetail => Future[Result])(using request: SessionRequest[AnyContent]): Future[Result] =
LettingHistory
Expand Down
8 changes: 4 additions & 4 deletions app/controllers/lettingHistory/WelshJourneySupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,24 @@
package controllers.lettingHistory

import actions.SessionRequest
import models.submissions.lettingHistory.RentPeriod
import models.submissions.lettingHistory.RentalPeriod
import play.api.mvc.AnyContent

import java.time.LocalDate
import java.time.Month.{APRIL, MARCH}

trait WelshJourneySupport:
private def lastFiscalYearEnd = {
def lastFiscalYearEnd = {
val now = LocalDate.now()
if now.getMonth.getValue > 3
then now.getYear
else now.getYear - 1
}

// The Welsh journey requires 3 years of data instead of 1 year
def previousRentPeriod(using request: SessionRequest[AnyContent]) =
def previousRentalPeriod(using request: SessionRequest[AnyContent]) =
val numberOfYearsBack = if request.sessionData.isWelsh then 3 else 1
RentPeriod(
RentalPeriod(
fromDate = LocalDate.of(lastFiscalYearEnd - numberOfYearsBack, APRIL, 1),
toDate = LocalDate.of(lastFiscalYearEnd, MARCH, 31)
)
41 changes: 41 additions & 0 deletions app/form/lettingHistory/OccupierDetailForm.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2024 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package form.lettingHistory

import form.AddressLine2Mapping.validateAddressLineTwo as line2
import form.BuildingNameNumberMapping.validateBuildingNameNumber as line1
import form.CountyMapping.validateCounty as county
import form.PostcodeMapping.postcode
import form.TownMapping.validateTown as town
import form.lettingHistory.FieldMappings.nonEmptyText
import models.submissions.lettingHistory.{Address, OccupierDetail}
import play.api.data.Form
import play.api.data.Forms.{mapping, optional}

object OccupierDetailForm:
val theForm = Form(
mapping(
"name" -> nonEmptyText(errorMessage = "lettingHistory.occupierDetail.name.required"),
"address" -> mapping(
"line1" -> line1,
"line2" -> optional(line2),
"town" -> town,
"county" -> optional(county),
"postcode" -> postcode(requiredError = "error.postcodeAlternativeContact.required")
)(Address.apply)(Address.unapply)
)(OccupierDetail.apply)(OccupierDetail.unapply)
)
32 changes: 32 additions & 0 deletions app/models/submissions/lettingHistory/Address.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2024 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package models.submissions.lettingHistory

import play.api.libs.json.{Format, Json}

case class Address(
line1: String,
line2: Option[String],
town: String,
county: Option[String],
postcode: String
)

object Address:
def unapply(obj: Address): Option[(String, Option[String], String, Option[String], String)] =
Some(obj.line1, obj.line2, obj.town, obj.county, obj.postcode)
given Format[Address] = Json.format
42 changes: 41 additions & 1 deletion app/models/submissions/lettingHistory/LettingHistory.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ case class LettingHistory(
hasPermanentResidents: Option[AnswersYesNo] = None,
permanentResidents: List[ResidentDetail] = Nil,
hasCompletedLettings: Option[AnswersYesNo] = None,
completedLettings: List[ResidentDetail] = Nil
completedLettings: List[OccupierDetail] = Nil
)

object LettingHistory:
Expand Down Expand Up @@ -119,4 +119,44 @@ object LettingHistory:
lettingHistory.copy(hasCompletedLettings = Some(AnswerNo), completedLettings = Nil)
)

def byAddingOccupierNameAndAddress(name: String, address: Address)(using session: Session): Session =
val occupierDetail = OccupierDetail(name, address)
val ifEmpty =
LettingHistory(
hasCompletedLettings = Some(AnswerYes),
completedLettings = List(occupierDetail)
)

val copyFunc: LettingHistory => LettingHistory = { lettingHistory =>
lettingHistory.completedLettings.zipWithIndex
.find { (occupier, _) =>
// find the eventually existing resident by name (and more importantly its index)
occupier.name == name
}
.map { (_, foundIndex) =>
// patch the occupier detail if it exists at foundIndex
val patchedOccupier = lettingHistory
.completedLettings(foundIndex)
.copy(name = name, address = address)

val patchedCompletedLettings = lettingHistory.completedLettings.patch(foundIndex, List(patchedOccupier), 1)
val copiedLettingHistory = lettingHistory.copy(completedLettings = patchedCompletedLettings)
copiedLettingHistory
}
.getOrElse {
// not found ... then append it to the list of completed lettings
val extendedCompletedLettings = lettingHistory.completedLettings.:+(occupierDetail)
val copiedLettingHistory = lettingHistory.copy(completedLettings = extendedCompletedLettings)
copiedLettingHistory
}
}
val updatedSession = session.lettingHistory.fold(ifEmpty)(copyFunc)
session.copy(lettingHistory = Some(updatedSession))

def completedLettings(session: Session): List[OccupierDetail] =
for
lettingHistory <- session.lettingHistory.toList
completedLettings <- lettingHistory.completedLettings
yield completedLettings

given Format[LettingHistory] = Json.format
Loading

0 comments on commit ac3f1a6

Please sign in to comment.