Skip to content

Commit

Permalink
Merge pull request #43 from hmrc/SASS-7724
Browse files Browse the repository at this point in the history
SASS-7724:  Add delete capability for the state pension journey
  • Loading branch information
vivekhmrc authored Apr 23, 2024
2 parents 2dd2ca5 + 961af96 commit 240fc3d
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 174 deletions.
32 changes: 19 additions & 13 deletions app/controllers/ClaimDataController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ import java.util.UUID
import javax.inject.Inject
import scala.concurrent.{ExecutionContext, Future}

class ClaimDataController @Inject()(authorisedAction: AuthorisedAction,
stateBenefitsService: StateBenefitsService,
cc: ControllerComponents)
(implicit ec: ExecutionContext) extends BackendController(cc) with Logging {
class ClaimDataController @Inject() (authorisedAction: AuthorisedAction, stateBenefitsService: StateBenefitsService, cc: ControllerComponents)(
implicit ec: ExecutionContext)
extends BackendController(cc)
with Logging {

private val invalidRequestLogMessage = "[ClaimDataController][saveUserData] Save state benefits request is invalid"

Expand All @@ -49,36 +49,42 @@ class ClaimDataController @Inject()(authorisedAction: AuthorisedAction,
def remove(nino: String, sessionDataId: UUID): Action[AnyContent] = authorisedAction.async { implicit request =>
stateBenefitsService.removeClaim(nino, sessionDataId).map {
case Left(DataNotFoundError) => NotFound
case Left(_) => InternalServerError
case Right(_) => NoContent
case Left(_) => InternalServerError
case Right(_) => NoContent
}
}

def removeClaim(nino: String, taxYear: Int, benefitId: UUID): Action[AnyContent] = authorisedAction.async { implicit request =>
stateBenefitsService.removeClaimById(nino, taxYear, request.user.mtditid, benefitId).map {
case Left(DataNotFoundError) => NotFound
case Left(_) => InternalServerError
case Right(_) => NoContent
}
}

def restore(nino: String, sessionDataId: UUID): Action[AnyContent] = authorisedAction.async { implicit request =>
stateBenefitsService.restoreClaim(nino, sessionDataId).map {
case Left(_) => InternalServerError
case Left(_) => InternalServerError
case Right(_) => NoContent
}
}

private def handleSaveUserData(nino: String, sessionDataId: Option[UUID], userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): Future[Result] = {
private def handleSaveUserData(nino: String, sessionDataId: Option[UUID], userData: StateBenefitsUserData)(implicit
hc: HeaderCarrier): Future[Result] =
if (userData.nino != nino || !userData.sessionDataId.equals(sessionDataId)) {
logger.warn(invalidRequestLogMessage)
Future.successful(BadRequest)
} else {
stateBenefitsService.saveClaim(userData, sessionDataId.nonEmpty).map {
case Left(_) => InternalServerError
case Left(_) => InternalServerError
case Right(_) => NoContent
}
}
}
private def performSave(nino: String, sessionDataId: Option[UUID], authRequest: AuthorisationRequest[AnyContent])(implicit hc:HeaderCarrier) = {
private def performSave(nino: String, sessionDataId: Option[UUID], authRequest: AuthorisationRequest[AnyContent])(implicit hc: HeaderCarrier) =
authRequest.request.body.asJson.map(_.validate[StateBenefitsUserData]) match {
case Some(data: JsSuccess[StateBenefitsUserData]) => handleSaveUserData(nino, sessionDataId, data.value)
case _ =>
logger.warn(invalidRequestLogMessage)
Future.successful(BadRequest)
}
}
}
78 changes: 38 additions & 40 deletions app/services/IntegrationFrameworkService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package services

import cats.data.EitherT
import cats.implicits.toBifunctorOps
import connectors.IntegrationFrameworkConnector
import models.api.{AddStateBenefit, AllStateBenefitsData, StateBenefitDetailOverride, UpdateStateBenefit}
import models.errors.ApiServiceError
Expand All @@ -28,28 +29,23 @@ import javax.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}

@Singleton
class IntegrationFrameworkService @Inject()(connector: IntegrationFrameworkConnector)
(implicit ec: ExecutionContext) {
class IntegrationFrameworkService @Inject() (connector: IntegrationFrameworkConnector)(implicit ec: ExecutionContext) {

def getAllStateBenefitsData(taxYear: Int, nino: String)
(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, Option[AllStateBenefitsData]]] = {
def getAllStateBenefitsData(taxYear: Int, nino: String)(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, Option[AllStateBenefitsData]]] =
connector.getAllStateBenefitsData(taxYear, nino).map {
case Left(error) => Left(ApiServiceError(error.status.toString))
case Left(error) => Left(ApiServiceError(error.status.toString))
case Right(allStateBenefitsData) => Right(allStateBenefitsData)
}
}

def saveStateBenefitsUserData(stateBenefitsUserData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, UUID]] = {
def saveStateBenefitsUserData(stateBenefitsUserData: StateBenefitsUserData)(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, UUID]] = {
val response = for {
benefitId <- createOrUpdateStateBenefit(stateBenefitsUserData)
result <- createOrUpdateBenefitDetails(stateBenefitsUserData, benefitId)
result <- createOrUpdateBenefitDetails(stateBenefitsUserData, benefitId)
} yield result
response.value
}

def removeOrIgnoreClaim(stateBenefitsUserData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, Unit]] = {
def removeOrIgnoreClaim(stateBenefitsUserData: StateBenefitsUserData)(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, Unit]] = {
val benefitId = stateBenefitsUserData.claim.get.benefitId.get
val eventualIgnoreOrDelete = if (stateBenefitsUserData.isHmrcData) {
connector.ignoreStateBenefit(stateBenefitsUserData.taxYear, stateBenefitsUserData.nino, benefitId)
Expand All @@ -59,58 +55,60 @@ class IntegrationFrameworkService @Inject()(connector: IntegrationFrameworkConne

eventualIgnoreOrDelete.map {
case Left(error) => Left(ApiServiceError(error.status.toString))
case Right(_) => Right(())
case Right(_) => Right(())
}
}

def unIgnoreClaim(stateBenefitsUserData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, Unit]] = {
def removeClaim(nino: String, taxYear: Int, benefitId: UUID)(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, Unit]] = {
connector
.deleteStateBenefit(taxYear, nino, benefitId)
.map(_.leftMap(error => ApiServiceError(error.status.toString)))
}

def unIgnoreClaim(stateBenefitsUserData: StateBenefitsUserData)(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, Unit]] = {
val benefitId = stateBenefitsUserData.claim.get.benefitId.get
connector.unIgnoreStateBenefit(stateBenefitsUserData.taxYear, stateBenefitsUserData.nino, benefitId).map {
case Left(error) => Left(ApiServiceError(error.status.toString))
case Right(_) => Right(())
case Right(_) => Right(())
}
}

private def createOrUpdateStateBenefit(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] = userData match {
case _ if userData.isNewClaim => addCustomerStateBenefit(userData)
case _ if userData.isHmrcData => createCustomerOverride(userData)
case _ => updateCustomerStateBenefit(userData)
}
private def createOrUpdateStateBenefit(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] =
userData match {
case _ if userData.isNewClaim => addCustomerStateBenefit(userData)
case _ if userData.isHmrcData => createCustomerOverride(userData)
case _ => updateCustomerStateBenefit(userData)
}

private def createOrUpdateBenefitDetails(userData: StateBenefitsUserData, benefitId: UUID)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] = EitherT {
val claimData = userData.claim.get
private def createOrUpdateBenefitDetails(userData: StateBenefitsUserData, benefitId: UUID)(implicit
hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] = EitherT {
val claimData = userData.claim.get
val detailOverride = StateBenefitDetailOverride(claimData.amount.get, claimData.taxPaid)
connector.createOrUpdateStateBenefitDetailOverride(userData.taxYear, userData.nino, benefitId, detailOverride).map {
case Left(error) => Left(ApiServiceError(error.status.toString))
case Right(_) => Right(benefitId)
case Right(_) => Right(benefitId)
}
}

private def updateCustomerStateBenefit(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] = EitherT {
val claimData = userData.claim.get
val benefitId = claimData.benefitId.get
connector.updateCustomerStateBenefit(userData.taxYear, userData.nino, benefitId, UpdateStateBenefit(claimData)).map {
case Left(error) => Left(ApiServiceError(error.status.toString))
case Right(_) => Right(benefitId)
private def updateCustomerStateBenefit(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] =
EitherT {
val claimData = userData.claim.get
val benefitId = claimData.benefitId.get
connector.updateCustomerStateBenefit(userData.taxYear, userData.nino, benefitId, UpdateStateBenefit(claimData)).map {
case Left(error) => Left(ApiServiceError(error.status.toString))
case Right(_) => Right(benefitId)
}
}
}

private def createCustomerOverride(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] = {
private def createCustomerOverride(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] =
for {
benefitId <- createOrUpdateBenefitDetails(userData, userData.claim.get.benefitId.get)
_ <- updateCustomerStateBenefit(userData)
_ <- updateCustomerStateBenefit(userData)
} yield benefitId
}

private def addCustomerStateBenefit(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] = EitherT {
private def addCustomerStateBenefit(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] = EitherT {
connector.addCustomerStateBenefit(userData.taxYear, userData.nino, AddStateBenefit(userData.benefitType, userData.claim.get)).map {
case Left(error) => Left(ApiServiceError(error.status.toString))
case Left(error) => Left(ApiServiceError(error.status.toString))
case Right(benefitId) => Right(benefitId)
}
}
Expand Down
79 changes: 38 additions & 41 deletions app/services/StateBenefitsService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,23 @@ import javax.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}

@Singleton
class StateBenefitsService @Inject()(ifService: IntegrationFrameworkService,
desService: DESService,
submissionService: SubmissionService,
stateBenefitsUserDataRepository: StateBenefitsUserDataRepository)
(implicit ec: ExecutionContext) {

def getAllStateBenefitsData(taxYear: Int, nino: String)
(implicit hc: HeaderCarrier): Future[Either[ServiceError, Option[AllStateBenefitsData]]] = {
class StateBenefitsService @Inject() (ifService: IntegrationFrameworkService,
desService: DESService,
submissionService: SubmissionService,
stateBenefitsUserDataRepository: StateBenefitsUserDataRepository)(implicit ec: ExecutionContext) {

def getAllStateBenefitsData(taxYear: Int, nino: String)(implicit hc: HeaderCarrier): Future[Either[ServiceError, Option[AllStateBenefitsData]]] =
ifService.getAllStateBenefitsData(taxYear, nino)
}

def getPriorData(taxYear: Int, nino: String, mtdtid: String)
(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, IncomeTaxUserData]] = {
def getPriorData(taxYear: Int, nino: String, mtdtid: String)(implicit hc: HeaderCarrier): Future[Either[ApiServiceError, IncomeTaxUserData]] =
submissionService.getIncomeTaxUserData(taxYear, nino, mtdtid)
}

def getSessionData(nino: String, sessionDataId: UUID): Future[Either[ServiceError, StateBenefitsUserData]] = {
def getSessionData(nino: String, sessionDataId: UUID): Future[Either[ServiceError, StateBenefitsUserData]] =
findSessionData(nino, sessionDataId).value
}

def createSessionData(stateBenefitsUserData: StateBenefitsUserData): Future[Either[ServiceError, UUID]] = {
val response = for {
_ <- clearSessionData(stateBenefitsUserData)
_ <- clearSessionData(stateBenefitsUserData)
result <- createOrUpdateUserSessionData(stateBenefitsUserData)
} yield result
response.value
Expand All @@ -60,60 +54,63 @@ class StateBenefitsService @Inject()(ifService: IntegrationFrameworkService,
def updateSessionData(userData: StateBenefitsUserData): Future[Either[ServiceError, UUID]] =
createOrUpdateUserSessionData(userData).value

def saveClaim(stateBenefitsUserData: StateBenefitsUserData, useSessionData: Boolean = true)
(implicit hc: HeaderCarrier): Future[Either[ServiceError, Unit]] = {
def saveClaim(stateBenefitsUserData: StateBenefitsUserData, useSessionData: Boolean = true)(implicit
hc: HeaderCarrier): Future[Either[ServiceError, Unit]] = {
val response = for {
data <- if (useSessionData) { findSessionData(stateBenefitsUserData.nino, stateBenefitsUserData.sessionDataId.get) }
else {EitherT(Future(Either.cond(test = true, stateBenefitsUserData, ApiServiceError("saveClaim with StateBenefitsUserData"))))}
data <-
if (useSessionData) {
findSessionData(stateBenefitsUserData.nino, stateBenefitsUserData.sessionDataId.get)
} else { EitherT(Future(Either.cond(test = true, stateBenefitsUserData, ApiServiceError("saveClaim with StateBenefitsUserData")))) }
_ <- saveStateBenefitsUserData(data)
_ <- refreshSubmissionServiceData(data)
_ <- clearSessionData(data)
} yield ()
response.value
}

def removeClaim(nino: String, sessionDataId: UUID)
(implicit hc: HeaderCarrier): Future[Either[ServiceError, Unit]] = {
def removeClaim(nino: String, sessionDataId: UUID)(implicit hc: HeaderCarrier): Future[Either[ServiceError, Unit]] = {
val response = for {
userData <- findSessionData(nino, sessionDataId)
_ <- removeStateBenefitUserData(userData)
_ <- refreshSubmissionServiceData(userData)
_ <- clearSessionData(userData)
_ <- removeStateBenefitUserData(userData)
_ <- refreshSubmissionServiceData(userData)
_ <- clearSessionData(userData)
} yield ()
response.value
}

def restoreClaim(nino: String, sessionDataId: UUID)
(implicit hc: HeaderCarrier): Future[Either[ServiceError, Unit]] = {
def removeClaimById(nino: String, taxYear: Int, mtdItId: String, benefitId: UUID)(implicit hc: HeaderCarrier): Future[Either[ServiceError, Unit]] =
(for {
_ <- EitherT(ifService.removeClaim(nino, taxYear, benefitId))
_ <- EitherT(submissionService.refreshStateBenefits(taxYear, nino, mtdItId))
} yield ()).value

def restoreClaim(nino: String, sessionDataId: UUID)(implicit hc: HeaderCarrier): Future[Either[ServiceError, Unit]] = {
val response = for {
userData <- findSessionData(nino, sessionDataId)
_ <- unIgnoreClaim(userData)
_ <- refreshSubmissionServiceData(userData)
_ <- clearSessionData(userData)
_ <- unIgnoreClaim(userData)
_ <- refreshSubmissionServiceData(userData)
_ <- clearSessionData(userData)
} yield ()
response.value
}

private def findSessionData(nino: String, sessionDataId: UUID): EitherT[Future, ServiceError, StateBenefitsUserData] =
EitherT(stateBenefitsUserDataRepository.find(nino, sessionDataId))

private def refreshSubmissionServiceData(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, Unit] =
private def refreshSubmissionServiceData(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, Unit] =
EitherT(submissionService.refreshStateBenefits(userData.taxYear, userData.nino, userData.mtdItId))

private def removeStateBenefitUserData(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ServiceError, Unit] = userData match {
case _ if userData.isNewClaim => EitherT(Future.successful[Either[ServiceError, Unit]](Right(())))
case _ if userData.isCustomerAdded || userData.isHmrcData => EitherT(ifService.removeOrIgnoreClaim(userData))
case _ => EitherT(desService.removeCustomerOverride(userData))
}
private def removeStateBenefitUserData(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ServiceError, Unit] =
userData match {
case _ if userData.isNewClaim => EitherT(Future.successful[Either[ServiceError, Unit]](Right(())))
case _ if userData.isCustomerAdded || userData.isHmrcData => EitherT(ifService.removeOrIgnoreClaim(userData))
case _ => EitherT(desService.removeCustomerOverride(userData))
}

private def unIgnoreClaim(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, Unit] =
private def unIgnoreClaim(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, Unit] =
EitherT(ifService.unIgnoreClaim(userData))

private def saveStateBenefitsUserData(userData: StateBenefitsUserData)
(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] =
private def saveStateBenefitsUserData(userData: StateBenefitsUserData)(implicit hc: HeaderCarrier): EitherT[Future, ApiServiceError, UUID] =
EitherT(ifService.saveStateBenefitsUserData(userData))

private def clearSessionData(userData: StateBenefitsUserData): EitherT[Future, ServiceError, Unit] =
Expand Down
1 change: 1 addition & 0 deletions conf/app.routes
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ PUT /session-data/nino/:nino/session/:sessionDataId controllers.
PUT /claim-data/nino/:nino/session/:sessionDataId controllers.ClaimDataController.save(nino: String, sessionDataId: java.util.UUID)
PUT /claim-data/nino/:nino controllers.ClaimDataController.saveByData(nino: String)
DELETE /claim-data/nino/:nino/session/:sessionDataId controllers.ClaimDataController.remove(nino: String, sessionDataId: java.util.UUID)
DELETE /claim-data/nino/:nino/:taxYear/:benefitId/remove controllers.ClaimDataController.removeClaim(nino: String, taxYear: Int, benefitId: java.util.UUID)
DELETE /claim-data/nino/:nino/session/:sessionDataId/ignore controllers.ClaimDataController.restore(nino: String, sessionDataId: java.util.UUID)
Loading

0 comments on commit 240fc3d

Please sign in to comment.