Skip to content

Commit 9296ee7

Browse files
authored
DTR-3131: Partnership CYA page (#81)
* DTR-3131: Partnership CYA page --------- Co-authored-by: szaniszlo <15050363+szaniszlo@users.noreply.github.com>
1 parent 7f4bcf7 commit 9296ee7

File tree

34 files changed

+1303
-913
lines changed

34 files changed

+1303
-913
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2026 HM Revenue & Customs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package controllers.add.partnership
18+
19+
import controllers.actions.*
20+
import models.UserAnswers
21+
import models.add.partnership.ValidatedPartnership
22+
import models.contact.ContactOptions.*
23+
import pages.add.partnership.PartnershipChooseContactDetailsPage
24+
import play.api.Logging
25+
import play.api.i18n.{I18nSupport, Messages, MessagesApi}
26+
import play.api.mvc.{Action, AnyContent, MessagesControllerComponents}
27+
import uk.gov.hmrc.govukfrontend.views.viewmodels.summarylist.SummaryListRow
28+
import uk.gov.hmrc.play.bootstrap.frontend.controller.FrontendBaseController
29+
import viewmodels.checkAnswers.add.TypeOfSubcontractorSummary
30+
import viewmodels.checkAnswers.add.partnership.{PartnershipWorksReferenceNumberYesNoSummary, *}
31+
import viewmodels.govuk.summarylist.*
32+
import views.html.add.partnership.PartnershipCheckYourAnswersView
33+
34+
import javax.inject.Inject
35+
36+
class PartnershipCheckYourAnswersController @Inject() (
37+
override val messagesApi: MessagesApi,
38+
identify: IdentifierAction,
39+
getData: DataRetrievalAction,
40+
requireData: DataRequiredAction,
41+
val controllerComponents: MessagesControllerComponents,
42+
view: PartnershipCheckYourAnswersView
43+
) extends FrontendBaseController
44+
with I18nSupport
45+
with Logging {
46+
47+
private def contactDetailsPage(ua: UserAnswers)(implicit messages: Messages): Option[SummaryListRow] =
48+
ua.get(PartnershipChooseContactDetailsPage).flatMap {
49+
case Email => PartnershipEmailAddressSummary.row(ua)
50+
case Phone => PartnershipPhoneNumberSummary.row(ua)
51+
case Mobile => PartnershipMobileNumberSummary.row(ua)
52+
case _ => None
53+
}
54+
55+
def onPageLoad: Action[AnyContent] = (identify andThen getData andThen requireData) { implicit request =>
56+
val ua = request.userAnswers
57+
ValidatedPartnership.build(ua) match {
58+
case Right(_) =>
59+
val list = SummaryListViewModel(
60+
rows = Seq(
61+
TypeOfSubcontractorSummary.row(ua),
62+
PartnershipNameSummary.row(ua),
63+
PartnershipAddressYesNoSummary.row(ua),
64+
PartnershipAddressSummary.row(ua),
65+
PartnershipChooseContactDetailsSummary.row(ua),
66+
contactDetailsPage(ua),
67+
PartnershipHasUtrYesNoSummary.row(ua),
68+
PartnershipUniqueTaxpayerReferenceSummary.row(ua),
69+
PartnershipNominatedPartnerNameSummary.row(ua),
70+
PartnershipNominatedPartnerUtrYesNoSummary.row(ua),
71+
PartnershipNominatedPartnerUtrSummary.row(ua),
72+
PartnershipNominatedPartnerNinoYesNoSummary.row(ua),
73+
PartnershipNominatedPartnerNinoSummary.row(ua),
74+
PartnershipNominatedPartnerCrnYesNoSummary.row(ua),
75+
PartnershipNominatedPartnerCrnSummary.row(ua),
76+
PartnershipWorksReferenceNumberYesNoSummary.row(ua),
77+
PartnershipWorksReferenceNumberSummary.row(ua)
78+
).flatten
79+
)
80+
81+
Ok(view(list))
82+
case Left(error) =>
83+
logger.error(s"[PartnershipCheckYourAnswersController.onPageLoad] Failed to load the page: $error")
84+
Redirect(controllers.routes.JourneyRecoveryController.onPageLoad())
85+
}
86+
}
87+
88+
}

app/controllers/add/partnership/PartnershipContactDetailsYesNoController.scala

Lines changed: 0 additions & 82 deletions
This file was deleted.

app/models/Validation.scala

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2026 HM Revenue & Customs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package models
18+
19+
import pages.QuestionPage
20+
import play.api.libs.json.Reads
21+
22+
trait Validation {
23+
def getPageValue[A](
24+
answers: UserAnswers,
25+
questionPage: QuestionPage[A]
26+
)(implicit reads: Reads[A]): Either[ValidationError, A] =
27+
answers.get(questionPage) match {
28+
case Some(value) => Right(value)
29+
case None => Left(MissingAnswer(questionPage))
30+
}
31+
32+
def getOptionalPageValue[A](
33+
answers: UserAnswers,
34+
questionPage: QuestionPage[A],
35+
yesNoPage: QuestionPage[Boolean]
36+
)(implicit reads: Reads[A]): Either[ValidationError, Option[A]] =
37+
(answers.get(questionPage), answers.get(yesNoPage)) match {
38+
case (_, None) => Left(MissingAnswer(yesNoPage))
39+
case (Some(value), Some(true)) => Right(Some(value))
40+
case (None, Some(false)) => Right(None)
41+
case _ => Left(InvalidAnswer(questionPage))
42+
}
43+
44+
}

app/models/add/ValidatedSubcontractor.scala

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@
1616

1717
package models.add
1818

19-
import models.{InvalidAnswer, MissingAnswer, UserAnswers, ValidationError}
19+
import models.{InvalidAnswer, UserAnswers, Validation, ValidationError}
2020
import pages.add.*
21-
import pages.QuestionPage
22-
import play.api.libs.json._
21+
import play.api.libs.json.*
2322

2423
final case class ValidatedSubcontractor(
2524
typeOfSubcontractor: TypeOfSubcontractor,
@@ -32,7 +31,7 @@ final case class ValidatedSubcontractor(
3231
contactDetails: Option[SubContactDetails]
3332
)
3433

35-
object ValidatedSubcontractor {
34+
object ValidatedSubcontractor extends Validation {
3635
def build(answers: UserAnswers): Either[ValidationError, ValidatedSubcontractor] =
3736
for {
3837
typeOfSubcontractor <- getType(answers)
@@ -54,23 +53,8 @@ object ValidatedSubcontractor {
5453
contactDetails
5554
)
5655

57-
private def getType(answers: UserAnswers): Either[ValidationError, TypeOfSubcontractor] =
58-
answers.get(TypeOfSubcontractorPage) match {
59-
case Some(value) => Right(value)
60-
case _ => Left(MissingAnswer(TypeOfSubcontractorPage))
61-
}
62-
63-
private def getOptionalPageValue[A](
64-
answers: UserAnswers,
65-
questionPage: QuestionPage[A],
66-
yesNoPage: QuestionPage[Boolean]
67-
)(implicit reads: Reads[A]): Either[ValidationError, Option[A]] =
68-
(answers.get(questionPage), answers.get(yesNoPage)) match {
69-
case (_, None) => Left(MissingAnswer(yesNoPage))
70-
case (Some(value), Some(true)) => Right(Some(value))
71-
case (None, Some(false)) => Right(None)
72-
case _ => Left(InvalidAnswer(questionPage))
73-
}
56+
def getType(answers: UserAnswers): Either[ValidationError, TypeOfSubcontractor] =
57+
getPageValue(answers, TypeOfSubcontractorPage)
7458

7559
// SubTradingNameYesNoPage is inverted for SubcontractorNamePage
7660
// Yes -> SubcontractorNamePage not required
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2026 HM Revenue & Customs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package models.add.partnership
18+
19+
import models.add.{InternationalAddress, TypeOfSubcontractor}
20+
import models.contact.ContactOptions
21+
import models.contact.ContactOptions.*
22+
import models.{InvalidAnswer, MissingAnswer, UserAnswers, Validation, ValidationError}
23+
import pages.QuestionPage
24+
import pages.add.TypeOfSubcontractorPage
25+
import pages.add.partnership.*
26+
import play.api.libs.json.*
27+
28+
final case class ValidatedPartnership(
29+
partnershipName: String,
30+
partnershipAddress: Option[InternationalAddress],
31+
partnershipContactDetails: ContactOptions,
32+
partnershipEmail: Option[String],
33+
partnershipPhone: Option[String],
34+
partnershipMobile: Option[String],
35+
partnershipUtr: Option[String],
36+
partnershipNominatedPartnerName: String,
37+
partnershipNominatedPartnerUtr: Option[String],
38+
partnershipNominatedPartnerNino: Option[String],
39+
partnershipNominatedPartnerCrn: Option[String],
40+
partnershipWorkRefNumber: Option[String]
41+
)
42+
43+
object ValidatedPartnership extends Validation {
44+
def build(answers: UserAnswers): Either[ValidationError, ValidatedPartnership] =
45+
for {
46+
_ <- validateType(answers)
47+
partnershipName <- getPageValue(answers, PartnershipNamePage)
48+
partnershipAddress <- getOptionalPageValue(answers, PartnershipAddressPage, PartnershipAddressYesNoPage)
49+
partnershipContactDetails <- getPageValue(answers, PartnershipChooseContactDetailsPage)
50+
partnershipEmail <- getContactPageValue(answers, PartnershipEmailAddressPage, partnershipContactDetails)
51+
partnershipPhone <- getContactPageValue(answers, PartnershipPhoneNumberPage, partnershipContactDetails)
52+
partnershipMobile <- getContactPageValue(answers, PartnershipMobileNumberPage, partnershipContactDetails)
53+
partnershipUtr <-
54+
getOptionalPageValue(answers, PartnershipUniqueTaxpayerReferencePage, PartnershipHasUtrYesNoPage)
55+
partnershipNominatedPartnerName <- getPageValue(answers, PartnershipNominatedPartnerNamePage)
56+
partnershipNominatedPartnerUtr <-
57+
getOptionalPageValue(answers, PartnershipNominatedPartnerUtrPage, PartnershipNominatedPartnerUtrYesNoPage)
58+
partnershipNominatedPartnerNino <-
59+
getOptionalPageValue(answers, PartnershipNominatedPartnerNinoPage, PartnershipNominatedPartnerNinoYesNoPage)
60+
partnershipNominatedPartnerCrn <-
61+
getOptionalPageValue(answers, PartnershipNominatedPartnerCrnPage, PartnershipNominatedPartnerCrnYesNoPage)
62+
partnershipWorkRefNumber <-
63+
getOptionalPageValue(answers, PartnershipWorksReferenceNumberPage, PartnershipWorksReferenceNumberYesNoPage)
64+
65+
} yield ValidatedPartnership(
66+
partnershipName,
67+
partnershipAddress,
68+
partnershipContactDetails,
69+
partnershipEmail,
70+
partnershipPhone,
71+
partnershipMobile,
72+
partnershipUtr,
73+
partnershipNominatedPartnerName,
74+
partnershipNominatedPartnerUtr,
75+
partnershipNominatedPartnerNino,
76+
partnershipNominatedPartnerCrn,
77+
partnershipWorkRefNumber
78+
)
79+
80+
private def validateType(answers: UserAnswers): Either[ValidationError, Unit] =
81+
getPageValue(answers, TypeOfSubcontractorPage).flatMap {
82+
case TypeOfSubcontractor.Partnership => Right(())
83+
case _ => Left(InvalidAnswer(TypeOfSubcontractorPage))
84+
}
85+
86+
private def getContactPageValue[A](
87+
answers: UserAnswers,
88+
questionPage: QuestionPage[A],
89+
contactOptions: ContactOptions
90+
)(implicit reads: Reads[A]): Either[ValidationError, Option[A]] = {
91+
val expectedPage: Option[QuestionPage[_]] = contactOptions match {
92+
case Email => Some(PartnershipEmailAddressPage)
93+
case Phone => Some(PartnershipPhoneNumberPage)
94+
case Mobile => Some(PartnershipMobileNumberPage)
95+
case NoDetails => None
96+
}
97+
98+
if (expectedPage.contains(questionPage)) {
99+
answers.get(questionPage).toRight(MissingAnswer(questionPage)).map(Some(_))
100+
} else if (expectedPage.isDefined) {
101+
Right(None)
102+
} else {
103+
answers
104+
.get(questionPage)
105+
.fold(Right(None): Either[ValidationError, Option[A]])(_ => Left(InvalidAnswer(questionPage)))
106+
}
107+
}
108+
109+
}

0 commit comments

Comments
 (0)