Skip to content

Commit

Permalink
APSR-1926 Add new endpoint to delete submission for an application (#525
Browse files Browse the repository at this point in the history
)

* APSR-1926 Add new endpoint to delete submission for an application

* APSR-1926 Add new endpoint to delete submission for an application

* APSR-1926 Add new endpoint to delete submission for an application
  • Loading branch information
petekirby-ee authored Nov 7, 2024
1 parent 2f0eaaa commit 6f73f4b
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ import uk.gov.hmrc.thirdpartyapplication.services.ApplicationDataService
object ApprovalsController {
case class TouUpliftRequest(gatekeeperUserName: String, reasons: String)
implicit val readsTouUpliftRequest: Reads[TouUpliftRequest] = Json.reads[TouUpliftRequest]

case class TouDeleteRequest(gatekeeperUserName: String)
implicit val readsTouDeleteRequest: Reads[TouDeleteRequest] = Json.reads[TouDeleteRequest]
}

@Singleton
Expand Down Expand Up @@ -100,6 +103,20 @@ class ApprovalsController @Inject() (
.recover(recovery)
}

def deleteTouUplift(applicationId: ApplicationId) = withApplicationAndSubmission(applicationId) { implicit request =>
import GrantApprovalsService._

withJsonBodyFromAnyContent[TouDeleteRequest] { deleteRequest =>
grantApprovalService.deleteTouUplift(request.application, request.submission, deleteRequest.gatekeeperUserName)
.map(_ match {
case Actioned(application) => Ok(Json.toJson(Application(application)))
case RejectedDueToIncorrectApplicationState =>
PreconditionFailed(asJsonError("APPLICATION_IN_INCORRECT_STATE", s"Application is not in state '${State.PRODUCTION}'"))
})
}
.recover(recovery)
}

private def asJsonError(errorCode: String, message: String): JsValue =
Json.toJson(
Json.obj(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,23 @@ class GrantApprovalsService @Inject() (
)
.fold[Result](identity, identity)
}

def deleteTouUplift(
originalApp: StoredApplication,
submission: Submission,
gatekeeperUserName: String
): Future[GrantApprovalsService.Result] = {
import cats.instances.future.catsStdInstancesForFuture

val ET = EitherTHelper.make[Result]
(
for {
_ <- ET.cond(originalApp.isInProduction, (), RejectedDueToIncorrectApplicationState)
count <- ET.liftF(submissionService.deleteAllAnswersForApplication(originalApp.id))
_ <- ET.liftF(responsibleIndividualVerificationRepository.deleteAllByApplicationId(originalApp.id))
_ <- ET.liftF(termsOfUseInvitationService.updateResetBackToEmailSent(originalApp.id))
} yield Actioned(originalApp)
)
.fold[Result](identity, identity)
}
}
1 change: 1 addition & 0 deletions conf/approvals.routes
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
POST /application/:id/grant-with-warn-tou uk.gov.hmrc.apiplatform.modules.approvals.controllers.ApprovalsController.grantWithWarningsForTouUplift(id: ApplicationId)
POST /application/:id/decline-tou uk.gov.hmrc.apiplatform.modules.approvals.controllers.ApprovalsController.declineForTouUplift(id: ApplicationId)
POST /application/:id/reset-tou uk.gov.hmrc.apiplatform.modules.approvals.controllers.ApprovalsController.resetForTouUplift(id: ApplicationId)
POST /application/:id/delete-tou uk.gov.hmrc.apiplatform.modules.approvals.controllers.ApprovalsController.deleteTouUplift(id: ApplicationId)

GET /responsible-individual-verification/:code uk.gov.hmrc.apiplatform.modules.approvals.controllers.ResponsibleIndividualVerificationController.getVerification(code: String)
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ApprovalsControllerSpec extends AsyncHmrcSpec with ApplicationTestData wit
val request = FakeRequest().withJsonBody(jsonBody)
val application = anApplicationData(appId, productionState("bob"))

"return 'no content' success response if successful" in new Setup {
"return 'OK' success response if successful" in new Setup {
hasApp
hasSubmission
GrantApprovalsServiceMock.DeclineForTouUplift.thenReturn(GrantApprovalsService.Actioned(application))
Expand All @@ -82,7 +82,7 @@ class ApprovalsControllerSpec extends AsyncHmrcSpec with ApplicationTestData wit
val request = FakeRequest().withJsonBody(jsonBody)
val application = anApplicationData(appId, productionState("bob"))

"return 'no content' success response if successful" in new Setup {
"return 'OK' success response if successful" in new Setup {
hasApp
hasSubmission
GrantApprovalsServiceMock.GrantWithWarningsForTouUplift.thenReturn(GrantApprovalsService.Actioned(application))
Expand All @@ -98,7 +98,7 @@ class ApprovalsControllerSpec extends AsyncHmrcSpec with ApplicationTestData wit
val request = FakeRequest().withJsonBody(jsonBody)
val application = anApplicationData(appId, productionState("bob"))

"return 'no content' success response if successful" in new Setup {
"return 'OK' success response if successful" in new Setup {
hasApp
hasSubmission
GrantApprovalsServiceMock.ResetForTouUplift.thenReturn(GrantApprovalsService.Actioned(application))
Expand All @@ -107,4 +107,20 @@ class ApprovalsControllerSpec extends AsyncHmrcSpec with ApplicationTestData wit
status(result) shouldBe OK
}
}

"deleteTouUplift" should {
implicit val writes: OWrites[ApprovalsController.TouDeleteRequest] = Json.writes[ApprovalsController.TouDeleteRequest]
val jsonBody = Json.toJson(ApprovalsController.TouDeleteRequest("Bob from SDST"))
val request = FakeRequest().withJsonBody(jsonBody)
val application = anApplicationData(appId, productionState("bob"))

"return 'OK' success response if successful" in new Setup {
hasApp
hasSubmission
GrantApprovalsServiceMock.DeleteTouUplift.thenReturn(GrantApprovalsService.Actioned(application))
val result = underTest.deleteTouUplift(appId)(request)

status(result) shouldBe OK
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ trait GrantApprovalsServiceMockModule extends MockitoSugar with ArgumentMatchers
object ResetForTouUplift {
def thenReturn(result: GrantApprovalsService.Result) = when(aMock.resetForTouUplift(*, *, *, *)).thenReturn(successful(result))
}

object DeleteTouUplift {
def thenReturn(result: GrantApprovalsService.Result) = when(aMock.deleteTouUplift(*, *, *)).thenReturn(successful(result))
}
}

object GrantApprovalsServiceMock extends BaseGrantApprovalsServiceMock {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,28 @@ class GrantApprovalsServiceSpec extends AsyncHmrcSpec {
result shouldBe GrantApprovalsService.RejectedDueToIncorrectApplicationState
}
}

"GrantApprovalsService.deleteTouUplift" should {
"delete the specified ToU submission" in new Setup {

SubmissionsServiceMock.DeleteAll.thenReturn()
TermsOfUseInvitationServiceMock.UpdateResetBackToEmailSent.thenReturn()
ResponsibleIndividualVerificationRepositoryMock.DeleteAllByApplicationId.succeeds()

val result = await(underTest.deleteTouUplift(applicationProduction, pendingRISubmission, gatekeeperUserName))

result should matchPattern {
case GrantApprovalsService.Actioned(app) =>
}
SubmissionsServiceMock.DeleteAll.verifyCalledWith(applicationProduction.id)
TermsOfUseInvitationServiceMock.UpdateResetBackToEmailSent.verifyCalledWith(applicationProduction.id)
ResponsibleIndividualVerificationRepositoryMock.DeleteAllByApplicationId.verifyCalledWith(applicationProduction.id)
}

"fail to delete the specified submission if the application is in the incorrect state" in new Setup {
val result = await(underTest.deleteTouUplift(anApplicationData(applicationId, testingState()), pendingRISubmission, gatekeeperUserName))

result shouldBe GrantApprovalsService.RejectedDueToIncorrectApplicationState
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ trait SubmissionsServiceMockModule extends MockitoSugar with ArgumentMatchersSug

def thenReturn() =
when(aMock.deleteAllAnswersForApplication(*[ApplicationId])).thenReturn(successful(1))

def verifyCalledWith(applicationId: ApplicationId) = {
SubmissionsServiceMock.verify.deleteAllAnswersForApplication(applicationId)
}
}

object Store {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ trait ResponsibleIndividualVerificationRepositoryMockModule extends MockitoSugar
}

object DeleteAllByApplicationId {
def succeeds() = when(aMock.deleteAllByApplicationId(*[ApplicationId])).thenReturn(successful(HasSucceeded))
def succeeds() = when(aMock.deleteAllByApplicationId(*[ApplicationId])).thenReturn(successful(HasSucceeded))
def verifyCalledWith(applicationId: ApplicationId) = verify(aMock).deleteAllByApplicationId(applicationId)
}

object ApplyEvents {
Expand Down

0 comments on commit 6f73f4b

Please sign in to comment.