Skip to content

Commit f5c7d7f

Browse files
PIN-4332 - Update of daily calls with the same value of the previous version is not allowed (#196)
1 parent 3c15b99 commit f5c7d7f

File tree

4 files changed

+72
-12
lines changed

4 files changed

+72
-12
lines changed

src/main/scala/it/pagopa/interop/purposeprocess/api/impl/PurposeApiServiceImpl.scala

+10
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ final case class PurposeApiServiceImpl(
211211
purposeUUID <- purposeId.toFutureUUID
212212
purpose <- purposeManagementService.getPurposeById(purposeUUID)
213213
_ <- assertOrganizationIsAConsumer(organizationId, purpose.consumerId)
214+
_ <- assertDailyCallsIsDifferentThanBefore(purpose, seed.dailyCalls)
214215
version <- purposeManagementService.createPurposeVersion(purposeUUID, seed.toManagement)
215216
published <- publish(organizationId, purpose, version.toPersistent)
216217
} yield published.toApi
@@ -734,6 +735,15 @@ final case class PurposeApiServiceImpl(
734735
else Future.failed(PurposeNotInDraftState(purpose.id))
735736
}
736737

738+
private def assertDailyCallsIsDifferentThanBefore(purpose: PersistentPurpose, dailyCalls: Int): Future[Unit] = {
739+
val ordering: Ordering[OffsetDateTime] = Ordering(Ordering.by[OffsetDateTime, Long](_.toEpochSecond).reverse)
740+
val previousDailyCalls = purpose.versions.sortBy(_.createdAt)(ordering).map(_.dailyCalls).headOption
741+
previousDailyCalls match {
742+
case Some(x) if x == dailyCalls => Future.failed(UnchangedDailyCalls(purpose.id))
743+
case _ => Future.successful(())
744+
}
745+
}
746+
737747
private def isRiskAnalysisFormValid(
738748
riskAnalysisForm: Option[RiskAnalysisForm],
739749
schemaOnlyValidation: Boolean = false

src/main/scala/it/pagopa/interop/purposeprocess/api/impl/ResponseHandlers.scala

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ object ResponseHandlers extends AkkaResponses {
7575
)(result: Try[T])(implicit contexts: Seq[(String, String)], logger: LoggerTakingImplicit[ContextFieldsToLog]): Route =
7676
result match {
7777
case Success(s) => success(s)
78+
case Failure(ex: UnchangedDailyCalls) => badRequest(ex, logMessage)
7879
case Failure(ex: OrganizationIsNotTheConsumer) => forbidden(ex, logMessage)
7980
case Failure(ex: PurposeNotFound) => notFound(ex, logMessage)
8081
case Failure(ex: PurposeVersionConflict) => conflict(ex, logMessage)

src/main/scala/it/pagopa/interop/purposeprocess/error/PurposeProcessErrors.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,6 @@ object PurposeProcessErrors {
9191
extends ComponentError("0026", s"EService ${eServiceId.toString} has not Receive mode")
9292
final case class RiskAnalysisNotFound(eServiceId: UUID, riskAnalysisId: UUID)
9393
extends ComponentError("0027", s"EService $eServiceId does not contain Risk Analysis $riskAnalysisId")
94-
94+
final case class UnchangedDailyCalls(purposeId: UUID)
95+
extends ComponentError("0028", s"Creation of new version without changing daily calls for purpose $purposeId")
9596
}

src/test/scala/it/pagopa/interop/purposeprocess/PurposeApiServiceSpec.scala

+59-11
Original file line numberDiff line numberDiff line change
@@ -2156,19 +2156,20 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
21562156
implicit val context: Seq[(String, String)] =
21572157
Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> consumerId.toString)
21582158

2159-
val version2_1 = SpecData.purposeVersion.copy(id = UUID.randomUUID(), state = Active, dailyCalls = 1000)
2159+
val version2_1 = SpecData.purposeVersion.copy(id = UUID.randomUUID(), state = Active, dailyCalls = 1002)
21602160
val purpose2 = SpecData.purpose.copy(eserviceId = eserviceId, consumerId = consumerId, versions = Seq(version2_1))
21612161

21622162
val path: String = "/here/there/foo/bar.pdf"
21632163
val document: PersistentPurposeVersionDocument =
21642164
PersistentPurposeVersionDocument(documentId, "application/pdf", path, SpecData.timestamp)
21652165

2166-
val version1_1 = SpecData.purposeVersion.copy(id = purposeVersionId1, state = Active)
2166+
val version1_1 = SpecData.purposeVersion.copy(id = purposeVersionId1, state = Active, dailyCalls = 1000)
21672167
val version1_2 = SpecData.purposeVersion.copy(
21682168
id = purposeVersionId2,
21692169
state = WaitingForApproval,
21702170
riskAnalysis = Some(document),
2171-
firstActivationAt = Some(SpecData.timestamp)
2171+
firstActivationAt = Some(SpecData.timestamp),
2172+
dailyCalls = 1001
21722173
)
21732174

21742175
val purpose =
@@ -2180,15 +2181,15 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
21802181
)
21812182

21822183
val purposes = Seq(purpose, purpose2)
2183-
val seed: PurposeVersionSeed = PurposeVersionSeed(dailyCalls = 1000)
2184+
val seed: PurposeVersionSeed = PurposeVersionSeed(dailyCalls = 2000)
21842185

21852186
val purposeVersion = PersistentPurposeVersion(
21862187
id = purposeVersionId3,
21872188
state = Active,
21882189
createdAt = SpecData.timestamp,
21892190
updatedAt = None,
21902191
expectedApprovalDate = None,
2191-
dailyCalls = seed.dailyCalls,
2192+
dailyCalls = 2000,
21922193
riskAnalysis = Some(document),
21932194
firstActivationAt = Some(SpecData.timestamp),
21942195
suspendedAt = None
@@ -2216,7 +2217,8 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
22162217
riskAnalysis = Some(
22172218
PurposeManagementDependency.PurposeVersionDocument(documentId, "application/pdf", path, SpecData.timestamp)
22182219
),
2219-
firstActivationAt = Some(SpecData.timestamp)
2220+
firstActivationAt = Some(SpecData.timestamp),
2221+
dailyCalls = 2000
22202222
)
22212223

22222224
mockVersionFirstActivation(purposeId, purposeVersionId3, eService.producerId, purpose.consumerId, updatedVersion)
@@ -2248,7 +2250,7 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
22482250
implicit val context: Seq[(String, String)] =
22492251
Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> consumerId.toString)
22502252

2251-
val version2_1 = SpecData.purposeVersion.copy(id = UUID.randomUUID(), state = Active, dailyCalls = 1000)
2253+
val version2_1 = SpecData.purposeVersion.copy(id = UUID.randomUUID(), state = Active, dailyCalls = 1002)
22522254
val purpose2 = SpecData.purpose.copy(eserviceId = eserviceId, consumerId = consumerId, versions = Seq(version2_1))
22532255

22542256
val path: String = "/here/there/foo/bar.pdf"
@@ -2260,7 +2262,8 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
22602262
id = purposeVersionId2,
22612263
state = WaitingForApproval,
22622264
riskAnalysis = Some(document),
2263-
firstActivationAt = Some(SpecData.timestamp)
2265+
firstActivationAt = Some(SpecData.timestamp),
2266+
dailyCalls = 1001
22642267
)
22652268

22662269
val purpose =
@@ -2272,15 +2275,15 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
22722275
)
22732276

22742277
val purposes = Seq(purpose, purpose2)
2275-
val seed: PurposeVersionSeed = PurposeVersionSeed(dailyCalls = 1000)
2278+
val seed: PurposeVersionSeed = PurposeVersionSeed(dailyCalls = 2000)
22762279

22772280
val purposeVersion = PersistentPurposeVersion(
22782281
id = purposeVersionId3,
22792282
state = WaitingForApproval,
22802283
createdAt = SpecData.timestamp,
22812284
updatedAt = None,
22822285
expectedApprovalDate = None,
2283-
dailyCalls = seed.dailyCalls,
2286+
dailyCalls = 2000,
22842287
riskAnalysis = None,
22852288
firstActivationAt = Some(SpecData.timestamp),
22862289
suspendedAt = None
@@ -2306,7 +2309,8 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
23062309
id = purposeVersionId3,
23072310
state = PurposeManagementDependency.PurposeVersionState.WAITING_FOR_APPROVAL,
23082311
riskAnalysis = None,
2309-
firstActivationAt = Some(SpecData.timestamp)
2312+
firstActivationAt = Some(SpecData.timestamp),
2313+
dailyCalls = 2000
23102314
)
23112315

23122316
val payload = PurposeManagementDependency.StateChangeDetails(
@@ -2325,7 +2329,51 @@ class PurposeApiServiceSpec extends AnyWordSpecLike with SpecHelper with Scalate
23252329
responseAs[PurposeVersion] shouldEqual expected
23262330
}
23272331
}
2332+
"fail in case of version with the same dailyCalls than previous version" in {
2333+
2334+
val consumerId = UUID.randomUUID()
2335+
val documentId = UUID.randomUUID()
2336+
val purposeId = UUID.randomUUID()
2337+
val purposeVersionId1 = UUID.randomUUID()
2338+
val purposeVersionId2 = UUID.randomUUID()
2339+
val eserviceId = UUID.randomUUID()
2340+
2341+
implicit val context: Seq[(String, String)] =
2342+
Seq("bearer" -> bearerToken, USER_ROLES -> "admin", ORGANIZATION_ID_CLAIM -> consumerId.toString)
2343+
2344+
val path: String = "/here/there/foo/bar.pdf"
2345+
val document: PersistentPurposeVersionDocument =
2346+
PersistentPurposeVersionDocument(documentId, "application/pdf", path, SpecData.timestamp)
2347+
2348+
val version1_1 = SpecData.purposeVersion.copy(id = purposeVersionId1, state = Draft, dailyCalls = 1000)
2349+
val version1_2 = SpecData.purposeVersion.copy(
2350+
id = purposeVersionId2,
2351+
state = WaitingForApproval,
2352+
riskAnalysis = Some(document),
2353+
firstActivationAt = None,
2354+
createdAt = SpecData.timestamp.plusDays(1),
2355+
dailyCalls = 1001
2356+
)
2357+
2358+
val purpose =
2359+
SpecData.purpose.copy(
2360+
id = purposeId,
2361+
versions = Seq(version1_1, version1_2),
2362+
consumerId = consumerId,
2363+
eserviceId = eserviceId
2364+
)
2365+
2366+
val seed: PurposeVersionSeed = PurposeVersionSeed(dailyCalls = 1001)
23282367

2368+
mockPurposeRetrieve(purposeId, purpose)
2369+
2370+
Get() ~> service.createPurposeVersion(purposeId.toString, seed) ~> check {
2371+
status shouldEqual StatusCodes.BadRequest
2372+
val problem = responseAs[Problem]
2373+
problem.status shouldBe StatusCodes.BadRequest.intValue
2374+
problem.errors.head.code shouldBe "012-0028"
2375+
}
2376+
}
23292377
"fail if Purpose does not exist" in {
23302378

23312379
val purposeId = UUID.randomUUID()

0 commit comments

Comments
 (0)