Skip to content

Commit 07bb836

Browse files
authored
[JB][OPS-13611, OPS-13541] wire up change links to pay-frontend, upda… (#32)
* [JB][OPS-13611, OPS-13541] wire up change links to pay-frontend, update return url we pass to barclaycard to not use mdtp host name notation * [JB] fix broken url * tidy up commented out bits
1 parent 22e16e7 commit 07bb836

30 files changed

+242
-523
lines changed

app/uk/gov/hmrc/cardpaymentfrontend/config/AppConfig.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class AppConfig @Inject() (config: Configuration, servicesConfig: ServicesConfig
3232
val emailBaseUrl: String = servicesConfig.baseUrl("email-service")
3333

3434
val payFrontendBaseUrl: String = config.get[String]("urls.pay-frontend.base-url") + "/pay"
35+
val cardPaymentFrontendBaseUrl: String = config.get[String]("urls.card-payment-frontend.base-url")
3536

3637
val bankTransferRelativeUrl: String = config.get[String]("urls.pay-frontend.bank-transfer")
3738
val oneOffDirectDebitRelativeUrl: String = config.get[String]("urls.pay-frontend.one-off-direct-debit")

app/uk/gov/hmrc/cardpaymentfrontend/controllers/CheckYourAnswersController.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package uk.gov.hmrc.cardpaymentfrontend.controllers
1818

1919
import play.api.mvc.{Action, AnyContent, MessagesControllerComponents}
2020
import uk.gov.hmrc.cardpaymentfrontend.actions.{Actions, JourneyRequest}
21+
import uk.gov.hmrc.cardpaymentfrontend.config.AppConfig
2122
import uk.gov.hmrc.cardpaymentfrontend.models.{Address, CheckYourAnswersRow, EmailAddress}
2223
import uk.gov.hmrc.cardpaymentfrontend.models.CheckYourAnswersRow.summarise
2324
import uk.gov.hmrc.cardpaymentfrontend.models.extendedorigins.ExtendedOrigin
@@ -37,6 +38,7 @@ import scala.concurrent.ExecutionContext
3738
@Singleton()
3839
class CheckYourAnswersController @Inject() (
3940
actions: Actions,
41+
appConfig: AppConfig,
4042
cardPaymentService: CardPaymentService,
4143
checkYourAnswersPage: CheckYourAnswersPage,
4244
mcc: MessagesControllerComponents,
@@ -47,10 +49,10 @@ class CheckYourAnswersController @Inject() (
4749
def renderPage: Action[AnyContent] = actions.journeyAction { implicit journeyRequest: JourneyRequest[AnyContent] =>
4850
val extendedOrigin: ExtendedOrigin = journeyRequest.journey.origin.lift
4951

50-
val paymentDate: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersPaymentDateRow(journeyRequest)
51-
val referenceRow: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersReferenceRow(journeyRequest)
52+
val paymentDate: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersPaymentDateRow(journeyRequest)(appConfig.payFrontendBaseUrl)
53+
val referenceRow: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersReferenceRow(journeyRequest)(appConfig.payFrontendBaseUrl)
5254
val additionalReferenceRow: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersAdditionalReferenceRow(journeyRequest)
53-
val amountRow: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersAmountSummaryRow(journeyRequest)
55+
val amountRow: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersAmountSummaryRow(journeyRequest)(appConfig.payFrontendBaseUrl)
5456
val maybeEmailRow: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersEmailAddressRow(journeyRequest)
5557
val cardBillingAddressRow: Option[CheckYourAnswersRow] = extendedOrigin.checkYourAnswersCardBillingAddressRow(journeyRequest)
5658

@@ -73,7 +75,7 @@ class CheckYourAnswersController @Inject() (
7375
addressFromSession = journeyRequest.readFromSession[Address](journeyRequest.journeyId, Keys.address).getOrElse(throw new RuntimeException("We can't process a card payment without the billing address.")),
7476
maybeEmailFromSession = journeyRequest.readFromSession[EmailAddress](journeyRequest.journeyId, Keys.email),
7577
language = requestSupport.usableLanguage
76-
)(requestSupport.hc, journeyRequest.request)
78+
)(requestSupport.hc)
7779
.map { cardPaymentInitiatePaymentResponse =>
7880
Redirect(routes.PaymentStatusController.showIframe(RedirectUrl(cardPaymentInitiatePaymentResponse.redirectUrl)))
7981
}

app/uk/gov/hmrc/cardpaymentfrontend/forms/AddressForm.scala

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ object AddressForm {
4646
"county" -> optional(text.transform[String](_.trim, identity)
4747
.verifying(maxLength(60))
4848
.verifying(emojiConstraint("county", "address.field-name.error.invalid.char"))),
49-
"postCode" -> of(postCodeFormatter),
50-
"countryCode" -> text.verifying(countryConstraint)
49+
"postcode" -> of(postcodeFormatter),
50+
"country" -> text.verifying(countryConstraint)
5151
)(Address.apply)(Address.unapply)
5252
)
5353

@@ -66,22 +66,22 @@ object AddressForm {
6666

6767
}
6868

69-
def countryConstraint: Constraint[String] = Constraint[String]("constraint.countryCode") { o =>
70-
if (o.isBlank) Invalid(ValidationError("address.field-name.error.required.countryCode")) else if (o.trim.isEmpty) Invalid(ValidationError("address.field-name.error.required.countryCode")) else Valid
69+
def countryConstraint: Constraint[String] = Constraint[String]("constraint.country") { o =>
70+
if (o.isBlank) Invalid(ValidationError("address.field-name.error.required.country")) else if (o.trim.isEmpty) Invalid(ValidationError("address.field-name.error.required.country")) else Valid
7171
}
7272

73-
val postCodeFormatter: Formatter[String] = new Formatter[String] {
73+
val postcodeFormatter: Formatter[String] = new Formatter[String] {
7474

7575
override def bind(key: String, data: Map[String, String]): Either[Seq[FormError], String] = {
7676
// for accessibility, we need to allow users to enter spaces anywhere in postcode, we strip them to assert the postcode matches the regex, then use what the user entered.
77-
val postCode: String = data("postCode").filterNot(_.isWhitespace)
78-
val selectedCountryIsGBR: Boolean = data("countryCode").matches("GBR")
79-
if (selectedCountryIsGBR && postCode.isEmpty)
80-
Left(Seq(FormError("postCode", "address.field-name.error.empty.postCode")))
81-
else if (selectedCountryIsGBR && !postCode.matches(ukPostcodeRegex.regex))
82-
Left(Seq(FormError("postCode", "address.field-name.error.invalid.postCode")))
77+
val postcode: String = data("postcode").filterNot(_.isWhitespace)
78+
val selectedCountryIsGBR: Boolean = data("country").matches("GBR")
79+
if (selectedCountryIsGBR && postcode.isEmpty)
80+
Left(Seq(FormError("postcode", "address.field-name.error.empty.postcode")))
81+
else if (selectedCountryIsGBR && !postcode.matches(ukPostcodeRegex.regex))
82+
Left(Seq(FormError("postcode", "address.field-name.error.invalid.postcode")))
8383
else
84-
Right(postCode)
84+
Right(postcode)
8585
}
8686

8787
override def unbind(key: String, value: String): Map[String, String] = Map(key -> value)

app/uk/gov/hmrc/cardpaymentfrontend/models/Address.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ package uk.gov.hmrc.cardpaymentfrontend.models
1818

1919
import play.api.libs.json.{Json, OFormat}
2020

21+
//these fields are the same as pay-frontend, so we can reuse some pages
2122
final case class Address(
22-
line1: String,
23-
line2: Option[String] = None,
24-
city: Option[String] = None,
25-
county: Option[String] = None,
26-
postCode: String,
27-
countryCode: String
23+
line1: String,
24+
line2: Option[String] = None,
25+
city: Option[String] = None,
26+
county: Option[String] = None,
27+
postcode: String,
28+
country: String
2829
) {
2930
def hasSelect(maybeString: Option[String]): Boolean = {
3031
maybeString match {
@@ -37,7 +38,7 @@ final case class Address(
3738

3839
// For UK (GBR) addresses only, replace counties containing variations on Select with None.
3940
def sanitiseCounty(): Address =
40-
if (countryCode.matches("GBR") && hasSelect(this.county)) this.copy (county = None)
41+
if (country.matches("GBR") && hasSelect(this.county)) this.copy (county = None)
4142
else this
4243
}
4344

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 uk.gov.hmrc.cardpaymentfrontend.models.cardpayment
18+
19+
import play.api.libs.json.{Format, Json}
20+
21+
//barclaycard want field names in a specific way, so we have another case class for it to send to the backend
22+
final case class BarclaycardAddress(
23+
line1: String,
24+
line2: Option[String] = None,
25+
city: Option[String] = None,
26+
county: Option[String] = None,
27+
postCode: String,
28+
countryCode: String
29+
) {
30+
31+
def hasSelect(maybeString: Option[String]): Boolean = {
32+
maybeString match {
33+
case Some(s) =>
34+
val selectPattern = "(?i)select".r
35+
selectPattern.findFirstIn(s).isDefined
36+
case None => false
37+
}
38+
}
39+
40+
// For UK (GBR) addresses only, replace counties containing variations on Select with None.
41+
def sanitiseCounty(): BarclaycardAddress =
42+
if (countryCode.matches("GBR") && hasSelect(this.county)) this.copy (county = None)
43+
else this
44+
}
45+
46+
@SuppressWarnings(Array("org.wartremover.warts.Any"))
47+
object BarclaycardAddress {
48+
implicit val format: Format[BarclaycardAddress] = Json.format[BarclaycardAddress]
49+
}

app/uk/gov/hmrc/cardpaymentfrontend/models/cardpayment/CardPaymentInitiatePaymentRequest.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ package uk.gov.hmrc.cardpaymentfrontend.models.cardpayment
1818

1919
import payapi.corcommon.model.AmountInPence
2020
import play.api.libs.json.{Format, Json}
21-
import uk.gov.hmrc.cardpaymentfrontend.models.{Address, EmailAddress}
21+
import uk.gov.hmrc.cardpaymentfrontend.models.EmailAddress
2222

2323
final case class CardPaymentInitiatePaymentRequest(
2424
redirectUrl: String,
2525
clientId: String,
2626
purchaseDescription: String, // i.e. tax reference
2727
purchaseAmount: AmountInPence, //in pennies
28-
billingAddress: Address,
28+
billingAddress: BarclaycardAddress,
2929
emailAddress: Option[EmailAddress]
3030
)
3131

app/uk/gov/hmrc/cardpaymentfrontend/models/extendedorigins/DefaultExtendedOrigin.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,20 @@
1616

1717
package uk.gov.hmrc.cardpaymentfrontend.models.extendedorigins
1818

19-
import play.api.i18n.Messages
19+
import payapi.cardpaymentjourney.model.journey.JourneySpecificData
2020
import play.api.mvc.AnyContent
2121
import uk.gov.hmrc.cardpaymentfrontend.actions.JourneyRequest
22-
import payapi.cardpaymentjourney.model.journey.JourneySpecificData
23-
import uk.gov.hmrc.cardpaymentfrontend.models.{CheckYourAnswersRow, PaymentMethod}
2422
import uk.gov.hmrc.cardpaymentfrontend.models.openbanking.OriginSpecificSessionData
23+
import uk.gov.hmrc.cardpaymentfrontend.models.{CheckYourAnswersRow, PaymentMethod}
2524

2625
class DefaultExtendedOrigin extends ExtendedOrigin {
2726
def serviceNameMessageKey = ""
2827
def taxNameMessageKey: String = ""
2928
override def reference(request: JourneyRequest[AnyContent]): String = ""
3029
def cardFeesPagePaymentMethods: Set[PaymentMethod] = Set.empty[PaymentMethod]
3130
def paymentMethods(): Set[PaymentMethod] = Set.empty[PaymentMethod]
32-
def checkYourAnswersRows(request: JourneyRequest[AnyContent])(implicit messages: Messages): Seq[CheckYourAnswersRow] = Seq.empty[CheckYourAnswersRow]
3331

34-
override def checkYourAnswersReferenceRow(journeyRequest: JourneyRequest[AnyContent]): Option[CheckYourAnswersRow] = None
32+
override def checkYourAnswersReferenceRow(journeyRequest: JourneyRequest[AnyContent])(payFrontendBaseUrl: String): Option[CheckYourAnswersRow] = None
3533

3634
override def openBankingOriginSpecificSessionData: JourneySpecificData => Option[OriginSpecificSessionData] = _ => None
3735

app/uk/gov/hmrc/cardpaymentfrontend/models/extendedorigins/ExtendedAlcoholDuty.scala

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ package uk.gov.hmrc.cardpaymentfrontend.models.extendedorigins
1818

1919
import payapi.cardpaymentjourney.model.journey.{JourneySpecificData, JsdAlcoholDuty}
2020
import payapi.corcommon.model.taxes.ad.AlcoholDutyChargeReference
21-
import play.api.i18n.Messages
2221
import play.api.mvc.AnyContent
2322
import uk.gov.hmrc.cardpaymentfrontend.actions.JourneyRequest
24-
import uk.gov.hmrc.cardpaymentfrontend.models.{CheckYourAnswersRow, PaymentMethod}
25-
import uk.gov.hmrc.cardpaymentfrontend.models.openbanking.{AlcoholDutySessionData, OriginSpecificSessionData}
2623
import uk.gov.hmrc.cardpaymentfrontend.models.PaymentMethod.{Bacs, Card, OpenBanking}
24+
import uk.gov.hmrc.cardpaymentfrontend.models.openbanking.{AlcoholDutySessionData, OriginSpecificSessionData}
25+
import uk.gov.hmrc.cardpaymentfrontend.models.{CheckYourAnswersRow, PaymentMethod}
2726

2827
object ExtendedAlcoholDuty extends ExtendedOrigin {
2928
override val serviceNameMessageKey: String = "service-name.AlcoholDuty"
@@ -33,10 +32,7 @@ object ExtendedAlcoholDuty extends ExtendedOrigin {
3332

3433
def paymentMethods(): Set[PaymentMethod] = Set(Card, OpenBanking, Bacs)
3534

36-
//todo delete from ExtendedOrigin trait, we won't use it anymore
37-
def checkYourAnswersRows(request: JourneyRequest[AnyContent])(implicit messages: Messages): Seq[CheckYourAnswersRow] = Seq.empty
38-
39-
override def checkYourAnswersReferenceRow(journeyRequest: JourneyRequest[AnyContent]): Option[CheckYourAnswersRow] = {
35+
override def checkYourAnswersReferenceRow(journeyRequest: JourneyRequest[AnyContent])(payFrontendBaseUrl: String): Option[CheckYourAnswersRow] = {
4036
Some(CheckYourAnswersRow(
4137
titleMessageKey = "check-your-details.AlcoholDuty.reference",
4238
value = Seq(journeyRequest.journey.referenceValue),

app/uk/gov/hmrc/cardpaymentfrontend/models/extendedorigins/ExtendedBtaSa.scala

Lines changed: 3 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717
package uk.gov.hmrc.cardpaymentfrontend.models.extendedorigins
1818

1919
import payapi.cardpaymentjourney.model.journey.{JourneySpecificData, JsdBtaSa}
20-
import play.api.i18n.Messages
21-
import play.api.mvc.{AnyContent, Call}
20+
import play.api.mvc.AnyContent
2221
import uk.gov.hmrc.cardpaymentfrontend.actions.JourneyRequest
2322
import uk.gov.hmrc.cardpaymentfrontend.models.PaymentMethod._
24-
import uk.gov.hmrc.cardpaymentfrontend.models.openbanking.{BtaSaSessionData, OriginSpecificSessionData}
2523
import uk.gov.hmrc.cardpaymentfrontend.models._
26-
import uk.gov.hmrc.cardpaymentfrontend.session.JourneySessionSupport._
24+
import uk.gov.hmrc.cardpaymentfrontend.models.openbanking.{BtaSaSessionData, OriginSpecificSessionData}
2725

2826
object ExtendedBtaSa extends ExtendedOrigin {
2927
override val serviceNameMessageKey: String = "service-name.BtaSa"
@@ -32,7 +30,7 @@ object ExtendedBtaSa extends ExtendedOrigin {
3230
def cardFeesPagePaymentMethods: Set[PaymentMethod] = Set(OpenBanking, OneOffDirectDebit)
3331
def paymentMethods(): Set[PaymentMethod] = Set(Card, OpenBanking, OneOffDirectDebit, Bacs)
3432

35-
override def checkYourAnswersReferenceRow(journeyRequest: JourneyRequest[AnyContent]): Option[CheckYourAnswersRow] = {
33+
override def checkYourAnswersReferenceRow(journeyRequest: JourneyRequest[AnyContent])(payFrontendBaseUrl: String): Option[CheckYourAnswersRow] = {
3634
Some(CheckYourAnswersRow(
3735
titleMessageKey = "check-your-details.BtaSa.reference",
3836
value = Seq(journeyRequest.journey.referenceValue),
@@ -51,83 +49,5 @@ object ExtendedBtaSa extends ExtendedOrigin {
5149
override def surveyIsWelshSupported: Boolean = true
5250
override def surveyBannerTitle: String = serviceNameMessageKey
5351

54-
def checkYourAnswersRows(request: JourneyRequest[AnyContent])(implicit messages: Messages): Seq[CheckYourAnswersRow] = {
55-
val referenceRow = CheckYourAnswersRow(
56-
"btasa.reference.title",
57-
Seq(reference(request).dropRight(1)), //Do not display the final K in the Utr in the CYA table),
58-
None
59-
)
60-
61-
val dateRow = CheckYourAnswersRow(
62-
"btasa.date.title",
63-
Seq(Messages("btasa.date.today")),
64-
Some(Link(
65-
Call("GET", "this/that"),
66-
"btasa.date-change-link",
67-
"btasa.date.change-link.text"
68-
))
69-
)
70-
71-
val amountRow = CheckYourAnswersRow(
72-
"btasa.amount.title",
73-
Seq(amount(request)),
74-
Some(Link(
75-
Call("GET", "this/that"),
76-
"pfvat-reference-change-link",
77-
"pfvat.reference.change-link.text"
78-
))
79-
)
80-
81-
val addressRow = {
82-
val maybeAddress: Option[Address] = request.readFromSession[Address](request.journeyId, Keys.address)
83-
CheckYourAnswersRow(
84-
"btasa.address.title",
85-
maybeAddress match {
86-
case Some(addr) => Seq(addr.line1, addr.line2.getOrElse(""), addr.city.getOrElse(""), addr.county.getOrElse(""), addr.postCode, addr.countryCode).filter(_.nonEmpty)
87-
case None => Seq.empty
88-
},
89-
Some(Link(
90-
Call("GET", "this/that"),
91-
"ptasa-address-change-link",
92-
"ptasa.address.change-link.text"
93-
))
94-
)
95-
}
96-
97-
val emailRow = {
98-
val maybeEmailAddress: Option[EmailAddress] = request.readFromSession[EmailAddress](request.journeyId, Keys.email)
99-
maybeEmailAddress match {
100-
case Some(emailAddress) =>
101-
CheckYourAnswersRow(
102-
titleMessageKey = "btasa.email.title",
103-
value = Seq(emailAddress.value),
104-
changeLink = Some(Link(
105-
Call("GET", "change/email"),
106-
"btasa-email-supply-link",
107-
"btasa.email.supply-link.text.change"
108-
))
109-
)
110-
case None =>
111-
CheckYourAnswersRow(
112-
titleMessageKey = "btasa.email.title",
113-
value = Seq.empty,
114-
changeLink = Some(Link(
115-
Call("GET", "change/email"),
116-
"btasa-email-supply-link",
117-
"btasa.email.supply-link.text.new"
118-
))
119-
)
120-
}
121-
}
122-
123-
Seq(
124-
referenceRow,
125-
dateRow,
126-
amountRow,
127-
addressRow,
128-
emailRow
129-
)
130-
}
131-
13252
override def emailTaxTypeMessageKey: String = "email.tax-name.BtaSa"
13353
}

0 commit comments

Comments
 (0)