From 89bb433ba82df8c7abf583fd4e319e74dde2db7e Mon Sep 17 00:00:00 2001
From: PavelVjalicin <pavelvjalicin@users.noreply.github.com>
Date: Tue, 30 Jul 2024 10:05:34 +0100
Subject: [PATCH 1/3] PODS-9128: Exception handling

---
 app/controllers/address/ChooseAddressController.scala |  2 +-
 .../fileUpload/FileUploadResultController.scala       | 11 ++++++-----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/app/controllers/address/ChooseAddressController.scala b/app/controllers/address/ChooseAddressController.scala
index 2d251a9de..f5ecc3b80 100644
--- a/app/controllers/address/ChooseAddressController.scala
+++ b/app/controllers/address/ChooseAddressController.scala
@@ -53,7 +53,7 @@ class ChooseAddressController @Inject()(val controllerComponents: MessagesContro
             addresses,
             index
           ))
-        case _ => Redirect(controllers.routes.JourneyRecoveryController.onPageLoad(None).url)
+        case _ => throw new RuntimeException("User answers not available")
       }
     }
 
diff --git a/app/controllers/fileUpload/FileUploadResultController.scala b/app/controllers/fileUpload/FileUploadResultController.scala
index 53c4b169b..23cd6066e 100644
--- a/app/controllers/fileUpload/FileUploadResultController.scala
+++ b/app/controllers/fileUpload/FileUploadResultController.scala
@@ -112,14 +112,15 @@ class FileUploadResultController @Inject()(val controllerComponents: MessagesCon
           val originalUserAnswers = request.userAnswers.fold(UserAnswers())(identity)
           val updatedAnswers = originalUserAnswers.setOrException(FileUploadResultPage(eventType), value)
           val redirectResultPage: Result = Redirect(FileUploadResultPage(eventType).navigate(waypoints, originalUserAnswers, updatedAnswers).route)
-          userAnswersCacheConnector.save(request.pstr, eventType, updatedAnswers).map { _ =>
+          userAnswersCacheConnector.save(request.pstr, eventType, updatedAnswers).flatMap { _ =>
             if (value == FileUploadResult.Yes) {
               parsingAndValidationOutcomeCacheConnector
                 .deleteOutcome
                 .flatMap(_ => asyncGetUpscanFileAndParse(eventType))
-              redirectResultPage
+                .map(_ => redirectResultPage)
+
             } else {
-              redirectResultPage
+              Future.successful(redirectResultPage)
             }
           }
         }
@@ -213,8 +214,8 @@ class FileUploadResultController @Inject()(val controllerComponents: MessagesCon
                 sendUpscanFileDownloadAuditEvent(eventType, httpResponse.status, startTime, fileUploadOutcomeResponse)
                 httpResponse.status match {
                   case OK => performValidation(eventType, httpResponse.bodyAsSource, fileName) recoverWith {
-                    case e: Throwable =>
-                      setGeneralErrorOutcome("Unable to download file", fileName, Some(e))
+                    case e =>
+                      throw new RuntimeException("Unable to download file", e) //TODO: Might need to handle this in error handler.
                   }
                   case e =>
                     setGeneralErrorOutcome(s"Upscan download error response code $e", fileName)

From 3c3c5ccdd24f8c09d8214acbd0fec722953873c2 Mon Sep 17 00:00:00 2001
From: PavelVjalicin <pavelvjalicin@users.noreply.github.com>
Date: Mon, 5 Aug 2024 20:04:38 +0100
Subject: [PATCH 2/3] PODS-9128

---
 app/handlers/ErrorHandler.scala     | 12 +++++++---
 app/views/UserLockedView.scala.html | 37 +++++++++++++++++++++++++++++
 conf/messages.en                    |  2 ++
 3 files changed, 48 insertions(+), 3 deletions(-)
 create mode 100644 app/views/UserLockedView.scala.html

diff --git a/app/handlers/ErrorHandler.scala b/app/handlers/ErrorHandler.scala
index af066ecfe..665b53adb 100644
--- a/app/handlers/ErrorHandler.scala
+++ b/app/handlers/ErrorHandler.scala
@@ -17,12 +17,14 @@
 package handlers
 
 import config.FrontendAppConfig
+import play.api.Logging
 import play.api.i18n.{I18nSupport, MessagesApi}
 import play.api.mvc.Results.{Ok, Redirect}
-import play.api.mvc.{Request, RequestHeader, Result}
+import play.api.mvc.{Request, RequestHeader, Result, Results}
 import play.twirl.api.Html
+import uk.gov.hmrc.http.HttpException
 import uk.gov.hmrc.play.bootstrap.frontend.http.FrontendErrorHandler
-import views.html.{ErrorTemplate, NoDataEnteredErrorView, PageNotFoundErrorView}
+import views.html.{ErrorTemplate, NoDataEnteredErrorView, PageNotFoundErrorView, UserLockedView}
 
 import javax.inject.{Inject, Singleton}
 import scala.concurrent.Future
@@ -33,8 +35,9 @@ class ErrorHandler @Inject()(
                               view: ErrorTemplate,
                               noDataEnteredView: NoDataEnteredErrorView,
                               pageNotFoundView: PageNotFoundErrorView,
+                              userLockedView: UserLockedView,
                               config: FrontendAppConfig
-                            ) extends FrontendErrorHandler with I18nSupport {
+                            ) extends FrontendErrorHandler with I18nSupport with Logging {
 
   override def standardErrorTemplate(pageTitle: String, heading: String, message: String)(implicit rh: Request[_]): Html =
     view(pageTitle, heading, message)
@@ -44,6 +47,9 @@ class ErrorHandler @Inject()(
 
   override def onServerError(request: RequestHeader, exception: Throwable): Future[Result] = {
     exception match {
+      case e: HttpException if e.message.contains("EVENT_LOCKED") =>
+        logger.warn("User is locked on " + request.uri)
+        Future.successful(new Results.Status(e.responseCode)(userLockedView(config.contactHmrcURL)(Request(request, ""), request2Messages(request))))
       case _ : TaxYearNotAvailableException =>
         Future.successful(Redirect(config.yourPensionSchemesUrl))
       case _: NothingToSubmitException =>
diff --git a/app/views/UserLockedView.scala.html b/app/views/UserLockedView.scala.html
new file mode 100644
index 000000000..6d90fcd81
--- /dev/null
+++ b/app/views/UserLockedView.scala.html
@@ -0,0 +1,37 @@
+@*
+ * 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.
+ *@
+
+@this(
+    layout: templates.Layout
+)
+
+@(contactHmrcUrl: String)(implicit request: Request[_], messages: Messages)
+
+@layout(
+    pageTitle    = titleNoForm(messages("userLocked.text")),
+    showBackLink = false
+) {
+
+    <h1 class="govuk-heading-xl">@messages("userLocked.text")</h1>
+    <p class="govuk-body">        
+        @messages("pageNotFound404.p3")
+        <a href="@contactHmrcUrl" class="govuk-link">
+            @messages("pageNotFound404.p4")
+        </a>
+    </p>
+
+}
+
diff --git a/conf/messages.en b/conf/messages.en
index 384141bcc..dd52a8639 100644
--- a/conf/messages.en
+++ b/conf/messages.en
@@ -1850,6 +1850,8 @@ pageNotFound404.p2 = If you pasted the web address, check you copied the entire
 pageNotFound404.p3 = If the web address is correct or you selected a link or button,
 pageNotFound404.p4 = contact HMRC.
 
+userLocked.text = Event is locked by a user
+
 cannotResume.title = This event report cannot be submitted
 cannotResume.heading = This event report cannot be submitted
 cannotResume.p1 = You have attempted to amend or create an event report but no changes have been made.

From 3dd6c6e51de3bf75279baba1ae7c1635081bbc9c Mon Sep 17 00:00:00 2001
From: PavelVjalicin <pavelvjalicin@users.noreply.github.com>
Date: Tue, 6 Aug 2024 12:44:24 +0100
Subject: [PATCH 3/3] PODS-9128: fixed tests

---
 .../fileUpload/FileUploadResultControllerSpec.scala      | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/test/controllers/fileUpload/FileUploadResultControllerSpec.scala b/test/controllers/fileUpload/FileUploadResultControllerSpec.scala
index e20593ab2..6261a412f 100644
--- a/test/controllers/fileUpload/FileUploadResultControllerSpec.scala
+++ b/test/controllers/fileUpload/FileUploadResultControllerSpec.scala
@@ -17,7 +17,7 @@
 package controllers.fileUpload
 
 import base.SpecBase
-import connectors.{EventReportingConnector, UserAnswersCacheConnector}
+import connectors.{EventReportingConnector, ParsingAndValidationOutcomeCacheConnector, UserAnswersCacheConnector}
 import forms.fileUpload.FileUploadResultFormProvider
 import models.FileUploadOutcomeResponse
 import models.FileUploadOutcomeStatus.{FAILURE, IN_PROGRESS, SUCCESS}
@@ -51,10 +51,12 @@ class FileUploadResultControllerSpec extends SpecBase with BeforeAndAfterEach {
 
   private val mockUserAnswersCacheConnector = mock[UserAnswersCacheConnector]
   private val mockERConnector = mock[EventReportingConnector]
+  private val mockParsingAndValidationOutcomeCacheConnector = mock[ParsingAndValidationOutcomeCacheConnector]
 
   private val extraModules: Seq[GuiceableModule] = Seq[GuiceableModule](
     bind[UserAnswersCacheConnector].toInstance(mockUserAnswersCacheConnector),
-    bind[EventReportingConnector].toInstance(mockERConnector)
+    bind[EventReportingConnector].toInstance(mockERConnector),
+    bind[ParsingAndValidationOutcomeCacheConnector].toInstance(mockParsingAndValidationOutcomeCacheConnector)
   )
 
   private def getRoute(eventType: EventType): String = routes.FileUploadResultController.onPageLoad(waypoints, eventType).url
@@ -63,8 +65,11 @@ class FileUploadResultControllerSpec extends SpecBase with BeforeAndAfterEach {
 
   override def beforeEach(): Unit = {
     super.beforeEach()
+    reset(mockParsingAndValidationOutcomeCacheConnector)
     reset(mockUserAnswersCacheConnector)
     reset(mockERConnector)
+    when(mockParsingAndValidationOutcomeCacheConnector.deleteOutcome(any(), any())).thenReturn(Future.successful())
+    when(mockParsingAndValidationOutcomeCacheConnector.setOutcome(any())(any(), any())).thenReturn(Future.successful())
   }
 
   "FileUploadResult Controller" - {