diff --git a/app/controllers/IncomeSourceSummaryController.scala b/app/controllers/IncomeSourceSummaryController.scala index 13776f6a0..a07cd9554 100644 --- a/app/controllers/IncomeSourceSummaryController.scala +++ b/app/controllers/IncomeSourceSummaryController.scala @@ -19,15 +19,15 @@ package controllers import cats.implicits.* import controllers.auth.AuthJourney import pages.benefits.EndCompanyBenefitsUpdateIncomePage -import play.api.mvc.{Action, AnyContent, MessagesControllerComponents, Result} +import play.api.mvc.{Action, AnyContent, MessagesControllerComponents} import uk.gov.hmrc.http.UpstreamErrorResponse import uk.gov.hmrc.play.audit.http.connector.AuditConnector import uk.gov.hmrc.tai.model.TaxYear +import uk.gov.hmrc.tai.model.domain.{Available, Employment, IabdDetails, TemporarilyUnavailable} import uk.gov.hmrc.tai.service.{EmploymentService, IabdService, RtiService, TaxAccountService} import uk.gov.hmrc.tai.util.{EmpIdCheck, TaxAccountHelper} import uk.gov.hmrc.tai.viewModels.IncomeSourceSummaryViewModel import views.html.IncomeSourceSummaryView -import uk.gov.hmrc.tai.model.domain.{Available, Employment, IabdDetails} import javax.inject.Inject import scala.concurrent.{ExecutionContext, Future} @@ -62,6 +62,7 @@ class IncomeSourceSummaryController @Inject() ( taxAccountService.taxCodeIncomes(nino, TaxYear()), taxAccountService.taxAccountSummary(nino, TaxYear()).value, rtiService.getPaymentsForEmploymentAndYear(nino, TaxYear(), empId).value, + rtiService.getAllPaymentsForYear(nino, TaxYear()).value, cacheUpdatedIncomeAmountFuture, iabdService.getIabds(nino, TaxYear()).value ).mapN { @@ -69,7 +70,8 @@ class IncomeSourceSummaryController @Inject() ( Some(employment), taxCodeIncomes, taxAccountSummary, - payments, + paymentsForEmp, + paymentsForYear, cacheUpdatedIncomeAmount, Right(iabds) ) => @@ -77,18 +79,19 @@ class IncomeSourceSummaryController @Inject() ( val estimatedPayOverrides = TaxAccountHelper.getIabdLatestEstimatedIncome(iabds, TaxAccountSummaryDate, Some(empId)) + val rtiUnavailableMarkerPresent: Boolean = + paymentsForYear.exists(_.exists(a => a.sequenceNumber == 0 && a.realTimeStatus == TemporarilyUnavailable)) + + val rtiAvailableCalculated: Boolean = paymentsForEmp.exists(_.exists(_.realTimeStatus == Available)) + val vm = IncomeSourceSummaryViewModel.apply( empId = empId, displayName = request.fullName, optTaxCodeIncome = taxCodeIncomes.fold(_ => None, _.find(_.employmentId.contains(employment.sequenceNumber))), employment = employment, - payments = payments.toOption.flatten, - // TODO: handle a failure vs no payment present - // The way the rti availability is implemented using a stub Annual account is not compatible with None type - // So when no annual account found for an employment, assuming rti is down. - // The service also does not handle the case when there is no payments but assume the rti api not been available. - rtiAvailable = payments.fold(_ => false, _.fold(false)(_.realTimeStatus == Available)), + payments = paymentsForEmp.toOption.flatten, + rtiAvailable = if (rtiUnavailableMarkerPresent) false else rtiAvailableCalculated, cacheUpdatedIncomeAmount = cacheUpdatedIncomeAmount, estimatedPayOverrides = estimatedPayOverrides ) diff --git a/app/controllers/IncomeTaxComparisonController.scala b/app/controllers/IncomeTaxComparisonController.scala index e87773034..5db41bbdb 100644 --- a/app/controllers/IncomeTaxComparisonController.scala +++ b/app/controllers/IncomeTaxComparisonController.scala @@ -100,7 +100,7 @@ class IncomeTaxComparisonController @Inject() ( val cyCodingComponents = CodingComponentForYear(currentTaxYear, codingComponentsCY) val cyPlusOneTaxComponents = CodingComponentForYear(nextTaxYear, codingComponentsCYPlusOne) val cyTaxSummary = TaxAccountSummaryForYear(currentTaxYear, taxAccountSummaryCY) - val cyPlusOneTaxSummary = TaxAccountSummaryForYear(currentTaxYear, taxAccountSummaryCYPlusOne) + val cyPlusOneTaxSummary = TaxAccountSummaryForYear(nextTaxYear, taxAccountSummaryCYPlusOne) TaxFreeAmountComparisonViewModel( Seq(cyCodingComponents, cyPlusOneTaxComponents), diff --git a/app/controllers/WhatDoYouWantToDoController.scala b/app/controllers/WhatDoYouWantToDoController.scala index 4130a9807..8aa80c26a 100644 --- a/app/controllers/WhatDoYouWantToDoController.scala +++ b/app/controllers/WhatDoYouWantToDoController.scala @@ -59,7 +59,6 @@ class WhatDoYouWantToDoController @Inject() ( nino: Nino )(implicit hc: HeaderCarrier): EitherT[Future, UpstreamErrorResponse, Boolean] = { val taxYears = - // start from the current year which is the most probable year to be present (TaxYear().year to (TaxYear().year - applicationConfig.numberOfPreviousYearsToShowIncomeTaxHistory) by -1) .map(TaxYear(_)) .toList @@ -67,7 +66,6 @@ class WhatDoYouWantToDoController @Inject() ( taxYears.foldLeft(EitherT.rightT[Future, UpstreamErrorResponse](false)) { (acc, year) => EitherT(acc.value.flatMap { case Right(true) => - // Short-circuit if we've already found an employment Future.successful(Right[UpstreamErrorResponse, Boolean](true)) case _ => employmentService @@ -122,7 +120,7 @@ class WhatDoYouWantToDoController @Inject() ( Right(None) case Left(_) => // don't fail the page when we get an error for CY+1 - Right(none) + Right(None) } } else { EitherT.rightT[Future, UpstreamErrorResponse](None: Option[TaxAccountSummary]) diff --git a/test/controllers/IncomeSourceSummaryControllerSpec.scala b/test/controllers/IncomeSourceSummaryControllerSpec.scala index 26f9a6630..937be38bd 100644 --- a/test/controllers/IncomeSourceSummaryControllerSpec.scala +++ b/test/controllers/IncomeSourceSummaryControllerSpec.scala @@ -20,18 +20,18 @@ import builders.RequestBuilder import cats.data.EitherT import org.jsoup.Jsoup import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito import org.mockito.Mockito.{times, verify, when} import org.mockito.stubbing.OngoingStubbing -import org.mockito.Mockito import org.scalatest.AppendedClues.convertToClueful import pages.benefits.EndCompanyBenefitsUpdateIncomePage import play.api.i18n.Messages import play.api.mvc.Results.NotFound -import play.api.test.Helpers._ +import play.api.test.Helpers.* import uk.gov.hmrc.http.UpstreamErrorResponse import uk.gov.hmrc.play.audit.http.connector.AuditConnector import uk.gov.hmrc.tai.model.UserAnswers -import uk.gov.hmrc.tai.model.domain._ +import uk.gov.hmrc.tai.model.domain.* import uk.gov.hmrc.tai.model.domain.income.{Live, OtherBasisOfOperation, TaxCodeIncome, Week1Month1BasisOfOperation} import uk.gov.hmrc.tai.service.{EmploymentService, IabdService, RtiService, TaxAccountService} import uk.gov.hmrc.tai.util.TaxYearRangeUtil @@ -109,6 +109,9 @@ class IncomeSourceSummaryControllerSpec extends BaseSpec { when(mockIabdService.getIabds(any(), any())(any())) .thenReturn(EitherT.rightT[Future, UpstreamErrorResponse](Seq.empty[IabdDetails])) + + when(mockRtiService.getAllPaymentsForYear(any(), any())(any())) + .thenReturn(EitherT.rightT[Future, UpstreamErrorResponse](Seq.empty[AnnualAccount])) } private val employmentId = 1 @@ -308,6 +311,31 @@ class IncomeSourceSummaryControllerSpec extends BaseSpec { verify(mockEmploymentService, times(1)).employment(any(), any(), any())(any()) } + "asked for pension details and NOT include RTI section where yearly RTI unavailable marker is present" in { + setUpPension(Right(Some(annualAccount))) + + val unavailableMarker = annualAccount.copy( + sequenceNumber = 0, + realTimeStatus = TemporarilyUnavailable + ) + + when(mockRtiService.getAllPaymentsForYear(any(), any())(any())) + .thenReturn(EitherT.rightT[Future, UpstreamErrorResponse](Seq(unavailableMarker))) + + val result = sut.onPageLoad(pensionId)(RequestBuilder.buildFakeRequestWithAuth("GET")) + + status(result) mustBe OK + + val doc = Jsoup.parse(contentAsString(result)) + + Option(doc.getElementById("incomeReceivedToDate")) + .map(_.text()) mustBe Some( + "Your income received to date is unavailable. Try again later" + ) withClue "html id incomeReceivedToDate" + + Option(doc.getElementById("updatePension")).isDefined mustBe false withClue "html id updatePension" + } + "failed to read tax code incomes" in { when(mockTaxAccountService.taxCodeIncomes(any(), any())(any())) .thenReturn(Future.successful(Left("Failed")))