diff --git a/app/v1/models/response/penalties/PenaltiesResponse.scala b/app/v1/models/response/penalties/PenaltiesResponse.scala index 1b34f67d..683636f1 100644 --- a/app/v1/models/response/penalties/PenaltiesResponse.scala +++ b/app/v1/models/response/penalties/PenaltiesResponse.scala @@ -201,7 +201,7 @@ object LateSubmissionPenaltySummary { implicit val reads: Reads[LateSubmissionPenaltySummary] = ( (JsPath \ "activePenaltyPoints").read[BigDecimal] and (JsPath \ "inactivePenaltyPoints").read[Int] and - (JsPath \ "PoCAchievementDate").read[String] and + ((JsPath \ "PoCAchievementDate").read[String] orElse Reads.pure("9999-12-31")) and (JsPath \ "regimeThreshold").read[Int] and (JsPath \ "penaltyChargeAmount").read[BigDecimal] )(LateSubmissionPenaltySummary.apply _) @@ -230,8 +230,10 @@ case class LateSubmissionPenaltyDetails( object LateSubmissionPenaltyDetails { implicit val reads: Reads[LateSubmissionPenaltyDetails] = for { penaltyNumber <- (JsPath \ "penaltyNumber").read[String] - penaltyOrder <- (JsPath \ "penaltyOrder").read[String] - penaltyCategory <- (JsPath \ "penaltyCategory").read[LateSubmissionPenaltyCategoryDownstream].map(_.toUpstreamPenaltyCategory) + penaltyOrder <- (JsPath \ "penaltyOrder").read[String] orElse Reads.pure("NA") + penaltyCategory <- (JsPath \ "penaltyCategory").read[LateSubmissionPenaltyCategoryDownstream].map(_.toUpstreamPenaltyCategory) orElse + (Reads.pure(LateSubmissionPenaltyCategoryDownstream.`P`).map(_.toUpstreamPenaltyCategory)) + penaltyStatus <- (JsPath \ "penaltyStatus").read[LateSubmissionPenaltyStatusDownstream].map(_.toUpstreamPenaltyStatus) fAPIndicator <- (JsPath \ "FAPIndicator").readNullable[String] penaltyCreationDate <- (JsPath \ "penaltyCreationDate").read[String] @@ -277,7 +279,18 @@ case class LateSubmissions( ) object LateSubmissions { - implicit val format: OFormat[LateSubmissions] = Json.format[LateSubmissions] + + implicit val reads: Reads[LateSubmissions] = ( + (JsPath \ "lateSubmissionID").read[String] and + ((JsPath \ "taxReturnStatus").read[TaxReturnStatus] orElse Reads.pure(TaxReturnStatus.`Reversed`)) and + (JsPath \ "taxPeriodStartDate").readNullable[String] and + (JsPath \ "taxPeriodEndDate").readNullable[String] and + (JsPath \ "taxPeriodDueDate").readNullable[String] and + (JsPath \ "returnReceiptDate").readNullable[String] + )(LateSubmissions.apply _) + + implicit val writes: OWrites[LateSubmissions] = Json.writes[LateSubmissions] + } @@ -289,7 +302,8 @@ case class AppealInformation ( object AppealInformation { implicit val reads: Reads[AppealInformation] = ( (JsPath \ "appealStatus").read[AppealStatusDownstream].map(_.toUpstreamAppealStatus) and - (JsPath \ "appealLevel").read[AppealLevelDownstream].map(_.toUpstreamAppealLevel) + ((JsPath \ "appealLevel").read[AppealLevelDownstream].map(_.toUpstreamAppealLevel) orElse + (Reads.pure(AppealLevelDownstream.`01`).map(_.toUpstreamAppealLevel))) )(AppealInformation.apply _) implicit val writes: OWrites[AppealInformation] = Json.writes[AppealInformation] diff --git a/func/test/v1/endpoints/PenaltiesControllerISpec.scala b/func/test/v1/endpoints/PenaltiesControllerISpec.scala index 33c5302e..5e5f9a11 100644 --- a/func/test/v1/endpoints/PenaltiesControllerISpec.scala +++ b/func/test/v1/endpoints/PenaltiesControllerISpec.scala @@ -74,7 +74,7 @@ class PenaltiesControllerISpec extends IntegrationBaseSpec { "a valid request is made" must { - "return 200 and penalties data" in new Test { + "return 200 and penalties data (full)" in new Test { override def setupStubs(): StubMapping = { AuditStub.audit() @@ -87,6 +87,19 @@ class PenaltiesControllerISpec extends IntegrationBaseSpec { response.json shouldBe PenaltiesConstants.upstreamTestPenaltiesResponseJsonMax response.header("Content-Type") shouldBe Some("application/json") } + "return 200 and penalties data (min with new optional fields missing)" in new Test { + + override def setupStubs(): StubMapping = { + AuditStub.audit() + AuthStub.authorised() + PenaltiesStub.onSuccess(PenaltiesStub.GET, PenaltiesConstants.penaltiesURl(), OK, PenaltiesConstants.downstreamTestPenaltiesResponseJsonMissingFields) + } + + val response: WSResponse = await(request.get()) + response.status shouldBe OK + response.json shouldBe PenaltiesConstants.upstreamTestPenaltiesResponseJsonMissingField + response.header("Content-Type") shouldBe Some("application/json") + } } "an invalid request is made" must { diff --git a/test/v1/constants/PenaltiesConstants.scala b/test/v1/constants/PenaltiesConstants.scala index aad69dd7..7bb006a5 100644 --- a/test/v1/constants/PenaltiesConstants.scala +++ b/test/v1/constants/PenaltiesConstants.scala @@ -106,6 +106,38 @@ object PenaltiesConstants { ) } + def testlateSubmissionPenaltyDetailsMissingFields(testChargeRef: String): LateSubmissionPenaltyDetails = { + LateSubmissionPenaltyDetails( + penaltyNumber = "123", + penaltyOrder = "NA", + penaltyCategory = LateSubmissionPenaltyCategoryUpstream.`point`, + penaltyStatus = LateSubmissionPenaltyStatusUpstream.`active`, + frequencyAdjustmentPointIndicator = Some("123"), + penaltyCreationDate = "123", + penaltyExpiryDate = "123", + expiryReason = Some(ExpiryReasonUpstream.`appeal`), + communicationsDate = Some("123"), + lateSubmissions = Some(List(LateSubmissions( + lateSubmissionID = "123", + taxReturnStatus = TaxReturnStatus.`Reversed`, + taxPeriodStartDate = Some("123"), + taxPeriodEndDate = Some("2022-10-11"), + taxPeriodDueDate = Some("2022-10-11"), + returnReceiptDate = Some("2022-10-11") + ))), + appealInformation = Some(List( + AppealInformation( + appealStatus = AppealStatusUpstream.`under-appeal`, + appealLevel = AppealLevelUpstream.`statutory-review` + ) + )), + chargeReference = Some(testChargeRef), + chargeAmount = Some(123), + chargeOutstandingAmount = Some(123), + chargeDueDate = Some("2022-10-11") + ) + } + def testLatePaymentPenaltyDetails(testPrincipalChargeReference: String): LatePaymentPenaltyDetails = { LatePaymentPenaltyDetails( principalChargeReference = testPrincipalChargeReference, @@ -159,6 +191,20 @@ object PenaltiesConstants { ) ) + val testLateSubmissionPenaltyMissingFields: LateSubmissionPenalty = LateSubmissionPenalty( + summary = LateSubmissionPenaltySummary( + activePenaltyPoints = 2, + inactivePenaltyPoints = 2, + periodOfComplianceAchievement = "9999-12-31", + regimeThreshold = 2, + penaltyChargeAmount = 123 + ), + details = List( + testlateSubmissionPenaltyDetailsMissingFields("123"), + testlateSubmissionPenaltyDetailsMissingFields("1234") + ) + ) + val downstreamTestLateSubmissionDetailsJson: JsValue = { Json.parse( """|[{ @@ -231,6 +277,70 @@ object PenaltiesConstants { |""".stripMargin) } + val downstreamTestLateSubmissionDetailsJsonMissingFields: JsValue = { + Json.parse( + """|[{ + | "penaltyNumber":"123", + | "penaltyStatus":"ACTIVE", + | "FAPIndicator":"123", + | "penaltyCreationDate":"123", + | "triggeringProcess":"123", + | "penaltyExpiryDate":"123", + | "expiryReason": "APP", + | "communicationsDate":"123", + | "lateSubmissions":[ + | { + | "lateSubmissionID":"123", + | "taxPeriod":"123", + | "taxPeriodStartDate":"123", + | "taxPeriodEndDate":"2022-10-11", + | "taxPeriodDueDate":"2022-10-11", + | "returnReceiptDate":"2022-10-11" + | } + | ], + | "appealInformation":[ + | { + | "appealStatus":"A" + | } + | ], + | "chargeReference":"123", + | "chargeAmount":123, + | "chargeOutstandingAmount":123, + | "chargeDueDate":"2022-10-11" + | }, + | { + | "penaltyNumber":"123", + | "penaltyStatus":"ACTIVE", + | "FAPIndicator":"123", + | "penaltyCreationDate":"123", + | "triggeringProcess":"123", + | "penaltyExpiryDate":"123", + | "expiryReason":"APP", + | "communicationsDate":"123", + | "lateSubmissions":[ + | { + | "lateSubmissionID":"123", + | "taxPeriod":"123", + | "taxPeriodStartDate":"123", + | "taxPeriodEndDate":"2022-10-11", + | "taxPeriodDueDate":"2022-10-11", + | "returnReceiptDate":"2022-10-11" + | } + | ], + | "appealInformation":[ + | { + | "appealStatus":"A" + | } + | ], + | "chargeReference":"1234", + | "chargeAmount":123, + | "chargeOutstandingAmount":123, + | "chargeDueDate":"2022-10-11" + | } + | ] + |""".stripMargin) + } + val upstreamTestLateSubmissionDetailsJson: JsValue = { Json.parse( """|[{ @@ -300,6 +410,75 @@ object PenaltiesConstants { } + val upstreamTestLateSubmissionDetailsJsonMissingFields: JsValue = { + Json.parse( + """|[{ + | "penaltyNumber":"123", + | "penaltyOrder":"NA", + | "penaltyCategory":"point", + | "penaltyStatus":"active", + | "frequencyAdjustmentPointIndicator":"123", + | "penaltyCreationDate":"123", + | "penaltyExpiryDate":"123", + | "expiryReason": "appeal", + | "communicationsDate":"123", + | "lateSubmissions":[ + | { + | "lateSubmissionID":"123", + | "taxReturnStatus":"Reversed", + | "taxPeriodStartDate":"123", + | "taxPeriodEndDate":"2022-10-11", + | "taxPeriodDueDate":"2022-10-11", + | "returnReceiptDate":"2022-10-11" + | } + | ], + | "appealInformation":[ + | { + | "appealStatus":"under-appeal", + | "appealLevel":"statutory-review" + | } + | ], + | "chargeReference":"123", + | "chargeAmount":123, + | "chargeOutstandingAmount":123, + | "chargeDueDate":"2022-10-11" + | }, + | { + | "penaltyNumber":"123", + | "penaltyOrder":"NA", + | "penaltyCategory":"point", + | "penaltyStatus":"active", + | "frequencyAdjustmentPointIndicator":"123", + | "penaltyCreationDate":"123", + | "penaltyExpiryDate":"123", + | "expiryReason":"appeal", + | "communicationsDate":"123", + | "lateSubmissions":[ + | { + | "lateSubmissionID":"123", + | "taxReturnStatus":"Reversed", + | "taxPeriodStartDate":"123", + | "taxPeriodEndDate":"2022-10-11", + | "taxPeriodDueDate":"2022-10-11", + | "returnReceiptDate":"2022-10-11" + | } + | ], + | "appealInformation":[ + | { + | "appealStatus":"under-appeal", + | "appealLevel":"statutory-review" + | } + | ], + | "chargeReference":"1234", + | "chargeAmount":123, + | "chargeOutstandingAmount":123, + | "chargeDueDate":"2022-10-11" + | } + | ] + |""".stripMargin) + } + + val downstreamTestLatePaymentPenaltyDetailsJson: JsValue = { Json.parse( """ @@ -472,6 +651,14 @@ object PenaltiesConstants { "penaltyChargeAmount" -> 123 ) + val upstreamTestLateSubmissionPenaltySummaryJsonMissingFields: JsObject = Json.obj( + "activePenaltyPoints" -> 2, + "inactivePenaltyPoints" -> 2, + "periodOfComplianceAchievement" -> "9999-12-31", + "regimeThreshold" -> 2, + "penaltyChargeAmount" -> 123 + ) + val downstreamTestLateSubmissionPenaltySummaryJson: JsObject = Json.obj( "activePenaltyPoints" -> 2, "inactivePenaltyPoints" -> 2, @@ -480,6 +667,13 @@ object PenaltiesConstants { "penaltyChargeAmount" -> 123 ) + val downstreamTestLateSubmissionPenaltySummaryJsonMissingFields: JsObject = Json.obj( + "activePenaltyPoints" -> 2, + "inactivePenaltyPoints" -> 2, + "regimeThreshold" -> 2, + "penaltyChargeAmount" -> 123 + ) + val upstreamTestLatePaymentPenaltyJson: JsObject = Json.obj( "details" -> upstreamTestLatePaymentPenaltyDetailsJson ) @@ -493,11 +687,21 @@ object PenaltiesConstants { "details" -> downstreamTestLateSubmissionDetailsJson ) + val downstreamTestLateSubmissionPenaltyJsonMissingFields: JsObject = Json.obj( + "summary" -> downstreamTestLateSubmissionPenaltySummaryJsonMissingFields, + "details" -> downstreamTestLateSubmissionDetailsJsonMissingFields + ) + val upstreamTestLateSubmissionPenaltyJson: JsObject = Json.obj( "summary" -> upstreamTestLateSubmissionPenaltySummaryJson, "details" -> upstreamTestLateSubmissionDetailsJson ) + val upstreamTestLateSubmissionPenaltyJsonMissingFeilds: JsObject = Json.obj( + "summary" -> upstreamTestLateSubmissionPenaltySummaryJsonMissingFields, + "details" -> upstreamTestLateSubmissionDetailsJsonMissingFields + ) + val testPenaltiesResponseMax: PenaltiesResponse = PenaltiesResponse( totalisations = Some(testTotalisationMax), @@ -505,6 +709,12 @@ object PenaltiesConstants { latePaymentPenalty = Some(testLatePaymentPenalty) ) + val testPenaltiesResponseMissingFields: PenaltiesResponse = PenaltiesResponse( + totalisations = Some(testTotalisationMax), + lateSubmissionPenalty = Some(testLateSubmissionPenaltyMissingFields), + latePaymentPenalty = Some(testLatePaymentPenalty) + ) + val testPenaltiesResponseJsonMin: JsObject = Json.obj() val upstreamTestPenaltiesResponseJsonMax: JsObject = Json.obj( @@ -513,12 +723,24 @@ object PenaltiesConstants { "latePaymentPenalty" -> Some(upstreamTestLatePaymentPenaltyJson) ) + val upstreamTestPenaltiesResponseJsonMissingField: JsObject = Json.obj( + "totalisations" -> Some(upstreamTestPenaltiesTotalisationDataJsonMax), + "lateSubmissionPenalty" -> Some(upstreamTestLateSubmissionPenaltyJsonMissingFeilds), + "latePaymentPenalty" -> Some(upstreamTestLatePaymentPenaltyJson) + ) + val downstreamTestPenaltiesResponseJsonMax: JsObject = Json.obj( "totalisations" -> Some(downstreamTestPenaltiesTotalisationDataJsonMax), "lateSubmissionPenalty" -> Some(downstreamTestLateSubmissionPenaltyJson), "latePaymentPenalty" -> Some(downstreamTestLatePaymentPenaltyJson) ) + val downstreamTestPenaltiesResponseJsonMissingFields: JsObject = Json.obj( + "totalisations" -> Some(downstreamTestPenaltiesTotalisationDataJsonMax), + "lateSubmissionPenalty" -> Some(downstreamTestLateSubmissionPenaltyJsonMissingFields), + "latePaymentPenalty" -> Some(downstreamTestLatePaymentPenaltyJson) + ) + def wrappedPenaltiesResponse(penaltiesResponse: PenaltiesResponse = testPenaltiesResponseMin): ResponseWrapper[PenaltiesResponse] = { ResponseWrapper(correlationId, penaltiesResponse) } diff --git a/test/v1/models/response/penalties/PenaltiesResponseSpec.scala b/test/v1/models/response/penalties/PenaltiesResponseSpec.scala index 73b85c97..40ae5e28 100644 --- a/test/v1/models/response/penalties/PenaltiesResponseSpec.scala +++ b/test/v1/models/response/penalties/PenaltiesResponseSpec.scala @@ -24,22 +24,30 @@ class PenaltiesResponseSpec extends UnitSpec { "PenaltiesData" must { - "write data from json min" in { + "write data to json min" in { Json.toJson(testPenaltiesResponseMin) shouldBe testPenaltiesResponseJsonMin } - "read to json min" in { + "read from json min" in { testPenaltiesResponseJsonMin.as[PenaltiesResponse] shouldBe testPenaltiesResponseMin } - "write data from json max" in { + "write data to json max" in { Json.toJson(testPenaltiesResponseMax) shouldBe upstreamTestPenaltiesResponseJsonMax } - "read to json max" in { + "read from json max" in { downstreamTestPenaltiesResponseJsonMax.as[PenaltiesResponse] shouldBe testPenaltiesResponseMax } + + "write data to optional fields change json" in { + Json.toJson(testPenaltiesResponseMissingFields) shouldBe upstreamTestPenaltiesResponseJsonMissingField + } + + "read from optional fields change json" in { + downstreamTestPenaltiesResponseJsonMissingFields.as[PenaltiesResponse] shouldBe testPenaltiesResponseMissingFields + } } }