Skip to content

Commit

Permalink
PSR-1587 Added prepop shares list page
Browse files Browse the repository at this point in the history
  • Loading branch information
westwater committed Dec 12, 2024
1 parent 5e302c0 commit dd106a9
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 135 deletions.
4 changes: 4 additions & 0 deletions app/controllers/PSRController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ abstract class PSRController extends FrontendBaseController with I18nSupport wit
}
}

implicit class FutureEitherOps[A](f: Future[Either[A, A]])(implicit ec: ExecutionContext) {
def merge: Future[A] = f.map(_.merge)
}

implicit class EitherOps[A](maybe: Either[String, A]) {
def getOrRecoverJourney(implicit logger: Logger): Either[Result, A] =
maybe.leftMap { errMsg =>
Expand Down
227 changes: 156 additions & 71 deletions app/controllers/nonsipp/shares/SharesListController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import viewmodels.implicits._
import com.google.inject.Inject
import utils.ListUtils._
import utils.nonsipp.TaskListStatusUtils.getCompletedOrUpdatedTaskListStatus
import _root_.config.Constants
import controllers.actions.IdentifyAndRequireData
import forms.YesNoPageFormProvider
import viewmodels.models.TaskListStatus.Updated
Expand All @@ -33,15 +32,20 @@ import views.html.ListView
import models.SchemeId.Srn
import cats.implicits.{catsSyntaxApplicativeId, toShow, toTraverseOps}
import controllers.nonsipp.shares.SharesListController._
import _root_.config.Constants
import config.Constants.maxSharesTransactions
import pages.nonsipp.CompilationOrSubmissionDatePage
import play.api.Logger
import navigation.Navigator
import utils.DateTimeUtils.{localDateShow, localDateTimeShow}
import models._
import utils.nonsipp.check.SharesCheckStatusUtils
import play.api.i18n.MessagesApi
import viewmodels.DisplayMessage
import viewmodels.DisplayMessage.{LinkMessage, Message, ParagraphMessage}
import viewmodels.models._
import models.requests.DataRequest
import utils.MapUtils.UserAnswersMapOps
import play.api.data.Form

import scala.concurrent.{ExecutionContext, Future}
Expand All @@ -60,6 +64,8 @@ class SharesListController @Inject()(
)(implicit ec: ExecutionContext)
extends PSRController {

private implicit val logger = Logger(getClass)

val form: Form[Boolean] = SharesListController.form(formProvider)

def onPageLoad(srn: Srn, page: Int, mode: Mode): Action[AnyContent] = identifyAndRequireData(srn) {
Expand Down Expand Up @@ -105,23 +111,26 @@ class SharesListController @Inject()(
val indexes: List[Max5000] = request.userAnswers.map(SharesCompleted.all(srn)).keys.toList.refine[Max5000.Refined]

if (indexes.nonEmpty || mode.isViewOnlyMode) {
sharesData(srn, indexes).map { data =>
val filledForm =
request.userAnswers.get(SharesListPage(srn)).fold(form)(form.fill)
Ok(
view(
filledForm,
SharesListController.viewModel(
srn,
page,
mode,
data,
request.schemeDetails.schemeName,
viewOnlyViewModel,
showBackLink = showBackLink
shares(srn).map {
case (sharesToCheck, shares) =>
val filledForm =
request.userAnswers.get(SharesListPage(srn)).fold(form)(form.fill)
Ok(
view(
filledForm,
viewModel(
srn,
page,
mode,
shares,
sharesToCheck,
request.schemeDetails.schemeName,
viewOnlyViewModel,
showBackLink = showBackLink,
isPrePopulation
)
)
)
)
}.merge
} else {
Redirect(controllers.nonsipp.routes.TaskListController.onPageLoad(srn))
Expand All @@ -130,35 +139,36 @@ class SharesListController @Inject()(

def onSubmit(srn: Srn, page: Int, mode: Mode): Action[AnyContent] = identifyAndRequireData(srn).async {
implicit request =>
val indexes: List[Max5000] = request.userAnswers.map(SharesCompleted.all(srn)).keys.toList.refine[Max5000.Refined]

if (indexes.size >= Constants.maxSharesTransactions) {
Future.successful(
Redirect(
navigator.nextPage(SharesListPage(srn), mode, request.userAnswers)
)
)
} else {
form
.bindFromRequest()
.fold(
errors => {
sharesData(srn, indexes)
.map { data =>
BadRequest(view(errors, viewModel(srn, page, mode, data, "", showBackLink = true)))
}
.merge
.pure[Future]
},
addAnother =>
for {
updatedUserAnswers <- Future.fromTry(request.userAnswers.set(SharesListPage(srn), addAnother))
_ <- saveService.save(updatedUserAnswers)
} yield Redirect(
navigator.nextPage(SharesListPage(srn), mode, updatedUserAnswers)
shares(srn).traverse {
case (sharesToCheck, shares) =>
if (sharesToCheck.size + shares.size >= Constants.maxSharesTransactions) {
Future.successful(
Redirect(
navigator.nextPage(SharesListPage(srn), mode, request.userAnswers)
)
)
}
)
} else {
form
.bindFromRequest()
.fold(
errors => {
BadRequest(
view(
errors,
viewModel(srn, page, mode, shares, sharesToCheck, "", None, showBackLink = true, isPrePopulation)
)
).pure[Future]
},
addAnother =>
for {
updatedUserAnswers <- Future.fromTry(request.userAnswers.set(SharesListPage(srn), addAnother))
_ <- saveService.save(updatedUserAnswers)
} yield Redirect(
navigator.nextPage(SharesListPage(srn), mode, updatedUserAnswers)
)
)
}
}.merge
}

def onSubmitViewOnly(srn: Srn, year: String, current: Int, previous: Int): Action[AnyContent] =
Expand Down Expand Up @@ -195,20 +205,42 @@ class SharesListController @Inject()(
onPageLoadCommon(srn, page, ViewOnlyMode, Some(viewOnlyViewModel), showBackLink)
}

private def sharesData(srn: Srn, indexes: List[Max5000])(
implicit req: DataRequest[_]
): Either[Result, List[SharesData]] =
indexes
.sortBy(listRow => listRow.value)
.map { index =>
for {
typeOfSharesHeld <- requiredPage(TypeOfSharesHeldPage(srn, index))
companyName <- requiredPage(CompanyNameRelatedSharesPage(srn, index))
acquisitionType <- requiredPage(WhyDoesSchemeHoldSharesPage(srn, index))
acquisitionDate = req.userAnswers.get(WhenDidSchemeAcquireSharesPage(srn, index))
} yield SharesData(index, typeOfSharesHeld, companyName, acquisitionType, acquisitionDate)
}
.sequence
private def shares(srn: Srn)(
implicit request: DataRequest[_],
logger: Logger
): Either[Result, (List[SharesData], List[SharesData])] = {
// if return has been pre-populated, partition shares by those that need to be checked
def buildShares(index: Max5000): Either[Result, SharesData] =
for {
typeOfSharesHeld <- requiredPage(TypeOfSharesHeldPage(srn, index))
companyName <- requiredPage(CompanyNameRelatedSharesPage(srn, index))
acquisitionType <- requiredPage(WhyDoesSchemeHoldSharesPage(srn, index))
acquisitionDate = request.userAnswers.get(WhenDidSchemeAcquireSharesPage(srn, index))
} yield SharesData(index, typeOfSharesHeld, companyName, acquisitionType, acquisitionDate)

if (isPrePopulation) {
for {
indexes <- request.userAnswers
.map(TypeOfSharesHeldPages(srn))
.refine[Max5000.Refined]
.map(_.keys.toList)
.getOrRecoverJourney
shares <- indexes.traverse(buildShares)
} yield shares.partition(
shares => SharesCheckStatusUtils.checkSharesRecord(request.userAnswers, srn, shares.index)
)
} else {
val noSharesToCheck = List.empty[SharesData]
for {
indexes <- request.userAnswers
.map(TypeOfSharesHeldPages(srn))
.refine[Max5000.Refined]
.map(_.keys.toList)
.getOrRecoverJourney
shares <- indexes.traverse(buildShares)
} yield (noSharesToCheck, shares)
}
}
}

object SharesListController {
Expand All @@ -222,7 +254,8 @@ object SharesListController {
mode: Mode,
memberList: List[SharesData],
viewOnlyViewModel: Option[ViewOnlyViewModel],
schemeName: String
schemeName: String,
check: Boolean = false
): List[ListRow] =
(memberList, mode) match {
case (Nil, mode) if mode.isViewOnlyMode =>
Expand Down Expand Up @@ -261,6 +294,12 @@ object SharesListController {
.url,
Message("site.view.param", sharesMessage)
)
case _ if check =>
ListRow.check(
sharesMessage,
controllers.routes.UnauthorisedController.onPageLoad().url,
Message("site.check.param", sharesMessage)
)
case _ =>
ListRow(
sharesMessage,
Expand All @@ -278,34 +317,45 @@ object SharesListController {
srn: Srn,
page: Int,
mode: Mode,
data: List[SharesData],
shares: List[SharesData],
sharesToCheck: List[SharesData],
schemeName: String,
viewOnlyViewModel: Option[ViewOnlyViewModel] = None,
showBackLink: Boolean
showBackLink: Boolean,
isPrePop: Boolean
): FormPageViewModel[ListViewModel] = {

val lengthOfData = data.length
val sharesSize = if (isPrePop) shares.length + sharesToCheck.size else shares.length

val (title, heading) = ((mode, lengthOfData) match {
case (ViewOnlyMode, lengthOfData) if lengthOfData == 0 =>
val (title, heading) = ((mode, sharesSize) match {
// View only
case (ViewOnlyMode, 0) =>
("sharesList.view.title.none", "sharesList.view.heading.none")
case (ViewOnlyMode, lengthOfData) if lengthOfData > 1 =>
("sharesList.view.title.plural", "sharesList.view.heading.plural")
case (ViewOnlyMode, _) =>
("sharesList.view.title", "sharesList.view.heading")
// Pre-pop
case (_, _) if isPrePop && shares.nonEmpty =>
("sharesList.title.prepop.check", "sharesList.heading.prepop.check")
case (_, sharesSize) if isPrePop && sharesSize > 1 =>
("sharesList.title.prepop.plural", "sharesList.heading.prepop.plural")
case (_, _) if isPrePop =>
("sharesList.title.prepop", "sharesList.heading.prepop")
// Normal
case (_, lengthOfData) if lengthOfData > 1 =>
("sharesList.title.plural", "sharesList.heading.plural")
case _ =>
("sharesList.title", "sharesList.heading")
}) match {
case (title, heading) =>
(Message(title, lengthOfData), Message(heading, lengthOfData))
(Message(title, sharesSize), Message(heading, sharesSize))
}

val pagination = Pagination(
currentPage = page,
pageSize = Constants.pageSize,
totalSize = data.size,
totalSize = shares.size,
call = viewOnlyViewModel match {
case Some(ViewOnlyViewModel(_, year, currentVersion, previousVersion, _)) =>
routes.SharesListController
Expand All @@ -315,25 +365,60 @@ object SharesListController {
}
)

val paragraph = Option.when(sharesSize < maxSharesTransactions) {
if (sharesToCheck.nonEmpty) {
ParagraphMessage("sharesList.description.prepop") ++
ParagraphMessage("sharesList.description.disposal")
} else {
ParagraphMessage("sharesList.description") ++
ParagraphMessage("sharesList.description.disposal")
}
}

val conditionalInsetText: DisplayMessage = {
if (data.size >= Constants.maxSharesTransactions) {
if (shares.size >= Constants.maxSharesTransactions) {
ParagraphMessage("sharesList.inset")
} else {
Message("")
}
}

val sections = {
if (isPrePop) {
Option
.when(sharesToCheck.nonEmpty)(
ListSection(
heading = Some("sharesList.section.check"),
rows(srn, mode, sharesToCheck, viewOnlyViewModel, schemeName, check = true)
)
)
.toList ++
Option
.when(shares.nonEmpty)(
ListSection(
heading = Some("sharesList.section.added"),
rows(srn, mode, shares, viewOnlyViewModel, schemeName)
)
)
.toList
} else {
List(
ListSection(rows(srn, mode, shares, viewOnlyViewModel, schemeName))
)
}
}

FormPageViewModel(
mode = mode,
title = title,
heading = heading,
description = Some(ParagraphMessage("sharesList.description")),
description = paragraph,
page = ListViewModel(
inset = conditionalInsetText,
sections = List(ListSection(rows(srn, mode, data, viewOnlyViewModel, schemeName))),
sections = sections,
radioText = Message("sharesList.radios"),
showRadios = data.size < Constants.maxSharesTransactions,
showInsetWithRadios = !(data.length < Constants.maxSharesTransactions),
showRadios = shares.size < Constants.maxSharesTransactions,
showInsetWithRadios = !(shares.length < Constants.maxSharesTransactions),
paginatedViewModel = Some(
PaginatedViewModel(
Message(
Expand Down
2 changes: 1 addition & 1 deletion app/utils/nonsipp/MemberCountUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ object MemberCountUtils {
userAnswers.get(FeesCommissionsWagesSalariesPage(srn, NormalMode))
)
)
lazy val sharesExist = !noDataStatuses.contains(getSharesTaskListStatusAndLink(userAnswers, srn)._1)
lazy val sharesExist = !noDataStatuses.contains(getSharesTaskListStatusAndLink(userAnswers, srn, isPrePop)._1)
lazy val landOrPropertyExist =
!noDataStatuses.contains(getLandOrPropertyTaskListStatusAndLink(userAnswers, srn, isPrePop)._1)
lazy val bondsExist = !noDataStatuses.contains(getBondsTaskListStatusAndLink(userAnswers, srn)._1)
Expand Down
Loading

0 comments on commit dd106a9

Please sign in to comment.