Repository: hmrc/alcohol-duty-returns-frontend
Pull request #321: ADR-1528: Implement the Clear Return functionality on the task list page
Author: login: Bradleigh-L
Created: 2025-03-14T13:22:36Z | Merged: 2025-03-19T12:34:00Z



Diff:
diff --git a/app/controllers/ClearReturnAreYouSureQuestionController.scala b/app/controllers/ClearReturnAreYouSureQuestionController.scala
new file mode 100644
index 000000000..87c05e018
--- /dev/null
+++ b/app/controllers/ClearReturnAreYouSureQuestionController.scala
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 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
+
+import connectors.UserAnswersConnector
+import controllers.actions._
+import forms.ClearReturnAreYouSureQuestionFormProvider
+import models.ReturnId
+import models.requests.DataRequest
+import play.api.Logging
+import play.api.i18n.{I18nSupport, MessagesApi}
+import play.api.mvc.{Action, AnyContent, MessagesControllerComponents, Result}
+import uk.gov.hmrc.alcoholdutyreturns.models.ReturnAndUserDetails
+import uk.gov.hmrc.play.bootstrap.frontend.controller.FrontendBaseController
+import views.html.ClearReturnAreYouSureQuestionView
+
+import javax.inject.Inject
+import scala.concurrent.{ExecutionContext, Future}
+import scala.util.{Failure, Success}
+
+class ClearReturnAreYouSureQuestionController @Inject() (
+  override val messagesApi: MessagesApi,
+  userAnswersConnector: UserAnswersConnector,
+  identify: IdentifyWithEnrolmentAction,
+  getData: DataRetrievalAction,
+  requireData: DataRequiredAction,
+  formProvider: ClearReturnAreYouSureQuestionFormProvider,
+  val controllerComponents: MessagesControllerComponents,
+  view: ClearReturnAreYouSureQuestionView
+)(implicit ec: ExecutionContext)
+    extends FrontendBaseController
+    with I18nSupport
+    with Logging {
+
+  val form = formProvider()
+
+  def onPageLoad(): Action[AnyContent] = (identify andThen getData andThen requireData) { implicit request =>
+    Ok(view(form))
+  }
+
+  def onSubmit(): Action[AnyContent] = (identify andThen getData andThen requireData).async { implicit request =>
+    form
+      .bindFromRequest()
+      .fold(
+        formWithErrors => Future.successful(BadRequest(view(formWithErrors))),
+        value => handleAnswer(value, request.appaId, request.returnPeriod.toPeriodKey)
+      )
+  }
+
+  private def handleAnswer(clearUserAnswers: Boolean, appaId: String, periodKey: String)(implicit
+    request: DataRequest[AnyContent]
+  ): Future[Result] =
+    if (clearUserAnswers) {
+      userAnswersConnector.delete(appaId, periodKey).transformWith {
+        case Success(httpResponse) if httpResponse.status == OK =>
+          recreateUserAnswers(appaId, periodKey)
+        case Success(httpResponse)                              =>
+          logger.warn(s"Unable to clear user answers: $appaId/$periodKey: ${httpResponse.status} ${httpResponse.body}")
+          Future.successful(Redirect(controllers.routes.JourneyRecoveryController.onPageLoad()))
+        case Failure(e)                                         =>
+          logger.warn(s"Unable to clear user answers: $appaId/$periodKey", e)
+          Future.failed(e)
+      }
+    } else {
+      Future.successful(Redirect(routes.TaskListController.onPageLoad.url))
+    }
+
+  private def recreateUserAnswers(appaId: String, periodKey: String)(implicit
+    request: DataRequest[AnyContent]
+  ): Future[Result] = {
+    val returnAndUserDetails =
+      ReturnAndUserDetails(ReturnId(appaId, periodKey), request.groupId, request.userId)
+    userAnswersConnector.createUserAnswers(returnAndUserDetails).map {
+      case Right(_)    =>
+        logger.info(s"Return $appaId/$periodKey recreated")
+        Redirect(routes.TaskListController.onPageLoad.url)
+      case Left(error) =>
+        logger.warn(s"Unable to recreate userAnswers: $error")
+        Redirect(controllers.routes.JourneyRecoveryController.onPageLoad())
+    }
+  }
+}
diff --git a/app/forms/ClearReturnAreYouSureQuestionFormProvider.scala b/app/forms/ClearReturnAreYouSureQuestionFormProvider.scala
new file mode 100644
index 000000000..696e26d8b
--- /dev/null
+++ b/app/forms/ClearReturnAreYouSureQuestionFormProvider.scala
@@ -0,0 +1,30 @@
+/*
+ * 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
+
+import forms.mappings.Mappings
+import play.api.data.Form
+
+import javax.inject.Inject
+
+class ClearReturnAreYouSureQuestionFormProvider @Inject() extends Mappings {
+
+  def apply(): Form[Boolean] =
+    Form(
+      "clearReturnAreYouSureQuestion-yesNoValue" -> boolean("clearReturnAreYouSureQuestion.error.required")
+    )
+}
diff --git a/app/views/ClearReturnAreYouSureQuestionView.scala.html b/app/views/ClearReturnAreYouSureQuestionView.scala.html
new file mode 100644
index 000000000..cdba51df6
--- /dev/null
+++ b/app/views/ClearReturnAreYouSureQuestionView.scala.html
@@ -0,0 +1,65 @@
+@*
+ * Copyright 2023 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 components.{Link, Caption, PageHeading, FormGroupWithError}
+@import config.Constants.Css
+@import uk.gov.hmrc.govukfrontend.views.viewmodels.content.Empty
+
+@this(
+    layout: templates.Layout,
+    formHelper: FormWithCSRF,
+    govukErrorSummary: GovukErrorSummary,
+    govukRadios: GovukRadios,
+    govukButton: GovukButton,
+    link: Link,
+    caption: Caption,
+    pageHeading: PageHeading,
+    govukWarningText: GovukWarningText,
+    formGroupWithError: FormGroupWithError
+)
+
+@(form: Form[_])(implicit request: Request[_], messages: Messages)
+
+@layout(pageTitle = title(form, messages("clearReturnAreYouSureQuestion.title"))) {
+
+    @formHelper(action = controllers.routes.ClearReturnAreYouSureQuestionController.onSubmit(), Symbol("autoComplete") -> "off") {
+
+    @if(form.errors.nonEmpty) {
+        @govukErrorSummary(ErrorSummaryViewModel(form))
+    }
+
+    @formGroupWithError(form.errors.nonEmpty){
+        @pageHeading(messages("clearReturnAreYouSureQuestion.heading"))
+
+
+        @govukWarningText(WarningText(
+            iconFallbackText = Some(messages("site.warning")),
+            content = Text(messages("clearReturnAreYouSureQuestion.warning"))
+        ))
+
+        @govukRadios(
+            RadiosViewModel.yesNo(
+                field = form("clearReturnAreYouSureQuestion-yesNoValue"),
+                legend = LegendViewModel(messages("clearReturnAreYouSureQuestion.heading")).asVisuallyHidden()
+            )
+        )
+    }
+
+    @govukButton(
+            ButtonViewModel("continueButton", messages("site.continue"))
+        )
+    }
+}
diff --git a/app/views/TaskListView.scala.html b/app/views/TaskListView.scala.html
index c7d1c17f0..eb42f7ab2 100644
--- a/app/views/TaskListView.scala.html
+++ b/app/views/TaskListView.scala.html
@@ -55,5 +55,11 @@
             ))
         )
 
+    @govukButton(
+        ButtonViewModel("clearReturnButton",messages("taskList.button.clearReturn"))
+            .withCssClass("govuk-button--secondary")
+            .asLink(routes.ClearReturnAreYouSureQuestionController.onPageLoad().url)
+    )
+
 }
 
diff --git a/app/views/declareDuty/TellUsAboutMultipleSPRRateView.scala.html b/app/views/declareDuty/TellUsAboutMultipleSPRRateView.scala.html
index 5505df1bd..caac0d7b6 100644
--- a/app/views/declareDuty/TellUsAboutMultipleSPRRateView.scala.html
+++ b/app/views/declareDuty/TellUsAboutMultipleSPRRateView.scala.html
@@ -75,7 +75,7 @@
               case Seq(onlyButton) => Text(onlyButton.content.asHtml.toString)
               case _ => Text(messages(s"tellUsAboutMultipleSPRRate.h3.$regime"))
             },
-            classes = Css.fieldsetLegendSCssClass
+            classes = Css.fieldsetLegendMCssClass
           )),
           html = HtmlFormat.fill(List(
             Some(govukInput(
diff --git a/app/views/dutySuspended/DutySuspendedBeerView2.scala.html b/app/views/dutySuspended/DutySuspendedBeerView2.scala.html
deleted file mode 100644
index 0f6edf104..000000000
--- a/app/views/dutySuspended/DutySuspendedBeerView2.scala.html
+++ /dev/null
@@ -1,81 +0,0 @@
-@*
- * 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 components.{Caption, PageHeading, Paragraph, SubHeading}
-
-@this(
-    layout: templates.Layout,
-    formHelper: FormWithCSRF,
-    govukErrorSummary: GovukErrorSummary,
-    govukInput: GovukInput,
-    govukButton: GovukButton,
-    caption: Caption,
-    paragraph: Paragraph,
-    pageHeading: PageHeading,
-    subHeading: SubHeading,
-    govukFieldset: GovukFieldset
-)
-
-@(form: Form[_], mode: Mode)(implicit request: Request[_], messages: Messages)
-
-@layout(pageTitle = title(form, messages("dutySuspendedBeer.title"))) {
-
-    @formHelper(action = controllers.dutySuspended.routes.DutySuspendedBeerController.onSubmit(mode), Symbol("autoComplete") -> "off") {
-
-        @if(form.errors.nonEmpty) {
-            @govukErrorSummary(ErrorSummaryViewModel(form))
-        }
-
-        @caption(
-            id = "duty-suspended-beer-section",
-            text = messages("section.dutySuspended"),
-        )
-
-        @pageHeading(messages("dutySuspendedBeer.heading"))
-
-        @paragraph(messages("dutySuspendedBeer.p1"))
-
-        @govukFieldset(Fieldset(
-          html = HtmlFormat.fill(List(
-            govukInput(
-              InputViewModel(
-                field = form("totalBeer"),
-                label = LabelViewModel(messages("dutySuspendedBeer.subheading1")).asSubheading,
-              )
-              .asNumeric()
-              .withWidth(Fixed10)
-              .withSuffix(PrefixOrSuffix(content = messages("site.unit.litres")))
-              .withHint(Hint(content = HtmlContent(messages("dutySuspendedBeer.hint.1"))))
-            ),
-            govukInput(
-              InputViewModel(
-                field = form("pureAlcoholInBeer"),
-                label = LabelViewModel(messages("dutySuspendedBeer.subheading2")).asSubheading,
-              )
-              .asNumeric()
-              .withWidth(Fixed10)
-              .withSuffix(PrefixOrSuffix(content = messages("site.unit.litres")))
-              .withHint(Hint(content = HtmlContent(messages("dutySuspendedBeer.hint.2"))))
-            )
-          ))
-        ))
-
-        @govukButton(
-            ButtonViewModel("saveAndContinueButton",messages("site.saveAndContinue"))
-        )
-    }
-}
diff --git a/conf/app.routes b/conf/app.routes
index e1359b74e..f0d897ef9 100644
--- a/conf/app.routes
+++ b/conf/app.routes
@@ -34,6 +34,9 @@ GET         /view-payments                               controllers.payments.Vi
 
 GET         /complete-return/task-list                   controllers.TaskListController.onPageLoad
 
+GET         /clear-return                                controllers.ClearReturnAreYouSureQuestionController.onPageLoad()
+POST        /clear-return                                controllers.ClearReturnAreYouSureQuestionController.onSubmit()
+
 GET         /before-you-start-your-return/:periodKey     controllers.BeforeStartReturnController.onPageLoad(periodKey: String)
 POST        /before-you-start-your-return                controllers.BeforeStartReturnController.onSubmit()
 
diff --git a/conf/messages.en b/conf/messages.en
index 48f69503c..009aef735 100644
--- a/conf/messages.en
+++ b/conf/messages.en
@@ -83,6 +83,11 @@ noAppaId.heading = You need an Alcoholic Products Producer approval ID to access
 noAppaId.p = If you were producing alcoholic products before 1 February 2025, you can find your APPA ID on the online service letter you received from HMRC.
 noAppaId.link.text = Read guidance on getting approval to produce alcoholic products (opens in a new tab)
 
+clearReturnAreYouSureQuestion.title = Are you sure you want to clear your return?
+clearReturnAreYouSureQuestion.heading = Are you sure you want to clear your return?
+clearReturnAreYouSureQuestion.warning = This will delete all the information you have entered for this return.
+clearReturnAreYouSureQuestion.error.required = Select yes if you want to clear your return
+
 regime.beer = beer
 regime.cider = cider
 regime.wine = wine
@@ -236,6 +241,7 @@ taskList.section.spirits.hint = Every three months you must tell us about spirit
 taskList.section.checkAndSubmit.heading = Send return
 taskList.section.checkAndSubmit.needToDeclare = Check duty payable and send your return
 taskList.section.checkAndSubmit.hint = You must complete every section before you can send your return
+taskList.button.clearReturn = Clear return and start again
 
 beforeStartReturn.title = Before you start
 beforeStartReturn.heading = Before you start
@@ -916,3 +922,4 @@ returnSubmitted.warningText = Our bank details have changed. Choose Pay now and
 returnSubmitted.warningFallbackText = Warning
 
 # End of Check and submit sub-journey
+
diff --git a/test/controllers/ClearReturnAreYouSureQuestionControllerSpec.scala b/test/controllers/ClearReturnAreYouSureQuestionControllerSpec.scala
new file mode 100644
index 000000000..c1da27303
--- /dev/null
+++ b/test/controllers/ClearReturnAreYouSureQuestionControllerSpec.scala
@@ -0,0 +1,321 @@
+/*
+ * 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
+
+import base.SpecBase
+import connectors.UserAnswersConnector
+import forms.ClearReturnAreYouSureQuestionFormProvider
+import models.AlcoholRegime.Beer
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchersSugar.eqTo
+import play.api.inject.bind
+import play.api.test.Helpers._
+import uk.gov.hmrc.alcoholdutyreturns.models.ReturnAndUserDetails
+import uk.gov.hmrc.http.{HttpResponse, UpstreamErrorResponse}
+import views.html.ClearReturnAreYouSureQuestionView
+
+import scala.concurrent.Future
+
+class ClearReturnAreYouSureQuestionControllerSpec extends SpecBase {
+  "ClearReturnAreYouSureQuestion Controller" - {
+
+    "must return OK and the correct view for a GET" in new SetUp {
+      val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+        .overrides(
+          bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+        )
+        .build()
+
+      running(application) {
+        val request = FakeRequest(GET, clearReturnAreYouSureQuestionRoute)
+
+        val result = route(application, request).value
+
+        val view = application.injector.instanceOf[ClearReturnAreYouSureQuestionView]
+
+        status(result)          mustEqual OK
+        contentAsString(result) mustEqual view(form)(request, getMessages(application)).toString
+
+        verify(mockUserAnswersConnector, never).delete(any(), any())(any())
+        verify(mockUserAnswersConnector, never).createUserAnswers(any())(any())
+      }
+    }
+
+    "must clear down the return, recreate and redirect to the task list page when yes is selected" in new SetUp {
+      val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+        .overrides(
+          bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+        )
+        .build()
+
+      when(mockUserAnswersConnector.delete(any(), any())(any())).thenReturn(
+        Future.successful(
+          HttpResponse(
+            OK,
+            s"User answers deleted for user ${answersBeforeClearance.internalId} on return ${answersBeforeClearance.returnId.appaId}/${answersBeforeClearance.returnId.periodKey}"
+          )
+        )
+      )
+      when(
+        mockUserAnswersConnector.createUserAnswers(
+          eqTo(
+            ReturnAndUserDetails(
+              answersBeforeClearance.returnId,
+              answersBeforeClearance.groupId,
+              answersBeforeClearance.internalId
+            )
+          )
+        )(any())
+      ).thenReturn(Future.successful(Right(emptyUserAnswers)))
+
+      running(application) {
+        val request =
+          FakeRequest(POST, clearReturnAreYouSureQuestionRoute)
+            .withFormUrlEncodedBody(("clearReturnAreYouSureQuestion-yesNoValue", "true"))
+
+        val result = route(application, request).value
+
+        status(result)                 mustEqual SEE_OTHER
+        redirectLocation(result).value mustEqual controllers.routes.TaskListController.onPageLoad.url
+
+        verify(mockUserAnswersConnector, times(1))
+          .delete(eqTo(answersBeforeClearance.returnId.appaId), eqTo(answersBeforeClearance.returnId.periodKey))(any())
+        verify(mockUserAnswersConnector, times(1)).createUserAnswers(
+          eqTo(
+            ReturnAndUserDetails(
+              answersBeforeClearance.returnId,
+              answersBeforeClearance.groupId,
+              answersBeforeClearance.internalId
+            )
+          )
+        )(any())
+      }
+    }
+
+    "must redirect to journey recovery when yes is selected and unable to clear the return" in new SetUp {
+      val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+        .overrides(
+          bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+        )
+        .build()
+
+      when(mockUserAnswersConnector.delete(any(), any())(any()))
+        .thenReturn(Future.successful(HttpResponse(INTERNAL_SERVER_ERROR, "Computer says No!")))
+
+      running(application) {
+        val request =
+          FakeRequest(POST, clearReturnAreYouSureQuestionRoute)
+            .withFormUrlEncodedBody(("clearReturnAreYouSureQuestion-yesNoValue", "true"))
+
+        val result = route(application, request).value
+
+        status(result)                 mustEqual SEE_OTHER
+        redirectLocation(result).value mustEqual controllers.routes.JourneyRecoveryController.onPageLoad().url
+
+        verify(mockUserAnswersConnector, times(1))
+          .delete(eqTo(answersBeforeClearance.returnId.appaId), eqTo(answersBeforeClearance.returnId.periodKey))(any())
+        verify(mockUserAnswersConnector, never).createUserAnswers(any())(any())
+      }
+    }
+
+    "must throw an exception when yes is selected and clearing the return throws an exception" in new SetUp {
+      val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+        .overrides(
+          bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+        )
+        .build()
+
+      when(mockUserAnswersConnector.delete(any(), any())(any()))
+        .thenReturn(Future.failed(new RuntimeException("Failed")))
+
+      running(application) {
+        val request =
+          FakeRequest(POST, clearReturnAreYouSureQuestionRoute)
+            .withFormUrlEncodedBody(("clearReturnAreYouSureQuestion-yesNoValue", "true"))
+
+        intercept[RuntimeException] {
+          await(route(application, request).get)
+        }
+
+        verify(mockUserAnswersConnector, times(1))
+          .delete(eqTo(answersBeforeClearance.returnId.appaId), eqTo(answersBeforeClearance.returnId.periodKey))(any())
+        verify(mockUserAnswersConnector, never).createUserAnswers(any())(any())
+      }
+    }
+
+    "must redirect to journey recovery when yes is selected and unable to recreate the return" in new SetUp {
+      val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+        .overrides(
+          bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+        )
+        .build()
+
+      when(mockUserAnswersConnector.delete(any(), any())(any())).thenReturn(
+        Future.successful(
+          HttpResponse(
+            OK,
+            s"User answers deleted for user ${answersBeforeClearance.internalId} on return ${answersBeforeClearance.returnId.appaId}/${answersBeforeClearance.returnId.periodKey}"
+          )
+        )
+      )
+      when(
+        mockUserAnswersConnector.createUserAnswers(
+          eqTo(
+            ReturnAndUserDetails(
+              answersBeforeClearance.returnId,
+              answersBeforeClearance.groupId,
+              answersBeforeClearance.internalId
+            )
+          )
+        )(any())
+      ).thenReturn(Future.successful(Left(UpstreamErrorResponse("Computer says No!", INTERNAL_SERVER_ERROR))))
+
+      running(application) {
+        val request =
+          FakeRequest(POST, clearReturnAreYouSureQuestionRoute)
+            .withFormUrlEncodedBody(("clearReturnAreYouSureQuestion-yesNoValue", "true"))
+
+        val result = route(application, request).value
+
+        status(result)                 mustEqual SEE_OTHER
+        redirectLocation(result).value mustEqual controllers.routes.JourneyRecoveryController.onPageLoad().url
+
+        verify(mockUserAnswersConnector, times(1))
+          .delete(eqTo(answersBeforeClearance.returnId.appaId), eqTo(answersBeforeClearance.returnId.periodKey))(any())
+        verify(mockUserAnswersConnector, times(1)).createUserAnswers(
+          eqTo(
+            ReturnAndUserDetails(
+              answersBeforeClearance.returnId,
+              answersBeforeClearance.groupId,
+              answersBeforeClearance.internalId
+            )
+          )
+        )(any())
+      }
+    }
+
+    "must throw an exception when yes is selected and recreating the return throws an exception" in new SetUp {
+      val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+        .overrides(
+          bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+        )
+        .build()
+
+      when(mockUserAnswersConnector.delete(any(), any())(any())).thenReturn(
+        Future.successful(
+          HttpResponse(
+            OK,
+            s"User answers deleted for user ${answersBeforeClearance.internalId} on return ${answersBeforeClearance.returnId.appaId}/${answersBeforeClearance.returnId.periodKey}"
+          )
+        )
+      )
+      when(
+        mockUserAnswersConnector.createUserAnswers(
+          eqTo(
+            ReturnAndUserDetails(
+              answersBeforeClearance.returnId,
+              answersBeforeClearance.groupId,
+              answersBeforeClearance.internalId
+            )
+          )
+        )(any())
+      ).thenReturn(Future.failed(new RuntimeException("Failed")))
+
+      running(application) {
+        val request =
+          FakeRequest(POST, clearReturnAreYouSureQuestionRoute)
+            .withFormUrlEncodedBody(("clearReturnAreYouSureQuestion-yesNoValue", "true"))
+
+        intercept[RuntimeException] {
+          await(route(application, request).get)
+        }
+
+        verify(mockUserAnswersConnector, times(1))
+          .delete(eqTo(answersBeforeClearance.returnId.appaId), eqTo(answersBeforeClearance.returnId.periodKey))(any())
+        verify(mockUserAnswersConnector, times(1)).createUserAnswers(
+          eqTo(
+            ReturnAndUserDetails(
+              answersBeforeClearance.returnId,
+              answersBeforeClearance.groupId,
+              answersBeforeClearance.internalId
+            )
+          )
+        )(any())
+      }
+    }
+
+    s"must redirect to the task list page when no is selected" in new SetUp {
+      val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+        .overrides(
+          bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+        )
+        .build()
+
+      running(application) {
+        val request =
+          FakeRequest(POST, clearReturnAreYouSureQuestionRoute)
+            .withFormUrlEncodedBody(("clearReturnAreYouSureQuestion-yesNoValue", "false"))
+
+        val result = route(application, request).value
+
+        status(result)                 mustEqual SEE_OTHER
+        redirectLocation(result).value mustEqual controllers.routes.TaskListController.onPageLoad.url
+
+        verify(mockUserAnswersConnector, never).delete(any(), any())(any())
+        verify(mockUserAnswersConnector, never).createUserAnswers(any())(any())
+      }
+    }
+  }
+
+  "must return a Bad Request and errors when no data is submitted" in new SetUp {
+    val application = applicationBuilder(userAnswers = Some(answersBeforeClearance))
+      .overrides(
+        bind[UserAnswersConnector].toInstance(mockUserAnswersConnector)
+      )
+      .build()
+
+    running(application) {
+      val request =
+        FakeRequest(POST, clearReturnAreYouSureQuestionRoute)
+          .withFormUrlEncodedBody(("value", ""))
+
+      val boundForm = form.bind(Map("value" -> ""))
+
+      val view = application.injector.instanceOf[ClearReturnAreYouSureQuestionView]
+
+      val result = route(application, request).value
+
+      status(result)          mustEqual BAD_REQUEST
+      contentAsString(result) mustEqual view(boundForm)(request, getMessages(application)).toString
+
+      verify(mockUserAnswersConnector, never).delete(any(), any())(any())
+      verify(mockUserAnswersConnector, never).createUserAnswers(any())(any())
+    }
+  }
+
+  class SetUp {
+    val formProvider = new ClearReturnAreYouSureQuestionFormProvider()
+    val form         = formProvider()
+
+    val clearReturnAreYouSureQuestionRoute = controllers.routes.ClearReturnAreYouSureQuestionController.onPageLoad().url
+
+    val answersBeforeClearance =
+      specifyTellUsAboutAllSingleSPRRate(whatDoYouNeedToDeclarePage(userAnswersWithBeer, Beer, allRateBands), Beer)
+
+    val mockUserAnswersConnector = mock[UserAnswersConnector]
+  }
+}


Reviews:
user: login: davidfes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T14:39:55Z
user: login: ajchilts
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T15:08:24Z
user: login: matthew-goh
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T09:39:22Z
user: login: matthew-goh
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T09:39:41Z
user: login: ajchilts
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T10:33:42Z
user: login: matthew-goh
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T10:39:30Z
user: login: ajchilts
body: LGTM 👍 
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T10:40:53Z
user: login: ajchilts
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T16:41:08Z

Review comments:
diff_hunk: @@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 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
+
+import connectors.UserAnswersConnector
+import controllers.actions._
+import forms.ClearReturnAreYouSureQuestionFormProvider
+import models.ReturnId
+import models.requests.DataRequest
+import play.api.Logging
+import play.api.i18n.{I18nSupport, MessagesApi}
+import play.api.mvc.{Action, AnyContent, MessagesControllerComponents, Result}
+import uk.gov.hmrc.alcoholdutyreturns.models.ReturnAndUserDetails
+import uk.gov.hmrc.play.bootstrap.frontend.controller.FrontendBaseController
+import views.html.ClearReturnAreYouSureQuestionView
+
+import javax.inject.Inject
+import scala.concurrent.{ExecutionContext, Future}
+import scala.util.{Failure, Success}
+
+class ClearReturnAreYouSureQuestionController @Inject() (
+  override val messagesApi: MessagesApi,
+  userAnswersConnector: UserAnswersConnector,
+  identify: IdentifyWithEnrolmentAction,
+  getData: DataRetrievalAction,
+  requireData: DataRequiredAction,
+  formProvider: ClearReturnAreYouSureQuestionFormProvider,
+  val controllerComponents: MessagesControllerComponents,
+  view: ClearReturnAreYouSureQuestionView
+)(implicit ec: ExecutionContext)
+    extends FrontendBaseController
+    with I18nSupport
+    with Logging {
+
+  val form = formProvider()
+
+  def onPageLoad(): Action[AnyContent] = (identify andThen getData andThen requireData) { implicit request =>
+    Ok(view(form))
+  }
+
+  def onSubmit(): Action[AnyContent] = (identify andThen getData andThen requireData).async { implicit request =>
+    form
+      .bindFromRequest()
+      .fold(
+        formWithErrors => Future.successful(BadRequest(view(formWithErrors))),
+        value => handleAnswer(value, request.appaId, request.returnPeriod.toPeriodKey)
+      )
+  }
+
+  private def handleAnswer(shouldClear: Boolean, appaId: String, periodKey: String)(implicit
path: app/controllers/ClearReturnAreYouSureQuestionController.scala
user: login: ajchilts
body: consider renaming to 'clear' or 'clearUserAnswers' ? 
created_at: 2025-03-14T14:21:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+/*
+ * 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
+
+import forms.mappings.Mappings
+import play.api.data.Form
+
+import javax.inject.Inject
+
+class ClearReturnAreYouSureQuestionFormProvider @Inject() extends Mappings {
+
+  def apply(): Form[Boolean] =
+    Form(
+      "clearReturnAreYouSureQuestion-yesNoValue" -> boolean("clearReturnAreYouSureQuestion.error.required")
path: app/forms/ClearReturnAreYouSureQuestionFormProvider.scala
user: login: ajchilts
body: Have we requested the Welsh for this? 
created_at: 2025-03-14T14:23:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -83,6 +83,11 @@ noAppaId.heading = You need an Alcoholic Products Producer approval ID to access
 noAppaId.p = If you were producing alcoholic products before 1 February 2025, you can find your APPA ID on the online service letter you received from HMRC.
 noAppaId.link.text = Read guidance on getting approval to produce alcoholic products (opens in a new tab)
 
+clearReturnAreYouSureQuestion.title = Are you sure you want to clear your return?
+clearReturnAreYouSureQuestion.heading = Are you sure you want to clear your return?
+clearReturnAreYouSureQuestion.warning = This will delete all the information you have entered for this return.
+clearReturnAreYouSureQuestion.error.required = Select yes if you want to clear your return
+
path: conf/messages.en
user: login: ajchilts
body: Welsh requested? 
created_at: 2025-03-14T14:24:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,81 +0,0 @@
-@*
path: app/views/dutySuspended/DutySuspendedBeerView2.scala.html
user: login: davidfes
body: Not sure how this copy got checked in, but can remove.
created_at: 2025-03-14T14:39:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 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
+
+import connectors.UserAnswersConnector
+import controllers.actions._
+import forms.ClearReturnAreYouSureQuestionFormProvider
+import models.ReturnId
+import models.requests.DataRequest
+import play.api.Logging
+import play.api.i18n.{I18nSupport, MessagesApi}
+import play.api.mvc.{Action, AnyContent, MessagesControllerComponents, Result}
+import uk.gov.hmrc.alcoholdutyreturns.models.ReturnAndUserDetails
+import uk.gov.hmrc.play.bootstrap.frontend.controller.FrontendBaseController
+import views.html.ClearReturnAreYouSureQuestionView
+
+import javax.inject.Inject
+import scala.concurrent.{ExecutionContext, Future}
+import scala.util.{Failure, Success}
+
+class ClearReturnAreYouSureQuestionController @Inject() (
+  override val messagesApi: MessagesApi,
+  userAnswersConnector: UserAnswersConnector,
+  identify: IdentifyWithEnrolmentAction,
+  getData: DataRetrievalAction,
+  requireData: DataRequiredAction,
+  formProvider: ClearReturnAreYouSureQuestionFormProvider,
+  val controllerComponents: MessagesControllerComponents,
+  view: ClearReturnAreYouSureQuestionView
+)(implicit ec: ExecutionContext)
+    extends FrontendBaseController
+    with I18nSupport
+    with Logging {
+
+  val form = formProvider()
+
+  def onPageLoad(): Action[AnyContent] = (identify andThen getData andThen requireData) { implicit request =>
+    Ok(view(form))
+  }
+
+  def onSubmit(): Action[AnyContent] = (identify andThen getData andThen requireData).async { implicit request =>
+    form
+      .bindFromRequest()
+      .fold(
+        formWithErrors => Future.successful(BadRequest(view(formWithErrors))),
+        value => handleAnswer(value, request.appaId, request.returnPeriod.toPeriodKey)
+      )
+  }
+
+  private def handleAnswer(shouldClear: Boolean, appaId: String, periodKey: String)(implicit
path: app/controllers/ClearReturnAreYouSureQuestionController.scala
user: login: matthew-goh
body: Renamed it to clearUserAnswers :)
created_at: 2025-03-17T09:39:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,81 +0,0 @@
-@*
path: app/views/dutySuspended/DutySuspendedBeerView2.scala.html
user: login: matthew-goh
body: Looks like the file is already being removed in this PR
created_at: 2025-03-17T09:39:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,11 +57,11 @@ class ClearReturnAreYouSureQuestionController @Inject() (
       .bindFromRequest()
       .fold(
         formWithErrors => Future.successful(BadRequest(view(formWithErrors))),
-        value => handleAnswer(value, request.appaId, request.returnPeriod.toPeriodKey)
+        value => clearUserAnswers(value, request.appaId, request.returnPeriod.toPeriodKey)
       )
   }
 
-  private def handleAnswer(shouldClear: Boolean, appaId: String, periodKey: String)(implicit
+  private def clearUserAnswers(shouldClear: Boolean, appaId: String, periodKey: String)(implicit
path: app/controllers/ClearReturnAreYouSureQuestionController.scala
user: login: ajchilts
body: @matthew-goh  - Sorry. I meant change 'shouldClear' to 'clearUserAnswers'. The method name was OK. 
created_at: 2025-03-17T10:33:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,11 +57,11 @@ class ClearReturnAreYouSureQuestionController @Inject() (
       .bindFromRequest()
       .fold(
         formWithErrors => Future.successful(BadRequest(view(formWithErrors))),
-        value => handleAnswer(value, request.appaId, request.returnPeriod.toPeriodKey)
+        value => clearUserAnswers(value, request.appaId, request.returnPeriod.toPeriodKey)
       )
   }
 
-  private def handleAnswer(shouldClear: Boolean, appaId: String, periodKey: String)(implicit
+  private def clearUserAnswers(shouldClear: Boolean, appaId: String, periodKey: String)(implicit
path: app/controllers/ClearReturnAreYouSureQuestionController.scala
user: login: matthew-goh
body: Sorry, that's now been changed!
created_at: 2025-03-17T10:39:30Z
author_association: CONTRIBUTOR

PR comments:
user: login: platops-pr-bot
created_at: 2025-03-14T13:26:24Z
body: - `uk.gov.hmrc.sbt-distributables` can be updated to `2.6.0` in [project/plugins.sbt](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/plugins.sbt#L9)
- `uk.gov.hmrc:bootstrap-frontend-play-30` can be updated to `9.11.0` in [project/AppDependencies.scala](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/AppDependencies.scala#L1).
- `uk.gov.hmrc:play-frontend-hmrc-play-30` can be updated to `11.12.0` in [project/AppDependencies.scala](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/AppDependencies.scala#L1).
- `uk.gov.hmrc:bootstrap-test-play-30` can be updated to `9.11.0` in [project/AppDependencies.scala](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/AppDependencies.scala#L1).
- Your service can now use Java 21. Please set `JavaType.OPENJDK_JRE21` in [build-jobs](https://github.com/hmrc/build-jobs/blob/HEAD/jobs/live/alcoholDuty.groovy#L18) - See confluence https://confluence.tools.tax.service.gov.uk/x/xIACM
- There is a bobby warning (builds will be prevented after 30 Jun 2025) - see the pr builder for details
author_association: NONE
user: login: platops-pr-bot
created_at: 2025-03-14T13:39:32Z
body: - ~~`uk.gov.hmrc.sbt-distributables` can be updated to `2.6.0` in [project/plugins.sbt](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/plugins.sbt#L9)~~
- ~~`uk.gov.hmrc:bootstrap-frontend-play-30` can be updated to `9.11.0` in [project/AppDependencies.scala](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/AppDependencies.scala#L1).~~
- ~~`uk.gov.hmrc:play-frontend-hmrc-play-30` can be updated to `11.12.0` in [project/AppDependencies.scala](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/AppDependencies.scala#L1).~~
- ~~`uk.gov.hmrc:bootstrap-test-play-30` can be updated to `9.11.0` in [project/AppDependencies.scala](https://github.com/hmrc/alcohol-duty-returns-frontend/blob/ADR-1528/project/AppDependencies.scala#L1).~~
- Your service can now use Java 21. Please set `JavaType.OPENJDK_JRE21` in [build-jobs](https://github.com/hmrc/build-jobs/blob/HEAD/jobs/live/alcoholDuty.groovy#L18) - See confluence https://confluence.tools.tax.service.gov.uk/x/xIACM
- There is a bobby warning (builds will be prevented after 30 Jun 2025) - see the pr builder for details
author_association: NONE