From 3c18eafb28e2b4aa0405b5fbd62daa9e33c7e5f5 Mon Sep 17 00:00:00 2001 From: abhinavgupta-hmrc <269448599+abhinavgupta-hmrc@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:46:03 +0100 Subject: [PATCH 1/6] DTR-5901 Feat-CIS Verify Batch Polling Business Function F7 --- .../controllers/VerificationController.scala | 23 ++++ ...bmissionWithVerificationBatchRequest.scala | 28 ++++ ...missionWithVerificationBatchResponse.scala | 33 +++++ .../cis/repositories/CisFormpRepository.scala | 50 ++++++++ .../cis/services/VerificationService.scala | 5 + .../repositories/SdltFormpRepository.scala | 3 - .../VerificationControllerSpec.scala | 78 +++++++++++- .../repositories/CisFormpRepositorySpec.scala | 120 +++++++++++++++++- .../services/VerificationServiceSpec.scala | 50 ++++++++ 9 files changed, 385 insertions(+), 5 deletions(-) create mode 100644 app/uk/gov/hmrc/formpproxy/cis/models/requests/GetSubmissionWithVerificationBatchRequest.scala create mode 100644 app/uk/gov/hmrc/formpproxy/cis/models/response/GetSubmissionWithVerificationBatchResponse.scala diff --git a/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala b/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala index bffc1040..f5a08564 100644 --- a/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala +++ b/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala @@ -146,4 +146,27 @@ class VerificationController @Inject() ( } ) } + def getSubmissionWithVerificationBatch( + instanceId: String, + verificationBatchResourceRef: Long + ): Action[AnyContent] = + authorise.async { implicit request => + val getSubmissionWithVerificationBatchRequest = + GetSubmissionWithVerificationBatchRequest( + instanceId = instanceId, + verificationBatchResourceRef = verificationBatchResourceRef + ) + + service + .getSubmissionWithVerificationBatch(getSubmissionWithVerificationBatchRequest) + .map(res => Ok(Json.toJson(res))) + .recover { case t => + logger.error( + s"[getSubmissionWithVerificationBatch] failed for instanceId=$instanceId, verificationBatchResourceRef=$verificationBatchResourceRef", + t + ) + + InternalServerError(Json.obj("message" -> "Unexpected error")) + } + } } diff --git a/app/uk/gov/hmrc/formpproxy/cis/models/requests/GetSubmissionWithVerificationBatchRequest.scala b/app/uk/gov/hmrc/formpproxy/cis/models/requests/GetSubmissionWithVerificationBatchRequest.scala new file mode 100644 index 00000000..f5999f74 --- /dev/null +++ b/app/uk/gov/hmrc/formpproxy/cis/models/requests/GetSubmissionWithVerificationBatchRequest.scala @@ -0,0 +1,28 @@ +/* + * Copyright 2026 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 uk.gov.hmrc.formpproxy.cis.models.requests + +import play.api.libs.json.{Json, OFormat} + +final case class GetSubmissionWithVerificationBatchRequest( + instanceId: String, + verificationBatchResourceRef: Long +) +object GetSubmissionWithVerificationBatchRequest { + given format: OFormat[GetSubmissionWithVerificationBatchRequest] = + Json.format[GetSubmissionWithVerificationBatchRequest] +} diff --git a/app/uk/gov/hmrc/formpproxy/cis/models/response/GetSubmissionWithVerificationBatchResponse.scala b/app/uk/gov/hmrc/formpproxy/cis/models/response/GetSubmissionWithVerificationBatchResponse.scala new file mode 100644 index 00000000..6ad4af1c --- /dev/null +++ b/app/uk/gov/hmrc/formpproxy/cis/models/response/GetSubmissionWithVerificationBatchResponse.scala @@ -0,0 +1,33 @@ +/* + * Copyright 2026 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 uk.gov.hmrc.formpproxy.cis.models.response + +import play.api.libs.json.{Json, OFormat} +import uk.gov.hmrc.formpproxy.cis.models.* + +final case class GetSubmissionWithVerificationBatchResponse( + scheme: Option[ContractorScheme], + subcontractors: Seq[Subcontractor], + verifications: Seq[Verification], + verificationBatch: Option[VerificationBatch], + submission: Option[Submission] +) + +object GetSubmissionWithVerificationBatchResponse { + given format: OFormat[GetSubmissionWithVerificationBatchResponse] = + Json.format[GetSubmissionWithVerificationBatchResponse] +} diff --git a/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala b/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala index 06b75aa3..a7d83b44 100644 --- a/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala +++ b/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala @@ -69,6 +69,9 @@ trait CisMonthlyReturnSource { def createGovTalkStatusRecord(req: CreateGovTalkStatusRecordRequest): Future[Unit] def getNewestVerificationBatch(instanceId: String): Future[GetNewestVerificationBatchResponse] def getCurrentVerificationBatch(instanceId: String): Future[GetCurrentVerificationBatchResponse] + def getSubmissionWithVerificationBatch( + request: GetSubmissionWithVerificationBatchRequest + ): Future[GetSubmissionWithVerificationBatchResponse] def deleteUnsubmittedMonthlyReturn(req: DeleteUnsubmittedMonthlyReturnRequest): Future[Unit] def getMonthlyReturnComplete( instanceId: String, @@ -1238,6 +1241,53 @@ class CisFormpRepository @Inject() (@NamedDatabase("cis") db: Database)(implicit } } } + override def getSubmissionWithVerificationBatch( + request: GetSubmissionWithVerificationBatchRequest + ): Future[GetSubmissionWithVerificationBatchResponse] = { + logger.info( + s"[CIS] getSubmissionWithVerificationBatch(instanceId=${request.instanceId}, verificationBatchResourceRef=${request.verificationBatchResourceRef})" + ) + + Future { + db.withConnection { conn => + withCall(conn, CallGetSubmissionWithVerificationBatch) { cs => + cs.setString(1, request.instanceId) + cs.setLong(2, request.verificationBatchResourceRef) + + cs.registerOutParameter(3, OracleTypes.CURSOR) + cs.registerOutParameter(4, OracleTypes.CURSOR) + cs.registerOutParameter(5, OracleTypes.CURSOR) + cs.registerOutParameter(6, OracleTypes.CURSOR) + cs.registerOutParameter(7, OracleTypes.CURSOR) + + cs.execute() + + val scheme = + withCursor(cs, 3)(collectSchemes).headOption + + val subcontractors = + withCursor(cs, 4)(collectSubcontractors) + + val verifications = + withCursor(cs, 5)(collectVerifications) + + val verificationBatch = + withCursor(cs, 6)(collectVerificationBatches).headOption + + val submission = + withCursor(cs, 7)(collectSubmissionsForGetVerificationBatch).headOption + + GetSubmissionWithVerificationBatchResponse( + scheme = scheme, + subcontractors = subcontractors, + verifications = verifications, + verificationBatch = verificationBatch, + submission = submission + ) + } + } + } + } override def createVerificationBatchAndVerifications( req: CreateVerificationBatchAndVerificationsRequest diff --git a/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala b/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala index d8f8a1fc..6ad22899 100644 --- a/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala +++ b/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala @@ -27,6 +27,11 @@ import scala.concurrent.Future @Singleton class VerificationService @Inject() (repo: CisMonthlyReturnSource) { + def getSubmissionWithVerificationBatch( + request: GetSubmissionWithVerificationBatchRequest + ): Future[GetSubmissionWithVerificationBatchResponse] = + repo.getSubmissionWithVerificationBatch(request) + def getNewestVerificationBatch(instanceId: String): Future[GetNewestVerificationBatchResponse] = repo.getNewestVerificationBatch(instanceId) diff --git a/app/uk/gov/hmrc/formpproxy/sdlt/repositories/SdltFormpRepository.scala b/app/uk/gov/hmrc/formpproxy/sdlt/repositories/SdltFormpRepository.scala index a850fdde..6d46f091 100644 --- a/app/uk/gov/hmrc/formpproxy/sdlt/repositories/SdltFormpRepository.scala +++ b/app/uk/gov/hmrc/formpproxy/sdlt/repositories/SdltFormpRepository.scala @@ -2558,8 +2558,6 @@ class SdltFormpRepository @Inject() (@NamedDatabase("sdlt") db: Database)(implic cs.execute() - val submissionId = cs.getLong(4) - CreateSubmissionReturn(success = true) } finally cs.close() } @@ -2663,7 +2661,6 @@ class SdltFormpRepository @Inject() (@NamedDatabase("sdlt") db: Database)(implic cs.execute() - val errorDetailId = cs.getLong(5) CreateSubmissionErrorDetailReturn(success = true) } finally cs.close() } diff --git a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala index c726fab1..5c129dde 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala @@ -24,7 +24,7 @@ import play.api.test.Helpers.* import uk.gov.hmrc.formpproxy.actions.FakeAuthAction import uk.gov.hmrc.formpproxy.base.SpecBase import uk.gov.hmrc.formpproxy.cis.models.{ContractorScheme, CreateVerifications, DeleteVerifications, MonthlyReturn, Subcontractor, Submission, Verification, VerificationBatch} -import uk.gov.hmrc.formpproxy.cis.models.response.{GetCurrentVerificationBatchResponse, GetNewestVerificationBatchResponse} +import uk.gov.hmrc.formpproxy.cis.models.response.{GetCurrentVerificationBatchResponse, GetNewestVerificationBatchResponse, GetSubmissionWithVerificationBatchResponse} import uk.gov.hmrc.formpproxy.cis.models.requests._ import uk.gov.hmrc.formpproxy.cis.models.response.CreateVerificationBatchAndVerificationsResponse import uk.gov.hmrc.formpproxy.cis.models.response.CreateSubmissionAndUpdateVerificationsResponse @@ -949,4 +949,80 @@ class VerificationControllerSpec extends SpecBase { verifyNoMoreInteractions(mockService) } } + "GET /verification/submission-batch (getSubmissionWithVerificationBatch)" - { + + "returns 200 OK with JSON body when service succeeds" in { + val s = setup + import s.* + + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) + + val response = GetSubmissionWithVerificationBatchResponse( + scheme = None, + subcontractors = Seq.empty, + verifications = Seq.empty, + verificationBatch = None, + submission = None + ) + + when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) + .thenReturn(Future.successful(response)) + + val req = FakeRequest( + GET, + s"/verification/submission-batch?instanceId=${requestModel.instanceId}&verificationBatchResourceRef=${requestModel.verificationBatchResourceRef}" + ) + + val result = + controller + .getSubmissionWithVerificationBatch( + instanceId = requestModel.instanceId, + verificationBatchResourceRef = requestModel.verificationBatchResourceRef + ) + .apply(req) + + status(result) mustBe OK + contentType(result) mustBe Some(JSON) + contentAsJson(result) mustBe Json.toJson(response) + + verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verifyNoMoreInteractions(mockService) + } + + "returns 500 InternalServerError with error body when service fails" in { + val s = setup + import s.* + + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) + + when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) + .thenReturn(Future.failed(new RuntimeException("boom"))) + + val req = FakeRequest( + GET, + s"/verification/submission-batch?instanceId=${requestModel.instanceId}&verificationBatchResourceRef=${requestModel.verificationBatchResourceRef}" + ) + + val result = + controller + .getSubmissionWithVerificationBatch( + instanceId = requestModel.instanceId, + verificationBatchResourceRef = requestModel.verificationBatchResourceRef + ) + .apply(req) + + status(result) mustBe INTERNAL_SERVER_ERROR + contentType(result) mustBe Some(JSON) + contentAsJson(result) mustBe Json.obj("message" -> "Unexpected error") + + verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verifyNoMoreInteractions(mockService) + } + } } diff --git a/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala b/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala index eae21ca0..7469aeb1 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala @@ -27,6 +27,7 @@ import uk.gov.hmrc.formpproxy.base.SpecBase import uk.gov.hmrc.formpproxy.cis.models.* import uk.gov.hmrc.formpproxy.cis.models.requests.* import uk.gov.hmrc.formpproxy.cis.models.response.GetSubcontractorForDeleteResponse +import uk.gov.hmrc.formpproxy.cis.models.response.GetSubmissionWithVerificationBatchResponse import uk.gov.hmrc.formpproxy.shared.utils.CallableStatementUtils.* import java.sql.* @@ -3374,7 +3375,6 @@ final class CisFormpRepositorySpec extends SpecBase { verify(csUpdateV2).close() } } - "getBatchPollSubmissions" - { "register both cursors, execute the proc, and assemble the response" in { val db = mock[Database] @@ -3718,6 +3718,124 @@ final class CisFormpRepositorySpec extends SpecBase { verify(csUpdateSubmission).execute() } + "getSubmissionWithVerificationBatch" - { + + "call stored procedure and return empty response when all cursors are empty" in { + val db = mock[Database] + val conn = mock[Connection] + val cs = mock[CallableStatement] + + val schemeRs = mock[ResultSet] + val subcontractorsRs = mock[ResultSet] + val verificationsRs = mock[ResultSet] + val verificationBatchRs = mock[ResultSet] + val submissionRs = mock[ResultSet] + + when(db.withConnection(anyArg[Connection => Any])).thenAnswer { inv => + val f = inv.getArgument(0, classOf[Connection => Any]) + f(conn) + } + + val call = "{ call SUBMISSION_PROCS.Get_Verif_Batch_Submission(?, ?, ?, ?, ?, ?, ?) }" + + when(conn.prepareCall(eqTo(call))).thenReturn(cs) + + when(cs.getObject(eqTo(3), eqTo(classOf[ResultSet]))).thenReturn(schemeRs) + when(cs.getObject(eqTo(4), eqTo(classOf[ResultSet]))).thenReturn(subcontractorsRs) + when(cs.getObject(eqTo(5), eqTo(classOf[ResultSet]))).thenReturn(verificationsRs) + when(cs.getObject(eqTo(6), eqTo(classOf[ResultSet]))).thenReturn(verificationBatchRs) + when(cs.getObject(eqTo(7), eqTo(classOf[ResultSet]))).thenReturn(submissionRs) + + when(schemeRs.next()).thenReturn(false) + when(subcontractorsRs.next()).thenReturn(false) + when(verificationsRs.next()).thenReturn(false) + when(verificationBatchRs.next()).thenReturn(false) + when(submissionRs.next()).thenReturn(false) + + val repo = new CisFormpRepository(db) + + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) + + val result = repo.getSubmissionWithVerificationBatch(requestModel).futureValue + + result mustBe GetSubmissionWithVerificationBatchResponse( + scheme = None, + subcontractors = Seq.empty, + verifications = Seq.empty, + verificationBatch = None, + submission = None + ) + + verify(conn).prepareCall(eqTo(call)) + + verify(cs).setString(1, requestModel.instanceId) + verify(cs).setLong(2, requestModel.verificationBatchResourceRef) + + verify(cs).registerOutParameter(3, OracleTypes.CURSOR) + verify(cs).registerOutParameter(4, OracleTypes.CURSOR) + verify(cs).registerOutParameter(5, OracleTypes.CURSOR) + verify(cs).registerOutParameter(6, OracleTypes.CURSOR) + verify(cs).registerOutParameter(7, OracleTypes.CURSOR) + + verify(cs).execute() + + verify(schemeRs).close() + verify(subcontractorsRs).close() + verify(verificationsRs).close() + verify(verificationBatchRs).close() + verify(submissionRs).close() + + verify(cs).close() + } + + "fail when stored procedure call fails" in { + val db = mock[Database] + val conn = mock[Connection] + val cs = mock[CallableStatement] + + when(db.withConnection(anyArg[Connection => Any])).thenAnswer { inv => + val f = inv.getArgument(0, classOf[Connection => Any]) + f(conn) + } + + val call = "{ call SUBMISSION_PROCS.Get_Verif_Batch_Submission(?, ?, ?, ?, ?, ?, ?) }" + + when(conn.prepareCall(eqTo(call))).thenReturn(cs) + + val boom = new RuntimeException("stored procedure failed") + + doThrow(boom).when(cs).execute() + + val repo = new CisFormpRepository(db) + + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) + + val ex = repo.getSubmissionWithVerificationBatch(requestModel).failed.futureValue + + ex mustBe boom + + verify(conn).prepareCall(eqTo(call)) + + verify(cs).setString(1, requestModel.instanceId) + verify(cs).setLong(2, requestModel.verificationBatchResourceRef) + + verify(cs).registerOutParameter(3, OracleTypes.CURSOR) + verify(cs).registerOutParameter(4, OracleTypes.CURSOR) + verify(cs).registerOutParameter(5, OracleTypes.CURSOR) + verify(cs).registerOutParameter(6, OracleTypes.CURSOR) + verify(cs).registerOutParameter(7, OracleTypes.CURSOR) + + verify(cs).execute() + verify(cs).close() + } + } + "throws when scheme is missing" in { val db = mock[Database] val conn = mock[Connection] diff --git a/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala b/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala index 7dbf378a..fa0c7fbb 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala @@ -496,4 +496,54 @@ class VerificationServiceSpec extends SpecBase { } } + "VerificationService#getSubmissionWithVerificationBatch" - { + + "return successful response from repo" in { + val c = Ctx() + import c.* + + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) + + val response = GetSubmissionWithVerificationBatchResponse( + scheme = None, + subcontractors = Seq.empty, + verifications = Seq.empty, + verificationBatch = None, + submission = None + ) + + when(repo.getSubmissionWithVerificationBatch(eqTo(requestModel))) + .thenReturn(Future.successful(response)) + + service.getSubmissionWithVerificationBatch(requestModel).futureValue mustBe response + + verify(repo).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verifyNoMoreInteractions(repo) + } + + "propagates failure from repo" in { + val c = Ctx() + import c.* + + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) + + val boom = new RuntimeException("boom") + + when(repo.getSubmissionWithVerificationBatch(eqTo(requestModel))) + .thenReturn(Future.failed(boom)) + + val ex = service.getSubmissionWithVerificationBatch(requestModel).failed.futureValue + + ex mustBe boom + + verify(repo).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verifyNoMoreInteractions(repo) + } + } } From 0529ea6fc3781463087de379e2317957b9b6d2bd Mon Sep 17 00:00:00 2001 From: abhinavgupta-hmrc <269448599+abhinavgupta-hmrc@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:50:49 +0100 Subject: [PATCH 2/6] DTR-5901 Fix - app route updated --- conf/app.routes | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/app.routes b/conf/app.routes index 64f47ceb..b03f2c66 100644 --- a/conf/app.routes +++ b/conf/app.routes @@ -48,6 +48,7 @@ POST /cis/amend-monthly-return/create uk.gov.hmrc. POST /cis/verification/submission/create uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.createSubmissionAndUpdateVerifications() POST /cis/verification/submission/update uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.updateVerificationSubmission() +GET /cis/verification/submission-batch uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmissionWithVerificationBatch(instanceId: String, verificationBatchResourceRef: Long) GET /cis/batchpoll-submissions uk.gov.hmrc.formpproxy.cis.controllers.BatchPollController.getBatchPollSubmissions() From 1d614693c28e6bf1b02ad75e3289515b352dad46 Mon Sep 17 00:00:00 2001 From: abhinavgupta-hmrc <269448599+abhinavgupta-hmrc@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:08:23 +0100 Subject: [PATCH 3/6] DTR-5901 Fix-review comments addressed --- .../cis/repositories/CisFormpRepository.scala | 47 ++------ conf/app.routes | 2 +- .../VerificationControllerSpec.scala | 10 +- .../repositories/CisFormpRepositorySpec.scala | 114 +++++------------- .../services/VerificationServiceSpec.scala | 16 +-- 5 files changed, 54 insertions(+), 135 deletions(-) diff --git a/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala b/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala index a7d83b44..62161b4c 100644 --- a/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala +++ b/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala @@ -1250,41 +1250,20 @@ class CisFormpRepository @Inject() (@NamedDatabase("cis") db: Database)(implicit Future { db.withConnection { conn => - withCall(conn, CallGetSubmissionWithVerificationBatch) { cs => - cs.setString(1, request.instanceId) - cs.setLong(2, request.verificationBatchResourceRef) - - cs.registerOutParameter(3, OracleTypes.CURSOR) - cs.registerOutParameter(4, OracleTypes.CURSOR) - cs.registerOutParameter(5, OracleTypes.CURSOR) - cs.registerOutParameter(6, OracleTypes.CURSOR) - cs.registerOutParameter(7, OracleTypes.CURSOR) - - cs.execute() - - val scheme = - withCursor(cs, 3)(collectSchemes).headOption - - val subcontractors = - withCursor(cs, 4)(collectSubcontractors) - - val verifications = - withCursor(cs, 5)(collectVerifications) - - val verificationBatch = - withCursor(cs, 6)(collectVerificationBatches).headOption - - val submission = - withCursor(cs, 7)(collectSubmissionsForGetVerificationBatch).headOption - - GetSubmissionWithVerificationBatchResponse( - scheme = scheme, - subcontractors = subcontractors, - verifications = verifications, - verificationBatch = verificationBatch, - submission = submission + val result = + callGetSubmissionWithVerificationBatch( + conn, + request.instanceId, + request.verificationBatchResourceRef ) - } + + GetSubmissionWithVerificationBatchResponse( + scheme = result.scheme, + subcontractors = result.subcontractors, + verifications = result.verifications, + verificationBatch = result.verificationBatch, + submission = result.submission + ) } } } diff --git a/conf/app.routes b/conf/app.routes index b03f2c66..b5f27268 100644 --- a/conf/app.routes +++ b/conf/app.routes @@ -48,7 +48,7 @@ POST /cis/amend-monthly-return/create uk.gov.hmrc. POST /cis/verification/submission/create uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.createSubmissionAndUpdateVerifications() POST /cis/verification/submission/update uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.updateVerificationSubmission() -GET /cis/verification/submission-batch uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmissionWithVerificationBatch(instanceId: String, verificationBatchResourceRef: Long) +GET /cis/verification/submission/:instanceId/verification-batch/:verificationBatchResourceRef uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmissionWithVerificationBatch(instanceId: String, verificationBatchResourceRef: Long) GET /cis/batchpoll-submissions uk.gov.hmrc.formpproxy.cis.controllers.BatchPollController.getBatchPollSubmissions() diff --git a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala index 5c129dde..f6136010 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala @@ -24,10 +24,8 @@ import play.api.test.Helpers.* import uk.gov.hmrc.formpproxy.actions.FakeAuthAction import uk.gov.hmrc.formpproxy.base.SpecBase import uk.gov.hmrc.formpproxy.cis.models.{ContractorScheme, CreateVerifications, DeleteVerifications, MonthlyReturn, Subcontractor, Submission, Verification, VerificationBatch} -import uk.gov.hmrc.formpproxy.cis.models.response.{GetCurrentVerificationBatchResponse, GetNewestVerificationBatchResponse, GetSubmissionWithVerificationBatchResponse} import uk.gov.hmrc.formpproxy.cis.models.requests._ -import uk.gov.hmrc.formpproxy.cis.models.response.CreateVerificationBatchAndVerificationsResponse -import uk.gov.hmrc.formpproxy.cis.models.response.CreateSubmissionAndUpdateVerificationsResponse +import uk.gov.hmrc.formpproxy.cis.models.response.{CreateSubmissionAndUpdateVerificationsResponse, CreateVerificationBatchAndVerificationsResponse, GetCurrentVerificationBatchResponse, GetNewestVerificationBatchResponse, GetSubmissionWithVerificationBatchResponse} import uk.gov.hmrc.formpproxy.cis.services.VerificationService import java.time.LocalDateTime @@ -949,7 +947,7 @@ class VerificationControllerSpec extends SpecBase { verifyNoMoreInteractions(mockService) } } - "GET /verification/submission-batch (getSubmissionWithVerificationBatch)" - { + "GET /cis/verification/submission/:instanceId/verification-batch/:verificationBatchResourceRef (getSubmissionWithVerificationBatch)" - { "returns 200 OK with JSON body when service succeeds" in { val s = setup @@ -973,7 +971,7 @@ class VerificationControllerSpec extends SpecBase { val req = FakeRequest( GET, - s"/verification/submission-batch?instanceId=${requestModel.instanceId}&verificationBatchResourceRef=${requestModel.verificationBatchResourceRef}" + s"/cis/verification/submission/${requestModel.instanceId}/verification-batch/${requestModel.verificationBatchResourceRef}" ) val result = @@ -1006,7 +1004,7 @@ class VerificationControllerSpec extends SpecBase { val req = FakeRequest( GET, - s"/verification/submission-batch?instanceId=${requestModel.instanceId}&verificationBatchResourceRef=${requestModel.verificationBatchResourceRef}" + s"/cis/verification/submission/${requestModel.instanceId}/verification-batch/${requestModel.verificationBatchResourceRef}" ) val result = diff --git a/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala b/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala index 7469aeb1..fa84c737 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala @@ -27,7 +27,6 @@ import uk.gov.hmrc.formpproxy.base.SpecBase import uk.gov.hmrc.formpproxy.cis.models.* import uk.gov.hmrc.formpproxy.cis.models.requests.* import uk.gov.hmrc.formpproxy.cis.models.response.GetSubcontractorForDeleteResponse -import uk.gov.hmrc.formpproxy.cis.models.response.GetSubmissionWithVerificationBatchResponse import uk.gov.hmrc.formpproxy.shared.utils.CallableStatementUtils.* import java.sql.* @@ -3720,119 +3719,62 @@ final class CisFormpRepositorySpec extends SpecBase { "getSubmissionWithVerificationBatch" - { - "call stored procedure and return empty response when all cursors are empty" in { + "call Get_Verif_Batch_Submission and return response using existing helper mapping" in { val db = mock[Database] val conn = mock[Connection] val cs = mock[CallableStatement] - val schemeRs = mock[ResultSet] - val subcontractorsRs = mock[ResultSet] - val verificationsRs = mock[ResultSet] - val verificationBatchRs = mock[ResultSet] val submissionRs = mock[ResultSet] + val verificationBatchRs = mock[ResultSet] + val verificationsRs = mock[ResultSet] + val subcontractorsRs = mock[ResultSet] + val schemeRs = mock[ResultSet] - when(db.withConnection(anyArg[Connection => Any])).thenAnswer { inv => - val f = inv.getArgument(0, classOf[Connection => Any]) - f(conn) - } - - val call = "{ call SUBMISSION_PROCS.Get_Verif_Batch_Submission(?, ?, ?, ?, ?, ?, ?) }" - - when(conn.prepareCall(eqTo(call))).thenReturn(cs) - - when(cs.getObject(eqTo(3), eqTo(classOf[ResultSet]))).thenReturn(schemeRs) - when(cs.getObject(eqTo(4), eqTo(classOf[ResultSet]))).thenReturn(subcontractorsRs) - when(cs.getObject(eqTo(5), eqTo(classOf[ResultSet]))).thenReturn(verificationsRs) - when(cs.getObject(eqTo(6), eqTo(classOf[ResultSet]))).thenReturn(verificationBatchRs) - when(cs.getObject(eqTo(7), eqTo(classOf[ResultSet]))).thenReturn(submissionRs) - - when(schemeRs.next()).thenReturn(false) - when(subcontractorsRs.next()).thenReturn(false) - when(verificationsRs.next()).thenReturn(false) - when(verificationBatchRs.next()).thenReturn(false) - when(submissionRs.next()).thenReturn(false) - - val repo = new CisFormpRepository(db) - - val requestModel = GetSubmissionWithVerificationBatchRequest( + val request = GetSubmissionWithVerificationBatchRequest( instanceId = "abc-123", verificationBatchResourceRef = 77L ) - val result = repo.getSubmissionWithVerificationBatch(requestModel).futureValue - - result mustBe GetSubmissionWithVerificationBatchResponse( - scheme = None, - subcontractors = Seq.empty, - verifications = Seq.empty, - verificationBatch = None, - submission = None - ) - - verify(conn).prepareCall(eqTo(call)) - - verify(cs).setString(1, requestModel.instanceId) - verify(cs).setLong(2, requestModel.verificationBatchResourceRef) - - verify(cs).registerOutParameter(3, OracleTypes.CURSOR) - verify(cs).registerOutParameter(4, OracleTypes.CURSOR) - verify(cs).registerOutParameter(5, OracleTypes.CURSOR) - verify(cs).registerOutParameter(6, OracleTypes.CURSOR) - verify(cs).registerOutParameter(7, OracleTypes.CURSOR) - - verify(cs).execute() - - verify(schemeRs).close() - verify(subcontractorsRs).close() - verify(verificationsRs).close() - verify(verificationBatchRs).close() - verify(submissionRs).close() - - verify(cs).close() - } - - "fail when stored procedure call fails" in { - val db = mock[Database] - val conn = mock[Connection] - val cs = mock[CallableStatement] - when(db.withConnection(anyArg[Connection => Any])).thenAnswer { inv => val f = inv.getArgument(0, classOf[Connection => Any]) f(conn) } - val call = "{ call SUBMISSION_PROCS.Get_Verif_Batch_Submission(?, ?, ?, ?, ?, ?, ?) }" - - when(conn.prepareCall(eqTo(call))).thenReturn(cs) + when(conn.prepareCall("{ call SUBMISSION_PROCS.Get_Verif_Batch_Submission(?, ?, ?, ?, ?, ?, ?) }")) + .thenReturn(cs) - val boom = new RuntimeException("stored procedure failed") + when(cs.getObject(3, classOf[ResultSet])).thenReturn(submissionRs) + when(cs.getObject(4, classOf[ResultSet])).thenReturn(verificationBatchRs) + when(cs.getObject(5, classOf[ResultSet])).thenReturn(verificationsRs) + when(cs.getObject(6, classOf[ResultSet])).thenReturn(subcontractorsRs) + when(cs.getObject(7, classOf[ResultSet])).thenReturn(schemeRs) - doThrow(boom).when(cs).execute() + when(submissionRs.next()).thenReturn(false) + when(verificationBatchRs.next()).thenReturn(false) + when(verificationsRs.next()).thenReturn(false) + when(subcontractorsRs.next()).thenReturn(false) + when(schemeRs.next()).thenReturn(false) val repo = new CisFormpRepository(db) - val requestModel = GetSubmissionWithVerificationBatchRequest( - instanceId = "abc-123", - verificationBatchResourceRef = 77L - ) - - val ex = repo.getSubmissionWithVerificationBatch(requestModel).failed.futureValue + val result = + repo.getSubmissionWithVerificationBatch(request).futureValue - ex mustBe boom - - verify(conn).prepareCall(eqTo(call)) - - verify(cs).setString(1, requestModel.instanceId) - verify(cs).setLong(2, requestModel.verificationBatchResourceRef) + result.scheme mustBe None + result.subcontractors mustBe Seq.empty + result.verifications mustBe Seq.empty + result.verificationBatch mustBe None + result.submission mustBe None + verify(conn).prepareCall("{ call SUBMISSION_PROCS.Get_Verif_Batch_Submission(?, ?, ?, ?, ?, ?, ?) }") + verify(cs).setString(1, request.instanceId) + verify(cs).setLong(2, request.verificationBatchResourceRef) verify(cs).registerOutParameter(3, OracleTypes.CURSOR) verify(cs).registerOutParameter(4, OracleTypes.CURSOR) verify(cs).registerOutParameter(5, OracleTypes.CURSOR) verify(cs).registerOutParameter(6, OracleTypes.CURSOR) verify(cs).registerOutParameter(7, OracleTypes.CURSOR) - verify(cs).execute() - verify(cs).close() } } diff --git a/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala b/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala index fa0c7fbb..69d8b844 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/services/VerificationServiceSpec.scala @@ -502,7 +502,7 @@ class VerificationServiceSpec extends SpecBase { val c = Ctx() import c.* - val requestModel = GetSubmissionWithVerificationBatchRequest( + val request = GetSubmissionWithVerificationBatchRequest( instanceId = "abc-123", verificationBatchResourceRef = 77L ) @@ -515,12 +515,12 @@ class VerificationServiceSpec extends SpecBase { submission = None ) - when(repo.getSubmissionWithVerificationBatch(eqTo(requestModel))) + when(repo.getSubmissionWithVerificationBatch(eqTo(request))) .thenReturn(Future.successful(response)) - service.getSubmissionWithVerificationBatch(requestModel).futureValue mustBe response + service.getSubmissionWithVerificationBatch(request).futureValue mustBe response - verify(repo).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verify(repo).getSubmissionWithVerificationBatch(eqTo(request)) verifyNoMoreInteractions(repo) } @@ -528,21 +528,21 @@ class VerificationServiceSpec extends SpecBase { val c = Ctx() import c.* - val requestModel = GetSubmissionWithVerificationBatchRequest( + val request = GetSubmissionWithVerificationBatchRequest( instanceId = "abc-123", verificationBatchResourceRef = 77L ) val boom = new RuntimeException("boom") - when(repo.getSubmissionWithVerificationBatch(eqTo(requestModel))) + when(repo.getSubmissionWithVerificationBatch(eqTo(request))) .thenReturn(Future.failed(boom)) - val ex = service.getSubmissionWithVerificationBatch(requestModel).failed.futureValue + val ex = service.getSubmissionWithVerificationBatch(request).failed.futureValue ex mustBe boom - verify(repo).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verify(repo).getSubmissionWithVerificationBatch(eqTo(request)) verifyNoMoreInteractions(repo) } } From eabed09b77565c40e0b502b6a0066cc024f4eb8e Mon Sep 17 00:00:00 2001 From: abhinavgupta-hmrc <269448599+abhinavgupta-hmrc@users.noreply.github.com> Date: Mon, 13 Jul 2026 08:54:33 +0100 Subject: [PATCH 4/6] DTR-5901 Fix-review comments addressed --- conf/app.routes | 2 +- .../cis/controllers/VerificationControllerSpec.scala | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/conf/app.routes b/conf/app.routes index b5f27268..e35e9c05 100644 --- a/conf/app.routes +++ b/conf/app.routes @@ -48,7 +48,7 @@ POST /cis/amend-monthly-return/create uk.gov.hmrc. POST /cis/verification/submission/create uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.createSubmissionAndUpdateVerifications() POST /cis/verification/submission/update uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.updateVerificationSubmission() -GET /cis/verification/submission/:instanceId/verification-batch/:verificationBatchResourceRef uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmissionWithVerificationBatch(instanceId: String, verificationBatchResourceRef: Long) +GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmissionWithVerificationBatch(instanceId: String, verificationBatchResourceRef: Long) GET /cis/batchpoll-submissions uk.gov.hmrc.formpproxy.cis.controllers.BatchPollController.getBatchPollSubmissions() diff --git a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala index f6136010..e7c2b898 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala @@ -947,7 +947,8 @@ class VerificationControllerSpec extends SpecBase { verifyNoMoreInteractions(mockService) } } - "GET /cis/verification/submission/:instanceId/verification-batch/:verificationBatchResourceRef (getSubmissionWithVerificationBatch)" - { + + "GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef (getSubmissionWithVerificationBatch)" - { "returns 200 OK with JSON body when service succeeds" in { val s = setup @@ -971,7 +972,7 @@ class VerificationControllerSpec extends SpecBase { val req = FakeRequest( GET, - s"/cis/verification/submission/${requestModel.instanceId}/verification-batch/${requestModel.verificationBatchResourceRef}" + s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" ) val result = @@ -1004,7 +1005,7 @@ class VerificationControllerSpec extends SpecBase { val req = FakeRequest( GET, - s"/cis/verification/submission/${requestModel.instanceId}/verification-batch/${requestModel.verificationBatchResourceRef}" + s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" ) val result = From 9f55dc9eebb1d011ef6baccce8e199336ce67b2d Mon Sep 17 00:00:00 2001 From: abhinavgupta-hmrc <269448599+abhinavgupta-hmrc@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:30:41 +0100 Subject: [PATCH 5/6] DTR-5901 fix-merge issue resolved --- .../VerificationControllerSpec.scala | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala index 0eaba152..3a98744f 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala @@ -24,7 +24,7 @@ import play.api.test.Helpers.* import uk.gov.hmrc.formpproxy.actions.FakeAuthAction import uk.gov.hmrc.formpproxy.base.SpecBase import uk.gov.hmrc.formpproxy.cis.models.{ContractorScheme, CreateVerifications, DeleteVerifications, MonthlyReturn, Subcontractor, Submission, Verification, VerificationBatch} -import uk.gov.hmrc.formpproxy.cis.models.response.{CreateSubmissionAndUpdateVerificationsResponse, CreateVerificationBatchAndVerificationsResponse, GetCurrentVerificationBatchResponse, GetNewestVerificationBatchResponse, GetSubmittedVerificationsResponse, GetSubmissionWithVerificationBatchResponse} +import uk.gov.hmrc.formpproxy.cis.models.response.{CreateSubmissionAndUpdateVerificationsResponse, CreateVerificationBatchAndVerificationsResponse, GetCurrentVerificationBatchResponse, GetNewestVerificationBatchResponse, GetSubmissionWithVerificationBatchResponse, GetSubmittedVerificationsResponse} import uk.gov.hmrc.formpproxy.cis.models.requests.* import uk.gov.hmrc.formpproxy.cis.services.VerificationService @@ -981,50 +981,83 @@ class VerificationControllerSpec extends SpecBase { verify(mockService).getSubmittedVerifications(eqTo(requestModel)) verifyNoMoreInteractions(mockService) } - - "GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef (getSubmissionWithVerificationBatch)" - { - "returns 200 OK with JSON body when service succeeds" in { - val s = setup - import s.* + "GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef (getSubmissionWithVerificationBatch)" - { - val requestModel = GetSubmissionWithVerificationBatchRequest( - instanceId = "abc-123", - verificationBatchResourceRef = 77L - ) + "returns 200 OK with JSON body when service succeeds" in { + val s = setup + import s.* - val response = GetSubmissionWithVerificationBatchResponse( - scheme = None, - subcontractors = Seq.empty, - verifications = Seq.empty, - verificationBatch = None, - submission = None - ) + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) - when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) - .thenReturn(Future.successful(response)) + val response = GetSubmissionWithVerificationBatchResponse( + scheme = None, + subcontractors = Seq.empty, + verifications = Seq.empty, + verificationBatch = None, + submission = None + ) - val req = FakeRequest( - GET, - s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" - ) + when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) + .thenReturn(Future.successful(response)) - val result = - controller - .getSubmissionWithVerificationBatch( - instanceId = requestModel.instanceId, - verificationBatchResourceRef = requestModel.verificationBatchResourceRef - ) - .apply(req) + val req = FakeRequest( + GET, + s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" + ) - status(result) mustBe OK - contentType(result) mustBe Some(JSON) - contentAsJson(result) mustBe Json.toJson(response) + val result = + controller + .getSubmissionWithVerificationBatch( + instanceId = requestModel.instanceId, + verificationBatchResourceRef = requestModel.verificationBatchResourceRef + ) + .apply(req) + + status(result) mustBe OK + contentType(result) mustBe Some(JSON) + contentAsJson(result) mustBe Json.toJson(response) + + verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verifyNoMoreInteractions(mockService) + } + + "returns 500 InternalServerError with error body when service fails" in { + val s = setup + import s.* + + val requestModel = GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) - verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) - verifyNoMoreInteractions(mockService) - } + when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) + .thenReturn(Future.failed(new RuntimeException("boom"))) + + val req = FakeRequest( + GET, + s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" + ) + val result = + controller + .getSubmissionWithVerificationBatch( + instanceId = requestModel.instanceId, + verificationBatchResourceRef = requestModel.verificationBatchResourceRef + ) + .apply(req) + + status(result) mustBe INTERNAL_SERVER_ERROR + contentType(result) mustBe Some(JSON) + contentAsJson(result) mustBe Json.obj("message" -> "Unexpected error") + + verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verifyNoMoreInteractions(mockService) + } + } "returns 400 BadRequest with error payload when JSON is invalid" in { val s = setup import s.* @@ -1069,38 +1102,5 @@ class VerificationControllerSpec extends SpecBase { verify(mockService).getSubmittedVerifications(eqTo(requestModel)) verifyNoMoreInteractions(mockService) } - - "returns 500 InternalServerError with error body when service fails" in { - val s = setup - import s.* - - val requestModel = GetSubmissionWithVerificationBatchRequest( - instanceId = "abc-123", - verificationBatchResourceRef = 77L - ) - - when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) - .thenReturn(Future.failed(new RuntimeException("boom"))) - - val req = FakeRequest( - GET, - s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" - ) - - val result = - controller - .getSubmissionWithVerificationBatch( - instanceId = requestModel.instanceId, - verificationBatchResourceRef = requestModel.verificationBatchResourceRef - ) - .apply(req) - - status(result) mustBe INTERNAL_SERVER_ERROR - contentType(result) mustBe Some(JSON) - contentAsJson(result) mustBe Json.obj("message" -> "Unexpected error") - - verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) - verifyNoMoreInteractions(mockService) - } } } From abb1983bc2ad959d59996457b4d1e3717483cf66 Mon Sep 17 00:00:00 2001 From: abhinavgupta-hmrc <269448599+abhinavgupta-hmrc@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:45:14 +0100 Subject: [PATCH 6/6] DTR-5901 fix-code refactor post merge conflicts --- .../controllers/VerificationController.scala | 71 ++++++++------ .../cis/repositories/CisFormpRepository.scala | 29 ------ .../cis/services/VerificationService.scala | 5 - conf/app.routes | 2 +- .../VerificationControllerSpec.scala | 98 ++++++++----------- .../repositories/CisFormpRepositorySpec.scala | 3 +- 6 files changed, 84 insertions(+), 124 deletions(-) diff --git a/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala b/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala index 2efdf8b4..d821d4f1 100644 --- a/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala +++ b/app/uk/gov/hmrc/formpproxy/cis/controllers/VerificationController.scala @@ -18,7 +18,7 @@ package uk.gov.hmrc.formpproxy.cis.controllers import play.api.Logging import play.api.libs.json.{JsError, JsValue, Json} -import play.api.mvc.{Action, AnyContent, ControllerComponents} +import play.api.mvc.{Action, AnyContent, ControllerComponents, Result} import uk.gov.hmrc.formpproxy.actions.AuthAction import uk.gov.hmrc.formpproxy.cis.services.VerificationService import uk.gov.hmrc.play.bootstrap.backend.controller.BackendController @@ -26,6 +26,7 @@ import uk.gov.hmrc.formpproxy.cis.models.requests._ import javax.inject.Inject import scala.concurrent.{ExecutionContext, Future} +import scala.util.control.NonFatal class VerificationController @Inject() ( authorise: AuthAction, @@ -57,24 +58,6 @@ class VerificationController @Inject() ( } } - def getSubmissionWithVerificationBatch: Action[JsValue] = - Action(parse.json).async { implicit request => - request.body - .validate[GetSubmissionWithVerificationBatchRequest] - .fold( - errs => - Future.successful(BadRequest(Json.obj("message" -> "Invalid payload", "errors" -> JsError.toJson(errs)))), - req => - service - .getSubmissionWithVerificationBatch(req) - .map(res => Ok(Json.toJson(res))) - .recover { case t => - logger.error("[getSubmissionWithVerificationBatch] failed", t) - InternalServerError(Json.obj("message" -> "Unexpected error")) - } - ) - } - def createVerificationBatchAndVerifications(): Action[JsValue] = authorise(parse.json).async { implicit request => request.body @@ -164,30 +147,54 @@ class VerificationController @Inject() ( } ) } - def getSubmissionWithVerificationBatch( + def getSubmissionWithVerificationBatchByRefs( instanceId: String, verificationBatchResourceRef: Long ): Action[AnyContent] = authorise.async { implicit request => - val getSubmissionWithVerificationBatchRequest = + handleGetSubmissionWithVerificationBatch( GetSubmissionWithVerificationBatchRequest( instanceId = instanceId, verificationBatchResourceRef = verificationBatchResourceRef ) + ) + } - service - .getSubmissionWithVerificationBatch(getSubmissionWithVerificationBatchRequest) - .map(res => Ok(Json.toJson(res))) - .recover { case t => - logger.error( - s"[getSubmissionWithVerificationBatch] failed for instanceId=$instanceId, verificationBatchResourceRef=$verificationBatchResourceRef", - t - ) - - InternalServerError(Json.obj("message" -> "Unexpected error")) - } + def getSubmissionWithVerificationBatch: Action[JsValue] = + Action(parse.json).async { implicit request => + request.body + .validate[GetSubmissionWithVerificationBatchRequest] + .fold( + errors => + Future.successful( + BadRequest( + Json.obj( + "message" -> "Invalid payload", + "errors" -> JsError.toJson(errors) + ) + ) + ), + handleGetSubmissionWithVerificationBatch + ) } + private def handleGetSubmissionWithVerificationBatch( + request: GetSubmissionWithVerificationBatchRequest + ): Future[Result] = + service + .getSubmissionWithVerificationBatch(request) + .map(response => Ok(Json.toJson(response))) + .recover { case NonFatal(exception) => + logger.error( + s"[VerificationController][getSubmissionWithVerificationBatch] failed for " + + s"instanceId=${request.instanceId}, " + + s"verificationBatchResourceRef=${request.verificationBatchResourceRef}", + exception + ) + + InternalServerError(Json.obj("message" -> "Unexpected error")) + } + def getSubmittedVerifications(): Action[JsValue] = authorise(parse.json).async { implicit request => request.body diff --git a/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala b/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala index eae809b8..1dfe751c 100644 --- a/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala +++ b/app/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepository.scala @@ -69,9 +69,6 @@ trait CisMonthlyReturnSource { def createGovTalkStatusRecord(req: CreateGovTalkStatusRecordRequest): Future[Unit] def getNewestVerificationBatch(instanceId: String): Future[GetNewestVerificationBatchResponse] def getCurrentVerificationBatch(instanceId: String): Future[GetCurrentVerificationBatchResponse] - def getSubmissionWithVerificationBatch( - request: GetSubmissionWithVerificationBatchRequest - ): Future[GetSubmissionWithVerificationBatchResponse] def deleteUnsubmittedMonthlyReturn(req: DeleteUnsubmittedMonthlyReturnRequest): Future[Unit] def getMonthlyReturnComplete( instanceId: String, @@ -1249,32 +1246,6 @@ class CisFormpRepository @Inject() (@NamedDatabase("cis") db: Database)(implicit } } } - override def getSubmissionWithVerificationBatch( - request: GetSubmissionWithVerificationBatchRequest - ): Future[GetSubmissionWithVerificationBatchResponse] = { - logger.info( - s"[CIS] getSubmissionWithVerificationBatch(instanceId=${request.instanceId}, verificationBatchResourceRef=${request.verificationBatchResourceRef})" - ) - - Future { - db.withConnection { conn => - val result = - callGetSubmissionWithVerificationBatch( - conn, - request.instanceId, - request.verificationBatchResourceRef - ) - - GetSubmissionWithVerificationBatchResponse( - scheme = result.scheme, - subcontractors = result.subcontractors, - verifications = result.verifications, - verificationBatch = result.verificationBatch, - submission = result.submission - ) - } - } - } override def createVerificationBatchAndVerifications( req: CreateVerificationBatchAndVerificationsRequest diff --git a/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala b/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala index a35b0246..f71c42c3 100644 --- a/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala +++ b/app/uk/gov/hmrc/formpproxy/cis/services/VerificationService.scala @@ -27,11 +27,6 @@ import scala.concurrent.Future @Singleton class VerificationService @Inject() (repo: CisMonthlyReturnSource) { - def getSubmissionWithVerificationBatch( - request: GetSubmissionWithVerificationBatchRequest - ): Future[GetSubmissionWithVerificationBatchResponse] = - repo.getSubmissionWithVerificationBatch(request) - def getNewestVerificationBatch(instanceId: String): Future[GetNewestVerificationBatchResponse] = repo.getNewestVerificationBatch(instanceId) diff --git a/conf/app.routes b/conf/app.routes index 17f7d704..2b20840b 100644 --- a/conf/app.routes +++ b/conf/app.routes @@ -52,7 +52,7 @@ POST /cis/amend-monthly-return/create uk.gov.hmrc. POST /cis/verification/submission/create uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.createSubmissionAndUpdateVerifications() POST /cis/verification/submitted-verifications uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmittedVerifications() POST /cis/verification/submission/update uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.updateVerificationSubmission() -GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmissionWithVerificationBatch(instanceId: String, verificationBatchResourceRef: Long) +GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef uk.gov.hmrc.formpproxy.cis.controllers.VerificationController.getSubmissionWithVerificationBatchByRefs(instanceId: String, verificationBatchResourceRef: Long) GET /cis/batchpoll-submissions uk.gov.hmrc.formpproxy.cis.controllers.BatchPollController.getBatchPollSubmissions() diff --git a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala index 011d8984..d6c8731a 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/controllers/VerificationControllerSpec.scala @@ -1099,46 +1099,51 @@ class VerificationControllerSpec extends SpecBase { verifyNoMoreInteractions(mockService) } - "GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef (getSubmissionWithVerificationBatch)" - { + "GET /cis/verification/submission-batch/:instanceId/:verificationBatchResourceRef (getSubmissionWithVerificationBatchByRefs)" - { "returns 200 OK with JSON body when service succeeds" in { val s = setup import s.* - val requestModel = GetSubmissionWithVerificationBatchRequest( - instanceId = "abc-123", - verificationBatchResourceRef = 77L - ) + val requestModel = + GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) - val response = GetSubmissionWithVerificationBatchResponse( - scheme = None, - subcontractors = Seq.empty, - verifications = Seq.empty, - verificationBatch = None, - submission = None - ) + val responseModel = + GetSubmissionWithVerificationBatchResponse( + scheme = None, + subcontractors = Seq.empty, + verifications = Seq.empty, + verificationBatch = None, + submission = None + ) when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) - .thenReturn(Future.successful(response)) + .thenReturn(Future.successful(responseModel)) - val req = FakeRequest( - GET, - s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" - ) + val req = + FakeRequest( + GET, + s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" + ) val result = controller - .getSubmissionWithVerificationBatch( - instanceId = requestModel.instanceId, - verificationBatchResourceRef = requestModel.verificationBatchResourceRef + .getSubmissionWithVerificationBatchByRefs( + requestModel.instanceId, + requestModel.verificationBatchResourceRef ) .apply(req) status(result) mustBe OK contentType(result) mustBe Some(JSON) - contentAsJson(result) mustBe Json.toJson(response) + contentAsJson(result) mustBe Json.toJson(responseModel) + + verify(mockService) + .getSubmissionWithVerificationBatch(eqTo(requestModel)) - verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) verifyNoMoreInteractions(mockService) } @@ -1146,24 +1151,26 @@ class VerificationControllerSpec extends SpecBase { val s = setup import s.* - val requestModel = GetSubmissionWithVerificationBatchRequest( - instanceId = "abc-123", - verificationBatchResourceRef = 77L - ) + val requestModel = + GetSubmissionWithVerificationBatchRequest( + instanceId = "abc-123", + verificationBatchResourceRef = 77L + ) when(mockService.getSubmissionWithVerificationBatch(eqTo(requestModel))) .thenReturn(Future.failed(new RuntimeException("boom"))) - val req = FakeRequest( - GET, - s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" - ) + val req = + FakeRequest( + GET, + s"/cis/verification/submission-batch/${requestModel.instanceId}/${requestModel.verificationBatchResourceRef}" + ) val result = controller - .getSubmissionWithVerificationBatch( - instanceId = requestModel.instanceId, - verificationBatchResourceRef = requestModel.verificationBatchResourceRef + .getSubmissionWithVerificationBatchByRefs( + requestModel.instanceId, + requestModel.verificationBatchResourceRef ) .apply(req) @@ -1171,31 +1178,12 @@ class VerificationControllerSpec extends SpecBase { contentType(result) mustBe Some(JSON) contentAsJson(result) mustBe Json.obj("message" -> "Unexpected error") - verify(mockService).getSubmissionWithVerificationBatch(eqTo(requestModel)) + verify(mockService) + .getSubmissionWithVerificationBatch(eqTo(requestModel)) + verifyNoMoreInteractions(mockService) } } - "returns 400 BadRequest with error payload when JSON is invalid" in { - val s = setup - import s.* - - val badJson = Json.obj("wrong" -> "value") - - val req = FakeRequest(POST, url) - .withHeaders(CONTENT_TYPE -> JSON) - .withBody(badJson) - - val result = controller.getSubmittedVerifications().apply(req) - - status(result) mustBe BAD_REQUEST - contentType(result) mustBe Some(JSON) - - val body = contentAsJson(result) - (body \ "message").as[String] mustBe "Invalid payload" - (body \ "errors").isDefined mustBe true - - verifyNoInteractions(mockService) - } "returns 500 InternalServerError with error body when service fails" in { val s = setup diff --git a/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala b/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala index 2bd4b515..0df2d79a 100644 --- a/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala +++ b/test/uk/gov/hmrc/formpproxy/cis/repositories/CisFormpRepositorySpec.scala @@ -26,10 +26,9 @@ import play.api.db.Database import uk.gov.hmrc.formpproxy.base.SpecBase import uk.gov.hmrc.formpproxy.cis.models.* import uk.gov.hmrc.formpproxy.cis.models.requests.* -import uk.gov.hmrc.formpproxy.cis.repositories.CisStoredProcedures.CallDeleteSubcontractor import uk.gov.hmrc.formpproxy.cis.models.response.* +import uk.gov.hmrc.formpproxy.cis.repositories.CisStoredProcedures.CallDeleteSubcontractor import uk.gov.hmrc.formpproxy.shared.utils.CallableStatementUtils.* -import uk.gov.hmrc.formpproxy.cis.models.response.GetSubcontractorResponse import java.sql.* import java.time.{Instant, LocalDateTime}