Skip to content
8 changes: 7 additions & 1 deletion app/connectors/NationalDirectDebitConnector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package connectors

import models.NddResponse
import models.requests.{ChrisSubmissionRequest, GenerateDdiRefRequest, WorkingDaysOffsetRequest}
import models.responses.{EarliestPaymentDate, GenerateDdiRefResponse, NddDDPaymentPlansResponse, PaymentPlanResponse}
import models.responses.*
import play.api.Logging
import play.api.http.Status.OK
import play.api.libs.json.Json
Expand Down Expand Up @@ -106,4 +106,10 @@ class NationalDirectDebitConnector @Inject() (config: ServicesConfig, http: Http
.get(url"$nationalDirectDebitBaseUrl/direct-debits/$directDebitReference/payment-plans/$paymentPlanReference")(hc)
.execute[PaymentPlanResponse]
}

def lockPaymentPlan(directDebitReference: String, paymentPlanReference: String)(implicit hc: HeaderCarrier): Future[AmendLockResponse] = {
http
.put(url"$nationalDirectDebitBaseUrl/direct-debits/$directDebitReference/payment-plans/$paymentPlanReference/lock")(hc)
.execute[AmendLockResponse]
}
}
15 changes: 14 additions & 1 deletion app/controllers/AmendPaymentPlanConfirmationController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,20 @@ class AmendPaymentPlanConfirmationController @Inject() (
nddService.submitChrisData(chrisRequest).flatMap { success =>
if (success) {
logger.info(s"CHRIS submission successful for DDI Ref [$ddiReference]")
Future.successful(Redirect(routes.AmendPaymentPlanUpdateController.onPageLoad()))
for {
directDebitReference <- Future.fromTry(Try(ua.get(DirectDebitReferenceQuery).get))
paymentPlanReference <- Future.fromTry(Try(ua.get(PaymentPlanReferenceQuery).get))
lockResponse <- nddService.lockPaymentPlan(directDebitReference, paymentPlanReference)
} yield {
if (lockResponse.lockSuccessful) {
logger.info(s"Payment plan lock returns: ${lockResponse.lockSuccessful}")
println(s"Payment plan lock returns: ${lockResponse.lockSuccessful}")
} else {
logger.error(s"Payment plan lock returns: ${lockResponse.lockSuccessful}")
println(s"Payment plan lock returns: ${lockResponse.lockSuccessful}")
}
Redirect(routes.AmendPaymentPlanUpdateController.onPageLoad())
}
} else {
logger.error(s"CHRIS submission failed for DDI Ref [$ddiReference]")
Future.successful(
Expand Down
25 changes: 25 additions & 0 deletions app/models/responses/AmendLockResponse.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2025 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 models.responses

import play.api.libs.json.*

case class AmendLockResponse(lockSuccessful: Boolean)

object AmendLockResponse {
implicit val format: OFormat[AmendLockResponse] = Json.format
}
4 changes: 4 additions & 0 deletions app/services/NationalDirectDebitService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,8 @@ class NationalDirectDebitService @Inject() (nddConnector: NationalDirectDebitCon
nddConnector.getPaymentPlanDetails(directDebitReference, paymentPlanReference)
}

def lockPaymentPlan(directDebitReference: String, paymentPlanReference: String)(implicit hc: HeaderCarrier): Future[AmendLockResponse] = {
nddConnector.lockPaymentPlan(directDebitReference, paymentPlanReference)
}

}
54 changes: 40 additions & 14 deletions it/test/connectors/NationalDirectDebitConnectorSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import com.github.tomakehurst.wiremock.client.WireMock.*
import com.github.tomakehurst.wiremock.http.Fault
import itutil.ApplicationWithWiremock
import models.requests.{ChrisSubmissionRequest, GenerateDdiRefRequest, WorkingDaysOffsetRequest}
import models.responses.{BankAddress, Country, EarliestPaymentDate, GenerateDdiRefResponse}
import models.responses.*
import models.{DirectDebitSource, PaymentDateDetails, PaymentPlanType, PaymentsFrequency, PlanStartDateDetails, YourBankDetailsWithAuddisStatus}
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import org.scalatest.matchers.should.Matchers
Expand Down Expand Up @@ -287,28 +287,28 @@ class NationalDirectDebitConnectorSpec extends ApplicationWithWiremock with Matc
)

val submission = ChrisSubmissionRequest(
serviceType = DirectDebitSource.TC,
paymentPlanType = PaymentPlanType.TaxCreditRepaymentPlan,
serviceType = DirectDebitSource.TC,
paymentPlanType = PaymentPlanType.TaxCreditRepaymentPlan,
paymentPlanReferenceNumber = None,
paymentFrequency = Some(PaymentsFrequency.Monthly.toString),
paymentFrequency = Some(PaymentsFrequency.Monthly.toString),
yourBankDetailsWithAuddisStatus = YourBankDetailsWithAuddisStatus(
accountHolderName = "Test",
sortCode = "123456",
accountNumber = "12345678",
auddisStatus = false,
accountVerified = false
),
planStartDate = Some(planStartDateDetails),
planEndDate = None,
paymentDate = Some(paymentDateDetails),
yearEndAndMonth = None,
ddiReferenceNo = "DDI123456789",
paymentReference = "testReference",
totalAmountDue = Some(BigDecimal(200)),
paymentAmount = Some(BigDecimal(100.00)),
planStartDate = Some(planStartDateDetails),
planEndDate = None,
paymentDate = Some(paymentDateDetails),
yearEndAndMonth = None,
ddiReferenceNo = "DDI123456789",
paymentReference = "testReference",
totalAmountDue = Some(BigDecimal(200)),
paymentAmount = Some(BigDecimal(100.00)),
regularPaymentAmount = Some(BigDecimal(90.00)),
amendPaymentAmount = None,
calculation = None
amendPaymentAmount = None,
calculation = None
)

"successfully return true when CHRIS submission succeeds with 200 OK" in {
Expand Down Expand Up @@ -939,4 +939,30 @@ class NationalDirectDebitConnectorSpec extends ApplicationWithWiremock with Matc
result.paymentPlanDetails.hodService shouldBe DirectDebitSource.MGD.toString
}
}

"lockPaymentPlan" should {
"successfully lock payment plan" in {

val responseJson =
"""
|{
| "lockSuccessful": true
|}
""".stripMargin

stubFor(
put(urlEqualTo("/national-direct-debit/direct-debits/test-dd-ref/payment-plans/test-pp-ref/lock"))
.willReturn(
aResponse()
.withStatus(OK)
.withBody(responseJson)
)
)

val result = connector.lockPaymentPlan("test-dd-ref", "test-pp-ref").futureValue

result.lockSuccessful shouldBe true

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package controllers

import base.SpecBase
import models.responses.{DirectDebitDetails, PaymentPlanDetails, PaymentPlanResponse}
import models.responses.*
import models.{NormalMode, PaymentPlanType, UserAnswers}
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.when
Expand Down Expand Up @@ -278,6 +278,8 @@ class AmendPaymentPlanConfirmationControllerSpec extends SpecBase with DirectDeb

when(mockNddService.submitChrisData(any())(any[HeaderCarrier]))
.thenReturn(Future.successful(true))
when(mockNddService.lockPaymentPlan(any(), any())(any[HeaderCarrier]))
.thenReturn(Future.successful(AmendLockResponse(lockSuccessful = true)))

val directDebitReference = "DDI123456789"

Expand Down
22 changes: 21 additions & 1 deletion test/services/NationalDirectDebitServiceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import connectors.NationalDirectDebitConnector
import controllers.routes
import models.DirectDebitSource.{MGD, SA, TC}
import models.PaymentPlanType.{BudgetPaymentPlan, TaxCreditRepaymentPlan, VariablePaymentPlan}
import models.responses.{EarliestPaymentDate, GenerateDdiRefResponse, NddDDPaymentPlansResponse}
import models.responses.{AmendLockResponse, EarliestPaymentDate, GenerateDdiRefResponse, NddDDPaymentPlansResponse}
import models.{DirectDebitSource, NddDetails, NddResponse, PaymentPlanType, YourBankDetailsWithAuddisStatus}
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.*
Expand Down Expand Up @@ -608,6 +608,26 @@ class NationalDirectDebitServiceSpec extends SpecBase with MockitoSugar with Dir
result.getMessage must include("error")
}
}

"lockPaymentPlan" - {
"must successfully return Ok" in {
when(mockConnector.lockPaymentPlan(any(), any())(any()))
.thenReturn(Future.successful(AmendLockResponse(lockSuccessful = true)))

val result = service.lockPaymentPlan("test-dd-ref", "test-pp-ref").futureValue

result mustBe AmendLockResponse(lockSuccessful = true)
}

"fail when the connector call fails" in {
when(mockConnector.lockPaymentPlan(any(), any())(any()))
.thenReturn(Future.failed(new Exception("bang")))

val result = intercept[Exception](service.lockPaymentPlan("test-dd-ref", "test-pp-ref").futureValue)

result.getMessage must include("bang")
}
}
}

}