Skip to content

Commit 064dce9

Browse files
DTR-1609: SDLT - Corporation Tax Unique Taxpayer Reference page pr-5d (#63)
* DTR-1609: Adds Corporation Tax UTR page and tests * DTR-1609: Addresses review comments
1 parent bfe44c3 commit 064dce9

File tree

14 files changed

+752
-5
lines changed

14 files changed

+752
-5
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2025 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.purchaser
18+
19+
import controllers.actions.*
20+
import forms.purchaser.PurchaserCorporationTaxUTRFormProvider
21+
import models.purchaser.{PurchaserConfirmIdentity, WhoIsMakingThePurchase}
22+
import models.{Mode, NormalMode}
23+
import navigation.Navigator
24+
import pages.purchaser.{NameOfPurchaserPage, PurchaserConfirmIdentityPage, PurchaserCorporationTaxUTRPage}
25+
import play.api.i18n.{I18nSupport, MessagesApi}
26+
import play.api.mvc.{Action, AnyContent, MessagesControllerComponents}
27+
import repositories.SessionRepository
28+
import services.purchaser.PurchaserService
29+
import uk.gov.hmrc.play.bootstrap.frontend.controller.FrontendBaseController
30+
import views.html.purchaser.PurchaserCorporationTaxUTRView
31+
32+
import javax.inject.Inject
33+
import scala.concurrent.{ExecutionContext, Future}
34+
35+
class PurchaserCorporationTaxUTRController @Inject()(
36+
override val messagesApi: MessagesApi,
37+
sessionRepository: SessionRepository,
38+
navigator: Navigator,
39+
identify: IdentifierAction,
40+
getData: DataRetrievalAction,
41+
requireData: DataRequiredAction,
42+
purchaserService: PurchaserService,
43+
formProvider: PurchaserCorporationTaxUTRFormProvider,
44+
val controllerComponents: MessagesControllerComponents,
45+
view: PurchaserCorporationTaxUTRView
46+
)(implicit ec: ExecutionContext) extends FrontendBaseController with I18nSupport {
47+
48+
val form = formProvider()
49+
50+
def onPageLoad(mode: Mode): Action[AnyContent] = (identify andThen getData andThen requireData) {
51+
implicit request =>
52+
53+
val userAnswers = request.userAnswers
54+
val nameOfPurchaser: Option[String] = userAnswers.get(NameOfPurchaserPage).map(_.fullName)
55+
val purchaserConfirmIdentity: Option[PurchaserConfirmIdentity] = userAnswers.get(PurchaserConfirmIdentityPage)
56+
57+
purchaserService.checkPurchaserTypeAndCompanyDetails(
58+
WhoIsMakingThePurchase.Company,
59+
userAnswers,
60+
continueRoute = (nameOfPurchaser, purchaserConfirmIdentity) match {
61+
case (Some(purchaserName), Some(identity)) if identity == PurchaserConfirmIdentity.CorporationTaxUTR =>
62+
val preparedForm = request.userAnswers.get(PurchaserCorporationTaxUTRPage) match {
63+
case None => form
64+
case Some(formValue) => form.fill(formValue)
65+
}
66+
Ok(view(preparedForm, purchaserName, mode))
67+
68+
case (Some(purchaserName), _) => Redirect(controllers.purchaser.routes.PurchaserConfirmIdentityController.onPageLoad(NormalMode))
69+
case (None, _) => Redirect(controllers.purchaser.routes.NameOfPurchaserController.onPageLoad(NormalMode))
70+
}
71+
)
72+
}
73+
74+
def onSubmit(mode: Mode): Action[AnyContent] = (identify andThen getData andThen requireData).async {
75+
implicit request =>
76+
77+
val userAnswers = request.userAnswers
78+
val nameOfPurchaser: Option[String] = userAnswers.get(NameOfPurchaserPage).map(_.fullName)
79+
80+
nameOfPurchaser match {
81+
case None => Future.successful(Redirect(controllers.purchaser.routes.NameOfPurchaserController.onPageLoad(NormalMode)))
82+
83+
case Some(purchaserName) =>
84+
form.bindFromRequest().fold(
85+
formWithErrors =>
86+
Future.successful(BadRequest(view(formWithErrors, purchaserName, mode))),
87+
88+
value =>
89+
for {
90+
updatedAnswers <- Future.fromTry(request.userAnswers.set(PurchaserCorporationTaxUTRPage, value))
91+
_ <- sessionRepository.set(updatedAnswers)
92+
} yield Redirect(navigator.nextPage(PurchaserCorporationTaxUTRPage, mode, updatedAnswers))
93+
)
94+
}
95+
}
96+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2025 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 forms.purchaser
18+
19+
import forms.mappings.Mappings
20+
import play.api.data.Form
21+
import play.api.data.validation.Constraints.minLength
22+
23+
import javax.inject.Inject
24+
25+
class PurchaserCorporationTaxUTRFormProvider @Inject() extends Mappings {
26+
27+
def apply(): Form[String] =
28+
Form(
29+
"value" -> text("purchaser.purchaserCorporationTaxUTR.error.required")
30+
.verifying(validUtr("purchaser.purchaserCorporationTaxUTR.error"))
31+
)
32+
}

app/navigation/Navigator.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class Navigator @Inject()() {
6262

6363
private def isPurchaserSection(page: Page): Boolean = page match {
6464

65-
case WhoIsMakingThePurchasePage | NameOfPurchaserPage | DoesPurchaserHaveNIPage | PurchaserNationalInsurancePage | PurchaserFormOfIdIndividualPage | AddPurchaserPhoneNumberPage | PurchaserDateOfBirthPage | EnterPurchaserPhoneNumberPage | PurchaserPartnershipUtrPage => true
65+
case WhoIsMakingThePurchasePage | NameOfPurchaserPage | DoesPurchaserHaveNIPage | PurchaserNationalInsurancePage | PurchaserFormOfIdIndividualPage | AddPurchaserPhoneNumberPage | PurchaserDateOfBirthPage | EnterPurchaserPhoneNumberPage | PurchaserPartnershipUtrPage | PurchaserCorporationTaxUTRPage => true
6666

6767
case _ => false
6868
}
@@ -86,6 +86,8 @@ class Navigator @Inject()() {
8686
_ => routes.ReturnTaskListController.onPageLoad() // TODO: Update to pr-6 'Is the Purchaser a trustee?' in DTR-1682
8787
case PurchaserPartnershipUtrPage => //TODO: to be updated to 'type of business' (DTR-1679 pr-9 - sprint 5)
8888
_ => controllers.purchaser.routes.PurchaserPartnershipUtrController.onPageLoad(NormalMode)
89+
case PurchaserCorporationTaxUTRPage => //TODO: to be updated to 'type of business' (DTR-1679 pr-9 - sprint 5)
90+
_ => controllers.purchaser.routes.PurchaserCorporationTaxUTRController.onPageLoad(NormalMode)
8991
case _ => _ => routes.IndexController.onPageLoad()
9092
}
9193

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2025 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 pages.purchaser
18+
19+
import pages.QuestionPage
20+
import play.api.libs.json.JsPath
21+
22+
case object PurchaserCorporationTaxUTRPage extends QuestionPage[String] {
23+
24+
override def path: JsPath = JsPath \ "purchaserCurrent" \ toString
25+
26+
override def toString: String = "purchaserCorporationTaxUTR"
27+
}

app/services/purchaser/PurchaserService.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ class PurchaserService {
114114
case PurchaserConfirmIdentity.PartnershipUTR =>
115115
controllers.purchaser.routes.PurchaserPartnershipUtrController.onPageLoad(NormalMode)
116116
case PurchaserConfirmIdentity.CorporationTaxUTR =>
117-
// TODO: redirect to Corp Tax UTR page
118-
controllers.purchaser.routes.NameOfPurchaserController.onPageLoad(NormalMode)
117+
controllers.purchaser.routes.PurchaserCorporationTaxUTRController.onPageLoad(NormalMode)
119118
case PurchaserConfirmIdentity.VatRegistrationNumber =>
120119
// TODO: redirect to Vat Reg Num page
121120
controllers.purchaser.routes.NameOfPurchaserController.onPageLoad(NormalMode)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2025 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 viewmodels.checkAnswers.purchaser
18+
19+
import controllers.purchaser.routes
20+
import models.{CheckMode, UserAnswers}
21+
import pages.purchaser.PurchaserCorporationTaxUTRPage
22+
import play.api.i18n.Messages
23+
import play.twirl.api.HtmlFormat
24+
import uk.gov.hmrc.govukfrontend.views.viewmodels.content.HtmlContent
25+
import uk.gov.hmrc.govukfrontend.views.viewmodels.summarylist.SummaryListRow
26+
import viewmodels.govuk.summarylist.*
27+
import viewmodels.implicits.*
28+
29+
object PurchaserCorporationTaxUTRSummary {
30+
31+
def row(answers: UserAnswers)(implicit messages: Messages): Option[SummaryListRow] =
32+
answers.get(PurchaserCorporationTaxUTRPage).map {
33+
answer =>
34+
35+
SummaryListRowViewModel(
36+
key = "purchaser.purchaserCorporationTaxUTR.checkYourAnswersLabel",
37+
value = ValueViewModel(HtmlContent(HtmlFormat.escape(answer).toString)),
38+
actions = Seq(
39+
ActionItemViewModel("site.change", controllers.purchaser.routes.PurchaserCorporationTaxUTRController.onPageLoad(CheckMode).url)
40+
.withVisuallyHiddenText(messages("purchaser.purchaserCorporationTaxUTR.change.hidden"))
41+
)
42+
)
43+
}
44+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
@*
2+
* Copyright 2025 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+
@import viewmodels.InputWidth._
18+
@import viewmodels.LabelSize.Medium
19+
@import views.html.components.h1
20+
@import views.html.components.p
21+
22+
@this(
23+
layout: templates.Layout,
24+
formHelper: FormWithCSRF,
25+
govukErrorSummary: GovukErrorSummary,
26+
govukInput: GovukInput,
27+
govukButton: GovukButton,
28+
h1: h1,
29+
p:p
30+
)
31+
32+
@(form: Form[_], purchaserName: String, mode: Mode)(implicit request: Request[_], messages: Messages)
33+
34+
@layout(pageTitle = title(form, messages("purchaser.purchaserCorporationTaxUTR.title"))) {
35+
36+
@formHelper(action = controllers.purchaser.routes.PurchaserCorporationTaxUTRController.onSubmit(mode)) {
37+
38+
@if(form.errors.nonEmpty) {
39+
@govukErrorSummary(ErrorSummaryViewModel(form))
40+
}
41+
42+
<div class="govuk-caption-l">@messages("purchaser.caption")</div>
43+
@h1(messages("purchaser.purchaserCorporationTaxUTR.h1", purchaserName))
44+
@p(Html(messages("purchaser.purchaserCorporationTaxUTR.p")))
45+
46+
@govukInput(
47+
InputViewModel(
48+
field = form("value"),
49+
label = LabelViewModel(messages("purchaser.purchaserCorporationTaxUTR.h2", purchaserName)).asPageHeading(size = Medium)
50+
)
51+
.withWidth(Full)
52+
.withHint(HintViewModel(HtmlContent(Html(messages("purchaser.purchaserCorporationTaxUTR.hint")))))
53+
)
54+
55+
@govukButton(
56+
ButtonViewModel(messages("site.save.continue"))
57+
)
58+
}
59+
}

conf/app.routes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,8 @@ GET /about-the-purchaser/partnership-utr
184184
POST /about-the-purchaser/partnership-utr controllers.purchaser.PurchaserPartnershipUtrController.onSubmit(mode: Mode = NormalMode)
185185
GET /about-the-purchaser/partnership-utr/change controllers.purchaser.PurchaserPartnershipUtrController.onPageLoad(mode: Mode = CheckMode)
186186
POST /about-the-purchaser/partnership-utr/change controllers.purchaser.PurchaserPartnershipUtrController.onSubmit(mode: Mode = CheckMode)
187+
188+
GET /about-the-purchaser/corporation-tax-utr controllers.purchaser.PurchaserCorporationTaxUTRController.onPageLoad(mode: Mode = NormalMode)
189+
POST /about-the-purchaser/corporation-tax-utr controllers.purchaser.PurchaserCorporationTaxUTRController.onSubmit(mode: Mode = NormalMode)
190+
GET /about-the-purchaser/corporation-tax-utr/change controllers.purchaser.PurchaserCorporationTaxUTRController.onPageLoad(mode: Mode = CheckMode)
191+
POST /about-the-purchaser/corporation-tax-utr/change controllers.purchaser.PurchaserCorporationTaxUTRController.onSubmit(mode: Mode = CheckMode)

conf/messages.en

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,3 +539,15 @@ purchaserPartnershipUtr.error.length = Th
539539
purchaserPartnershipUtr.error.invalid = Please enter a valid UTR
540540
purchaserPartnershipUtr.error.regex.invalid = The UTR should only contain numbers
541541
purchaserPartnershipUtr.change.hidden = PurchaserPartnershipUtr
542+
543+
purchaser.purchaserCorporationTaxUTR.title = What is the purchaser’s Corporation Tax Unique Taxpayer Reference (UTR)? - About the purchaser
544+
purchaser.purchaserCorporationTaxUTR.h1 = {0}’s Corporation Tax Unique Taxpayer Reference (UTR)
545+
purchaser.purchaserCorporationTaxUTR.p = It will be on tax returns and other letters about Corporation Tax. It might be called ‘reference’, ‘UTR’ or ‘official use’.
546+
purchaser.purchaserCorporationTaxUTR.h2 = What is {0}’s Corporation Tax UTR?
547+
purchaser.purchaserCorporationTaxUTR.hint = Their UTR should be 10 digits long
548+
purchaser.purchaserCorporationTaxUTR.checkYourAnswersLabel = Corporation Tax Unique Taxpayer Reference (UTR)
549+
purchaser.purchaserCorporationTaxUTR.error.required = Enter Corporation Tax Unique Taxpayer Reference (UTR)
550+
purchaser.purchaserCorporationTaxUTR.error.length = Corporation Tax Unique Taxpayer Reference (UTR) must be 10 characters
551+
purchaser.purchaserCorporationTaxUTR.error.regex.invalid = Enter a valid UTR
552+
purchaser.purchaserCorporationTaxUTR.error.invalid = Enter a valid UTR
553+
purchaser.purchaserCorporationTaxUTR.change.hidden = Corporation Tax Unique Taxpayer Reference (UTR)

0 commit comments

Comments
 (0)