Skip to content

Commit

Permalink
SASS-9703: Expenses section: Create 'Other allowable property expense…
Browse files Browse the repository at this point in the history
…s' page
  • Loading branch information
RGlossop committed Nov 27, 2024
1 parent 86dbb9f commit a988e1a
Show file tree
Hide file tree
Showing 11 changed files with 524 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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.foreign.expenses

import controllers.actions._
import forms.foreign.expenses.ForeignOtherAllowablePropertyExpensesFormProvider
import models.Mode
import navigation.ForeignPropertyNavigator
import pages.foreign.expenses.ForeignOtherAllowablePropertyExpensesPage
import play.api.i18n.{I18nSupport, MessagesApi}
import play.api.mvc.{Action, AnyContent, MessagesControllerComponents}
import repositories.SessionRepository
import uk.gov.hmrc.play.bootstrap.frontend.controller.FrontendBaseController
import views.html.foreign.expenses.ForeignOtherAllowablePropertyExpensesView

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

class ForeignOtherAllowablePropertyExpensesController @Inject()(
override val messagesApi: MessagesApi,
sessionRepository: SessionRepository,
foreignNavigator: ForeignPropertyNavigator,
identify: IdentifierAction,
getData: DataRetrievalAction,
requireData: DataRequiredAction,
formProvider: ForeignOtherAllowablePropertyExpensesFormProvider,
val controllerComponents: MessagesControllerComponents,
view: ForeignOtherAllowablePropertyExpensesView
)(implicit ec: ExecutionContext) extends FrontendBaseController with I18nSupport {



def onPageLoad(taxYear: Int, countryCode: String,mode: Mode): Action[AnyContent] = (identify andThen getData andThen requireData) {
implicit request =>
val form = formProvider(request.user.isAgentMessageKey)
val preparedForm = request.userAnswers.get(ForeignOtherAllowablePropertyExpensesPage(countryCode)) match {
case None => form
case Some(value) => form.fill(value)
}

Ok(view(preparedForm, taxYear, countryCode, request.user.isAgentMessageKey, mode))
}

def onSubmit(taxYear: Int, countryCode: String, mode: Mode): Action[AnyContent] = (identify andThen getData andThen requireData).async {
implicit request =>
val form = formProvider(request.user.isAgentMessageKey)
form.bindFromRequest().fold(
formWithErrors =>
Future.successful(BadRequest(view(formWithErrors, taxYear, countryCode, request.user.isAgentMessageKey, mode))),

value =>
for {
updatedAnswers <- Future.fromTry(request.userAnswers.set(ForeignOtherAllowablePropertyExpensesPage(countryCode), value))
_ <- sessionRepository.set(updatedAnswers)
} yield Redirect(foreignNavigator.nextPage(ForeignOtherAllowablePropertyExpensesPage(countryCode), taxYear, mode, request.userAnswers, updatedAnswers))
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 forms.foreign.expenses

import forms.mappings.Mappings
import play.api.data.Form

import javax.inject.Inject

class ForeignOtherAllowablePropertyExpensesFormProvider @Inject() extends Mappings {

val minimum = 0
val maximum = 100000000
def apply(individualOrAgent: String): Form[BigDecimal] =
Form(
"otherAllowablePropertyExpensesAmount" -> currency(
s"foreignOtherAllowablePropertyExpenses.error.required.$individualOrAgent",
s"foreignOtherAllowablePropertyExpenses.error.nonNumeric.$individualOrAgent",
s"foreignOtherAllowablePropertyExpenses.error.nonNumeric.$individualOrAgent")
.verifying(inRange(BigDecimal(minimum), BigDecimal(maximum), "foreignOtherAllowablePropertyExpenses.error.outOfRange"))
)
}
2 changes: 2 additions & 0 deletions app/pages/PageConstants.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ object PageConstants {

val foreignTaxPath: PropertyType => String = labelForPropertyType(_, "ForeignTax")

val foreignPropertyExpensesPath: PropertyType => String = labelForPropertyType(_, "expenses")

val foreignPropertySectionFinished: String = "foreignPropertySectionFinished"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 pages.foreign.expenses

import models.ForeignProperty
import pages.PageConstants.foreignPropertyExpensesPath
import pages.QuestionPage
import play.api.libs.json.JsPath

case class ForeignOtherAllowablePropertyExpensesPage(countryCode: String) extends QuestionPage[BigDecimal] {

override def path: JsPath = JsPath \ foreignPropertyExpensesPath(ForeignProperty) \ countryCode.toUpperCase \ toString

override def toString: String = "foreignOtherAllowablePropertyExpenses"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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 viewmodels.checkAnswers.foreign.expenses

import controllers.routes
import models.{CheckMode, UserAnswers}
import pages.foreign.expenses.ForeignOtherAllowablePropertyExpensesPage
import play.api.i18n.Messages
import uk.gov.hmrc.govukfrontend.views.viewmodels.summarylist.SummaryListRow
import viewmodels.govuk.summarylist._
import viewmodels.implicits._

object ForeignOtherAllowablePropertyExpensesSummary {

def row(taxYear: Int, countryCode: String, answers: UserAnswers)(implicit messages: Messages): Option[SummaryListRow] =
answers.get(ForeignOtherAllowablePropertyExpensesPage(countryCode)).map {
answer =>

SummaryListRowViewModel(
key = "foreignOtherAllowablePropertyExpenses.checkYourAnswersLabel",
value = ValueViewModel(answer.toString),
actions = Seq(
ActionItemViewModel("site.change", controllers.foreign.expenses.routes.ForeignOtherAllowablePropertyExpensesController.onPageLoad(taxYear, countryCode, CheckMode).url)
.withVisuallyHiddenText(messages("foreignOtherAllowablePropertyExpenses.change.hidden"))
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@*
* 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.
*@

@import viewmodels.InputWidth._
@import viewmodels.LabelSize

@this(
layout: templates.Layout,
formHelper: FormWithCSRF,
govukErrorSummary: GovukErrorSummary,
govukInput: GovukInput,
govukButton: GovukButton
)

@(form: Form[_], taxYear: Int, countryCode: String, individualOrAgent: String, mode: Mode)(implicit request: Request[_], messages: Messages)

@layout(pageTitle = title(form, messages("foreignOtherAllowablePropertyExpenses.title"))) {

@formHelper(action = controllers.foreign.expenses.routes.ForeignOtherAllowablePropertyExpensesController.onSubmit(taxYear, countryCode, mode), Symbol("autoComplete") -> "off") {

@if(form.errors.nonEmpty) {
@govukErrorSummary(ErrorSummaryViewModel(form))
}
<h1 class="govuk-heading-l">@messages("foreignOtherAllowablePropertyExpenses.heading")</h1>
<ul class="govuk-list govuk-list--bullet">
<li>@messages("foreignOtherAllowablePropertyExpenses.bullet1")</li>
<li>@messages("foreignOtherAllowablePropertyExpenses.bullet2")</li>
<li>@messages("foreignOtherAllowablePropertyExpenses.bullet3")</li>
<li>@messages("foreignOtherAllowablePropertyExpenses.bullet4")</li>
<li>@messages(s"foreignOtherAllowablePropertyExpenses.bullet5.$individualOrAgent")</li>
<li>@messages("foreignOtherAllowablePropertyExpenses.bullet6")</li>
<li>@messages(s"foreignOtherAllowablePropertyExpenses.bullet7.$individualOrAgent")</li>
</ul>
<p class="govuk-body">@messages("foreignOtherAllowablePropertyExpenses.hyperlink.text.1") <a href="https://www.gov.uk/expenses-if-youre-self-employed">@messages("foreignOtherAllowablePropertyExpenses.hyperlink.text.2")</a></p>
@govukInput(
InputViewModel(
field = form("otherAllowablePropertyExpensesAmount"),
label = LabelViewModel(messages(s"foreignOtherAllowablePropertyExpenses.label.$individualOrAgent")).withCssClass("govuk-label govuk-label--m")
).withHint(HintViewModel(messages("foreignOtherAllowablePropertyExpenses.hint")))
.asNumeric()
.withWidth(Fixed10).withPrefix(PrefixOrSuffix(content = Text("£")))
)

@govukButton(
ButtonViewModel(messages("site.continue")).withId("continue")
)
}
}
5 changes: 5 additions & 0 deletions conf/foreign.routes
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,8 @@ GET /:taxYear/foreign-property/income/:countryCode/foreign-income-section
POST /:taxYear/foreign-property/income/:countryCode/foreign-income-section-finished controllers.foreign.income.ForeignIncomeSectionCompleteController.onSubmit(taxYear: Int, countryCode: String, mode: Mode = CheckMode)

GET /:taxYear/foreign-property/expenses/:countryCode/foreign-property-expenses-start controllers.foreign.expenses.ForeignPropertyExpensesStartController.onPageLoad(taxYear: Int, countryCode: String)

GET /:taxYear/foreign-property/expenses/:countryCode/foreign-other-allowable-property-expenses controllers.foreign.expenses.ForeignOtherAllowablePropertyExpensesController.onPageLoad(taxYear: Int, countryCode: String, mode: Mode = NormalMode)
POST /:taxYear/foreign-property/expenses/:countryCode/foreign-other-allowable-property-expenses controllers.foreign.expenses.ForeignOtherAllowablePropertyExpensesController.onSubmit(taxYear: Int, countryCode: String, mode: Mode = NormalMode)
GET /:taxYear/foreign-property/expenses/:countryCode/change-foreign-other-allowable-property-expenses controllers.foreign.expenses.ForeignOtherAllowablePropertyExpensesController.onPageLoad(taxYear: Int, countryCode: String, mode: Mode = CheckMode)
POST /:taxYear/foreign-property/expenses/:countryCode/change-foreign-other-allowable-property-expenses controllers.foreign.expenses.ForeignOtherAllowablePropertyExpensesController.onSubmit(taxYear: Int, countryCode: String, mode: Mode = CheckMode)
26 changes: 25 additions & 1 deletion conf/messages.cy
Original file line number Diff line number Diff line change
Expand Up @@ -2029,4 +2029,28 @@ foreignPropertyExpensesStart.p4.individual = *Missing Welsh*
foreignPropertyExpensesStart.p4.agent = *Missing Welsh*
foreignPropertyExpensesStart.p5 = *Missing Welsh*
foreignPropertyExpensesStart.p6 = *Missing Welsh*
foreignPropertyExpensesStart.p7 = *Missing Welsh*
foreignPropertyExpensesStart.p7 = *Missing Welsh*

foreignOtherAllowablePropertyExpenses.title = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.heading = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet1 = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet2 = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet3 = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet4 = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet5.individual = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet5.agent = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet6 = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet7.individual = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.bullet7.agent = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.hyperlink.text.1 = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.hyperlink.text.2 = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.label.individual = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.label.agent = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.hint = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.checkYourAnswersLabel = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.error.nonNumeric.individual = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.error.nonNumeric.agent = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.error.required.individual = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.error.required.agent = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.error.outOfRange = *Missing Welsh*
foreignOtherAllowablePropertyExpenses.change.hidden = *Missing Welsh*
24 changes: 24 additions & 0 deletions conf/messages.en
Original file line number Diff line number Diff line change
Expand Up @@ -2057,3 +2057,27 @@ foreignPropertyExpensesStart.p4.agent = Your client can claim:
foreignPropertyExpensesStart.p5 = Consolidated expenses, where you add up all of your expenses and enter one total amount.
foreignPropertyExpensesStart.p6 = or
foreignPropertyExpensesStart.p7 = Individual expenses, where you enter an amount for each separate expenses type.

foreignOtherAllowablePropertyExpenses.title = Other allowable property expenses
foreignOtherAllowablePropertyExpenses.heading = Other allowable property expenses
foreignOtherAllowablePropertyExpenses.bullet1 = office costs, for example stationery or phone bills
foreignOtherAllowablePropertyExpenses.bullet2 = clothing expenses, for example uniforms
foreignOtherAllowablePropertyExpenses.bullet3 = things you buy to sell on, for example stock or raw materials
foreignOtherAllowablePropertyExpenses.bullet4 = financial costs, for example insurance or bank charges
foreignOtherAllowablePropertyExpenses.bullet5.individual = costs of your business premises, for example heating, lighting, business rates
foreignOtherAllowablePropertyExpenses.bullet5.agent = costs of your clients business premises, for example heating, lighting, business rates
foreignOtherAllowablePropertyExpenses.bullet6 = advertising or marketing, for example website costs
foreignOtherAllowablePropertyExpenses.bullet7.individual = training courses related to your business, for example refresher courses
foreignOtherAllowablePropertyExpenses.bullet7.agent = training courses related to your clients business, for example refresher courses
foreignOtherAllowablePropertyExpenses.hyperlink.text.1 = Read more about
foreignOtherAllowablePropertyExpenses.hyperlink.text.2 = allowable property expenses at GOV.UK (opens in new tab).
foreignOtherAllowablePropertyExpenses.label.individual = How much were your other allowable property expenses?
foreignOtherAllowablePropertyExpenses.label.agent = How much were your client's other allowable property expenses?
foreignOtherAllowablePropertyExpenses.hint = For example, £900 or £100.20
foreignOtherAllowablePropertyExpenses.checkYourAnswersLabel = Other allowable property expenses
foreignOtherAllowablePropertyExpenses.error.nonNumeric.individual = The amount for your other allowable property expenses can only include pounds and pence, for example £600 or £600.20
foreignOtherAllowablePropertyExpenses.error.nonNumeric.agent = The amount for your clients other allowable property expenses can only include pounds and pence, for example £600 or £600.20
foreignOtherAllowablePropertyExpenses.error.required.individual = Enter the amount for your other allowable property expenses
foreignOtherAllowablePropertyExpenses.error.required.agent = Enter the amount for your clients other allowable property expenses
foreignOtherAllowablePropertyExpenses.error.outOfRange = Enter an amount between {0} and {1}
foreignOtherAllowablePropertyExpenses.change.hidden = Other allowable property expenses
Loading

0 comments on commit a988e1a

Please sign in to comment.