From 4b9438110a64c53bcdf5e962ef296eedd231bb06 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 9 Dec 2024 14:13:56 +0100 Subject: [PATCH 1/6] test/add the counterpartyLimit test --- .../scala/code/api/v4_0_0/APIMethods400.scala | 24 +- .../api/v5_1_0/CounterpartyLimitTest.scala | 238 +++++++++++- .../api/v5_1_0/VRPConsentRequestTest.scala | 364 +++++++++++++++++- 3 files changed, 583 insertions(+), 43 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index e55b2f25c0..96d27790d9 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -12526,23 +12526,23 @@ object APIMethods400 extends RestHelper with APIMethods400 { s"which is $currentTransactionAmountWithFxApplied ${fromAccount.currency}. ", cc = callContext) { maxSingleAmount >= currentTransactionAmountWithFxApplied } - _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_monthly_amount is $maxSingleAmount, but current monthly amount is ${sumOfTransactionsFromAccountToCounterpartyMonthly.amount}", cc = callContext) { - maxMonthlyAmount >= BigDecimal(sumOfTransactionsFromAccountToCounterpartyMonthly.amount) + _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_monthly_amount is $maxMonthlyAmount, but current monthly amount is ${BigDecimal(sumOfTransactionsFromAccountToCounterpartyMonthly.amount)+currentTransactionAmountWithFxApplied}", cc = callContext) { + maxMonthlyAmount >= BigDecimal(sumOfTransactionsFromAccountToCounterpartyMonthly.amount)+currentTransactionAmountWithFxApplied } - _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_monthly_transactions is $maxSingleAmount, but current count of monthly transactions is ${countOfTransactionsFromAccountToCounterpartyMonthly}", cc = callContext) { - maxNumberOfMonthlyTransactions >= countOfTransactionsFromAccountToCounterpartyMonthly + _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_monthly_transactions is $maxNumberOfMonthlyTransactions, but current count of monthly transactions is ${countOfTransactionsFromAccountToCounterpartyMonthly+1}", cc = callContext) { + maxNumberOfMonthlyTransactions >= countOfTransactionsFromAccountToCounterpartyMonthly+1 } - _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_yearly_amount is $maxYearlyAmount, but current yearly amount is ${sumOfTransactionsFromAccountToCounterpartyYearly.amount}", cc = callContext) { - maxYearlyAmount >= BigDecimal(sumOfTransactionsFromAccountToCounterpartyYearly.amount) + _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_yearly_amount is $maxYearlyAmount, but current yearly amount is ${BigDecimal(sumOfTransactionsFromAccountToCounterpartyYearly.amount)+currentTransactionAmountWithFxApplied}", cc = callContext) { + maxYearlyAmount >= BigDecimal(sumOfTransactionsFromAccountToCounterpartyYearly.amount)+currentTransactionAmountWithFxApplied } - result <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_yearly_transactions is $maxNumberOfYearlyTransactions, but current count of yearly transaction is ${countOfTransactionsFromAccountToCounterpartyYearly}", cc = callContext) { - maxNumberOfYearlyTransactions >= countOfTransactionsFromAccountToCounterpartyYearly + result <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_yearly_transactions is $maxNumberOfYearlyTransactions, but current count of yearly transaction is ${countOfTransactionsFromAccountToCounterpartyYearly+1}", cc = callContext) { + maxNumberOfYearlyTransactions >= countOfTransactionsFromAccountToCounterpartyYearly+1 } - _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_total_amount is $maxTotalAmount, but current amount is ${sumOfAllTransactionsFromAccountToCounterparty.amount}", cc = callContext) { - maxTotalAmount >= BigDecimal(sumOfAllTransactionsFromAccountToCounterparty.amount) + _ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_total_amount is $maxTotalAmount, but current amount is ${BigDecimal(sumOfAllTransactionsFromAccountToCounterparty.amount)+currentTransactionAmountWithFxApplied}", cc = callContext) { + maxTotalAmount >= BigDecimal(sumOfAllTransactionsFromAccountToCounterparty.amount)+currentTransactionAmountWithFxApplied } - result <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_transactions is $maxNumberOfTransactions, but current count of all transactions is ${countOfAllTransactionsFromAccountToCounterparty}", cc = callContext) { - maxNumberOfTransactions >= countOfAllTransactionsFromAccountToCounterparty + result <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_transactions is $maxNumberOfTransactions, but current count of all transactions is ${countOfAllTransactionsFromAccountToCounterparty+1}", cc = callContext) { + maxNumberOfTransactions >= countOfAllTransactionsFromAccountToCounterparty+1 } }yield{ result diff --git a/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala index 4824bd5e1b..796d0321b9 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala @@ -1,11 +1,13 @@ package code.api.v5_1_0 import java.util.UUID -import code.api.Constant.{SYSTEM_MANAGE_CUSTOM_VIEWS_VIEW_ID, SYSTEM_OWNER_VIEW_ID} +import code.api.Constant.{SYSTEM_OWNER_VIEW_ID} import code.api.util.ErrorMessages._ import code.api.util.APIUtil.OAuth._ +import code.api.v2_1_0.{CounterpartyIdJson, TransactionRequestBodyCounterpartyJSON} +import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0 import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0 import com.github.dwickern.macros.NameOf.nameOf -import com.openbankproject.commons.model.ErrorMessage +import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage} import com.openbankproject.commons.util.ApiVersion import net.liftweb.json.Serialization.write import org.scalatest.Tag @@ -23,12 +25,22 @@ class CounterpartyLimitTest extends V510ServerSetup { object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.getCounterpartyLimit)) object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.updateCounterpartyLimit)) object ApiEndpoint4 extends Tag(nameOf(Implementations5_1_0.deleteCounterpartyLimit)) + object ApiEndpoint5 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestCounterparty)) val bankId = testBankId1.value val accountId = testAccountId1.value val ownerView = SYSTEM_OWNER_VIEW_ID - val postCounterpartyLimitV510 = code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.postCounterpartyLimitV510 + val postCounterpartyLimitTestMonthly = PostCounterpartyLimitV510( + currency = "EUR", + max_single_amount = "10.0", // if I transfer 11 euros, then we trigger this guard. + max_monthly_amount = "11.0", // if I transfer 10, then transfer 20, --> we trigger this guard. + max_number_of_monthly_transactions = 2, //if I transfer 10, then transfer 2, then transfer 3 --> we can trigger this guard. + max_yearly_amount = "30.0", // + max_number_of_yearly_transactions = 5, + max_total_amount = "50.0", // + max_number_of_transactions = 6 + ) val putCounterpartyLimitV510 = PostCounterpartyLimitV510( currency = "EUR", max_single_amount = "1.1", @@ -39,7 +51,27 @@ class CounterpartyLimitTest extends V510ServerSetup { max_total_amount="6.1", max_number_of_transactions=7, ) - + val postCounterpartyLimitTestYearly = PostCounterpartyLimitV510( + currency = "EUR", + max_single_amount = "100", + max_monthly_amount = "200", + max_number_of_monthly_transactions = 20, + max_yearly_amount = "11", //if I transfer 11 euros, then we trigger this guard. + max_number_of_yearly_transactions = 2,//if I transfer 1, then transfer 2, then transfer 3 --> we can trigger this guard. + max_total_amount = "50", + max_number_of_transactions = 20 + ) + + val postCounterpartyLimitTestTotal = PostCounterpartyLimitV510( + currency = "EUR", + max_single_amount = "100", + max_monthly_amount = "200", + max_number_of_monthly_transactions = 20, + max_yearly_amount = "100", + max_number_of_yearly_transactions = 20, + max_total_amount = "11", //if I transfer 5 euros, then transfer 10 --> we can trigger this guard. + max_number_of_transactions = 2//if I transfer 1, then transfer 2, then transfer 3 --> we can trigger this guard. + ) feature(s"test $ApiEndpoint1,$ApiEndpoint2, $ApiEndpoint3, $ApiEndpoint4, Authorized access") { @@ -48,7 +80,7 @@ class CounterpartyLimitTest extends V510ServerSetup { When("We make a request v5.1.0") val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / "views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").POST - val response510 = makePostRequest(request510, write(postCounterpartyLimitV510)) + val response510 = makePostRequest(request510, write(postCounterpartyLimitTestMonthly)) Then("We should get a 401") response510.code should equal(401) response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn) @@ -56,7 +88,7 @@ class CounterpartyLimitTest extends V510ServerSetup { { val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId /"views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").PUT - val response510 = makePutRequest(request510, write(postCounterpartyLimitV510)) + val response510 = makePutRequest(request510, write(postCounterpartyLimitTestMonthly)) Then("We should get a 401") response510.code should equal(401) response510.body.extract[ErrorMessage].message should equal(UserNotLoggedIn) @@ -85,25 +117,25 @@ class CounterpartyLimitTest extends V510ServerSetup { When("We make a request v5.1.0") val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / "views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").POST <@ (user1) - val response510 = makePostRequest(request510, write(postCounterpartyLimitV510)) + val response510 = makePostRequest(request510, write(postCounterpartyLimitTestMonthly)) Then("We should get a 201") response510.code should equal(201) - response510.body.extract[CounterpartyLimitV510].max_monthly_amount should equal(postCounterpartyLimitV510.max_monthly_amount) - response510.body.extract[CounterpartyLimitV510].max_number_of_monthly_transactions should equal(postCounterpartyLimitV510.max_number_of_monthly_transactions) - response510.body.extract[CounterpartyLimitV510].max_number_of_yearly_transactions should equal(postCounterpartyLimitV510.max_number_of_yearly_transactions) - response510.body.extract[CounterpartyLimitV510].max_single_amount should equal(postCounterpartyLimitV510.max_single_amount) - response510.body.extract[CounterpartyLimitV510].max_yearly_amount should equal(postCounterpartyLimitV510.max_yearly_amount) + response510.body.extract[CounterpartyLimitV510].max_monthly_amount should equal(postCounterpartyLimitTestMonthly.max_monthly_amount) + response510.body.extract[CounterpartyLimitV510].max_number_of_monthly_transactions should equal(postCounterpartyLimitTestMonthly.max_number_of_monthly_transactions) + response510.body.extract[CounterpartyLimitV510].max_number_of_yearly_transactions should equal(postCounterpartyLimitTestMonthly.max_number_of_yearly_transactions) + response510.body.extract[CounterpartyLimitV510].max_single_amount should equal(postCounterpartyLimitTestMonthly.max_single_amount) + response510.body.extract[CounterpartyLimitV510].max_yearly_amount should equal(postCounterpartyLimitTestMonthly.max_yearly_amount) { val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId /"views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").GET<@ (user1) val response510 = makeGetRequest(request510) Then("We should get a 200") response510.code should equal(200) - response510.body.extract[CounterpartyLimitV510].max_monthly_amount should equal(postCounterpartyLimitV510.max_monthly_amount) - response510.body.extract[CounterpartyLimitV510].max_number_of_monthly_transactions should equal(postCounterpartyLimitV510.max_number_of_monthly_transactions) - response510.body.extract[CounterpartyLimitV510].max_number_of_yearly_transactions should equal(postCounterpartyLimitV510.max_number_of_yearly_transactions) - response510.body.extract[CounterpartyLimitV510].max_single_amount should equal(postCounterpartyLimitV510.max_single_amount) - response510.body.extract[CounterpartyLimitV510].max_yearly_amount should equal(postCounterpartyLimitV510.max_yearly_amount) + response510.body.extract[CounterpartyLimitV510].max_monthly_amount should equal(postCounterpartyLimitTestMonthly.max_monthly_amount) + response510.body.extract[CounterpartyLimitV510].max_number_of_monthly_transactions should equal(postCounterpartyLimitTestMonthly.max_number_of_monthly_transactions) + response510.body.extract[CounterpartyLimitV510].max_number_of_yearly_transactions should equal(postCounterpartyLimitTestMonthly.max_number_of_yearly_transactions) + response510.body.extract[CounterpartyLimitV510].max_single_amount should equal(postCounterpartyLimitTestMonthly.max_single_amount) + response510.body.extract[CounterpartyLimitV510].max_yearly_amount should equal(postCounterpartyLimitTestMonthly.max_yearly_amount) } @@ -149,7 +181,7 @@ class CounterpartyLimitTest extends V510ServerSetup { When("We make a request v5.1.0") val request510 = (v5_1_0_Request / "banks" / "wrongId" / "accounts" / accountId / "views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").POST <@ (user1) - val response510 = makePostRequest(request510, write(postCounterpartyLimitV510)) + val response510 = makePostRequest(request510, write(postCounterpartyLimitTestMonthly)) Then("We should get a 404") response510.code should equal(404) response510.body.extract[ErrorMessage].message contains(BankNotFound) shouldBe (true) @@ -188,5 +220,175 @@ class CounterpartyLimitTest extends V510ServerSetup { response510.body.extract[ErrorMessage].message contains(BankNotFound) shouldBe (true) } } + + scenario("We will create consent properly, and test the counterparty limit - monthly guard", ApiEndpoint1, ApiEndpoint4, VersionOfApi) { + When(s"We try $ApiEndpoint1 v5.1.0") + val counterparty = createCounterparty(bankId, accountId, accountId, true, UUID.randomUUID.toString); + + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / "views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").POST <@ (user1) + val response510 = makePostRequest(request510, write(postCounterpartyLimitTestMonthly)) + Then("We should get a 201") + response510.code should equal(201) + + Then("We can test the COUNTERPARTY payment limit") + + val createTransReqRequest = (v4_0_0_Request / "banks" / bankId / "accounts" / accountId / + ownerView / "transaction-request-types" / "COUNTERPARTY" / "transaction-requests").POST <@ (user1) + + val transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON( + to = CounterpartyIdJson(counterparty.counterpartyId), + value = AmountOfMoneyJsonV121("EUR","11"), + description ="testing the limit", + charge_policy = "SHARED", + future_date = None + ) + + val response = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty)) + + response.code shouldBe(400) + response.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response.body.extract[ErrorMessage].message contains("max_single_amount") shouldBe(true) + + //("we try the max_monthly_amount limit (11 euros) . now we transfer 9 euro first. then 9 euros, we will get the error") + val response1 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","3"))) + ) + response1.code shouldBe(201) + val response2 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","9"))) + ) + + response2.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response2.body.extract[ErrorMessage].message contains("max_monthly_amount") shouldBe(true) + + //("we try the max_number_of_monthly_transactions limit (2 times), we try the 3rd request, we will get the error. response2 failed, so does not count in database.") + val response3 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))) + ) + response3.code shouldBe(201) + + val response4 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))) + ) + response4.code shouldBe(400) + + response4.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response4.body.extract[ErrorMessage].message contains("max_number_of_monthly_transactions") shouldBe(true) + + } + + scenario("We will create consent properly, and test the counterparty limit - yearly guard", ApiEndpoint1, ApiEndpoint4, VersionOfApi) { + When(s"We try $ApiEndpoint1 v5.1.0") + val counterparty = createCounterparty(bankId, accountId, accountId, true, UUID.randomUUID.toString); + + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / "views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").POST <@ (user1) + val response510 = makePostRequest(request510, write(postCounterpartyLimitTestYearly)) + Then("We should get a 201") + response510.code should equal(201) + + Then("We can test the COUNTERPARTY payment limit") + + val createTransReqRequest = (v4_0_0_Request / "banks" / bankId / "accounts" / accountId / + ownerView / "transaction-request-types" / "COUNTERPARTY" / "transaction-requests").POST <@ (user1) + + val transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON( + to = CounterpartyIdJson(counterparty.counterpartyId), + value = AmountOfMoneyJsonV121("EUR","11"), + description ="testing the limit", + charge_policy = "SHARED", + future_date = None + ) + + val response1 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","3"))) + ) + response1.code shouldBe(201) + val response2 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","9"))) + ) + response2.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response2.body.extract[ErrorMessage].message contains("max_yearly_amount") shouldBe(true) + + //("we try the max_number_of_monthly_transactions limit (2 times), we try the 3rd request, we will get the error. response2 failed, so does not count in database.") + val response3 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))) + ) + response3.code shouldBe(201) + + val response4 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))) + ) + response4.code shouldBe(400) + + response4.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response4.body.extract[ErrorMessage].message contains("max_number_of_yearly_transactions") shouldBe(true) + + } + + scenario("We will create consent properly, and test the counterparty limit - total guard", ApiEndpoint1, ApiEndpoint4, VersionOfApi) { + When(s"We try $ApiEndpoint1 v5.1.0") + val counterparty = createCounterparty(bankId, accountId, accountId, true, UUID.randomUUID.toString); + + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / "views" / ownerView /"counterparties" / counterparty.counterpartyId /"limits").POST <@ (user1) + val response510 = makePostRequest(request510, write(postCounterpartyLimitTestTotal)) + Then("We should get a 201") + response510.code should equal(201) + + Then("We can test the COUNTERPARTY payment limit") + + val createTransReqRequest = (v4_0_0_Request / "banks" / bankId / "accounts" / accountId / + ownerView / "transaction-request-types" / "COUNTERPARTY" / "transaction-requests").POST <@ (user1) + + val transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON( + to = CounterpartyIdJson(counterparty.counterpartyId), + value = AmountOfMoneyJsonV121("EUR","11"), + description ="testing the limit", + charge_policy = "SHARED", + future_date = None + ) + + //("we try the max_monthly_amount limit (11 euros) . now we transfer 9 euro first. then 9 euros, we will get the error") + val response1 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","3"))) + ) + response1.code shouldBe(201) + val response2 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","9"))) + ) + + response2.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response2.body.extract[ErrorMessage].message contains("max_total_amount") shouldBe(true) + + //("we try the max_number_of_monthly_transactions limit (2 times), we try the 3rd request, we will get the error. response2 failed, so does not count in database.") + val response3 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))) + ) + response3.code shouldBe(201) + + val response4 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))) + ) + response4.code shouldBe(400) + + response4.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response4.body.extract[ErrorMessage].message contains("max_number_of_transactions") shouldBe(true) + + } + } } diff --git a/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala index 4c548a674f..480c27f688 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/VRPConsentRequestTest.scala @@ -33,9 +33,12 @@ import code.api.util.ApiRole._ import code.api.util.Consent import code.api.util.ErrorMessages._ import code.api.util.ExampleValue.counterpartyNameExample +import code.api.v2_1_0.{CounterpartyIdJson, TransactionRequestBodyCounterpartyJSON} +import code.api.v3_0_0.CoreAccountsJsonV300 +import code.api.v3_0_0.OBPAPI3_0_0.Implementations3_0_0 import code.api.v3_1_0.PostConsentChallengeJsonV310 import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0 -import code.api.v4_0_0.UsersJsonV400 +import code.api.v4_0_0.{TransactionRequestWithChargeJSON400, UsersJsonV400} import code.api.v5_0_0.ConsentRequestResponseJson import code.api.v5_0_0.OBPAPI5_0_0.Implementations5_0_0 import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0 @@ -43,7 +46,7 @@ import code.consent.ConsentStatus import code.entitlement.Entitlement import code.setup.PropsReset import com.github.dwickern.macros.NameOf.nameOf -import com.openbankproject.commons.model.ErrorMessage +import com.openbankproject.commons.model.{AmountOfMoneyJsonV121, ErrorMessage} import com.openbankproject.commons.util.ApiVersion import net.liftweb.json.Serialization.write import org.scalatest.Tag @@ -65,8 +68,9 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ object ApiEndpoint2 extends Tag(nameOf(Implementations5_0_0.getConsentByConsentRequestId)) object ApiEndpoint3 extends Tag(nameOf(Implementations5_0_0.createConsentByConsentRequestId)) object ApiEndpoint4 extends Tag(nameOf(Implementations5_0_0.getConsentByConsentRequestId)) - object ApiEndpoint5 extends Tag(nameOf(Implementations4_0_0.getUsers)) + object ApiEndpoint5 extends Tag(nameOf(Implementations3_0_0.corePrivateAccountsAllBanks)) object ApiEndpoint6 extends Tag(nameOf(Implementations5_0_0.getConsentRequest)) + object ApiEndpoint7 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestCounterparty)) @@ -84,23 +88,64 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ branch_routing = branchRoutingJsonV141 ) + val postCounterpartyLimitTestMonthly = PostCounterpartyLimitV510( + currency = "EUR", + max_single_amount = "10", // if I transfer 11 euros, then we trigger this guard. + max_monthly_amount = "11", // if I transfer 10, then transfer 20, --> we trigger this guard. + max_number_of_monthly_transactions = 2, //if I transfer 10, then transfer 2, then transfer 3 --> we can trigger this guard. + max_yearly_amount = "30", // + max_number_of_yearly_transactions = 5, + max_total_amount = "50", // + max_number_of_transactions = 6 + ) + + val postCounterpartyLimitTestYearly = PostCounterpartyLimitV510( + currency = "EUR", + max_single_amount = "100", + max_monthly_amount = "200", + max_number_of_monthly_transactions = 20, + max_yearly_amount = "11", //if I transfer 11 euros, then we trigger this guard. + max_number_of_yearly_transactions = 2,//if I transfer 1, then transfer 2, then transfer 3 --> we can trigger this guard. + max_total_amount = "50", + max_number_of_transactions = 20 + ) + + val postCounterpartyLimitTestTotal = PostCounterpartyLimitV510( + currency = "EUR", + max_single_amount = "100", + max_monthly_amount = "200", + max_number_of_monthly_transactions = 20, + max_yearly_amount = "100", + max_number_of_yearly_transactions = 20, + max_total_amount = "11", //if I transfer 5 euros, then transfer 10 --> we can trigger this guard. + max_number_of_transactions = 2//if I transfer 1, then transfer 2, then transfer 3 --> we can trigger this guard. + ) + val toAccountJson = ConsentRequestToAccountJson ( counterparty_name = counterpartyNameExample.value, bank_routing = bankRoutingJsonV121.copy(address = testBankId1.value), account_routing = accountRoutingJsonV121.copy(address = testAccountId1.value), branch_routing = branchRoutingJsonV141, - limit = postCounterpartyLimitV510 + limit = postCounterpartyLimitTestMonthly + ) + lazy val postVRPConsentRequestMonthlyGuardJson = SwaggerDefinitionsJSON.postVRPConsentRequestJsonV510.copy( + from_account=fromAccountJson, + to_account=toAccountJson.copy(limit= postCounterpartyLimitTestMonthly) ) - lazy val postVRPConsentRequestJson = SwaggerDefinitionsJSON.postVRPConsentRequestJsonV510.copy( + lazy val postVRPConsentRequestYearlyGuardJson = SwaggerDefinitionsJSON.postVRPConsentRequestJsonV510.copy( from_account=fromAccountJson, - to_account=toAccountJson + to_account=toAccountJson.copy(limit= postCounterpartyLimitTestYearly) + ) + lazy val postVRPConsentRequestTotalGuardJson = SwaggerDefinitionsJSON.postVRPConsentRequestJsonV510.copy( + from_account=fromAccountJson, + to_account=toAccountJson.copy(limit= postCounterpartyLimitTestTotal) ) feature("Create/Get Consent Request v5.1.0") { scenario("We will call the Create endpoint without a user credentials", ApiEndpoint1, VersionOfApi) { When("We make a request v5.1.0") - val response510 = makePostRequest(createVRPConsentRequestWithoutLoginUrl, write(postVRPConsentRequestJson)) + val response510 = makePostRequest(createVRPConsentRequestWithoutLoginUrl, write(postVRPConsentRequestMonthlyGuardJson)) Then("We should get a 401") response510.code should equal(401) response510.body.extract[ErrorMessage].message should equal (ApplicationNotIdentified) @@ -108,7 +153,7 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ scenario("We will call the Create, Get and Delete endpoints with user credentials ", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, VersionOfApi) { When(s"We try $ApiEndpoint1 v5.1.0") - val createConsentResponse = makePostRequest(createVRPConsentRequestUrl, write(postVRPConsentRequestJson)) + val createConsentResponse = makePostRequest(createVRPConsentRequestUrl, write(postVRPConsentRequestMonthlyGuardJson)) Then("We should get a 201") createConsentResponse.code should equal(201) val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson] @@ -136,7 +181,7 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ accountAccess.get.view_id contains("_vrp-") shouldBe( true) setPropsValues("consumer_validation_method_for_consent"->"NONE") - val requestWhichFails = (v5_1_0_Request / "users").GET + val requestWhichFails = (v5_1_0_Request / "my"/ "accounts").GET val responseWhichFails = makeGetRequest(requestWhichFails, List((s"Consent-JWT", consentJwt))) Then("We get 401 error") responseWhichFails.code should equal(401) @@ -159,13 +204,36 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ getConsentByRequestResponseJson.status should be(ConsentStatus.ACCEPTED.toString) - val requestGetUsers = (v5_1_0_Request / "users").GET + val requestGetMyAccounts = (v5_1_0_Request / "my"/ "accounts").GET + val responseGetMyAccounts = makeGetRequest(requestGetMyAccounts, List((s"Consent-JWT", consentJwt))) + Then("We get 200 and proper response") + responseGetMyAccounts.code should equal(200) + responseGetMyAccounts.body.extract[CoreAccountsJsonV300].accounts.length > 0 shouldBe(true) - } + Then("We can test the COUNTERPARTY payment limit") + val consentRequestBankId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.bank_id + val consentRequestAccountId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.account_id + val consentRequestViewId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.view_id + val consentRequestCounterpartyId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.helper_info.counterparty_id + + val createTransReqRequest = (v4_0_0_Request / "banks" / consentRequestBankId / "accounts" / consentRequestAccountId / + consentRequestViewId / "transaction-request-types" / "COUNTERPARTY" / "transaction-requests").POST + val transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON( + to = CounterpartyIdJson(consentRequestCounterpartyId.head), + value = AmountOfMoneyJsonV121("EUR","1"), + description ="testing the limit", + charge_policy = "SHARED", + future_date =None + ) + val response = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty), (s"Consent-JWT", consentJwt)) + response.code shouldBe(201) + response.body.extract[TransactionRequestWithChargeJSON400].status shouldBe("COMPLETED") + } + scenario("We will call the Create (IMPLICIT), Get and Delete endpoints with user credentials ", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, ApiEndpoint4, ApiEndpoint5, ApiEndpoint6, VersionOfApi) { When(s"We try $ApiEndpoint1 v5.1.0") - val createConsentResponse = makePostRequest(createVRPConsentRequestUrl, write(postVRPConsentRequestJson)) + val createConsentResponse = makePostRequest(createVRPConsentRequestUrl, write(postVRPConsentRequestMonthlyGuardJson)) Then("We should get a 201") createConsentResponse.code should equal(201) val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson] @@ -194,7 +262,7 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ setPropsValues("consumer_validation_method_for_consent"->"NONE") - val requestWhichFails = (v5_1_0_Request / "users").GET + val requestWhichFails = (v5_1_0_Request / "my"/ "accounts").GET val responseWhichFails = makeGetRequest(requestWhichFails, List((s"Consent-JWT", consentJwt))) Then("We get successful response") responseWhichFails.code should equal(401) @@ -216,7 +284,277 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ getConsentByRequestResponseJson.status should be(ConsentStatus.ACCEPTED.toString) } + scenario("We will create consent properly, and test the counterparty limit - monthly guard", ApiEndpoint1, ApiEndpoint3, ApiEndpoint7, VersionOfApi) { + When(s"We try $ApiEndpoint1 v5.1.0") + val createConsentResponse = makePostRequest(createVRPConsentRequestUrl, write(postVRPConsentRequestMonthlyGuardJson)) + Then("We should get a 201") + createConsentResponse.code should equal(201) + val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson] + val consentRequestId = createConsentRequestResponseJson.consent_request_id + + When("We try to make the GET request v5.1.0") + val successGetRes = makeGetRequest(getConsentRequestUrl(consentRequestId)) + Then("We should get a 200") + successGetRes.code should equal(200) + val getConsentRequestResponseJson = successGetRes.body.extract[ConsentRequestResponseJson] + getConsentRequestResponseJson.payload should not be("") + + When("We try to make the GET request v5.1.0") + Then("We grant the role and test it again") + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString) + val createConsentByRequestResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write("")) + Then("We should get a 200") + createConsentByRequestResponse.code should equal(201) + val consentId = createConsentByRequestResponse.body.extract[ConsentJsonV500].consent_id + val consentJwt = createConsentByRequestResponse.body.extract[ConsentJsonV500].jwt + val accountAccess = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access + accountAccess.isDefined should equal(true) + accountAccess.get.bank_id should equal(fromAccountJson.bank_routing.address) + accountAccess.get.account_id should equal(fromAccountJson.account_routing.address) + accountAccess.get.view_id contains("_vrp-") shouldBe( true) + + val answerConsentChallengeRequest = (v5_1_0_Request / "banks" / testBankId1.value / "consents" / consentId / "challenge").POST <@ (user1) + val challenge = Consent.challengeAnswerAtTestEnvironment + val post = PostConsentChallengeJsonV310(answer = challenge) + val answerConsentChallengeResponse = makePostRequest(answerConsentChallengeRequest, write(post)) + Then("We should get a 201") + answerConsentChallengeResponse.code should equal(201) + + Then("We can test the COUNTERPARTY payment limit") + + val consentRequestBankId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.bank_id + val consentRequestAccountId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.account_id + val consentRequestViewId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.view_id + val consentRequestCounterpartyId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.helper_info.counterparty_id + + val createTransReqRequest = (v4_0_0_Request / "banks" / consentRequestBankId / "accounts" / consentRequestAccountId / + consentRequestViewId / "transaction-request-types" / "COUNTERPARTY" / "transaction-requests").POST + val transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON( + to = CounterpartyIdJson(consentRequestCounterpartyId.head), + value = AmountOfMoneyJsonV121("EUR","11"), + description ="testing the limit", + charge_policy = "SHARED", + future_date =None + ) + setPropsValues("consumer_validation_method_for_consent"->"NONE") + val response = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty), (s"Consent-JWT", consentJwt)) + response.code shouldBe(400) + response.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response.body.extract[ErrorMessage].message contains("max_single_amount") shouldBe(true) + + //("we try the max_monthly_amount limit (11 euros) . now we transfer 9 euro first. then 9 euros, we will get the error") + val response1 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","3"))), + (s"Consent-JWT", consentJwt) + ) + response1.code shouldBe(201) + val response2 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","9"))), + (s"Consent-JWT", consentJwt) + ) + + response2.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response2.body.extract[ErrorMessage].message contains("max_monthly_amount") shouldBe(true) + + //("we try the max_number_of_monthly_transactions limit (2 times), we try the 3rd request, we will get the error. response2 failed, so does not count in database.") + val response3 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))), + (s"Consent-JWT", consentJwt) + ) + response3.code shouldBe(201) + + val response4 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))), + (s"Consent-JWT", consentJwt) + ) + response4.code shouldBe(400) + + response4.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response4.body.extract[ErrorMessage].message contains("max_number_of_monthly_transactions") shouldBe(true) + + } + + scenario("We will create consent properly, and test the counterparty limit - yearly guard", ApiEndpoint1, ApiEndpoint3, ApiEndpoint7, VersionOfApi) { + When(s"We try $ApiEndpoint1 v5.1.0") + val createConsentResponse = makePostRequest(createVRPConsentRequestUrl, write(postVRPConsentRequestYearlyGuardJson)) + Then("We should get a 201") + createConsentResponse.code should equal(201) + val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson] + val consentRequestId = createConsentRequestResponseJson.consent_request_id + + When("We try to make the GET request v5.1.0") + val successGetRes = makeGetRequest(getConsentRequestUrl(consentRequestId)) + Then("We should get a 200") + successGetRes.code should equal(200) + val getConsentRequestResponseJson = successGetRes.body.extract[ConsentRequestResponseJson] + getConsentRequestResponseJson.payload should not be("") + + When("We try to make the GET request v5.1.0") + Then("We grant the role and test it again") + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString) + val createConsentByRequestResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write("")) + Then("We should get a 200") + createConsentByRequestResponse.code should equal(201) + val consentId = createConsentByRequestResponse.body.extract[ConsentJsonV500].consent_id + val consentJwt = createConsentByRequestResponse.body.extract[ConsentJsonV500].jwt + val accountAccess = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access + accountAccess.isDefined should equal(true) + accountAccess.get.bank_id should equal(fromAccountJson.bank_routing.address) + accountAccess.get.account_id should equal(fromAccountJson.account_routing.address) + accountAccess.get.view_id contains("_vrp-") shouldBe( true) + + val answerConsentChallengeRequest = (v5_1_0_Request / "banks" / testBankId1.value / "consents" / consentId / "challenge").POST <@ (user1) + val challenge = Consent.challengeAnswerAtTestEnvironment + val post = PostConsentChallengeJsonV310(answer = challenge) + val answerConsentChallengeResponse = makePostRequest(answerConsentChallengeRequest, write(post)) + Then("We should get a 201") + answerConsentChallengeResponse.code should equal(201) + + Then("We can test the COUNTERPARTY payment limit") + + val consentRequestBankId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.bank_id + val consentRequestAccountId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.account_id + val consentRequestViewId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.view_id + val consentRequestCounterpartyId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.helper_info.counterparty_id + + val createTransReqRequest = (v4_0_0_Request / "banks" / consentRequestBankId / "accounts" / consentRequestAccountId / + consentRequestViewId / "transaction-request-types" / "COUNTERPARTY" / "transaction-requests").POST + val transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON( + to = CounterpartyIdJson(consentRequestCounterpartyId.head), + value = AmountOfMoneyJsonV121("EUR","11"), + description ="testing the limit", + charge_policy = "SHARED", + future_date =None + ) + setPropsValues("consumer_validation_method_for_consent"->"NONE") + val response1 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","3"))), + (s"Consent-JWT", consentJwt) + ) + response1.code shouldBe(201) + val response2 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","9"))), + (s"Consent-JWT", consentJwt) + ) + response2.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response2.body.extract[ErrorMessage].message contains("max_yearly_amount") shouldBe(true) + + //("we try the max_number_of_monthly_transactions limit (2 times), we try the 3rd request, we will get the error. response2 failed, so does not count in database.") + val response3 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))), + (s"Consent-JWT", consentJwt) + ) + response3.code shouldBe(201) + + val response4 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))), + (s"Consent-JWT", consentJwt) + ) + response4.code shouldBe(400) + + response4.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response4.body.extract[ErrorMessage].message contains("max_number_of_yearly_transactions") shouldBe(true) + + } + + scenario("We will create consent properly, and test the counterparty limit - total guard", ApiEndpoint1, ApiEndpoint3, ApiEndpoint7, VersionOfApi) { + When(s"We try $ApiEndpoint1 v5.1.0") + val createConsentResponse = makePostRequest(createVRPConsentRequestUrl, write(postVRPConsentRequestTotalGuardJson)) + Then("We should get a 201") + createConsentResponse.code should equal(201) + val createConsentRequestResponseJson = createConsentResponse.body.extract[ConsentRequestResponseJson] + val consentRequestId = createConsentRequestResponseJson.consent_request_id + + When("We try to make the GET request v5.1.0") + val successGetRes = makeGetRequest(getConsentRequestUrl(consentRequestId)) + Then("We should get a 200") + successGetRes.code should equal(200) + val getConsentRequestResponseJson = successGetRes.body.extract[ConsentRequestResponseJson] + getConsentRequestResponseJson.payload should not be("") + + When("We try to make the GET request v5.1.0") + Then("We grant the role and test it again") + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString) + val createConsentByRequestResponse = makePostRequest(createConsentByConsentRequestIdEmail(consentRequestId), write("")) + Then("We should get a 200") + createConsentByRequestResponse.code should equal(201) + val consentId = createConsentByRequestResponse.body.extract[ConsentJsonV500].consent_id + val consentJwt = createConsentByRequestResponse.body.extract[ConsentJsonV500].jwt + val accountAccess = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access + accountAccess.isDefined should equal(true) + accountAccess.get.bank_id should equal(fromAccountJson.bank_routing.address) + accountAccess.get.account_id should equal(fromAccountJson.account_routing.address) + accountAccess.get.view_id contains("_vrp-") shouldBe( true) + + val answerConsentChallengeRequest = (v5_1_0_Request / "banks" / testBankId1.value / "consents" / consentId / "challenge").POST <@ (user1) + val challenge = Consent.challengeAnswerAtTestEnvironment + val post = PostConsentChallengeJsonV310(answer = challenge) + val answerConsentChallengeResponse = makePostRequest(answerConsentChallengeRequest, write(post)) + Then("We should get a 201") + answerConsentChallengeResponse.code should equal(201) + + Then("We can test the COUNTERPARTY payment limit") + + val consentRequestBankId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.bank_id + val consentRequestAccountId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.account_id + val consentRequestViewId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.view_id + val consentRequestCounterpartyId = createConsentByRequestResponse.body.extract[ConsentJsonV500].account_access.get.helper_info.counterparty_id + + val createTransReqRequest = (v4_0_0_Request / "banks" / consentRequestBankId / "accounts" / consentRequestAccountId / + consentRequestViewId / "transaction-request-types" / "COUNTERPARTY" / "transaction-requests").POST + val transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON( + to = CounterpartyIdJson(consentRequestCounterpartyId.head), + value = AmountOfMoneyJsonV121("EUR","11"), + description ="testing the limit", + charge_policy = "SHARED", + future_date =None + ) + setPropsValues("consumer_validation_method_for_consent"->"NONE") + //("we try the max_monthly_amount limit (11 euros) . now we transfer 9 euro first. then 9 euros, we will get the error") + val response1 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","3"))), + (s"Consent-JWT", consentJwt) + ) + response1.code shouldBe(201) + val response2 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","9"))), + (s"Consent-JWT", consentJwt) + ) + + response2.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response2.body.extract[ErrorMessage].message contains("max_total_amount") shouldBe(true) + + //("we try the max_number_of_monthly_transactions limit (2 times), we try the 3rd request, we will get the error. response2 failed, so does not count in database.") + val response3 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))), + (s"Consent-JWT", consentJwt) + ) + response3.code shouldBe(201) + + val response4 = makePostRequest( + createTransReqRequest, + write(transactionRequestBodyCounterparty.copy(value=AmountOfMoneyJsonV121("EUR","2"))), + (s"Consent-JWT", consentJwt) + ) + response4.code shouldBe(400) + + response4.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) + response4.body.extract[ErrorMessage].message contains("max_number_of_transactions") shouldBe(true) + + } + } } From dc8520bcd539fcd9111ee956b0004a05928d6147 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 9 Dec 2024 17:47:39 +0100 Subject: [PATCH 2/6] feature/added the getCounterpartyLimitStatus endpoint --- .../SwaggerDefinitionsJSON.scala | 27 ++++ .../scala/code/api/v5_1_0/APIMethods510.scala | 144 ++++++++++++++++++ .../code/api/v5_1_0/JSONFactory5.1.0.scala | 27 ++++ 3 files changed, 198 insertions(+) diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala index 53ab522b76..73d5b8b730 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala @@ -5482,6 +5482,33 @@ object SwaggerDefinitionsJSON { max_total_amount = maxTotalAmountExample.value, max_number_of_transactions = maxNumberOfTransactionsExample.value.toInt ) + + val counterpartyLimitStatus = CounterpartyLimitStatus( + currency_status = currencyExample.value, + max_monthly_amount_status = maxSingleAmountExample.value, + max_number_of_monthly_transactions_status = maxNumberOfMonthlyTransactionsExample.value.toInt, + max_yearly_amount_status = maxYearlyAmountExample.value, + max_number_of_yearly_transactions_status = maxNumberOfYearlyTransactionsExample.value.toInt, + max_total_amount_status = maxTotalAmountExample.value, + max_number_of_transactions_status = maxNumberOfTransactionsExample.value.toInt + ) + + val counterpartyLimitStatusV510 = CounterpartyLimitStatusV510( + counterparty_limit_id = counterpartyLimitIdExample.value, + bank_id = bankIdExample.value, + account_id = accountIdExample.value, + view_id = viewIdExample.value, + counterparty_id = counterpartyIdExample.value, + currency = currencyExample.value, + max_single_amount = maxSingleAmountExample.value, + max_monthly_amount = maxMonthlyAmountExample.value, + max_number_of_monthly_transactions = maxNumberOfMonthlyTransactionsExample.value.toInt, + max_yearly_amount = maxYearlyAmountExample.value, + max_number_of_yearly_transactions = maxNumberOfYearlyTransactionsExample.value.toInt, + max_total_amount = maxTotalAmountExample.value, + max_number_of_transactions = maxNumberOfTransactionsExample.value.toInt, + status = counterpartyLimitStatus + ) val atmsJsonV510 = AtmsJsonV510( atms = List(atmJsonV510) diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index 30037f3b92..f40dc89bb2 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -54,6 +54,7 @@ import net.liftweb.mapper.By import net.liftweb.util.Helpers.tryo import net.liftweb.util.{Helpers, StringHelpers} +import java.time.{LocalDate, ZoneId} import java.util.Date import scala.collection.immutable.{List, Nil} import scala.collection.mutable.ArrayBuffer @@ -3117,6 +3118,149 @@ trait APIMethods510 { } } + + staticResourceDocs += ResourceDoc( + getCounterpartyLimitStatus, + implementedInApiVersion, + nameOf(getCounterpartyLimitStatus), + "GET", + "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits-status", + "Get Counterparty Limit Status", + s"""Get Counterparty Limit Status.""", + EmptyBody, + counterpartyLimitStatusV510, + List( + $UserNotLoggedIn, + $BankNotFound, + $BankAccountNotFound, + $UserNoPermissionAccessView, + $CounterpartyNotFoundByCounterpartyId, + InvalidJsonFormat, + UnknownError + ), + List(apiTagCounterpartyLimits), + ) + lazy val getCounterpartyLimitStatus: OBPEndpoint = { + case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits-status" :: Nil JsonGet _ => { + cc => implicit val ec = EndpointContext(Some(cc)) + for { + (counterpartyLimit, callContext) <- NewStyle.function.getCounterpartyLimit( + bankId.value, + accountId.value, + viewId.value, + counterpartyId.value, + cc.callContext + ) + // Get the first day of the current month + firstDayOfMonth: LocalDate = LocalDate.now().withDayOfMonth(1) + + // Get the last day of the current month + lastDayOfMonth: LocalDate = LocalDate.now().withDayOfMonth( + LocalDate.now().lengthOfMonth() + ) + // Get the first day of the current year + firstDayOfYear: LocalDate = LocalDate.now().withDayOfYear(1) + + // Get the last day of the current year + lastDayOfYear: LocalDate = LocalDate.now().withDayOfYear( + LocalDate.now().lengthOfYear() + ) + + (fromBankAccount, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext) + // Convert LocalDate to Date + zoneId: ZoneId = ZoneId.systemDefault() + firstCurrentMonthDate: Date = Date.from(firstDayOfMonth.atStartOfDay(zoneId).toInstant) + lastCurrentMonthDate: Date = Date.from(lastDayOfMonth.atStartOfDay(zoneId).toInstant) + + firstCurrentYearDate: Date = Date.from(firstDayOfYear.atStartOfDay(zoneId).toInstant) + lastCurrentYearDate: Date = Date.from(lastDayOfYear.atStartOfDay(zoneId).toInstant) + + defaultFromDate: Date = theEpochTime + defaultToDate: Date = APIUtil.ToDateInFuture + + (sumOfTransactionsFromAccountToCounterpartyMonthly, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty( + bankId, + accountId, + counterpartyId, + firstCurrentMonthDate: Date, + lastCurrentMonthDate: Date, + callContext: Option[CallContext] + ) + + (countOfTransactionsFromAccountToCounterpartyMonthly, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty( + bankId, + accountId, + counterpartyId, + firstCurrentMonthDate: Date, + lastCurrentMonthDate: Date, + callContext: Option[CallContext] + ) + + (sumOfTransactionsFromAccountToCounterpartyYearly, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty( + bankId, + accountId, + counterpartyId, + firstCurrentYearDate: Date, + lastCurrentYearDate: Date, + callContext: Option[CallContext] + ) + + (countOfTransactionsFromAccountToCounterpartyYearly, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty( + bankId, + accountId, + counterpartyId, + firstCurrentYearDate: Date, + lastCurrentYearDate: Date, + callContext: Option[CallContext] + ) + + (sumOfAllTransactionsFromAccountToCounterparty, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty( + bankId, + accountId, + counterpartyId, + defaultFromDate: Date, + defaultToDate: Date, + callContext: Option[CallContext] + ) + + (countOfAllTransactionsFromAccountToCounterparty, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty( + bankId, + accountId, + counterpartyId, + defaultFromDate: Date, + defaultToDate: Date, + callContext: Option[CallContext] + ) + + } yield { + (CounterpartyLimitStatusV510( + counterparty_limit_id = counterpartyLimit.counterpartyLimitId: String, + bank_id = counterpartyLimit.bankId: String, + account_id = counterpartyLimit.accountId: String, + view_id = counterpartyLimit.viewId: String, + counterparty_id = counterpartyLimit.counterpartyId: String, + currency = counterpartyLimit.currency: String, + max_single_amount = counterpartyLimit.maxSingleAmount.toString(), + max_monthly_amount = counterpartyLimit.maxMonthlyAmount.toString(), + max_number_of_monthly_transactions = counterpartyLimit.maxNumberOfMonthlyTransactions: Int, + max_yearly_amount = counterpartyLimit.maxYearlyAmount.toString(), + max_number_of_yearly_transactions = counterpartyLimit.maxNumberOfYearlyTransactions: Int, + max_total_amount = counterpartyLimit.maxTotalAmount.toString(), + max_number_of_transactions = counterpartyLimit.maxNumberOfTransactions: Int, + status = CounterpartyLimitStatus( + currency_status = fromBankAccount.currency, + max_monthly_amount_status = sumOfTransactionsFromAccountToCounterpartyMonthly.amount, + max_number_of_monthly_transactions_status = countOfTransactionsFromAccountToCounterpartyMonthly, + max_yearly_amount_status = sumOfTransactionsFromAccountToCounterpartyYearly.amount, + max_number_of_yearly_transactions_status = countOfTransactionsFromAccountToCounterpartyYearly, + max_total_amount_status = sumOfAllTransactionsFromAccountToCounterparty.amount, + max_number_of_transactions_status = countOfAllTransactionsFromAccountToCounterparty + ) + ), HttpCode.`200`(callContext)) + } + } + } + staticResourceDocs += ResourceDoc( deleteCounterpartyLimit, implementedInApiVersion, diff --git a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala index e3eb826347..bb0f988481 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala @@ -216,6 +216,33 @@ case class CounterpartyLimitV510( max_number_of_transactions: Int ) +case class CounterpartyLimitStatus( + currency_status: String, + max_monthly_amount_status: String, + max_number_of_monthly_transactions_status: Int, + max_yearly_amount_status: String, + max_number_of_yearly_transactions_status: Int, + max_total_amount_status: String, + max_number_of_transactions_status: Int +) + +case class CounterpartyLimitStatusV510( + counterparty_limit_id: String, + bank_id: String, + account_id: String, + view_id: String, + counterparty_id: String, + currency: String, + max_single_amount: String, + max_monthly_amount: String, + max_number_of_monthly_transactions: Int, + max_yearly_amount: String, + max_number_of_yearly_transactions: Int, + max_total_amount: String, + max_number_of_transactions: Int, + status: CounterpartyLimitStatus +) + case class AtmJsonV510 ( id : Option[String], bank_id : String, From 7578a8e9d990026d2f006e1eb3e4f88c0c639fcd Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 9 Dec 2024 17:59:22 +0100 Subject: [PATCH 3/6] test/added the getCounterpartyLimitStatus test --- .../src/main/scala/code/api/v5_1_0/APIMethods510.scala | 4 ++-- .../scala/code/api/v5_1_0/CounterpartyLimitTest.scala | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala index f40dc89bb2..21889797af 100644 --- a/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala +++ b/obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala @@ -3124,7 +3124,7 @@ trait APIMethods510 { implementedInApiVersion, nameOf(getCounterpartyLimitStatus), "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limits-status", + "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/counterparties/COUNTERPARTY_ID/limit-status", "Get Counterparty Limit Status", s"""Get Counterparty Limit Status.""", EmptyBody, @@ -3141,7 +3141,7 @@ trait APIMethods510 { List(apiTagCounterpartyLimits), ) lazy val getCounterpartyLimitStatus: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits-status" :: Nil JsonGet _ => { + case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limit-status" :: Nil JsonGet _ => { cc => implicit val ec = EndpointContext(Some(cc)) for { (counterpartyLimit, callContext) <- NewStyle.function.getCounterpartyLimit( diff --git a/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala index 796d0321b9..35e1b2346d 100644 --- a/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala +++ b/obp-api/src/test/scala/code/api/v5_1_0/CounterpartyLimitTest.scala @@ -26,6 +26,7 @@ class CounterpartyLimitTest extends V510ServerSetup { object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.updateCounterpartyLimit)) object ApiEndpoint4 extends Tag(nameOf(Implementations5_1_0.deleteCounterpartyLimit)) object ApiEndpoint5 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestCounterparty)) + object ApiEndpoint6 extends Tag(nameOf(Implementations5_1_0.getCounterpartyLimitStatus)) val bankId = testBankId1.value @@ -388,6 +389,14 @@ class CounterpartyLimitTest extends V510ServerSetup { response4.body.extract[ErrorMessage].message contains(CounterpartyLimitValidationError) shouldBe (true) response4.body.extract[ErrorMessage].message contains("max_number_of_transactions") shouldBe(true) + val requestLimitStatus = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / "views" / ownerView /"counterparties" / counterparty.counterpartyId /"limit-status").POST <@ (user1) + val responseLimitStatus = makeGetRequest(requestLimitStatus) + responseLimitStatus.code shouldBe (200) + responseLimitStatus.body.extract[CounterpartyLimitStatusV510].status.currency_status shouldBe("EUR") + responseLimitStatus.body.extract[CounterpartyLimitStatusV510].status.max_number_of_monthly_transactions_status shouldBe(2) + responseLimitStatus.body.extract[CounterpartyLimitStatusV510].status.max_number_of_yearly_transactions_status shouldBe(2) + responseLimitStatus.body.extract[CounterpartyLimitStatusV510].status.max_number_of_transactions_status shouldBe(2) + } } From bcac59447c65aa4ea75a0494bc907fd6ef67489a Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 10 Dec 2024 10:29:43 +0100 Subject: [PATCH 4/6] refactor/use BankAttributeTrait for connector method --- .../scala/code/api/MxOF/JSONFactory_MXOF_1_0_0.scala | 2 +- obp-api/src/main/scala/code/api/util/NewStyle.scala | 2 +- .../scala/code/api/v4_0_0/JSONFactory4.0.0.scala | 7 +++---- .../scala/code/api/v5_0_0/JSONFactory5.0.0.scala | 12 ++++++------ .../main/scala/code/bankconnectors/Connector.scala | 2 +- .../code/bankconnectors/LocalMappedConnector.scala | 2 +- .../openbankproject/commons/dto/JsonsTransfer.scala | 3 +++ .../openbankproject/commons/model/CommonModel.scala | 10 ++++++++++ 8 files changed, 26 insertions(+), 14 deletions(-) diff --git a/obp-api/src/main/scala/code/api/MxOF/JSONFactory_MXOF_1_0_0.scala b/obp-api/src/main/scala/code/api/MxOF/JSONFactory_MXOF_1_0_0.scala index e3fe813715..40d51a82e6 100644 --- a/obp-api/src/main/scala/code/api/MxOF/JSONFactory_MXOF_1_0_0.scala +++ b/obp-api/src/main/scala/code/api/MxOF/JSONFactory_MXOF_1_0_0.scala @@ -97,7 +97,7 @@ object JSONFactory_MXOF_0_0_1 extends CustomJsonFormats { final val BANK_ATTRIBUTE_LICENSE = "ATM_META_LICENCE" final val BANK_ATTRIBUTE_TERMSOFUSE = "ATM_META_TERMS_OF_USE" - def createGetAtmsResponse (banks: List[Bank], atms: List[AtmT], attributes:List[BankAttribute]) :GetAtmsResponseJson = { + def createGetAtmsResponse (banks: List[Bank], atms: List[AtmT], attributes:List[BankAttributeTrait]) :GetAtmsResponseJson = { def access24HoursIndicator (atm: AtmT) = { atm.OpeningTimeOnMonday.equals(Some("00:00")) && atm.ClosingTimeOnMonday.equals(Some("23:59")) atm.OpeningTimeOnTuesday.equals(Some("00:00")) && atm.ClosingTimeOnTuesday.equals(Some("23:59")) diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index c8e30f030f..6be04dc8e1 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -1813,7 +1813,7 @@ object NewStyle extends MdcLoggable{ } } - def getBankAttributesByBank(bank: BankId,callContext: Option[CallContext]): OBPReturnType[List[BankAttribute]] = { + def getBankAttributesByBank(bank: BankId,callContext: Option[CallContext]): OBPReturnType[List[BankAttributeTrait]] = { Connector.connector.vend.getBankAttributesByBank( bank: BankId, callContext: Option[CallContext] diff --git a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala index 00bf4c370e..1038489db1 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala @@ -47,7 +47,6 @@ import code.api.v3_1_0.{AccountAttributeResponseJson, CustomerJsonV310, JSONFact import code.apicollection.ApiCollectionTrait import code.apicollectionendpoint.ApiCollectionEndpointTrait import code.atms.Atms.Atm -import code.bankattribute.BankAttribute import code.consent.MappedConsent import code.entitlement.Entitlement import code.loginattempts.LoginAttempt @@ -1200,7 +1199,7 @@ object JSONFactory400 { } - def createBankJSON400(bank: Bank, attributes: List[BankAttribute] = Nil): BankJson400 = { + def createBankJSON400(bank: Bank, attributes: List[BankAttributeTrait] = Nil): BankJson400 = { val obp = BankRoutingJsonV121("OBP", bank.bankId.value) val bic = BankRoutingJsonV121("BIC", bank.swiftBic) val routings = bank.bankRoutingScheme match { @@ -1814,7 +1813,7 @@ object JSONFactory400 { value = productAttribute.value, is_active = productAttribute.isActive ) - def createBankAttributeJson(bankAttribute: BankAttribute): BankAttributeResponseJsonV400 = + def createBankAttributeJson(bankAttribute: BankAttributeTrait): BankAttributeResponseJsonV400 = BankAttributeResponseJsonV400( bank_id = bankAttribute.bankId.value, bank_attribute_id = bankAttribute.bankAttributeId, @@ -1823,7 +1822,7 @@ object JSONFactory400 { value = bankAttribute.value, is_active = bankAttribute.isActive ) - def createBankAttributesJson(bankAttributes: List[BankAttribute]): BankAttributesResponseJsonV400 = + def createBankAttributesJson(bankAttributes: List[BankAttributeTrait]): BankAttributesResponseJsonV400 = BankAttributesResponseJsonV400(bankAttributes.map(createBankAttributeJson)) diff --git a/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala b/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala index 0075b279bd..0385494bcb 100644 --- a/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala +++ b/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala @@ -37,13 +37,13 @@ import code.api.v1_3_0.JSONFactory1_3_0.{cardActionsToString, createAccountJson, import code.api.v1_3_0.{PinResetJSON, ReplacementJSON} import code.api.v1_4_0.JSONFactory1_4_0.{CustomerFaceImageJson, MetaJsonV140} import code.api.v2_1_0.CustomerCreditRatingJSON -import code.api.v3_0_0.{AdapterInfoJsonV300, CustomerAttributeResponseJsonV300, JSONFactory300} -import code.api.v3_1_0.{AccountAttributeResponseJson, AccountBasicV310, CustomerWithAttributesJsonV310, PhysicalCardWithAttributesJsonV310, PostConsentEntitlementJsonV310} +import code.api.v3_0_0.{CustomerAttributeResponseJsonV300, JSONFactory300} +import code.api.v3_1_0.{AccountBasicV310,PostConsentEntitlementJsonV310} import code.api.v4_0_0.{APIInfoJson400, BankAttributeBankResponseJsonV400, EnergySource400, HostedAt400, HostedBy400} -import code.bankattribute.BankAttribute import code.consent.ConsentRequest -import com.openbankproject.commons.model.CustomerAccountLinkTrait -import com.openbankproject.commons.model.{AccountAttribute, AccountRouting, AccountRoutingJsonV121, AmountOfMoneyJsonV121, Bank, BankAccount, CardAttribute, CreateViewJson, Customer, CustomerAttribute, InboundAdapterInfoInternal, InboundStatusMessage, PhysicalCardTrait, UpdateViewJSON, User, UserAuthContext, UserAuthContextUpdate, View, ViewBasic} +import com.openbankproject.commons.model.{CustomerAccountLinkTrait,BankAttributeTrait} +import com.openbankproject.commons.model.{AccountAttribute, AccountRoutingJsonV121, AmountOfMoneyJsonV121, Bank, BankAccount, CardAttribute, CreateViewJson, Customer, CustomerAttribute, InboundAdapterInfoInternal, + InboundStatusMessage, PhysicalCardTrait, UpdateViewJSON, User, UserAuthContext, UserAuthContextUpdate, View, ViewBasic} import com.openbankproject.commons.util.ApiVersion import net.liftweb.json.JsonAST.JValue import net.liftweb.util.Helpers @@ -599,7 +599,7 @@ object JSONFactory500 { ) } - def createBankJSON500(bank: Bank, attributes: List[BankAttribute] = Nil): BankJson500 = { + def createBankJSON500(bank: Bank, attributes: List[BankAttributeTrait] = Nil): BankJson500 = { val obp = BankRoutingJsonV121("OBP", bank.bankId.value) val bic = BankRoutingJsonV121("BIC", bank.swiftBic) val routings = bank.bankRoutingScheme match { diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 87ef777ced..a9a2eb71b3 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -1302,7 +1302,7 @@ trait Connector extends MdcLoggable { callContext: Option[CallContext] ): OBPReturnType[Box[AtmAttribute]] = Future{(Failure(setUnimplementedError(nameOf(createOrUpdateAtmAttribute _))), callContext)} - def getBankAttributesByBank(bank: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttribute]]] = + def getBankAttributesByBank(bank: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttributeTrait]]] = Future{(Failure(setUnimplementedError(nameOf(getBankAttributesByBank _))), callContext)} def getAtmAttributesByAtm(bank: BankId, atm: AtmId, callContext: Option[CallContext]): OBPReturnType[Box[List[AtmAttribute]]] = diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index 7fd9012393..484f6767f4 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -3524,7 +3524,7 @@ object LocalMappedConnector extends Connector with MdcLoggable { } - override def getBankAttributesByBank(bank: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttribute]]] = + override def getBankAttributesByBank(bank: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttributeTrait]]] = BankAttributeX.bankAttributeProvider.vend.getBankAttributesFromProvider(bank: BankId) map { (_, callContext) } diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala index 424b16f3a9..71f2972873 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala @@ -1146,6 +1146,9 @@ case class InBoundGetTransactionIdsByAttributeNameValues(inboundAdapterCallConte case class OutBoundGetTransactionAttributes(outboundAdapterCallContext: OutboundAdapterCallContext, bankId: BankId, transactionId: TransactionId) extends TopicTrait case class InBoundGetTransactionAttributes(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[TransactionAttributeCommons]) extends InBoundTrait[List[TransactionAttributeCommons]] +case class OutBoundGetBankAttributesByBank(outboundAdapterCallContext: OutboundAdapterCallContext, bankId: BankId) extends TopicTrait +case class InBoundGetBankAttributesByBank(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[TransactionAttributeCommons]) extends InBoundTrait[List[TransactionAttributeCommons]] + case class OutBoundGetCustomerAttributeById(outboundAdapterCallContext: OutboundAdapterCallContext, customerAttributeId: String) extends TopicTrait case class InBoundGetCustomerAttributeById(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: CustomerAttributeCommons) extends InBoundTrait[CustomerAttributeCommons] diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala index 0fce669ce0..9a7bf93275 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala @@ -509,6 +509,16 @@ case class TransactionAttributeCommons ( ) extends TransactionAttribute object TransactionAttributeCommons extends Converter[TransactionAttribute, TransactionAttributeCommons] +case class BankAttributeCommons ( + override val bankId: BankId, + override val bankAttributeId: String, + override val attributeType: BankAttributeType.Value, + override val name: String, + override val value: String, + override val isActive: Option[Boolean] +) extends BankAttributeTrait +object BankAttributeCommons extends Converter[BankAttributeTrait, BankAttributeCommons] + case class FXRateCommons ( override val bankId : BankId, override val fromCurrencyCode: String, From 5cd3b2536b8117a104a79580ed776295aa66d931 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 10 Dec 2024 10:52:36 +0100 Subject: [PATCH 5/6] feature/added getBankAttributesByBank to RabbitMQConnector_vOct2024 --- .../main/scala/code/api/util/NewStyle.scala | 4 +- .../code/api/v5_0_0/JSONFactory5.0.0.scala | 2 - .../scala/code/bankconnectors/Connector.scala | 2 +- .../bankconnectors/LocalMappedConnector.scala | 4 +- .../generator/ConnectorBuilderUtil.scala | 1 + .../rabbitmq/RabbitMQConnector_vOct2024.scala | 63 ++++++++++++++++--- .../commons/dto/JsonsTransfer.scala | 2 +- 7 files changed, 62 insertions(+), 16 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index 6be04dc8e1..3e731510f6 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -1813,9 +1813,9 @@ object NewStyle extends MdcLoggable{ } } - def getBankAttributesByBank(bank: BankId,callContext: Option[CallContext]): OBPReturnType[List[BankAttributeTrait]] = { + def getBankAttributesByBank(bankId: BankId,callContext: Option[CallContext]): OBPReturnType[List[BankAttributeTrait]] = { Connector.connector.vend.getBankAttributesByBank( - bank: BankId, + bankId: BankId, callContext: Option[CallContext] ) map { i => (connectorEmptyResponse(i._1, callContext), i._2) diff --git a/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala b/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala index 0385494bcb..3b2c111bd8 100644 --- a/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala +++ b/obp-api/src/main/scala/code/api/v5_0_0/JSONFactory5.0.0.scala @@ -48,8 +48,6 @@ import com.openbankproject.commons.util.ApiVersion import net.liftweb.json.JsonAST.JValue import net.liftweb.util.Helpers -import scala.collection.immutable.List - case class PostBankJson500( id: Option[String], bank_code: String, diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index a9a2eb71b3..673c3e1b47 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -1302,7 +1302,7 @@ trait Connector extends MdcLoggable { callContext: Option[CallContext] ): OBPReturnType[Box[AtmAttribute]] = Future{(Failure(setUnimplementedError(nameOf(createOrUpdateAtmAttribute _))), callContext)} - def getBankAttributesByBank(bank: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttributeTrait]]] = + def getBankAttributesByBank(bankId: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttributeTrait]]] = Future{(Failure(setUnimplementedError(nameOf(getBankAttributesByBank _))), callContext)} def getAtmAttributesByAtm(bank: BankId, atm: AtmId, callContext: Option[CallContext]): OBPReturnType[Box[List[AtmAttribute]]] = diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index 484f6767f4..793ca63ca7 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -3524,8 +3524,8 @@ object LocalMappedConnector extends Connector with MdcLoggable { } - override def getBankAttributesByBank(bank: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttributeTrait]]] = - BankAttributeX.bankAttributeProvider.vend.getBankAttributesFromProvider(bank: BankId) map { + override def getBankAttributesByBank(bankId: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttributeTrait]]] = + BankAttributeX.bankAttributeProvider.vend.getBankAttributesFromProvider(bankId: BankId) map { (_, callContext) } diff --git a/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala b/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala index 819c24ad86..1187c5a96f 100644 --- a/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala +++ b/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala @@ -383,6 +383,7 @@ object ConnectorBuilderUtil { "getCustomerAttributesForCustomers", "getTransactionIdsByAttributeNameValues", "getTransactionAttributes", + "getBankAttributesByBank", "getCustomerAttributeById", "createDirectDebit", "deleteCustomerAttribute", diff --git a/obp-api/src/main/scala/code/bankconnectors/rabbitmq/RabbitMQConnector_vOct2024.scala b/obp-api/src/main/scala/code/bankconnectors/rabbitmq/RabbitMQConnector_vOct2024.scala index 2f39c01489..b4729b83b0 100644 --- a/obp-api/src/main/scala/code/bankconnectors/rabbitmq/RabbitMQConnector_vOct2024.scala +++ b/obp-api/src/main/scala/code/bankconnectors/rabbitmq/RabbitMQConnector_vOct2024.scala @@ -24,15 +24,12 @@ Berlin 13359, Germany */ import java.util.Date - import code.api.ResourceDocs1_4_0.MessageDocsSwaggerDefinitions import code.api.util.APIUtil.{AdapterImplementation, MessageDoc, OBPReturnType, _} import code.api.util.ErrorMessages._ import code.api.util.ExampleValue._ -import code.api.util.{APIUtil, CallContext, HashUtil, OBPQueryParam} +import code.api.util.{CallContext, OBPQueryParam} import code.bankconnectors._ -import code.customer.internalMapping.MappedCustomerIdMappingProvider -import code.model.dataAccess.internalMapping.MappedAccountIdMappingProvider import code.util.Helper import code.util.Helper.MdcLoggable import com.openbankproject.commons.ExecutionContext.Implicits.global @@ -73,7 +70,7 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { val connectorName = "rabbitmq_vOct2024" //---------------- dynamic start -------------------please don't modify this line -// ---------- created on 2024-10-28T12:32:40Z +// ---------- created on 2024-12-10T10:42:33Z messageDocs += getAdapterInfoDoc def getAdapterInfoDoc = MessageDoc( @@ -2281,6 +2278,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -2444,6 +2443,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -2793,6 +2794,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -2897,6 +2900,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -2977,7 +2982,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { value=attributeValueExample.value))))) ), exampleInboundMessage = ( - InBoundGetTransactionRequestTypes(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, status=MessageDocsSwaggerDefinitions.inboundStatus, + InBoundGetTransactionRequestTypes(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, data=List(TransactionRequestType(transactionRequestTypeExample.value))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) @@ -3066,6 +3072,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -3149,6 +3157,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -3818,6 +3828,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -4088,6 +4100,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -4187,6 +4201,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { amount=amountExample.value), creditorAccount=PaymentAccount("string"), creditorName="string")), + to_agent=Some( transactionRequestAgentCashWithdrawal(bank_id=bank_idExample.value, + agent_number="string")), value= AmountOfMoney(currency=currencyExample.value, amount=amountExample.value), description=descriptionExample.value), @@ -5365,6 +5381,37 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { response.map(convertToTuple[ProductAttributeCommons](callContext)) } + messageDocs += getBankAttributesByBankDoc + def getBankAttributesByBankDoc = MessageDoc( + process = "obp.getBankAttributesByBank", + messageFormat = messageFormat, + description = "Get Bank Attributes By Bank", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAttributesByBank(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetBankAttributesByBank(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BankAttributeCommons(bankId=BankId(bankIdExample.value), + bankAttributeId="string", + attributeType=com.openbankproject.commons.model.enums.BankAttributeType.example, + name=nameExample.value, + value=valueExample.value, + isActive=Some(isActiveExample.value.toBoolean)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAttributesByBank(bankId: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAttributeTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAttributesByBank => InBound, OutBoundGetBankAttributesByBank => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_attributes_by_bank", req, callContext) + response.map(convertToTuple[List[BankAttributeCommons]](callContext)) + } + messageDocs += getProductAttributeByIdDoc def getProductAttributeByIdDoc = MessageDoc( process = "obp.getProductAttributeById", @@ -6950,8 +6997,8 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { response.map(convertToTuple[Boolean](callContext)) } -// ---------- created on 2024-10-28T12:32:40Z -//---------------- dynamic end ---------------------please don't modify this line +// ---------- created on 2024-12-10T10:42:33Z +//---------------- dynamic end ---------------------please don't modify this line private val availableOperation = DynamicEntityOperation.values.map(it => s""""$it"""").mkString("[", ", ", "]") diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala index 71f2972873..c1a40d0b86 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala @@ -1147,7 +1147,7 @@ case class OutBoundGetTransactionAttributes(outboundAdapterCallContext: Outbound case class InBoundGetTransactionAttributes(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[TransactionAttributeCommons]) extends InBoundTrait[List[TransactionAttributeCommons]] case class OutBoundGetBankAttributesByBank(outboundAdapterCallContext: OutboundAdapterCallContext, bankId: BankId) extends TopicTrait -case class InBoundGetBankAttributesByBank(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[TransactionAttributeCommons]) extends InBoundTrait[List[TransactionAttributeCommons]] +case class InBoundGetBankAttributesByBank(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[BankAttributeCommons]) extends InBoundTrait[List[BankAttributeCommons]] case class OutBoundGetCustomerAttributeById(outboundAdapterCallContext: OutboundAdapterCallContext, customerAttributeId: String) extends TopicTrait case class InBoundGetCustomerAttributeById(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: CustomerAttributeCommons) extends InBoundTrait[CustomerAttributeCommons] From 3a4f95a410e1c5eea4b202afd0d1a1d4574dc39f Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 10 Dec 2024 12:42:54 +0100 Subject: [PATCH 6/6] refactor/typo --- obp-api/src/main/scala/code/api/v3_0_0/JSONFactory3.0.0.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v3_0_0/JSONFactory3.0.0.scala b/obp-api/src/main/scala/code/api/v3_0_0/JSONFactory3.0.0.scala index 3effc4857c..5a5319d999 100644 --- a/obp-api/src/main/scala/code/api/v3_0_0/JSONFactory3.0.0.scala +++ b/obp-api/src/main/scala/code/api/v3_0_0/JSONFactory3.0.0.scala @@ -608,8 +608,8 @@ object JSONFactory300{ } //stated -- Transaction relevant methods ///// - def createTransactionsJson(moderatedTansactionsWithAttributes: List[ModeratedTransactionWithAttributes]) : TransactionsJsonV300 = { - TransactionsJsonV300(moderatedTansactionsWithAttributes.map(t => createTransactionJSON(t.transaction, t.transactionAttributes))) + def createTransactionsJson(moderatedTransactionsWithAttributes: List[ModeratedTransactionWithAttributes]) : TransactionsJsonV300 = { + TransactionsJsonV300(moderatedTransactionsWithAttributes.map(t => createTransactionJSON(t.transaction, t.transactionAttributes))) } def createTransactionJSON(transaction : ModeratedTransaction, transactionAttributes: List[TransactionAttribute]) : TransactionJsonV300 = {