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 73d5b8b730..0bff4af52b 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 @@ -2293,12 +2293,19 @@ object SwaggerDefinitionsJSON { transaction_request_types = List(transactionRequestTypeJSONV210) ) + val transactionRequestAttributeJsonV400 = TransactionRequestAttributeJsonV400( + name = transactionRequestAttributeNameExample.value, + attribute_type = transactionRequestAttributeTypeExample.value, + value = transactionRequestAttributeValueExample.value + ) + val transactionRequestBodyCounterpartyJSON = TransactionRequestBodyCounterpartyJSON( counterpartyIdJson, amountOfMoneyJsonV121, - "A description for the transaction to the counterparty", + description = "A description for the transaction to the counterparty", chargePolicyExample.value, - Some(futureDateExample.value) + Some(futureDateExample.value), + Some(List(transactionRequestAttributeJsonV400)) ) val transactionRequestBodySEPAJSON = TransactionRequestBodySEPAJSON( @@ -4752,12 +4759,6 @@ object SwaggerDefinitionsJSON { `type` = transactionRequestAttributeTypeExample.value, value = transactionRequestAttributeValueExample.value ) - - val transactionRequestAttributeJsonV400 = TransactionRequestAttributeJsonV400( - name = transactionRequestAttributeNameExample.value, - `type` = transactionRequestAttributeTypeExample.value, - value = transactionRequestAttributeValueExample.value - ) val transactionRequestAttributesResponseJson = TransactionRequestAttributesResponseJson( transaction_request_attributes = List(transactionRequestAttributeResponseJson) @@ -4863,7 +4864,8 @@ object SwaggerDefinitionsJSON { start_date = DateWithDayExampleObject, end_date = DateWithDayExampleObject, challenges = List(challengeJsonV400), - charge = transactionRequestChargeJsonV200 + charge = transactionRequestChargeJsonV200, + attributes=Some(List(bankAttributeBankResponseJsonV400)), ) val postSimpleCounterpartyJson400 = PostSimpleCounterpartyJson400( diff --git a/obp-api/src/main/scala/code/api/util/ExampleValue.scala b/obp-api/src/main/scala/code/api/util/ExampleValue.scala index 80ea10f238..fa7f4f6ef1 100644 --- a/obp-api/src/main/scala/code/api/util/ExampleValue.scala +++ b/obp-api/src/main/scala/code/api/util/ExampleValue.scala @@ -215,7 +215,7 @@ object ExampleValue { lazy val transactionRequestAttributeNameExample = ConnectorField("HOUSE_RENT", s"Transaction Request attribute name") glossaryItems += makeGlossaryItem("Transaction Requests.attributeName", transactionRequestAttributeNameExample) - lazy val transactionRequestAttributeTypeExample = ConnectorField("DATE_WITH_DAY", s"Transaction Request attribute type.") + lazy val transactionRequestAttributeTypeExample = ConnectorField("STRING", s"Transaction Request attribute type.") glossaryItems += makeGlossaryItem("Transaction Requests.attributeType", transactionRequestAttributeTypeExample) lazy val transactionRequestAttributeValueExample = ConnectorField("123456789", s"Transaction Request attribute value.") 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 3e731510f6..9ee4e7e4ff 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -3174,17 +3174,39 @@ object NewStyle extends MdcLoggable{ } } - def getTransactionRequestIdsByAttributeNameValues(bankId: BankId, params: Map[String, List[String]], - callContext: Option[CallContext]): OBPReturnType[List[String]] = { + def getTransactionRequestIdsByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal: Boolean, + callContext: Option[CallContext] + ): OBPReturnType[List[String]] = { Connector.connector.vend.getTransactionRequestIdsByAttributeNameValues( bankId: BankId, params: Map[String, List[String]], + isPersonal, callContext: Option[CallContext] ) map { i => (connectorEmptyResponse(i._1, callContext), i._2) } } + + def getByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal: Boolean, + callContext: Option[CallContext] + ): OBPReturnType[List[TransactionRequestAttributeTrait]] = { + Connector.connector.vend.getByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal, + callContext + ) map { + i => (connectorEmptyResponse(i._1, callContext), i._2) + } + } + def createOrUpdateTransactionRequestAttribute(bankId: BankId, transactionRequestId: TransactionRequestId, transactionRequestAttributeId: Option[String], @@ -3207,12 +3229,14 @@ object NewStyle extends MdcLoggable{ def createTransactionRequestAttributes(bankId: BankId, transactionRequestId: TransactionRequestId, - transactionRequestAttributes: List[TransactionRequestAttributeTrait], + transactionRequestAttributes: List[TransactionRequestAttributeJsonV400], + isPersonal: Boolean, callContext: Option[CallContext]): OBPReturnType[List[TransactionRequestAttributeTrait]] = { Connector.connector.vend.createTransactionRequestAttributes( bankId: BankId, transactionRequestId: TransactionRequestId, - transactionRequestAttributes: List[TransactionRequestAttributeTrait], + transactionRequestAttributes: List[TransactionRequestAttributeJsonV400], + isPersonal: Boolean, callContext: Option[CallContext] ) map { i => (connectorEmptyResponse(i._1, callContext), i._2) diff --git a/obp-api/src/main/scala/code/api/v2_1_0/JSONFactory2.1.0.scala b/obp-api/src/main/scala/code/api/v2_1_0/JSONFactory2.1.0.scala index 7d08b7c459..b31c322dab 100644 --- a/obp-api/src/main/scala/code/api/v2_1_0/JSONFactory2.1.0.scala +++ b/obp-api/src/main/scala/code/api/v2_1_0/JSONFactory2.1.0.scala @@ -87,7 +87,8 @@ case class TransactionRequestBodyCounterpartyJSON( value: AmountOfMoneyJsonV121, description: String, charge_policy: String, - future_date: Option[String] = None + future_date: Option[String] = None, + attributes: Option[List[TransactionRequestAttributeJsonV400]]= None, ) extends TransactionRequestCommonBodyJSON // the data from endpoint, extract as valid JSON 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 96d27790d9..e5c0907807 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 @@ -1206,9 +1206,11 @@ trait APIMethods400 extends MdcLoggable { } } yield (transactionRequest, callContext) } + + (transactionRequestAttribute, callContext) <- NewStyle.function.getTransactionRequestAttributes(bankId, transactionRequest.id, callContext) } yield { - (JSONFactory400.createTransactionRequestWithChargeJSON(transactionRequest, challenges), HttpCode.`202`(callContext)) + (JSONFactory400.createTransactionRequestWithChargeJSON(transactionRequest, challenges, transactionRequestAttribute), HttpCode.`202`(callContext)) } } } @@ -1253,7 +1255,7 @@ trait APIMethods400 extends MdcLoggable { failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)" transactionRequestAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) { - TransactionRequestAttributeType.withName(postedData.`type`) + TransactionRequestAttributeType.withName(postedData.attribute_type) } (transactionRequestAttribute, callContext) <- NewStyle.function.createOrUpdateTransactionRequestAttribute( bankId, @@ -1391,7 +1393,7 @@ trait APIMethods400 extends MdcLoggable { failMsg = s"$InvalidJsonFormat The `Type` field can only accept the following field: " + s"${TransactionRequestAttributeType.DOUBLE}(12.1234), ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), ${TransactionRequestAttributeType.INTEGER}(123) and ${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)" transactionRequestAttributeType <- NewStyle.function.tryons(failMsg, 400, callContext) { - TransactionRequestAttributeType.withName(postedData.`type`) + TransactionRequestAttributeType.withName(postedData.attribute_type) } (_, callContext) <- NewStyle.function.getTransactionRequestAttributeById(transactionRequestAttributeId, callContext) (transactionRequestAttribute, callContext) <- NewStyle.function.createOrUpdateTransactionRequestAttribute( @@ -12413,6 +12415,28 @@ object APIMethods400 extends RestHelper with APIMethods400 { toCounterpartyId = transactionRequestBodyCounterparty.to.counterparty_id (toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(toCounterpartyId), callContext) + transactionRequestAttributes <- if(transactionRequestBodyCounterparty.attributes.isDefined && transactionRequestBodyCounterparty.attributes.head.length > 0 ) { + + val attributes = transactionRequestBodyCounterparty.attributes.head + + val failMsg = s"$InvalidJsonFormat The attribute `type` field can only accept the following field: " + + s"${TransactionRequestAttributeType.DOUBLE}(12.1234)," + + s" ${TransactionRequestAttributeType.STRING}(TAX_NUMBER), " + + s"${TransactionRequestAttributeType.INTEGER}(123) and " + + s"${TransactionRequestAttributeType.DATE_WITH_DAY}(2012-04-23)" + + for{ + _ <- NewStyle.function.tryons(failMsg, 400, callContext) { + attributes.map(attribute => TransactionRequestAttributeType.withName(attribute.attribute_type)) + } + }yield{ + attributes + } + + } else { + Future.successful(List.empty[TransactionRequestAttributeJsonV400]) + } + (counterpartyLimitBox, callContext) <- Connector.connector.vend.getCounterpartyLimit( bankId.value, accountId.value, @@ -12422,7 +12446,6 @@ object APIMethods400 extends RestHelper with APIMethods400 { ) _<- if(counterpartyLimitBox.isDefined){ for{ - counterpartyLimit <- Future.successful(counterpartyLimitBox.head) maxSingleAmount = counterpartyLimit.maxSingleAmount maxMonthlyAmount = counterpartyLimit.maxMonthlyAmount @@ -12576,6 +12599,14 @@ object APIMethods400 extends RestHelper with APIMethods400 { getScaMethodAtInstance(transactionRequestType.value).toOption, None, callContext) + + _ <- NewStyle.function.createTransactionRequestAttributes( + bankId: BankId, + createdTransactionRequest.id, + transactionRequestAttributes, + true, + callContext: Option[CallContext] + ) } yield (createdTransactionRequest, callContext) } case AGENT_CASH_WITHDRAWAL => { @@ -12758,8 +12789,13 @@ object APIMethods400 extends RestHelper with APIMethods400 { } } (challenges, callContext) <- NewStyle.function.getChallengesByTransactionRequestId(createdTransactionRequest.id.value, callContext) + (transactionRequestAttributes, callContext) <- NewStyle.function.getTransactionRequestAttributes( + bankId, + createdTransactionRequest.id, + callContext + ) } yield { - (JSONFactory400.createTransactionRequestWithChargeJSON(createdTransactionRequest, challenges), HttpCode.`201`(callContext)) + (JSONFactory400.createTransactionRequestWithChargeJSON(createdTransactionRequest, challenges, transactionRequestAttributes), HttpCode.`201`(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 1038489db1..fe681955ab 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 @@ -137,7 +137,8 @@ case class TransactionRequestWithChargeJSON400( start_date: Date, end_date: Date, challenges: List[ChallengeJsonV400], - charge : TransactionRequestChargeJsonV200 + charge : TransactionRequestChargeJsonV200, + attributes: Option[List[BankAttributeBankResponseJsonV400]] ) case class PostHistoricalTransactionAtBankJson( from_account_id: String, @@ -549,12 +550,6 @@ case class TransactionAttributesResponseJson( transaction_attributes: List[TransactionAttributeResponseJson] ) -case class TransactionRequestAttributeJsonV400( - name: String, - `type`: String, - value: String, -) - case class TransactionRequestAttributeResponseJson( transaction_request_attribute_id: String, name: String, @@ -1260,8 +1255,8 @@ object JSONFactory400 { account_attributes = accountAttributes.map(createAccountAttributeJson) ) - def createTransactionRequestWithChargeJSON(tr : TransactionRequest, challenges: List[ChallengeTrait]) : TransactionRequestWithChargeJSON400 = { - new TransactionRequestWithChargeJSON400( + def createTransactionRequestWithChargeJSON(tr : TransactionRequest, challenges: List[ChallengeTrait], transactionRequestAttribute: List[TransactionRequestAttributeTrait]) : TransactionRequestWithChargeJSON400 = { + TransactionRequestWithChargeJSON400( id = stringOrNull(tr.id.value), `type` = stringOrNull(tr.`type`), from = try{TransactionRequestAccountJsonV140 ( @@ -1322,7 +1317,12 @@ object JSONFactory400 { charge = try {TransactionRequestChargeJsonV200 (summary = stringOrNull(tr.charge.summary), value = AmountOfMoneyJsonV121(currency = stringOrNull(tr.charge.value.currency), amount = stringOrNull(tr.charge.value.amount)) - )} catch {case _ : Throwable => null} + )} catch {case _ : Throwable => null}, + attributes = if(transactionRequestAttribute.isEmpty) None else Some(transactionRequestAttribute + .map(attribute =>BankAttributeBankResponseJsonV400( + attribute.name, + attribute.value + ))) ) } 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 1aa13af558..ecd900e74e 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 @@ -2795,7 +2795,83 @@ trait APIMethods510 { } } + resourceDocs += ResourceDoc( + getTransactionRequests, + implementedInApiVersion, + nameOf(getTransactionRequests), + "GET", + "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests", + "Get Transaction Requests." , + """Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID. + | + |The VIEW_ID specified must be 'owner' and the user must have access to this view. + | + |Version 2.0.0 now returns charge information. + | + |Transaction Requests serve to initiate transactions that may or may not proceed. They contain information including: + | + |* Transaction Request Id + |* Type + |* Status (INITIATED, COMPLETED) + |* Challenge (in order to confirm the request) + |* From Bank / Account + |* Details including Currency, Value, Description and other initiation information specific to each type. (Could potentialy include a list of future transactions.) + |* Related Transactions + | + |PSD2 Context: PSD2 requires transparency of charges to the customer. + |This endpoint provides the charge that would be applied if the Transaction Request proceeds - and a record of that charge there after. + |The customer can proceed with the Transaction by answering the security challenge. + | + |We support query transaction request by attribute + |URL params example:/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests?invoiceNumber=123&referenceNumber=456 + | + """.stripMargin, + EmptyBody, + transactionRequestWithChargeJSONs210, + List( + UserNotLoggedIn, + BankNotFound, + BankAccountNotFound, + UserNoPermissionAccessView, + ViewDoesNotPermitAccess, + GetTransactionRequestsException, + UnknownError + ), + List(apiTagTransactionRequest, apiTagPSD2PIS)) + lazy val getTransactionRequests: OBPEndpoint = { + case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-requests" :: Nil JsonGet req => { + cc => implicit val ec = EndpointContext(Some(cc)) + for { + (Full(u), callContext) <- authenticatedAccess(cc) + _ <- NewStyle.function.isEnabledTransactionRequests(callContext) + (_, callContext) <- NewStyle.function.getBank(bankId, callContext) + (fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(bankId, accountId, callContext) + view <- NewStyle.function.checkAccountAccessAndGetView(viewId, BankIdAccountId(bankId, accountId), Full(u), callContext) + _ <- Helper.booleanToFuture( + s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${StringHelpers.snakify(nameOf(ViewDefinition.canSeeTransactionRequests_)).dropRight(1)}` permission on the View(${viewId.value})", + cc=callContext){ + view.canSeeTransactionRequests + } + (transactionRequests, callContext) <- Future(Connector.connector.vend.getTransactionRequests210(u, fromAccount, callContext)) map { + unboxFullOrFail(_, callContext, GetTransactionRequestsException) + } + (transactionRequestAttributes, callContext) <- NewStyle.function.getByAttributeNameValues(bankId, req.params, true, callContext) + transactionRequestIds = transactionRequestAttributes.map(_.transactionRequestId) + + transactionRequestsFiltered = if(req.params.isEmpty) + transactionRequests + else + transactionRequests.filter(transactionRequest => transactionRequestIds.contains(transactionRequest.id)) + + } yield { + val json = JSONFactory510.createTransactionRequestJSONs(transactionRequestsFiltered, transactionRequestAttributes) + + (json, HttpCode.`200`(callContext)) + } + } + } + staticResourceDocs += ResourceDoc( getAccountAccessByUserId, 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 1b9f1f6f4a..8cad60f028 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 @@ -30,7 +30,9 @@ import code.api.Constant import code.api.util.APIUtil.{DateWithDay, DateWithSeconds, gitCommit, stringOrNull} import code.api.util._ import code.api.v1_2_1.BankRoutingJsonV121 -import code.api.v1_4_0.JSONFactory1_4_0.{LocationJsonV140, MetaJsonV140, transformToLocationFromV140, transformToMetaFromV140} +import code.api.v1_4_0.JSONFactory1_4_0.{LocationJsonV140, MetaJsonV140, transformToLocationFromV140, transformToMetaFromV140, + TransactionRequestAccountJsonV140,ChallengeJsonV140} +import code.api.v2_0_0.TransactionRequestChargeJsonV200 import code.api.v2_1_0.ResourceUserJSON import code.api.v3_0_0.JSONFactory300.{createLocationJson, createMetaJson, transformToAddressFromV300} import code.api.v3_0_0.{AddressJsonV300, OpeningTimesV300} @@ -555,10 +557,67 @@ case class ConsumerLogoUrlJson( logo_url: String ) +case class TransactionRequestJsonV510( + transaction_request_id: String, + transaction_request_type: String, + from: TransactionRequestAccountJsonV140, + details: TransactionRequestBodyAllTypes, + transaction_ids: List[String], + status: String, + start_date: Date, + end_date: Date, + challenge: ChallengeJsonV140, + charge : TransactionRequestChargeJsonV200, + attributes: List[TransactionRequestAttributeJsonV400] +) + +case class TransactionRequestsJsonV510( + transaction_requests : List[TransactionRequestJsonV510] +) + case class SyncExternalUserJson(user_id: String) object JSONFactory510 extends CustomJsonFormats { + def createTransactionRequestJson(tr : TransactionRequest, transactionRequestAttributes: List[TransactionRequestAttributeTrait] ) : TransactionRequestJsonV510 = { + TransactionRequestJsonV510( + transaction_request_id = stringOrNull(tr.id.value), + transaction_request_type = stringOrNull(tr.`type`), + from = try{TransactionRequestAccountJsonV140 ( + bank_id = stringOrNull(tr.from.bank_id), + account_id = stringOrNull(tr.from.account_id) + )} catch {case _ : Throwable => null}, + details = try{tr.body} catch {case _ : Throwable => null}, + transaction_ids = tr.transaction_ids::Nil, + status = stringOrNull(tr.status), + start_date = tr.start_date, + end_date = tr.end_date, + // Some (mapped) data might not have the challenge. TODO Make this nicer + challenge = { + try {ChallengeJsonV140 (id = stringOrNull(tr.challenge.id), allowed_attempts = tr.challenge.allowed_attempts, challenge_type = stringOrNull(tr.challenge.challenge_type))} + // catch { case _ : Throwable => ChallengeJSON (id = "", allowed_attempts = 0, challenge_type = "")} + catch { case _ : Throwable => null} + }, + charge = try {TransactionRequestChargeJsonV200 (summary = stringOrNull(tr.charge.summary), + value = AmountOfMoneyJsonV121(currency = stringOrNull(tr.charge.value.currency), + amount = stringOrNull(tr.charge.value.amount)) + )} catch {case _ : Throwable => null}, + attributes = transactionRequestAttributes.filter(_.transactionRequestId==tr.id).map(transactionRequestAttribute => TransactionRequestAttributeJsonV400( + transactionRequestAttribute.name, + transactionRequestAttribute.attributeType.toString, + transactionRequestAttribute.value + )) + ) + } + + def createTransactionRequestJSONs(transactionRequests : List[TransactionRequest], transactionRequestAttributes: List[TransactionRequestAttributeTrait]) : TransactionRequestsJsonV510 = { + TransactionRequestsJsonV510( + transactionRequests.map( + transactionRequest => + createTransactionRequestJson(transactionRequest, transactionRequestAttributes) + )) + } + def createViewJson(view: View): CustomViewJsonV510 = { val alias = if (view.usePublicAliasIfOneExists) diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 673c3e1b47..79118a0d29 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -1550,8 +1550,19 @@ trait Connector extends MdcLoggable { def getTransactionRequestAttributeById(transactionRequestAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequestAttributeTrait]] = Future{(Failure(setUnimplementedError(nameOf(getTransactionRequestAttributeById _))), callContext)} - def getTransactionRequestIdsByAttributeNameValues(bankId: BankId, params: Map[String, List[String]], - callContext: Option[CallContext]): OBPReturnType[Box[List[String]]] = Future{(Failure(setUnimplementedError(nameOf(getTransactionRequestIdsByAttributeNameValues _))), callContext)} + def getTransactionRequestIdsByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal: Boolean, + callContext: Option[CallContext] + ): OBPReturnType[Box[List[String]]] = Future{(Failure(setUnimplementedError(nameOf(getTransactionRequestIdsByAttributeNameValues _))), callContext)} + + def getByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal: Boolean, + callContext: Option[CallContext] + ): OBPReturnType[Box[List[TransactionRequestAttributeTrait]]] = Future{(Failure(setUnimplementedError(nameOf(getByAttributeNameValues _))), callContext)} def createOrUpdateTransactionRequestAttribute(bankId: BankId, transactionRequestId: TransactionRequestId, @@ -1560,10 +1571,10 @@ trait Connector extends MdcLoggable { attributeType: TransactionRequestAttributeType.Value, value: String, callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequestAttributeTrait]] = Future{(Failure(setUnimplementedError(nameOf(createOrUpdateTransactionRequestAttribute _))), callContext)} - def createTransactionRequestAttributes(bankId: BankId, transactionRequestId: TransactionRequestId, - transactionRequestAttributes: List[TransactionRequestAttributeTrait], + transactionRequestAttributes: List[TransactionRequestAttributeJsonV400], + isPersonal: Boolean, callContext: Option[CallContext]): OBPReturnType[Box[List[TransactionRequestAttributeTrait]]] = Future{(Failure(setUnimplementedError(nameOf(createTransactionRequestAttributes _))), callContext)} def deleteTransactionRequestAttribute(transactionRequestAttributeId: String, diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index 793ca63ca7..93c8d2341a 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -1752,11 +1752,30 @@ object LocalMappedConnector extends Connector with MdcLoggable { ).map((_, callContext)) } - override def getTransactionRequestIdsByAttributeNameValues(bankId: BankId, params: Map[String, List[String]], - callContext: Option[CallContext]): OBPReturnType[Box[List[String]]] = { + override def getTransactionRequestIdsByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal: Boolean, + callContext: Option[CallContext] + ): OBPReturnType[Box[List[String]]] = { TransactionRequestAttributeX.transactionRequestAttributeProvider.vend.getTransactionRequestIdsByAttributeNameValues( bankId: BankId, - params: Map[String, List[String]] + params: Map[String, List[String]], + isPersonal + ).map((_, callContext)) + } + + + override def getByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal: Boolean, + callContext: Option[CallContext] + ): OBPReturnType[Box[List[TransactionRequestAttributeTrait]]] = { + TransactionRequestAttributeX.transactionRequestAttributeProvider.vend.getByAttributeNameValues( + bankId: BankId, + params: Map[String, List[String]], + isPersonal: Boolean, ).map((_, callContext)) } @@ -1779,12 +1798,14 @@ object LocalMappedConnector extends Connector with MdcLoggable { override def createTransactionRequestAttributes(bankId: BankId, transactionRequestId: TransactionRequestId, - transactionRequestAttributes: List[TransactionRequestAttributeTrait], + transactionRequestAttributes: List[TransactionRequestAttributeJsonV400], + isPersonal: Boolean, callContext: Option[CallContext]): OBPReturnType[Box[List[TransactionRequestAttributeTrait]]] = { TransactionRequestAttributeX.transactionRequestAttributeProvider.vend.createTransactionRequestAttributes( bankId: BankId, transactionRequestId: TransactionRequestId, - transactionRequestAttributes: List[TransactionRequestAttributeTrait] + transactionRequestAttributes: List[TransactionRequestAttributeJsonV400], + isPersonal: Boolean, ).map((_, callContext)) } @@ -4778,7 +4799,8 @@ object LocalMappedConnector extends Connector with MdcLoggable { value = AmountOfMoneyJsonV121(body.value.currency, body.value.amount), description = body.description, charge_policy = transactionRequest.charge_policy, - future_date = transactionRequest.future_date) + future_date = transactionRequest.future_date, + None)//this TransactionRequestAttributeJsonV400 is only in OBP side (transactionId, callContext) <- NewStyle.function.makePaymentv210( fromAccount, diff --git a/obp-api/src/main/scala/code/bankconnectors/generator/CommonsCaseClassGenerator.scala b/obp-api/src/main/scala/code/bankconnectors/generator/CommonsCaseClassGenerator.scala index 122d526e29..88a284b8c3 100644 --- a/obp-api/src/main/scala/code/bankconnectors/generator/CommonsCaseClassGenerator.scala +++ b/obp-api/src/main/scala/code/bankconnectors/generator/CommonsCaseClassGenerator.scala @@ -1,21 +1,30 @@ package code.bankconnectors.generator import code.bankconnectors.generator.ConnectorBuilderUtil._ - import scala.reflect.runtime.{universe => ru} object CommonsCaseClassGenerator extends App { + + //We will copy the output to the `obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala` + //We need to check if the classCommons is existing or not. + val allExistingClasses = getClassesFromPackage("com.openbankproject.commons.model") + .filter(it =>it.getName.endsWith("Commons")) + .toList - val returnModels: Iterable[ru.Type] = connectorDeclsMethodsReturnOBPRequiredType - .map(it => it.asMethod.returnType) + + val missingReturnModels: Set[ru.Type] = connectorDeclsMethodsReturnOBPRequiredType + .map(it => extractReturnModel(it.asMethod.returnType)) // OBPReturnType[Box[IbanChecker]] --> IbanChecker .filter(it => { val symbol = it.typeSymbol val isAbstract = symbol.isAbstract - isAbstract //Depends here, maybe no need this guard for some commons classes. + isAbstract //We only need the commons classes for abstract class, eg: ProductAttributeCommons instead of ProductAttribute }) + .filterNot(it => + allExistingClasses.find(thisClass=> thisClass.toString.contains(s"${it.typeSymbol.name}Commons")).isDefined + ) //filter what we have implemented .toSet - returnModels.map(_.typeSymbol.fullName).foreach(it => println(s"import $it")) + missingReturnModels.map(_.typeSymbol.fullName).foreach(it => println(s"import $it")) def mkClass(tp: ru.Type) = { val varibles = tp.decls.map(it => s"${it.name} :${it.typeSignature.typeSymbol.name}").mkString(", \n ") @@ -27,7 +36,10 @@ object CommonsCaseClassGenerator extends App { """.stripMargin } // private val str: String = ru.typeOf[Bank].decls.map(it => s"${it.name} :${it.typeSignature.typeSymbol.name}").mkString(", \n") - returnModels.map(mkClass).foreach(println) + private val caseClassStrings: Set[String] = missingReturnModels.map(mkClass) + caseClassStrings.foreach { + println + } println() } 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 1187c5a96f..43172d3fa7 100644 --- a/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala +++ b/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala @@ -9,7 +9,9 @@ import org.apache.commons.io.FileUtils import org.apache.commons.lang3.StringUtils.uncapitalize import java.io.File +import java.net.URL import java.util.Date +import scala.jdk.CollectionConverters.enumerationAsScalaIteratorConverter import scala.language.postfixOps import scala.reflect.runtime.universe._ import scala.reflect.runtime.{universe => ru} @@ -18,6 +20,26 @@ import scala.reflect.runtime.{universe => ru} * this is util for Connector builders, this should never be called by product code. */ object ConnectorBuilderUtil { + + def getClassesFromPackage(packageName: String): Seq[Class[_]] = { + val classLoader = Thread.currentThread().getContextClassLoader + val path = packageName.replace('.', '/') + val resources: Seq[URL] = classLoader.getResources(path).asScala.toSeq + + resources.flatMap { resource => + val file = new File(resource.toURI) + if (file.isDirectory) { + file.listFiles() + .filter(_.getName.endsWith(".class")) + .map(_.getName.stripSuffix(".class")) + .map(className => Class.forName(s"$packageName.$className")) + } else { + Seq.empty + } + } + } + + // rewrite method code.webuiprops.MappedWebUiPropsProvider#getWebUiPropsValue, avoid access DB cause dataSource not found exception { import javassist.ClassPool @@ -34,8 +56,8 @@ object ConnectorBuilderUtil { * //def getAdapterInfo(callContext: Option[CallContext]) : Future[Box[(InboundAdapterInfoInternal, Option[CallContext])]] = ??? * //def validateAndCheckIbanNumber(iban: String, callContext: Option[CallContext]): OBPReturnType[Box[IbanChecker]] = ??? * - * This method will only extact the first return class from the method, this is the OBP pattern. - * so we can use it for gernerate the commons case class. + * This method will only extract the first return class from the method, this is the OBP pattern. + * so we can use it for generate the commons case class. * * eg: getAdapterInfo --> return InboundAdapterInfoInternal * validateAndCheckIbanNumber -->return IbanChecker diff --git a/obp-api/src/main/scala/code/bankconnectors/generator/InOutCaseClassGenerator.scala b/obp-api/src/main/scala/code/bankconnectors/generator/InOutCaseClassGenerator.scala index c223dcd511..e5e4c5c416 100644 --- a/obp-api/src/main/scala/code/bankconnectors/generator/InOutCaseClassGenerator.scala +++ b/obp-api/src/main/scala/code/bankconnectors/generator/InOutCaseClassGenerator.scala @@ -4,30 +4,36 @@ import code.bankconnectors.generator.ConnectorBuilderUtil._ object InOutCaseClassGenerator extends App { - val code = connectorDeclsMethodsReturnOBPRequiredType.map(it => { - val returnType = it.returnType - val tp = extractReturnModel(returnType) - val isCaseClass = tp.typeSymbol.asClass.isCaseClass - var payload = returnType.toString - .replaceAll("([\\w\\.]+\\.)", "") - .replaceFirst("OBPReturnType\\[Box\\[(.*)\\]\\]$", "$1") - .replaceFirst("Future\\[Box\\[\\((.*), Option\\[CallContext\\]\\)\\]\\]$", "$1") - if(!isCaseClass) { - val name = tp.typeSymbol.name.toString - println(name) - payload = payload.replace(name, name+"Commons") - } - var parameters = it.asMethod.typeSignature.toString.replaceAll("([\\w\\.]+\\.)", "") - if(parameters.startsWith("(callContext: Option[CallContext])")) { - parameters = "" - } else { - parameters = parameters.replaceFirst("^\\(", ", ").replaceFirst(", callContext: Option.*$", "").replace(",", ",\n") - } - s""" - |case class OutBound${it.name.toString.capitalize} (outboundAdapterCallContext: OutboundAdapterCallContext$parameters) extends TopicTrait - |case class InBound${it.name.toString.capitalize} (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: $payload) extends InBoundTrait[$payload] + //We will copy the output to the `obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala` + //We need to check if the outbound/inbound is existing or not. + val allExistingClasses = getClassesFromPackage("com.openbankproject.commons.dto") + + val code = connectorDeclsMethodsReturnOBPRequiredType + .filter(it => allExistingClasses.toString.contains(s"OutBound${it.name.toString.capitalize} ")) //filter what we have implemented + .map(it => { + val returnType = it.returnType + val tp = extractReturnModel(returnType) + val isCaseClass = tp.typeSymbol.asClass.isCaseClass + var payload = returnType.toString + .replaceAll("([\\w\\.]+\\.)", "") + .replaceFirst("OBPReturnType\\[Box\\[(.*)\\]\\]$", "$1") + .replaceFirst("Future\\[Box\\[\\((.*), Option\\[CallContext\\]\\)\\]\\]$", "$1") + if (!isCaseClass) { + val name = tp.typeSymbol.name.toString + println(name) + payload = payload.replace(name, name + "Commons") + } + var parameters = it.asMethod.typeSignature.toString.replaceAll("([\\w\\.]+\\.)", "") + if (parameters.startsWith("(callContext: Option[CallContext])")) { + parameters = "" + } else { + parameters = parameters.replaceFirst("^\\(", ", ").replaceFirst(", callContext: Option.*$", "").replace(",", ",\n") + } + s""" + |case class OutBound${it.name.toString.capitalize} (outboundAdapterCallContext: OutboundAdapterCallContext$parameters) extends TopicTrait + |case class InBound${it.name.toString.capitalize} (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: $payload) extends InBoundTrait[$payload] """.stripMargin - }) + }) code.foreach(println) println("#################################Finished########################################################################") 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 b4729b83b0..16815c1363 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 @@ -5395,7 +5395,7 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { exampleInboundMessage = ( InBoundGetBankAttributesByBank(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, status=MessageDocsSwaggerDefinitions.inboundStatus, - data=List( BankAttributeCommons(bankId=BankId(bankIdExample.value), + data=List( BankAttributeTraitCommons(bankId=BankId(bankIdExample.value), bankAttributeId="string", attributeType=com.openbankproject.commons.model.enums.BankAttributeType.example, name=nameExample.value, @@ -5409,7 +5409,7 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable { 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)) + response.map(convertToTuple[List[BankAttributeTraitCommons]](callContext)) } messageDocs += getProductAttributeByIdDoc diff --git a/obp-api/src/main/scala/code/transactionRequestAttribute/MappedTransactionRequestAttributeProvider.scala b/obp-api/src/main/scala/code/transactionRequestAttribute/MappedTransactionRequestAttributeProvider.scala index 89e3f823e9..25ba094172 100644 --- a/obp-api/src/main/scala/code/transactionRequestAttribute/MappedTransactionRequestAttributeProvider.scala +++ b/obp-api/src/main/scala/code/transactionRequestAttribute/MappedTransactionRequestAttributeProvider.scala @@ -2,9 +2,9 @@ package code.transactionRequestAttribute import code.api.attributedefinition.AttributeDefinition import com.openbankproject.commons.model.enums.{AttributeCategory, TransactionRequestAttributeType} -import com.openbankproject.commons.model.{BankId, TransactionRequestAttributeTrait, TransactionRequestId, ViewId} +import com.openbankproject.commons.model.{BankId, TransactionRequestAttributeJsonV400, TransactionRequestAttributeTrait, TransactionRequestId, ViewId} import net.liftweb.common.{Box, Empty, Full} -import net.liftweb.mapper.{By, BySql, IHaveValidatedThisSQL} +import net.liftweb.mapper.{By, BySql,In, IHaveValidatedThisSQL} import net.liftweb.util.Helpers.tryo import scala.collection.immutable.List @@ -13,7 +13,7 @@ import scala.concurrent.Future object MappedTransactionRequestAttributeProvider extends TransactionRequestAttributeProvider { - override def getTransactionRequestAttributesFromProvider(transactionRequestId: TransactionRequestId): Future[Box[List[TransactionRequestAttribute]]] = + override def getTransactionRequestAttributesFromProvider(transactionRequestId: TransactionRequestId): Future[Box[List[TransactionRequestAttributeTrait]]] = Future { Box !! TransactionRequestAttribute.findAll( By(TransactionRequestAttribute.TransactionRequestId, transactionRequestId.value) @@ -23,7 +23,7 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri override def getTransactionRequestAttributes( bankId: BankId, transactionRequestId: TransactionRequestId - ): Future[Box[List[TransactionRequestAttribute]]] = { + ): Future[Box[List[TransactionRequestAttributeTrait]]] = { Future { Box !! TransactionRequestAttribute.findAll( By(TransactionRequestAttribute.BankId, bankId.value), @@ -34,7 +34,7 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri override def getTransactionRequestAttributesCanBeSeenOnView(bankId: BankId, transactionRequestId: TransactionRequestId, - viewId: ViewId): Future[Box[List[TransactionRequestAttribute]]] = { + viewId: ViewId): Future[Box[List[TransactionRequestAttributeTrait]]] = { Future { val attributeDefinitions = AttributeDefinition.findAll( By(AttributeDefinition.BankId, bankId.value), @@ -59,27 +59,40 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri TransactionRequestAttribute.find(By(TransactionRequestAttribute.TransactionRequestAttributeId, transactionRequestAttributeId)) } - override def getTransactionRequestIdsByAttributeNameValues(bankId: BankId, params: Map[String, List[String]]): Future[Box[List[String]]] = + override def getTransactionRequestIdsByAttributeNameValues(bankId: BankId, params: Map[String, List[String]], isPersonal: Boolean): Future[Box[List[String]]] = + getByAttributeNameValues(bankId: BankId, params, isPersonal) + .map( + attributesBox =>attributesBox + .map(attributes=> + attributes.map(attribute => + attribute.transactionRequestId.value + ))) + + override def getByAttributeNameValues(bankId: BankId, params: Map[String, List[String]], isPersonal: Boolean): Future[Box[List[TransactionRequestAttributeTrait]]] = Future { Box !! { if (params.isEmpty) { - TransactionRequestAttribute.findAll(By(TransactionRequestAttribute.BankId, bankId.value)).map(_.transactionRequestId.value) + TransactionRequestAttribute.findAll( + By(TransactionRequestAttribute.BankId, bankId.value), + By(TransactionRequestAttribute.IsPersonal, true) + ) } else { val paramList = params.toList val parameters: List[String] = TransactionRequestAttribute.getParameters(paramList) val sqlParametersFilter = TransactionRequestAttribute.getSqlParametersFilter(paramList) - val transactionRequestIdList = paramList.isEmpty match { + paramList.isEmpty match { case true => TransactionRequestAttribute.findAll( - By(TransactionRequestAttribute.BankId, bankId.value) - ).map(_.transactionRequestId.value) + By(TransactionRequestAttribute.BankId, bankId.value), + By(TransactionRequestAttribute.IsPersonal, true) + ) case false => TransactionRequestAttribute.findAll( By(TransactionRequestAttribute.BankId, bankId.value), + By(TransactionRequestAttribute.IsPersonal, true), BySql(sqlParametersFilter, IHaveValidatedThisSQL("developer", "2020-06-28"), parameters: _*) - ).map(_.transactionRequestId.value) + ) } - transactionRequestIdList } } } @@ -119,9 +132,12 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri } } - override def createTransactionRequestAttributes(bankId: BankId, - transactionRequestId: TransactionRequestId, - transactionRequestAttributes: List[TransactionRequestAttributeTrait]): Future[Box[List[TransactionRequestAttributeTrait]]] = { + override def createTransactionRequestAttributes( + bankId: BankId, + transactionRequestId: TransactionRequestId, + transactionRequestAttributes: List[TransactionRequestAttributeJsonV400], + isPersonal: Boolean + ): Future[Box[List[TransactionRequestAttributeTrait]]] = { Future { tryo { for { @@ -130,8 +146,9 @@ object MappedTransactionRequestAttributeProvider extends TransactionRequestAttri TransactionRequestAttribute.create.TransactionRequestId(transactionRequestId.value) .BankId(bankId.value) .Name(transactionRequestAttribute.name) - .Type(transactionRequestAttribute.attributeType.toString()) + .Type(transactionRequestAttribute.attribute_type) .`Value`(transactionRequestAttribute.value) + .IsPersonal(isPersonal) .saveMe() } } diff --git a/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttribute.scala b/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttribute.scala index 99c55d000b..dc57393293 100644 --- a/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttribute.scala +++ b/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttribute.scala @@ -22,6 +22,8 @@ class TransactionRequestAttribute extends TransactionRequestAttributeTrait with override def attributeType: TransactionRequestAttributeType.Value = TransactionRequestAttributeType.withName(Type.get) override def value: String = `Value`.get + + override def isPersonal: Boolean = IsPersonal.get object BankId extends UUIDString(this) // combination of this @@ -34,6 +36,8 @@ class TransactionRequestAttribute extends TransactionRequestAttributeTrait with object Type extends MappedString(this, 50) object `Value` extends MappedString(this, 255) + + object IsPersonal extends MappedBoolean(this) } diff --git a/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttributeProvider.scala b/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttributeProvider.scala index 3c5482cb99..e40acb4952 100644 --- a/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttributeProvider.scala +++ b/obp-api/src/main/scala/code/transactionRequestAttribute/TransactionRequestAttributeProvider.scala @@ -1,7 +1,7 @@ package code.transactionRequestAttribute import com.openbankproject.commons.model.enums.TransactionRequestAttributeType -import com.openbankproject.commons.model.{BankId, TransactionRequestAttributeTrait, TransactionRequestId, ViewId} +import com.openbankproject.commons.model.{BankId, TransactionRequestAttributeJsonV400, TransactionRequestAttributeTrait, TransactionRequestId, ViewId} import net.liftweb.common.{Box, Logger} import scala.collection.immutable.List @@ -22,8 +22,10 @@ trait TransactionRequestAttributeProvider { def getTransactionRequestAttributeById(transactionRequestAttributeId: String): Future[Box[TransactionRequestAttributeTrait]] - def getTransactionRequestIdsByAttributeNameValues(bankId: BankId, params: Map[String, List[String]]): Future[Box[List[String]]] - + def getTransactionRequestIdsByAttributeNameValues(bankId: BankId, params: Map[String, List[String]], isPersonal: Boolean): Future[Box[List[String]]] + + def getByAttributeNameValues(bankId: BankId, params: Map[String, List[String]], isPersonal: Boolean): Future[Box[List[TransactionRequestAttributeTrait]]] + def createOrUpdateTransactionRequestAttribute(bankId: BankId, transactionRequestId: TransactionRequestId, transactionRequestAttributeId: Option[String], @@ -33,7 +35,8 @@ trait TransactionRequestAttributeProvider { def createTransactionRequestAttributes(bankId: BankId, transactionRequestId: TransactionRequestId, - transactionRequestAttributes: List[TransactionRequestAttributeTrait]): Future[Box[List[TransactionRequestAttributeTrait]]] + transactionRequestAttributes: List[TransactionRequestAttributeJsonV400], + isPersonal: Boolean): Future[Box[List[TransactionRequestAttributeTrait]]] def deleteTransactionRequestAttribute(transactionRequestAttributeId: String): Future[Box[Boolean]] diff --git a/obp-api/src/test/resources/frozen_type_meta_data b/obp-api/src/test/resources/frozen_type_meta_data index 1eac092a2c..c3193620f7 100644 Binary files a/obp-api/src/test/resources/frozen_type_meta_data and b/obp-api/src/test/resources/frozen_type_meta_data differ diff --git a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala index b4b56e5c7f..c26e87f62e 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestAttributesTest.scala @@ -107,7 +107,7 @@ class TransactionRequestAttributesTest extends V400ServerSetup { responseWithRole.code should equal(201) responseWithRole.body.extract[TransactionRequestAttributeResponseJson].name equals ("test") should be(true) responseWithRole.body.extract[TransactionRequestAttributeResponseJson].value equals (postTransactionRequestAttributeJsonV400.value) should be(true) - responseWithRole.body.extract[TransactionRequestAttributeResponseJson].`type` equals (postTransactionRequestAttributeJsonV400.`type`) should be(true) + responseWithRole.body.extract[TransactionRequestAttributeResponseJson].`type` equals (postTransactionRequestAttributeJsonV400.attribute_type) should be(true) } } } @@ -168,7 +168,7 @@ class TransactionRequestAttributesTest extends V400ServerSetup { responseWithRole.code should equal(201) responseWithRole.body.extract[TransactionRequestAttributeResponseJson].name equals ("test") should be(true) responseWithRole.body.extract[TransactionRequestAttributeResponseJson].value equals (postTransactionRequestAttributeJsonV400.value) should be(true) - responseWithRole.body.extract[TransactionRequestAttributeResponseJson].`type` equals (postTransactionRequestAttributeJsonV400.`type`) should be(true) + responseWithRole.body.extract[TransactionRequestAttributeResponseJson].`type` equals (postTransactionRequestAttributeJsonV400.attribute_type) should be(true) } } } @@ -220,7 +220,7 @@ class TransactionRequestAttributesTest extends V400ServerSetup { responseWithId.body.extract[TransactionRequestAttributeResponseJson].name equals ("test") should be(true) responseWithId.body.extract[TransactionRequestAttributeResponseJson].value equals (putTransactionRequestAttributeJsonV400.value) should be(true) - responseWithId.body.extract[TransactionRequestAttributeResponseJson].`type` equals (putTransactionRequestAttributeJsonV400.`type`) should be(true) + responseWithId.body.extract[TransactionRequestAttributeResponseJson].`type` equals (putTransactionRequestAttributeJsonV400.attribute_type) should be(true) } } } @@ -275,7 +275,7 @@ class TransactionRequestAttributesTest extends V400ServerSetup { responseWithId.body.extract[TransactionRequestAttributeResponseJson].name should equal(postTransactionRequestAttributeJsonV400.name) responseWithId.body.extract[TransactionRequestAttributeResponseJson].value should equal(postTransactionRequestAttributeJsonV400.value) - responseWithId.body.extract[TransactionRequestAttributeResponseJson].`type` should equal(postTransactionRequestAttributeJsonV400.`type`) + responseWithId.body.extract[TransactionRequestAttributeResponseJson].`type` should equal(postTransactionRequestAttributeJsonV400.attribute_type) } } } diff --git a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala index 1da1d41d85..2988f76c8a 100644 --- a/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala +++ b/obp-api/src/test/scala/code/api/v4_0_0/TransactionRequestsTest.scala @@ -152,7 +152,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers { var transactionRequestBodySEPA = TransactionRequestBodySEPAJSON(bodyValue, IbanJson(counterpartySEPA.otherAccountSecondaryRoutingAddress), description, sharedChargePolicy) var transactionRequestBodyAgentCashWithdrawal = TransactionRequestBodyAgentJsonV400(AgentCashWithdrawalJson(agentCashWithdrawalAgent.bank_id,agentCashWithdrawalAgent.agent_number), bodyValue, description, sharedChargePolicy) - var transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON(CounterpartyIdJson(counterpartyCounterparty.counterpartyId), bodyValue, description, sharedChargePolicy) + var transactionRequestBodyCounterparty = TransactionRequestBodyCounterpartyJSON(CounterpartyIdJson(counterpartyCounterparty.counterpartyId), bodyValue, description,sharedChargePolicy) var transactionRequestBodySimple = TransactionRequestBodySimpleJsonV400(SwaggerDefinitionsJSON.postSimpleCounterpartyJson400.copy( other_account_routing_address = counterpartyCounterparty.otherAccountRoutingAddress, other_bank_routing_address= counterpartyCounterparty.otherBankRoutingAddress, 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 35e1b2346d..6033c5d51c 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 @@ -242,7 +242,8 @@ class CounterpartyLimitTest extends V510ServerSetup { value = AmountOfMoneyJsonV121("EUR","11"), description ="testing the limit", charge_policy = "SHARED", - future_date = None + future_date = None, + None, ) val response = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty)) @@ -303,7 +304,8 @@ class CounterpartyLimitTest extends V510ServerSetup { value = AmountOfMoneyJsonV121("EUR","11"), description ="testing the limit", charge_policy = "SHARED", - future_date = None + future_date = None, + None, ) val response1 = makePostRequest( @@ -356,7 +358,8 @@ class CounterpartyLimitTest extends V510ServerSetup { value = AmountOfMoneyJsonV121("EUR","11"), description ="testing the limit", charge_policy = "SHARED", - future_date = None + future_date = None, + None, ) //("we try the max_monthly_amount limit (11 euros) . now we transfer 9 euro first. then 9 euros, we will get the error") diff --git a/obp-api/src/test/scala/code/api/v5_1_0/TransactionRequestTest.scala b/obp-api/src/test/scala/code/api/v5_1_0/TransactionRequestTest.scala new file mode 100644 index 0000000000..e724286b50 --- /dev/null +++ b/obp-api/src/test/scala/code/api/v5_1_0/TransactionRequestTest.scala @@ -0,0 +1,169 @@ +/** +Open Bank Project - API +Copyright (C) 2011-2019, TESOBE GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +Email: contact@tesobe.com +TESOBE GmbH +Osloerstrasse 16/17 +Berlin 13359, Germany + +This product includes software developed at +TESOBE (http://www.tesobe.com/) +*/ +package code.api.v5_1_0 + +import code.api.Constant +import code.api.util.ErrorMessages._ +import code.api.util.APIUtil.OAuth._ +import code.api.v2_1_0.{CounterpartyIdJson, TransactionRequestBodyCounterpartyJSON, TransactionRequestWithChargeJSONs210} +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.{AmountOfMoneyJsonV121, ErrorMessage,TransactionRequestAttributeJsonV400} +import com.openbankproject.commons.util.ApiVersion +import net.liftweb.json.Serialization.write +import org.scalatest.Tag + +import java.util.UUID + +class TransactionRequestTest extends V510ServerSetup { + + /** + * Test tags + * Example: To run tests with tag "getPermissions": + * mvn test -D tagsToInclude + * + * This is made possible by the scalatest maven plugin + */ + object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString) + object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.getTransactionRequests)) + object ApiEndpoint2 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestCounterparty)) + + feature("Get Transaction Requests - v5.1.0") + { + scenario("We will Get Transaction Requests - user is NOT logged in", ApiEndpoint1, VersionOfApi) { + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "banks" / testBankId1.value / "accounts" / testAccountId0.value / Constant.SYSTEM_OWNER_VIEW_ID / "transaction-requests").GET + val response510 = makeGetRequest(request510) + Then("We should get a 401") + response510.code should equal(401) + And("error should be " + UserNotLoggedIn) + response510.body.extract[ErrorMessage].message should equal (UserNotLoggedIn) + } + scenario("We will Get Transaction Requests - user is logged in", ApiEndpoint1, VersionOfApi) { + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "banks" / testBankId1.value / "accounts" / testAccountId0.value / Constant.SYSTEM_OWNER_VIEW_ID / "transaction-requests").GET <@(user1) + val response510 = makeGetRequest(request510) + Then("We should get a 200") + response510.code should equal(200) + response510.body.extract[TransactionRequestsJsonV510] + } + scenario("We will try to Get Transaction Requests for someone else account - user is logged in", ApiEndpoint1, VersionOfApi) { + When("We make a request v5.1.0") + val request510 = ( + v5_1_0_Request / "banks" / testBankId1.value / "accounts" / testAccountId0.value / Constant.SYSTEM_OWNER_VIEW_ID / "transaction-requests").GET <@ (user2) + val response510 = makeGetRequest(request510) + Then("We should get a 403") + response510.code should equal(403) + And("error should be " + UserNoPermissionAccessView) + response510.body.extract[ErrorMessage].message contains (UserNoPermissionAccessView) shouldBe (true) + } + + scenario("We will try to Get Transaction Requests with Attributes", ApiEndpoint1, ApiEndpoint2, VersionOfApi) { + val bankId = testBankId1.value + val accountId = testAccountId1.value + val ownerView = Constant.SYSTEM_OWNER_VIEW_ID + + val counterparty = createCounterparty(bankId, accountId, accountId, true, UUID.randomUUID.toString); + + 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, + attributes = Some(List( + TransactionRequestAttributeJsonV400( + name = "Invoice_Number", + attribute_type ="STRING" , + value = "1"), + TransactionRequestAttributeJsonV400( + name = "Reference_Number", + attribute_type ="STRING" , + value = "2"), + ))) + + val response1 = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty)) + response1.code should equal(201) + + val response2 = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty.copy(attributes = Some(List( + TransactionRequestAttributeJsonV400( + name = "Invoice_Number", + attribute_type = "STRING", + value = "1") + ))))) + response2.code should equal(201) + + val response3 = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty.copy(attributes = None))) + response3.code should equal(201) + + { + When("We make a request v5.1.0") + val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / Constant.SYSTEM_OWNER_VIEW_ID / "transaction-requests").GET <@ (user1) + val response510 = makeGetRequest(request510) + Then("We should get a 200") + response510.code should equal(200) + response510.body.extract[TransactionRequestsJsonV510].transaction_requests.length > 3 shouldBe (true) + response510.body.extract[TransactionRequestsJsonV510].transaction_requests.map(_.attributes).toString().contains("Invoice_Number") shouldBe (true) + response510.body.extract[TransactionRequestsJsonV510].transaction_requests.map(_.attributes).toString().contains("Reference_Number") shouldBe (true) + } + + { + When("we try with url parameters") + val request510 = (v5_1_0_Request / "banks" / bankId / "accounts" / accountId / Constant.SYSTEM_OWNER_VIEW_ID / "transaction-requests").GET <@ (user1)<"NONE") val response = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty), (s"Consent-JWT", consentJwt)) @@ -428,7 +430,8 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ value = AmountOfMoneyJsonV121("EUR","11"), description ="testing the limit", charge_policy = "SHARED", - future_date =None + future_date = None, + None, ) setPropsValues("consumer_validation_method_for_consent"->"NONE") val response1 = makePostRequest( @@ -515,7 +518,8 @@ class VRPConsentRequestTest extends V510ServerSetup with PropsReset{ value = AmountOfMoneyJsonV121("EUR","11"), description ="testing the limit", charge_policy = "SHARED", - future_date =None + future_date = None, + 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") 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 c1a40d0b86..5e1da9bc5e 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[BankAttributeCommons]) extends InBoundTrait[List[BankAttributeCommons]] +case class InBoundGetBankAttributesByBank(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[BankAttributeTraitCommons]) extends InBoundTrait[List[BankAttributeTraitCommons]] 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 9a7bf93275..ceda33a154 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 @@ -381,8 +381,9 @@ case class ProductCommons(bankId: BankId, object ProductCommons extends Converter[Product, ProductCommons] case class TransactionRequestCommonBodyJSONCommons( - value : AmountOfMoneyJsonV121, - description: String) extends TransactionRequestCommonBodyJSON + value: AmountOfMoneyJsonV121, + description: String, +) extends TransactionRequestCommonBodyJSON object TransactionRequestCommonBodyJSONCommons extends Converter[TransactionRequestCommonBodyJSON, TransactionRequestCommonBodyJSONCommons] @@ -509,7 +510,7 @@ case class TransactionAttributeCommons ( ) extends TransactionAttribute object TransactionAttributeCommons extends Converter[TransactionAttribute, TransactionAttributeCommons] -case class BankAttributeCommons ( +case class BankAttributeTraitCommons ( override val bankId: BankId, override val bankAttributeId: String, override val attributeType: BankAttributeType.Value, @@ -517,7 +518,7 @@ case class BankAttributeCommons ( override val value: String, override val isActive: Option[Boolean] ) extends BankAttributeTrait -object BankAttributeCommons extends Converter[BankAttributeTrait, BankAttributeCommons] +object BankAttributeTraitCommons extends Converter[BankAttributeTrait, BankAttributeTraitCommons] case class FXRateCommons ( override val bankId : BankId, @@ -699,7 +700,9 @@ case class TransactionRequestAttributeTraitCommons( transactionRequestAttributeId: String, attributeType: TransactionRequestAttributeType, name: String, - value: String) extends TransactionRequestAttributeTrait + value: String, + isPersonal: Boolean +) extends TransactionRequestAttributeTrait object TransactionRequestAttributeTraitCommons extends Converter[TransactionRequestAttributeTrait, TransactionRequestAttributeTraitCommons] @@ -814,7 +817,7 @@ case class TransactionRequestAccount ( account_id : String ) -//For SEPA, it need the iban to find the toCounterpaty--> toBankAccount +//For SEPA, it needs the iban to find the toCounterpaty--> toBankAccount case class TransactionRequestIban (iban : String) case class AmountOfMoneyJsonV121( @@ -832,6 +835,12 @@ case class FromAccountTransfer( nickname: String ) +case class TransactionRequestAttributeJsonV400( + name: String, + attribute_type: String, + value: String, +) + case class ToAccountTransferToAtmKycDocument( `type`: String, number: String diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala index 1c81d8beb5..195a8c7abb 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModelTrait.scala @@ -595,6 +595,7 @@ trait TransactionRequestAttributeTrait { def attributeType: TransactionRequestAttributeType.Value def name: String def value: String + def isPersonal: Boolean } trait DirectDebitTrait {