From 498c0de8c4974448fcab93e385dca38021ad21d9 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Thu, 26 Feb 2026 08:57:51 +0100 Subject: [PATCH 01/19] Entitlement Request pagination + Enabling ABAC for account access --- .../scala/code/abacrule/AbacRuleEngine.scala | 110 +++++++++- .../code/abacrule/AbacRuleExamples.scala | 5 +- .../main/scala/code/api/util/APIUtil.scala | 102 +++++++--- .../scala/code/api/util/ErrorMessages.scala | 1 + .../main/scala/code/api/util/NewStyle.scala | 10 + .../scala/code/api/v3_0_0/APIMethods300.scala | 13 +- .../scala/code/api/v6_0_0/APIMethods600.scala | 4 +- .../EntilementRequest.scala | 3 + .../MappedEntitlementRquests.scala | 31 ++- .../main/scala/code/model/BankingData.scala | 189 ++++++++++-------- .../api/v3_0_0/EntitlementRequestsTest.scala | 124 +++++++++++- .../scala/code/api/v6_0_0/AbacRuleTests.scala | 77 ++++++- 12 files changed, 536 insertions(+), 133 deletions(-) diff --git a/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala b/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala index 29942a47f7..0016f5241d 100644 --- a/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala +++ b/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala @@ -83,6 +83,47 @@ object AbacRuleEngine { |""".stripMargin } + /** + * Check if a rule code is too permissive (contains tautological expressions that always evaluate to true). + * + * Detects two categories: + * 1. Whole-body tautologies: the entire rule is a trivially-true expression (e.g. "true", "1==1") + * 2. Sub-expression tautologies: a tautological operand after || makes the whole expression always true + * + * Note: "&& true" is NOT flagged — it's redundant but doesn't increase permissiveness. + * + * @param ruleCode The rule code to check + * @return true if the rule code is too permissive + */ + private def isTooPermissive(ruleCode: String): Boolean = { + val stripped = ruleCode.trim + + // Whole-body tautology patterns (entire rule is trivially true) + val wholeBodyTautologies = List( + """^true$""", // bare true + """^(\d+)\s*==\s*\1$""", // numeric identity: 1==1, 42==42 + """"([^"]+)"\s*==\s*"\1"""", // string identity: "a"=="a", "foo"=="foo" + """^true\s*==\s*true$""", // boolean identity: true==true + """^!false$""", // negated false + """^!\(false\)$""" // negated false with parens + ).map(_.r) + + // Sub-expression tautology patterns (tautology after || anywhere in the rule) + val subExprTautologies = List( + """\|\|\s*true(?!\s*==)""", // || true (but not || true==true, handled separately) + """\|\|\s*true\s*==\s*true""", // || true==true + """\|\|\s*(\d+)\s*==\s*\1""", // || 1==1, || 42==42 + """\|\|\s*"([^"]+)"\s*==\s*"\1"""", // || "a"=="a" + """\|\|\s*!false""", // || !false + """\|\|\s*!\(false\)""" // || !(false) + ).map(_.r) + + val isWholeBodyTautology = wholeBodyTautologies.exists(_.findFirstIn(stripped).isDefined) + val hasSubExprTautology = subExprTautologies.exists(_.findFirstIn(stripped).isDefined) + + isWholeBodyTautology || hasSubExprTautology + } + /** * Helper to lift a Box value into a Future, converting Failure/Empty to a failed Future. */ @@ -322,8 +363,8 @@ object AbacRuleEngine { val rules = MappedAbacRuleProvider.getActiveAbacRulesByPolicy(policy) if (rules.isEmpty) { - // No rules for this policy - default to allow - Future.successful(Full(true)) + // No rules for this policy - default to deny + Future.successful(Full(false)) } else { // Execute all rules in parallel and check if at least one passes val resultFutures = rules.map { rule => @@ -355,6 +396,59 @@ object AbacRuleEngine { } } + /** + * Execute all active ABAC rules with a specific policy and return detailed results. + * Returns which rule IDs denied access (for error reporting). + * + * @return Future[Box[(Boolean, List[String])]] - Full((true, Nil)) if any rule passes, + * Full((false, failingRuleIds)) if all fail, Full((false, Nil)) if no rules exist + */ + def executeRulesByPolicyDetailed( + policy: String, + authenticatedUserId: String, + callContext: CallContext, + bankId: Option[String] = None, + accountId: Option[String] = None, + viewId: Option[String] = None + ): Future[Box[(Boolean, List[String])]] = { + val rules = MappedAbacRuleProvider.getActiveAbacRulesByPolicy(policy) + + if (rules.isEmpty) { + // No rules for this policy - default to deny + Future.successful(Full((false, Nil))) + } else { + // Execute all rules in parallel and collect results with rule IDs + val resultFutures = rules.map { rule => + executeRule( + ruleId = rule.abacRuleId, + authenticatedUserId = authenticatedUserId, + callContext = callContext, + bankId = bankId, + accountId = accountId, + viewId = viewId + ).map(result => (rule.abacRuleId, result)) + } + + Future.sequence(resultFutures).map { results => + val passed = results.exists { + case (_, Full(true)) => true + case _ => false + } + + if (passed) { + Full((true, Nil)) + } else { + val failingRuleIds = results.collect { + case (ruleId, Full(false)) => ruleId + case (ruleId, Failure(_, _, _)) => ruleId + case (ruleId, Empty) => ruleId + } + Full((false, failingRuleIds.toList)) + } + } + } + } + /** * Validate ABAC rule code by attempting to compile it * @@ -362,10 +456,14 @@ object AbacRuleEngine { * @return Box[String] - Full("OK") if valid, Failure with error message if invalid */ def validateRuleCode(ruleCode: String): Box[String] = { - compileRuleInternal(ruleCode) match { - case Full(_) => Full("ABAC rule code is valid") - case Failure(msg, _, _) => Failure(s"Invalid ABAC rule code: $msg") - case Empty => Failure("Failed to validate ABAC rule code") + if (isTooPermissive(ruleCode)) { + Failure("ABAC rule is too permissive: the rule code contains a tautological expression that would always grant access. Please write a rule that checks specific attributes.") + } else { + compileRuleInternal(ruleCode) match { + case Full(_) => Full("ABAC rule code is valid") + case Failure(msg, _, _) => Failure(s"Invalid ABAC rule code: $msg") + case Empty => Failure("Failed to validate ABAC rule code") + } } } diff --git a/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala b/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala index 4f6d6f4381..cef3ee33d1 100644 --- a/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala +++ b/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala @@ -284,9 +284,10 @@ object AbacRuleExamples { /** * Example 33: Default to True (Allow All) - * Simple rule that always grants access (useful for testing) + * Always grants access. Note: bare `true` is rejected as too permissive, + * so we use a semantically equivalent non-tautological expression. */ - val allowAllRule: String = """true""" + val allowAllRule: String = """authenticatedUser.emailAddress.length >= 0""" /** * Example 34: Default to False (Deny All) diff --git a/obp-api/src/main/scala/code/api/util/APIUtil.scala b/obp-api/src/main/scala/code/api/util/APIUtil.scala index 98106ddd3b..b60f874634 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -29,6 +29,7 @@ package code.api.util import bootstrap.liftweb.CustomDBVendor import cats.effect.IO +import code.abacrule.AbacRuleEngine import code.accountholders.AccountHolders import code.api.Constant._ import code.api.UKOpenBanking.v2_0_0.OBP_UKOpenBanking_200 @@ -106,7 +107,8 @@ import java.util.{Calendar, Date, Locale, UUID} import scala.collection.immutable.{List, Nil} import scala.collection.mutable import scala.collection.mutable.{ArrayBuffer, ListBuffer} -import scala.concurrent.Future +import scala.concurrent.{Await, Future} +import scala.concurrent.duration.Duration import scala.io.BufferedSource import scala.language.{implicitConversions, reflectiveCalls} import scala.util.control.Breaks.{break, breakable} @@ -3703,6 +3705,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ def allowPublicViews: Boolean = getPropsAsBoolValue("allow_public_views", false) + def allowAbacAccountAccess: Boolean = getPropsAsBoolValue("allow_abac_account_access", false) def allowAccountFirehose: Boolean = ApiPropsWithAlias.allowAccountFirehose def allowCustomerFirehose: Boolean = ApiPropsWithAlias.allowCustomerFirehose def canUseAccountFirehose(user: User): Boolean = { @@ -3722,18 +3725,54 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ * @param user Option User, can be Empty(No Authentication), or Login user. * */ - def hasAccountAccess(view: View, bankIdAccountId: BankIdAccountId, user: Option[User], callContext: Option[CallContext]) : Boolean = { + def hasAccountAccess(view: View, bankIdAccountId: BankIdAccountId, user: Option[User], callContext: Option[CallContext]) : Box[Boolean] = { if(isPublicView(view: View))// No need for the Login user and public access - true + Full(true) else user match { - case Some(u) if hasAccountFirehoseAccessAtBank(view,u, bankIdAccountId.bankId) => true //Login User and Firehose access - case Some(u) if hasAccountFirehoseAccess(view,u) => true//Login User and Firehose access - case Some(u) if u.hasAccountAccess(view, bankIdAccountId, callContext)=> true // Login User and check view access + case Some(u) if hasAccountFirehoseAccessAtBank(view,u, bankIdAccountId.bankId) => Full(true) //Login User and Firehose access + case Some(u) if hasAccountFirehoseAccess(view,u) => Full(true)//Login User and Firehose access + case Some(u) if u.hasAccountAccess(view, bankIdAccountId, callContext)=> Full(true) // Login User and check view access + case Some(u) => + // Normal checks failed — try ABAC as fallback + checkAbacAccountAccess(u, view, bankIdAccountId, callContext) case _ => - false + Full(false) } } + + private def checkAbacAccountAccess( + user: User, + view: View, + bankIdAccountId: BankIdAccountId, + callContext: Option[CallContext] + ): Box[Boolean] = { + if (!allowAbacAccountAccess) return Full(false) + if (!hasEntitlement("", user.userId, ApiRole.canExecuteAbacRule)) return Full(false) + + callContext match { + case Some(cc) => + try { + val futureResult = AbacRuleEngine.executeRulesByPolicyDetailed( + policy = ABAC_POLICY_ACCOUNT_ACCESS, + authenticatedUserId = user.userId, + callContext = cc, + bankId = Some(bankIdAccountId.bankId.value), + accountId = Some(bankIdAccountId.accountId.value), + viewId = Some(view.viewId.value) + ) + Await.result(futureResult, Duration(10, java.util.concurrent.TimeUnit.SECONDS)) match { + case Full((true, _)) => Full(true) // ABAC granted + case Full((false, ruleIds)) if ruleIds.nonEmpty => + Failure(s"ABAC rules denied access. Failing rule IDs: ${ruleIds.mkString(", ")}") + case _ => Full(false) // No rules or other issue + } + } catch { + case _: Exception => Full(false) + } + case None => Full(false) + } + } /** * This function check does the user(anonymous or authenticated) have account access * to the account specified by parameter bankIdAccountId over the view specified by parameter viewId @@ -3747,25 +3786,42 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ case Full(v) if(v.isPublic && !allowPublicViews) => Failure(PublicViewsNotAllowedOnThisInstance) // 2nd: View is Pubic and Public views are allowed on this instance. case Full(v) if(isPublicView(v)) => customView - // 3rd: The user has account access to this custom view - case Full(v) if(user.isDefined && user.get.hasAccountAccess(v, bankIdAccountId, callContext: Option[CallContext])) => customView + // 3rd: The user has account access to this custom view (including ABAC fallback) + case Full(v) if user.isDefined => + hasAccountAccess(v, bankIdAccountId, user, callContext) match { + case Full(true) => customView + case f@Failure(_, _, _) => f // Propagate ABAC denial with rule IDs + case _ => // fall through to system view check + checkSystemView(viewId, bankIdAccountId, user, callContext) + } // The user has NO account access via custom view case _ => - val systemView = MapperViews.systemView(viewId) - systemView match { // CHECK SYSTEM VIEWS - // 1st: View is Pubic and Public views are NOT allowed on this instance. - case Full(v) if(v.isPublic && !allowPublicViews) => Failure(PublicViewsNotAllowedOnThisInstance) - // 2nd: View is Pubic and Public views are allowed on this instance. - case Full(v) if(isPublicView(v)) => systemView - // 3rd: The user has account access to this system view - case Full(v) if (user.isDefined && user.get.hasAccountAccess(v, bankIdAccountId, callContext: Option[CallContext])) => systemView - // 4th: The user has firehose access to this system view - case Full(v) if (user.isDefined && hasAccountFirehoseAccess(v, user.get)) => systemView - // 5th: The user has firehose access at a bank to this system view - case Full(v) if (user.isDefined && hasAccountFirehoseAccessAtBank(v, user.get, bankIdAccountId.bankId)) => systemView - // The user has NO account access at all - case _ => Empty + checkSystemView(viewId, bankIdAccountId, user, callContext) + } + } + + private def checkSystemView(viewId: ViewId, bankIdAccountId: BankIdAccountId, user: Option[User], callContext: Option[CallContext]): Box[View] = { + val systemView = MapperViews.systemView(viewId) + systemView match { // CHECK SYSTEM VIEWS + // 1st: View is Pubic and Public views are NOT allowed on this instance. + case Full(v) if(v.isPublic && !allowPublicViews) => Failure(PublicViewsNotAllowedOnThisInstance) + // 2nd: View is Pubic and Public views are allowed on this instance. + case Full(v) if(isPublicView(v)) => systemView + // 3rd: The user has account access to this system view (including ABAC fallback) + case Full(v) if user.isDefined => + hasAccountAccess(v, bankIdAccountId, user, callContext) match { + case Full(true) => systemView + case f@Failure(_, _, _) => f // Propagate ABAC denial with rule IDs + case _ => + // 4th: The user has firehose access to this system view + if (hasAccountFirehoseAccess(v, user.get)) systemView + // 5th: The user has firehose access at a bank to this system view + else if (hasAccountFirehoseAccessAtBank(v, user.get, bankIdAccountId.bankId)) systemView + // The user has NO account access at all + else Empty } + // The user has NO account access at all + case _ => Empty } } diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index 78fe567973..dc95d6dd10 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -687,6 +687,7 @@ object ErrorMessages { val AbacRuleNotFound = "OBP-38007: ABAC rule not found. Please specify a valid value for ABAC_RULE_ID." val AbacRuleNotActive = "OBP-38008: ABAC rule is not active." val AbacRuleExecutionFailed = "OBP-38009: ABAC rule execution failed. An error occurred while executing the rule." + val AbacRuleTooPermissive = "OBP-38010: ABAC rule is too permissive. The rule code contains a tautological expression (e.g. 'true', '1==1') that would always grant access. Please write a rule that checks specific attributes." // Transaction Request related messages (OBP-40XXX) val InvalidTransactionRequestType = "OBP-40001: Invalid value for TRANSACTION_REQUEST_TYPE" 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 a999cbb7d9..eff56b245f 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -760,6 +760,16 @@ object NewStyle extends MdcLoggable{ connectorEmptyResponse(_, callContext) } } + def getEntitlementRequestsFuture(queryParams: List[OBPQueryParam], callContext: Option[CallContext]): Future[List[EntitlementRequest]] = { + EntitlementRequest.entitlementRequest.vend.getEntitlementRequestsFuture(queryParams) map { + connectorEmptyResponse(_, callContext) + } + } + def getEntitlementRequestsFuture(userId: String, queryParams: List[OBPQueryParam], callContext: Option[CallContext]): Future[List[EntitlementRequest]] = { + EntitlementRequest.entitlementRequest.vend.getEntitlementRequestsFuture(userId, queryParams) map { + connectorEmptyResponse(_, callContext) + } + } def getCounterparties(bankId : BankId, accountId : AccountId, viewId : ViewId, callContext: Option[CallContext]): OBPReturnType[List[CounterpartyTrait]] = { Connector.connector.vend.getCounterparties(bankId,accountId,viewId, callContext) map { i=> diff --git a/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala b/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala index 39026cc285..ff8ab29da2 100644 --- a/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala +++ b/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala @@ -1913,6 +1913,8 @@ trait APIMethods300 { s""" |Get all Entitlement Requests | + |${urlParametersDocument(true, true)} + | |${userAuthenticationMessage(true)} """.stripMargin, EmptyBody, @@ -1933,7 +1935,8 @@ trait APIMethods300 { for { (Full(u), callContext) <- authenticatedAccess(cc) _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = UserHasMissingRoles + allowedEntitlementsTxt)("", u.userId, allowedEntitlements, callContext) - entitlementRequests <- NewStyle.function.getEntitlementRequestsFuture(callContext) + (requestParams, callContext) <- NewStyle.function.extractQueryParams(cc.url, List("limit", "offset", "sort_direction", "from_date", "to_date"), callContext) + entitlementRequests <- NewStyle.function.getEntitlementRequestsFuture(requestParams, callContext) } yield { (JSONFactory300.createEntitlementRequestsJSON(entitlementRequests), HttpCode.`200`(callContext)) } @@ -1950,6 +1953,7 @@ trait APIMethods300 { "Get Entitlement Requests for a User", s"""Get Entitlement Requests for a User. | + |${urlParametersDocument(true, true)} | |${userAuthenticationMessage(true)} | @@ -1972,7 +1976,8 @@ trait APIMethods300 { for { (Full(authorizedUser), callContext) <- authenticatedAccess(cc) _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = UserHasMissingRoles + allowedEntitlementsTxt)("", authorizedUser.userId, allowedEntitlements, callContext) - entitlementRequests <- NewStyle.function.getEntitlementRequestsFuture(userId, callContext) + (requestParams, callContext) <- NewStyle.function.extractQueryParams(cc.url, List("limit", "offset", "sort_direction", "from_date", "to_date"), callContext) + entitlementRequests <- NewStyle.function.getEntitlementRequestsFuture(userId, requestParams, callContext) } yield { (JSONFactory300.createEntitlementRequestsJSON(entitlementRequests), HttpCode.`200`(callContext)) } @@ -1989,6 +1994,7 @@ trait APIMethods300 { "Get Entitlement Requests for the current User", s"""Get Entitlement Requests for the current User. | + |${urlParametersDocument(true, true)} | |${userAuthenticationMessage(true)} | @@ -2008,7 +2014,8 @@ trait APIMethods300 { cc => implicit val ec = EndpointContext(Some(cc)) for { (Full(u), callContext) <- authenticatedAccess(cc) - entitlementRequests <- NewStyle.function.getEntitlementRequestsFuture(u.userId, callContext) + (requestParams, callContext) <- NewStyle.function.extractQueryParams(cc.url, List("limit", "offset", "sort_direction", "from_date", "to_date"), callContext) + entitlementRequests <- NewStyle.function.getEntitlementRequestsFuture(u.userId, requestParams, callContext) } yield { (JSONFactory300.createEntitlementRequestsJSON(entitlementRequests), HttpCode.`200`(callContext)) } diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index e41be365e3..bc07b82e8d 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -7700,7 +7700,9 @@ trait APIMethods600 { val cleanError = errorMsg.replace("Invalid ABAC rule code: ", "").replace("Failed to compile ABAC rule: ", "") // Determine the proper OBP error message and error type - val (obpErrorMessage, errorType) = if (cleanError.toLowerCase.contains("type mismatch") || cleanError.toLowerCase.contains("found:") && cleanError.toLowerCase.contains("required: boolean")) { + val (obpErrorMessage, errorType) = if (cleanError.toLowerCase.contains("too permissive") || cleanError.toLowerCase.contains("tautological")) { + (AbacRuleTooPermissive, "PermissivenessError") + } else if (cleanError.toLowerCase.contains("type mismatch") || cleanError.toLowerCase.contains("found:") && cleanError.toLowerCase.contains("required: boolean")) { (AbacRuleTypeMismatch, "TypeError") } else if (cleanError.toLowerCase.contains("syntax") || cleanError.toLowerCase.contains("parse")) { (AbacRuleSyntaxError, "SyntaxError") diff --git a/obp-api/src/main/scala/code/entitlementrequest/EntilementRequest.scala b/obp-api/src/main/scala/code/entitlementrequest/EntilementRequest.scala index c78498d5ee..1bb52a701f 100644 --- a/obp-api/src/main/scala/code/entitlementrequest/EntilementRequest.scala +++ b/obp-api/src/main/scala/code/entitlementrequest/EntilementRequest.scala @@ -2,6 +2,7 @@ package code.entitlementrequest import java.util.Date +import code.api.util.OBPQueryParam import com.openbankproject.commons.model.User import net.liftweb.common.Box import net.liftweb.util.SimpleInjector @@ -23,6 +24,8 @@ trait EntitlementRequestProvider { def getEntitlementRequestFuture(bankId: String, userId: String, roleName: String): Future[Box[EntitlementRequest]] def getEntitlementRequestsFuture(): Future[Box[List[EntitlementRequest]]] def getEntitlementRequestsFuture(userId: String): Future[Box[List[EntitlementRequest]]] + def getEntitlementRequestsFuture(queryParams: List[OBPQueryParam]): Future[Box[List[EntitlementRequest]]] + def getEntitlementRequestsFuture(userId: String, queryParams: List[OBPQueryParam]): Future[Box[List[EntitlementRequest]]] def deleteEntitlementRequestFuture(entitlementRequestId: String): Future[Box[Boolean]] } diff --git a/obp-api/src/main/scala/code/entitlementrequest/MappedEntitlementRquests.scala b/obp-api/src/main/scala/code/entitlementrequest/MappedEntitlementRquests.scala index c742136705..9c4bbc927f 100644 --- a/obp-api/src/main/scala/code/entitlementrequest/MappedEntitlementRquests.scala +++ b/obp-api/src/main/scala/code/entitlementrequest/MappedEntitlementRquests.scala @@ -2,7 +2,7 @@ package code.entitlementrequest import java.util.Date -import code.api.util.ErrorMessages +import code.api.util.{ErrorMessages, OBPAscending, OBPDescending, OBPFromDate, OBPLimit, OBPOffset, OBPOrdering, OBPQueryParam, OBPToDate} import code.users.Users import code.util.{MappedUUID, UUIDString} import com.openbankproject.commons.model.User @@ -64,6 +64,35 @@ object MappedEntitlementRequestsProvider extends EntitlementRequestProvider { } } + private def getOptionalParams(queryParams: List[OBPQueryParam]): Seq[QueryParam[MappedEntitlementRequest]] = { + val limit = queryParams.collect { case OBPLimit(value) => MaxRows[MappedEntitlementRequest](value) }.headOption + val offset = queryParams.collect { case OBPOffset(value) => StartAt[MappedEntitlementRequest](value) }.headOption + val fromDate = queryParams.collect { case OBPFromDate(date) => By_>=(MappedEntitlementRequest.createdAt, date) }.headOption + val toDate = queryParams.collect { case OBPToDate(date) => By_<=(MappedEntitlementRequest.createdAt, date) }.headOption + val ordering = queryParams.collect { + case OBPOrdering(_, direction) => + direction match { + case OBPAscending => OrderBy(MappedEntitlementRequest.createdAt, Ascending) + case OBPDescending => OrderBy(MappedEntitlementRequest.createdAt, Descending) + } + } + Seq(limit.toSeq, offset.toSeq, fromDate.toSeq, toDate.toSeq, ordering).flatten + } + + override def getEntitlementRequestsFuture(queryParams: List[OBPQueryParam]): Future[Box[List[EntitlementRequest]]] = { + Future { + val optionalParams = getOptionalParams(queryParams) + Full(MappedEntitlementRequest.findAll(optionalParams: _*)) + } + } + + override def getEntitlementRequestsFuture(userId: String, queryParams: List[OBPQueryParam]): Future[Box[List[EntitlementRequest]]] = { + Future { + val optionalParams = Seq(By(MappedEntitlementRequest.mUserId, userId)) ++ getOptionalParams(queryParams) + Full(MappedEntitlementRequest.findAll(optionalParams: _*)) + } + } + override def deleteEntitlementRequestFuture(entitlementRequestId: String): Future[Box[Boolean]] = { Future { MappedEntitlementRequest.find(By(MappedEntitlementRequest.mEntitlementRequestId, entitlementRequestId)) match { diff --git a/obp-api/src/main/scala/code/model/BankingData.scala b/obp-api/src/main/scala/code/model/BankingData.scala index 1976fb38ab..1c8413116f 100644 --- a/obp-api/src/main/scala/code/model/BankingData.scala +++ b/obp-api/src/main/scala/code/model/BankingData.scala @@ -293,28 +293,32 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable } final def moderatedTransaction(transactionId: TransactionId, view: View, bankIdAccountId: BankIdAccountId, user: Box[User], callContext: Option[CallContext] = None) : Box[(ModeratedTransaction, Option[CallContext])] = { - if(APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext)) - for{ - (transaction, callContext)<-Connector.connector.vend.getTransactionLegacy(bankId, accountId, transactionId, callContext) - moderatedTransaction<- view.moderateTransaction(transaction) - } yield (moderatedTransaction, callContext) - else - viewNotAllowed(view) + APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext) match { + case Full(true) => + for{ + (transaction, callContext)<-Connector.connector.vend.getTransactionLegacy(bankId, accountId, transactionId, callContext) + moderatedTransaction<- view.moderateTransaction(transaction) + } yield (moderatedTransaction, callContext) + case f@Failure(_, _, _) => f + case _ => viewNotAllowed(view) + } } final def moderatedTransactionFuture(transactionId: TransactionId, view: View, user: Box[User], callContext: Option[CallContext] = None) : Future[Box[(ModeratedTransaction, Option[CallContext])]] = { - if(APIUtil.hasAccountAccess(view, BankIdAccountId(bankId, accountId), user, callContext)) - for{ - (transaction, callContext)<-Connector.connector.vend.getTransaction(bankId, accountId, transactionId, callContext) map { - x => (unboxFullOrFail(x._1, callContext, TransactionNotFound, 400), x._2) - } - } yield { - view.moderateTransaction(transaction) match { - case Full(m) => Full((m, callContext)) - case _ => Failure("Server error - moderateTransactionsWithSameAccount") + APIUtil.hasAccountAccess(view, BankIdAccountId(bankId, accountId), user, callContext) match { + case Full(true) => + for{ + (transaction, callContext)<-Connector.connector.vend.getTransaction(bankId, accountId, transactionId, callContext) map { + x => (unboxFullOrFail(x._1, callContext, TransactionNotFound, 400), x._2) + } + } yield { + view.moderateTransaction(transaction) match { + case Full(m) => Full((m, callContext)) + case _ => Failure("Server error - moderateTransactionsWithSameAccount") + } } - } - else - Future(viewNotAllowed(view)) + case f@Failure(_, _, _) => Future(f) + case _ => Future(viewNotAllowed(view)) + } } /* @@ -323,57 +327,67 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable // TODO We should extract params (and their defaults) prior to this call, so this whole function can be cached. final def getModeratedTransactions(bank: Bank, user : Box[User], view : View, bankIdAccountId: BankIdAccountId, callContext: Option[CallContext], queryParams: List[OBPQueryParam] = Nil): Box[(List[ModeratedTransaction],Option[CallContext])] = { - if(APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext)) { - for { - (transactions, callContext) <- Connector.connector.vend.getTransactionsLegacy(bankId, accountId, callContext, queryParams) - moderated <- view.moderateTransactionsWithSameAccount(bank, transactions) ?~! "Server error" - } yield (moderated, callContext) + APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext) match { + case Full(true) => + for { + (transactions, callContext) <- Connector.connector.vend.getTransactionsLegacy(bankId, accountId, callContext, queryParams) + moderated <- view.moderateTransactionsWithSameAccount(bank, transactions) ?~! "Server error" + } yield (moderated, callContext) + case f@Failure(_, _, _) => f + case _ => viewNotAllowed(view) } - else viewNotAllowed(view) } final def getModeratedTransactionsFuture(bank: Bank, user : Box[User], view : View, callContext: Option[CallContext], queryParams: List[OBPQueryParam] = Nil): Future[Box[(List[ModeratedTransaction],Option[CallContext])]] = { - if(APIUtil.hasAccountAccess(view, BankIdAccountId(bankId, accountId), user, callContext)) { - for { - (transactions, callContext) <- Connector.connector.vend.getTransactions(bankId, accountId, callContext, queryParams) map { - x => (unboxFullOrFail(x._1, callContext, InvalidConnectorResponseForGetTransactions, 400), x._2) + APIUtil.hasAccountAccess(view, BankIdAccountId(bankId, accountId), user, callContext) match { + case Full(true) => + for { + (transactions, callContext) <- Connector.connector.vend.getTransactions(bankId, accountId, callContext, queryParams) map { + x => (unboxFullOrFail(x._1, callContext, InvalidConnectorResponseForGetTransactions, 400), x._2) + } + } yield { + logger.debug(s"getModeratedTransactionsFuture.view = $view") + logger.debug(s"getModeratedTransactionsFuture.transactions = $transactions") + view.moderateTransactionsWithSameAccount(bank, transactions) match { + case Full(m) => Full((m, callContext)) + case _ => Failure("Server error - moderateTransactionsWithSameAccount") + } } - } yield { - logger.debug(s"getModeratedTransactionsFuture.view = $view") - logger.debug(s"getModeratedTransactionsFuture.transactions = $transactions") - view.moderateTransactionsWithSameAccount(bank, transactions) match { - case Full(m) => Full((m, callContext)) - case _ => Failure("Server error - moderateTransactionsWithSameAccount") - } - } + case f@Failure(_, _, _) => Future(f) + case _ => Future(viewNotAllowed(view)) } - else Future(viewNotAllowed(view)) } // TODO We should extract params (and their defaults) prior to this call, so this whole function can be cached. final def getModeratedTransactionsCore(bank: Bank, user : Box[User], view : View, bankIdAccountId: BankIdAccountId, queryParams: List[OBPQueryParam], callContext: Option[CallContext] ): OBPReturnType[Box[List[ModeratedTransactionCore]]] = { - if(APIUtil.hasAccountAccess(view, bankIdAccountId,user, callContext)) { - for { - (transactions, callContext) <- NewStyle.function.getTransactionsCore(bankId, accountId, queryParams, callContext) - moderated <- Future {view.moderateTransactionsWithSameAccountCore(bank, transactions)} - } yield (moderated, callContext) + APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext) match { + case Full(true) => + for { + (transactions, callContext) <- NewStyle.function.getTransactionsCore(bankId, accountId, queryParams, callContext) + moderated <- Future {view.moderateTransactionsWithSameAccountCore(bank, transactions)} + } yield (moderated, callContext) + case f@Failure(_, _, _) => Future{(f, callContext)} + case _ => Future{(viewNotAllowed(view), callContext)} } - else Future{(viewNotAllowed(view), callContext)} } final def moderatedBankAccount(view: View, bankIdAccountId: BankIdAccountId, user: Box[User], callContext: Option[CallContext]) : Box[ModeratedBankAccount] = { - if(APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext)) - //implicit conversion from option to box - view.moderateAccountLegacy(bankAccount) - else - viewNotAllowed(view) + APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext) match { + case Full(true) => + //implicit conversion from option to box + view.moderateAccountLegacy(bankAccount) + case f@Failure(_, _, _) => f + case _ => viewNotAllowed(view) + } } final def moderatedBankAccountCore(view: View, bankIdAccountId: BankIdAccountId, user: Box[User], callContext: Option[CallContext]) : Box[ModeratedBankAccountCore] = { - if(APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext)) - //implicit conversion from option to box - view.moderateAccountCore(bankAccount) - else - viewNotAllowed(view) + APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext) match { + case Full(true) => + //implicit conversion from option to box + view.moderateAccountCore(bankAccount) + case f@Failure(_, _, _) => f + case _ => viewNotAllowed(view) + } } /** @@ -384,25 +398,27 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable * accounts that have at least one transaction in common with this bank account */ final def moderatedOtherBankAccounts(view : View, bankIdAccountId: BankIdAccountId, user : Box[User], callContext: Option[CallContext]) : OBPReturnType[Box[List[ModeratedOtherBankAccount]]] = - if(APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext)){ - val moderatedOtherBankAccountListFuture: Future[Full[List[ModeratedOtherBankAccount]]] = for{ - (implicitCounterpartyList, callContext) <- NewStyle.function.getCounterpartiesFromTransaction(bankId, accountId, callContext) - implicitModeratedOtherBankAccounts <- NewStyle.function.tryons(failMsg = InvalidJsonFormat, 400, callContext) { - implicitCounterpartyList.map(view.moderateOtherAccount).flatten - } - explicitCounterpartiesBox = Connector.connector.vend.getCounterpartiesLegacy(view.bankId, view.accountId, view.viewId) - explicitModeratedOtherBankAccounts <- NewStyle.function.tryons(failMsg = InvalidJsonFormat, 400, callContext) { - if(explicitCounterpartiesBox.isDefined) - explicitCounterpartiesBox.head._1.map(BankAccountX.toInternalCounterparty).flatMap(counterparty=>view.moderateOtherAccount(counterparty.head)) - else - Nil + APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext) match { + case Full(true) => + val moderatedOtherBankAccountListFuture: Future[Full[List[ModeratedOtherBankAccount]]] = for{ + (implicitCounterpartyList, callContext) <- NewStyle.function.getCounterpartiesFromTransaction(bankId, accountId, callContext) + implicitModeratedOtherBankAccounts <- NewStyle.function.tryons(failMsg = InvalidJsonFormat, 400, callContext) { + implicitCounterpartyList.map(view.moderateOtherAccount).flatten + } + explicitCounterpartiesBox = Connector.connector.vend.getCounterpartiesLegacy(view.bankId, view.accountId, view.viewId) + explicitModeratedOtherBankAccounts <- NewStyle.function.tryons(failMsg = InvalidJsonFormat, 400, callContext) { + if(explicitCounterpartiesBox.isDefined) + explicitCounterpartiesBox.head._1.map(BankAccountX.toInternalCounterparty).flatMap(counterparty=>view.moderateOtherAccount(counterparty.head)) + else + Nil + } + }yield{ + Full(explicitModeratedOtherBankAccounts ++ implicitModeratedOtherBankAccounts) } - }yield{ - Full(explicitModeratedOtherBankAccounts ++ implicitModeratedOtherBankAccounts) - } - moderatedOtherBankAccountListFuture.map( i=> (i,callContext)) - } else - Future{(viewNotAllowed(view), callContext)} + moderatedOtherBankAccountListFuture.map( i=> (i,callContext)) + case f@Failure(_, _, _) => Future{(f, callContext)} + case _ => Future{(viewNotAllowed(view), callContext)} + } /** * @param the ID of the other bank account that the user want have access @@ -412,21 +428,22 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable * account that have at least one transaction in common with this bank account */ final def moderatedOtherBankAccount(counterpartyID : String, view : View, bankIdAccountId: BankIdAccountId, user : Box[User], callContext: Option[CallContext]) : OBPReturnType[Box[ModeratedOtherBankAccount]] = - if(APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext)) { - for{ - (counterparty, callContext) <- Connector.connector.vend.getCounterpartyByCounterpartyId(CounterpartyId(counterpartyID), callContext) - moderateOtherAccount <- if(counterparty.isDefined) { - Future{ - counterparty.map(BankAccountX.toInternalCounterparty).flatten.map(view.moderateOtherAccount).flatten - } - } else { - Connector.connector.vend.getCounterpartyFromTransaction(bankId, accountId, counterpartyID, callContext).map(oAccTuple => view.moderateOtherAccount(oAccTuple._1.head)) + APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext) match { + case Full(true) => + for{ + (counterparty, callContext) <- Connector.connector.vend.getCounterpartyByCounterpartyId(CounterpartyId(counterpartyID), callContext) + moderateOtherAccount <- if(counterparty.isDefined) { + Future{ + counterparty.map(BankAccountX.toInternalCounterparty).flatten.map(view.moderateOtherAccount).flatten + } + } else { + Connector.connector.vend.getCounterpartyFromTransaction(bankId, accountId, counterpartyID, callContext).map(oAccTuple => view.moderateOtherAccount(oAccTuple._1.head)) + } + } yield{ + (moderateOtherAccount, callContext) } - } yield{ - (moderateOtherAccount, callContext) - } - } else { - Future{(viewNotAllowed(view),callContext)} + case f@Failure(_, _, _) => Future{(f, callContext)} + case _ => Future{(viewNotAllowed(view), callContext)} } } diff --git a/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala b/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala index c9a8697469..f9548adbeb 100644 --- a/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala +++ b/obp-api/src/test/scala/code/api/v3_0_0/EntitlementRequestsTest.scala @@ -199,7 +199,7 @@ class EntitlementRequestsTest extends V300ServerSetup with DefaultUsers { scenario("create entitlement request- delete entity -with role ", VersionOfApi, ApiEndpoint1, ApiEndpoint2) { Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanDeleteEntitlementRequestsAtAnyBank.toString) - + When("We make a request v3.0.0") val postJson = s"""{"bank_id":"${testBankId1.value}", "role_name":"CanCreateBankLevelEndpointTag"}""" val request300 = (v3_0Request / "entitlement-requests").POST <@(user1) @@ -208,7 +208,7 @@ class EntitlementRequestsTest extends V300ServerSetup with DefaultUsers { response300.code should equal(201) val result = response300.body.extract[EntitlementRequestJSON] result.bank_id should be (testBankId1.value) - + { val getMyUserALl = (v3_0Request /"my"/ "entitlement-requests").GET <@(user1) val responseGetMyUserALl = makeGetRequest(getMyUserALl) @@ -217,7 +217,7 @@ class EntitlementRequestsTest extends V300ServerSetup with DefaultUsers { val resultGetMyUserALl = responseGetMyUserALl.body.extract[EntitlementRequestsJSON] resultGetMyUserALl.entitlement_requests.length should be (1) } - + val entitlementRequestId = result.entitlement_request_id val deleteRequest300 = (v3_0Request / "entitlement-requests"/ entitlementRequestId ).DELETE <@(user1) val deleteResponse = makeDeleteRequest(deleteRequest300) @@ -234,4 +234,122 @@ class EntitlementRequestsTest extends V300ServerSetup with DefaultUsers { } + feature(s"Pagination and sorting for entitlement request endpoints") { + + scenario("Get my entitlement requests with limit parameter", VersionOfApi, ApiEndpoint5) { + // Create 3 entitlement requests + val roles = List("CanCreateBankLevelEndpointTag", "CanGetSystemLevelEndpointTag", "CanCreateBankLevelDynamicEndpoint") + val bankIds = List(testBankId1.value, "", testBankId1.value) + roles.zip(bankIds).foreach { case (role, bankId) => + val postJson = s"""{"bank_id":"$bankId", "role_name":"$role"}""" + val request = (v3_0Request / "entitlement-requests").POST <@(user1) + val response = makePostRequest(request, postJson) + response.code should equal(201) + } + + When("We request with limit=2") + val requestWithLimit = (v3_0Request / "my" / "entitlement-requests").GET <@(user1) < + val postJson = s"""{"bank_id":"$bankId", "role_name":"$role"}""" + val request = (v3_0Request / "entitlement-requests").POST <@(user1) + val response = makePostRequest(request, postJson) + response.code should equal(201) + } + + When("We request with offset=1") + val requestWithOffset = (v3_0Request / "my" / "entitlement-requests").GET <@(user1) <= 0""") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the allow-all rule") @@ -117,7 +117,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { } scenario("Execute rule with explicit authenticated_user_id", ApiEndpoint1, VersionOfApi) { - val ruleId = createAbacRuleViaApi("auth-user-test", "true") + val ruleId = createAbacRuleViaApi("auth-user-test", """authenticatedUser.emailAddress.length >= 0""") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the rule providing an explicit authenticated_user_id") @@ -142,7 +142,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { } scenario("Execute an inactive rule should return error", ApiEndpoint1, VersionOfApi) { - val ruleId = createAbacRuleViaApi("inactive-test", "true", isActive = false) + val ruleId = createAbacRuleViaApi("inactive-test", """authenticatedUser.emailAddress.length >= 0""", isActive = false) Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the inactive rule") @@ -191,7 +191,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { response.code should equal(404) } - scenario("Execute policy with no rules should default to allow (true)", ApiEndpoint2, VersionOfApi) { + scenario("Execute policy with no rules should default to deny (false)", ApiEndpoint2, VersionOfApi) { Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the account-access policy with no rules configured") @@ -199,14 +199,14 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { val execJson = ExecuteAbacRuleJsonV600(None, None, None, None, None, None, None, None, None) val response = makePostRequest(request, write(execJson)) - Then("We should get a 200 with result = true (default allow when no rules)") + Then("We should get a 200 with result = false (default deny when no rules)") response.code should equal(200) val result = response.body.extract[AbacRuleResultJsonV600] - result.result should equal(true) + result.result should equal(false) } scenario("Execute policy with one allow-all rule should return true", ApiEndpoint2, VersionOfApi) { - createAbacRuleViaApi("policy-allow-test", "true", policy = "account-access") + createAbacRuleViaApi("policy-allow-test", """authenticatedUser.emailAddress.length >= 0""", policy = "account-access") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the account-access policy") @@ -237,7 +237,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { scenario("Execute policy with mixed rules - OR logic means at least one must pass", ApiEndpoint2, VersionOfApi) { // Create one allow rule and one deny rule for the same policy - createAbacRuleViaApi("policy-mixed-allow", "true", policy = "account-access") + createAbacRuleViaApi("policy-mixed-allow", """authenticatedUser.emailAddress.length >= 0""", policy = "account-access") createAbacRuleViaApi("policy-mixed-deny", "false", policy = "account-access") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) @@ -252,4 +252,65 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { result.result should equal(true) } } + + // ==================== Tautology Detection Tests ==================== + + feature(s"Assuring that tautological ABAC rules are rejected - $VersionOfApi") { + + scenario("Creating a rule with bare 'true' should be rejected", ApiEndpoint3, VersionOfApi) { + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canCreateAbacRule.toString) + val createJson = CreateAbacRuleJsonV600( + rule_name = "tautology-true", + rule_code = "true", + description = "Should be rejected", + policy = "account-access", + is_active = true + ) + val request = (v6_0_0_Request / "management" / "abac-rules").POST <@ (user1) + val response = makePostRequest(request, write(createJson)) + Then("We should get a 400") + response.code should equal(400) + } + + scenario("Creating a rule with '1==1' should be rejected", ApiEndpoint3, VersionOfApi) { + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canCreateAbacRule.toString) + val createJson = CreateAbacRuleJsonV600( + rule_name = "tautology-numeric", + rule_code = "1==1", + description = "Should be rejected", + policy = "account-access", + is_active = true + ) + val request = (v6_0_0_Request / "management" / "abac-rules").POST <@ (user1) + val response = makePostRequest(request, write(createJson)) + Then("We should get a 400") + response.code should equal(400) + } + + scenario("Creating a rule with 'false' should be allowed (deny-all is fine)", ApiEndpoint3, VersionOfApi) { + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canCreateAbacRule.toString) + val createJson = CreateAbacRuleJsonV600( + rule_name = "deny-all-ok", + rule_code = "false", + description = "Deny all is allowed", + policy = "account-access", + is_active = true + ) + val request = (v6_0_0_Request / "management" / "abac-rules").POST <@ (user1) + val response = makePostRequest(request, write(createJson)) + Then("We should get a 201") + response.code should equal(201) + } + + scenario("Validating a rule with 'true' should return PermissivenessError", ApiEndpoint3, VersionOfApi) { + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canCreateAbacRule.toString) + val validateJson = ValidateAbacRuleJsonV600(rule_code = "true") + val request = (v6_0_0_Request / "management" / "abac-rules" / "validate").POST <@ (user1) + val response = makePostRequest(request, write(validateJson)) + Then("We should get a 200 with valid=false and PermissivenessError type") + response.code should equal(200) + (response.body \ "valid").extract[Boolean] should equal(false) + (response.body \ "details" \ "error_type").extract[String] should equal("PermissivenessError") + } + } } From 8d7025a3009a6db6181afef6b74af211000a5ecc Mon Sep 17 00:00:00 2001 From: simonredfern Date: Thu, 26 Feb 2026 10:05:51 +0100 Subject: [PATCH 02/19] Adding AbacRuleStatisticallyTooPermissive checks --- .../scala/code/abacrule/AbacRuleEngine.scala | 90 ++++++++++++++++++- .../code/abacrule/AbacRuleExamples.scala | 8 +- .../scala/code/api/util/ErrorMessages.scala | 1 + .../scala/code/api/v6_0_0/APIMethods600.scala | 21 ++--- .../scala/code/api/v6_0_0/AbacRuleTests.scala | 56 ++++++++++-- 5 files changed, 153 insertions(+), 23 deletions(-) diff --git a/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala b/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala index 0016f5241d..802a0abf12 100644 --- a/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala +++ b/obp-api/src/main/scala/code/abacrule/AbacRuleEngine.scala @@ -1,6 +1,6 @@ package code.abacrule -import code.api.util.{APIUtil, CallContext, DynamicUtil} +import code.api.util.{APIUtil, CallContext, DynamicUtil, ErrorMessages, OBPQueryParam, OBPLimit} import code.bankconnectors.Connector import code.model.dataAccess.ResourceUser import code.users.Users @@ -24,6 +24,9 @@ object AbacRuleEngine { private val compiledRulesCache: concurrent.Map[String, Box[AbacRuleFunction]] = new ConcurrentHashMap[String, Box[AbacRuleFunction]]().asScala + val StatisticalSampleSize: Int = 20 + val PermissivenessThreshold: Double = 0.50 + /** * Type alias for compiled ABAC rule function * Parameters: authenticatedUser (logged in), authenticatedUserAttributes (non-personal), authenticatedUserAuthContext (auth context), authenticatedUserEntitlements (roles), @@ -124,6 +127,65 @@ object AbacRuleEngine { isWholeBodyTautology || hasSubExprTautology } + /** + * Statistical permissiveness check: compile the candidate rule, evaluate it against a sample + * of real system users (with no resource context), and reject it if over 50% of users pass. + * + * @param ruleCode The rule code to check + * @return Future[Boolean] - true if the rule is statistically too permissive + */ + private def isStatisticallyTooPermissive(ruleCode: String): Future[Boolean] = { + val compiledBox = compileRuleInternal(ruleCode) + compiledBox match { + case Failure(_, _, _) | Empty => + // Compilation error caught elsewhere + Future.successful(false) + case Full(compiledFunc) => + val ns = code.api.util.NewStyle.function + Users.users.vend.getAllUsersF(List(OBPLimit(StatisticalSampleSize))).flatMap { userEntitlementPairs => + if (userEntitlementPairs.isEmpty) { + Future.successful(false) + } else { + val evaluationFutures = userEntitlementPairs.map { case (resourceUser, entitlementsBox) => + val userId = resourceUser.userId + val entitlements = entitlementsBox.openOr(Nil) + val userAsUser: User = resourceUser + + val attributesF = ns.getNonPersonalUserAttributes(userId, None).map(_._1).recover { case _ => Nil } + val authContextF = ns.getUserAuthContexts(userId, None).map(_._1).recover { case _ => Nil } + + for { + attributes <- attributesF + authContext <- authContextF + } yield { + try { + compiledFunc( + userAsUser, attributes, authContext, entitlements, + None, Nil, Nil, Nil, // onBehalfOfUser + None, Nil, // user + None, Nil, // bank + None, Nil, // account + None, Nil, // transaction + None, Nil, // transactionRequest + None, Nil, // customer + None // callContext + ) + } catch { + case _: Exception => false + } + } + } + + Future.sequence(evaluationFutures).map { results => + val passCount = results.count(_ == true) + val total = results.size + passCount.toDouble / total > PermissivenessThreshold + } + } + } + } + } + /** * Helper to lift a Box value into a Future, converting Failure/Empty to a failed Future. */ @@ -467,6 +529,32 @@ object AbacRuleEngine { } } + /** + * Async validation that includes both sync checks (regex + compilation) and + * the statistical permissiveness check against real system users. + * + * @param ruleCode The Scala code to validate + * @return Future[Box[String]] - Full("ABAC rule code is valid") if valid, Failure with error message if invalid + */ + def validateRuleCodeAsync(ruleCode: String): Future[Box[String]] = { + val syncResult = validateRuleCode(ruleCode) + syncResult match { + case f @ Failure(_, _, _) => + Future.successful(f) + case Full(_) => + isStatisticallyTooPermissive(ruleCode).map { tooPermissive => + if (tooPermissive) + Failure(ErrorMessages.AbacRuleStatisticallyTooPermissive) + else + Full("ABAC rule code is valid") + }.recover { + case _ => Failure(ErrorMessages.AbacRuleStatisticallyTooPermissive) + } + case Empty => + Future.successful(Empty) + } + } + /** * Clear the compiled rules cache */ diff --git a/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala b/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala index cef3ee33d1..f6e123881c 100644 --- a/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala +++ b/obp-api/src/main/scala/code/abacrule/AbacRuleExamples.scala @@ -283,11 +283,11 @@ object AbacRuleExamples { |accountOpt.exists(_.accountRoutings.nonEmpty)""".stripMargin /** - * Example 33: Default to True (Allow All) - * Always grants access. Note: bare `true` is rejected as too permissive, - * so we use a semantically equivalent non-tautological expression. + * Example 33: Entitlement-Based Access + * Grants access to users who have the CanCreateAbacRule entitlement. + * This checks for a specific entitlement rather than always granting access. */ - val allowAllRule: String = """authenticatedUser.emailAddress.length >= 0""" + val allowAllRule: String = """authenticatedUserEntitlements.exists(_.roleName == "CanCreateAbacRule")""" /** * Example 34: Default to False (Deny All) diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index dc95d6dd10..55dc7d756e 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -688,6 +688,7 @@ object ErrorMessages { val AbacRuleNotActive = "OBP-38008: ABAC rule is not active." val AbacRuleExecutionFailed = "OBP-38009: ABAC rule execution failed. An error occurred while executing the rule." val AbacRuleTooPermissive = "OBP-38010: ABAC rule is too permissive. The rule code contains a tautological expression (e.g. 'true', '1==1') that would always grant access. Please write a rule that checks specific attributes." + val AbacRuleStatisticallyTooPermissive = "OBP-38011: ABAC rule is statistically too permissive. When evaluated against a sample of system users with no resource context, the rule grants access to more than 50% of users. Please write a more selective rule that checks specific attributes." // Transaction Request related messages (OBP-40XXX) val InvalidTransactionRequestType = "OBP-40001: Invalid value for TRANSACTION_REQUEST_TYPE" diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index bc07b82e8d..328b832fe9 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -6942,10 +6942,8 @@ trait APIMethods600 { _ <- NewStyle.function.tryons(s"Rule code must not be empty", 400, callContext) { createJson.rule_code.nonEmpty } - // Validate rule code by attempting to compile it - _ <- Future { - AbacRuleEngine.validateRuleCode(createJson.rule_code) - } map { + // Validate rule code by attempting to compile it (includes statistical permissiveness check) + _ <- AbacRuleEngine.validateRuleCodeAsync(createJson.rule_code) map { unboxFullOrFail(_, callContext, s"Invalid ABAC rule code", 400) } rule <- Future { @@ -7198,10 +7196,8 @@ trait APIMethods600 { updateJson <- NewStyle.function.tryons(s"$InvalidJsonFormat", 400, callContext) { json.extract[UpdateAbacRuleJsonV600] } - // Validate rule code by attempting to compile it - _ <- Future { - AbacRuleEngine.validateRuleCode(updateJson.rule_code) - } map { + // Validate rule code by attempting to compile it (includes statistical permissiveness check) + _ <- AbacRuleEngine.validateRuleCodeAsync(updateJson.rule_code) map { unboxFullOrFail(_, callContext, s"Invalid ABAC rule code", 400) } rule <- Future { @@ -7688,8 +7684,7 @@ trait APIMethods600 { _ <- NewStyle.function.tryons(s"$AbacRuleCodeEmpty", 400, callContext) { validateJson.rule_code.trim.nonEmpty } - validationResult <- Future { - AbacRuleEngine.validateRuleCode(validateJson.rule_code) match { + validationResult <- AbacRuleEngine.validateRuleCodeAsync(validateJson.rule_code).map { case Full(msg) => Full(ValidateAbacRuleSuccessJsonV600( valid = true, @@ -7701,7 +7696,8 @@ trait APIMethods600 { // Determine the proper OBP error message and error type val (obpErrorMessage, errorType) = if (cleanError.toLowerCase.contains("too permissive") || cleanError.toLowerCase.contains("tautological")) { - (AbacRuleTooPermissive, "PermissivenessError") + val errorConst = if (cleanError.toLowerCase.contains("statistical")) AbacRuleStatisticallyTooPermissive else AbacRuleTooPermissive + (errorConst, "PermissivenessError") } else if (cleanError.toLowerCase.contains("type mismatch") || cleanError.toLowerCase.contains("found:") && cleanError.toLowerCase.contains("required: boolean")) { (AbacRuleTypeMismatch, "TypeError") } else if (cleanError.toLowerCase.contains("syntax") || cleanError.toLowerCase.contains("parse")) { @@ -7731,8 +7727,7 @@ trait APIMethods600 { error_type = "UnknownError" ) )) - } - } map { + } map { unboxFullOrFail(_, callContext, AbacRuleValidationFailed, 400) } } yield { diff --git a/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala b/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala index 975a3792f8..0793d15fe8 100644 --- a/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala +++ b/obp-api/src/test/scala/code/api/v6_0_0/AbacRuleTests.scala @@ -87,7 +87,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { } scenario("Execute an allow-all rule should return true", ApiEndpoint1, VersionOfApi) { - val ruleId = createAbacRuleViaApi("allow-all-test", """authenticatedUser.emailAddress.length >= 0""") + val ruleId = createAbacRuleViaApi("allow-all-test", s"""authenticatedUser.emailAddress == "${resourceUser1.emailAddress}"""") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the allow-all rule") @@ -117,7 +117,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { } scenario("Execute rule with explicit authenticated_user_id", ApiEndpoint1, VersionOfApi) { - val ruleId = createAbacRuleViaApi("auth-user-test", """authenticatedUser.emailAddress.length >= 0""") + val ruleId = createAbacRuleViaApi("auth-user-test", s"""authenticatedUser.emailAddress == "${resourceUser1.emailAddress}"""") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the rule providing an explicit authenticated_user_id") @@ -142,7 +142,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { } scenario("Execute an inactive rule should return error", ApiEndpoint1, VersionOfApi) { - val ruleId = createAbacRuleViaApi("inactive-test", """authenticatedUser.emailAddress.length >= 0""", isActive = false) + val ruleId = createAbacRuleViaApi("inactive-test", s"""authenticatedUser.emailAddress == "${resourceUser1.emailAddress}"""", isActive = false) Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the inactive rule") @@ -206,7 +206,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { } scenario("Execute policy with one allow-all rule should return true", ApiEndpoint2, VersionOfApi) { - createAbacRuleViaApi("policy-allow-test", """authenticatedUser.emailAddress.length >= 0""", policy = "account-access") + createAbacRuleViaApi("policy-allow-test", s"""authenticatedUser.emailAddress == "${resourceUser1.emailAddress}"""", policy = "account-access") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) When("We execute the account-access policy") @@ -237,7 +237,7 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { scenario("Execute policy with mixed rules - OR logic means at least one must pass", ApiEndpoint2, VersionOfApi) { // Create one allow rule and one deny rule for the same policy - createAbacRuleViaApi("policy-mixed-allow", """authenticatedUser.emailAddress.length >= 0""", policy = "account-access") + createAbacRuleViaApi("policy-mixed-allow", s"""authenticatedUser.emailAddress == "${resourceUser1.emailAddress}"""", policy = "account-access") createAbacRuleViaApi("policy-mixed-deny", "false", policy = "account-access") Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canExecuteAbacRule.toString) @@ -313,4 +313,50 @@ class AbacRuleTests extends V600ServerSetup with DefaultUsers { (response.body \ "details" \ "error_type").extract[String] should equal("PermissivenessError") } } + + // ==================== Statistical Permissiveness Detection Tests ==================== + + feature(s"Assuring that statistically too permissive ABAC rules are rejected - $VersionOfApi") { + + scenario("Creating a rule with 'emailAddress.length >= 0' should be rejected as statistically too permissive", ApiEndpoint3, VersionOfApi) { + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canCreateAbacRule.toString) + val createJson = CreateAbacRuleJsonV600( + rule_name = "statistical-tautology", + rule_code = "authenticatedUser.emailAddress.length >= 0", + description = "Should be rejected - statistically too permissive", + policy = "account-access", + is_active = true + ) + val request = (v6_0_0_Request / "management" / "abac-rules").POST <@ (user1) + val response = makePostRequest(request, write(createJson)) + Then("We should get a 400") + response.code should equal(400) + } + + scenario("Validating a statistically too permissive rule should return PermissivenessError", ApiEndpoint3, VersionOfApi) { + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canCreateAbacRule.toString) + val validateJson = ValidateAbacRuleJsonV600(rule_code = "authenticatedUser.emailAddress.length >= 0") + val request = (v6_0_0_Request / "management" / "abac-rules" / "validate").POST <@ (user1) + val response = makePostRequest(request, write(validateJson)) + Then("We should get a 200 with valid=false and PermissivenessError type") + response.code should equal(200) + (response.body \ "valid").extract[Boolean] should equal(false) + (response.body \ "details" \ "error_type").extract[String] should equal("PermissivenessError") + } + + scenario("Creating a selective attribute-checking rule should succeed", ApiEndpoint3, VersionOfApi) { + Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, canCreateAbacRule.toString) + val createJson = CreateAbacRuleJsonV600( + rule_name = "selective-rule", + rule_code = s"""authenticatedUser.emailAddress == "${resourceUser1.emailAddress}"""", + description = "Selective rule that only matches one specific user", + policy = "account-access", + is_active = true + ) + val request = (v6_0_0_Request / "management" / "abac-rules").POST <@ (user1) + val response = makePostRequest(request, write(createJson)) + Then("We should get a 201") + response.code should equal(201) + } + } } From 632d7ae89f6c35d6cdf1635f06a9dd5ae75b76f9 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Fri, 27 Feb 2026 05:45:02 +0100 Subject: [PATCH 03/19] grpc_vFeb2026 connector builder and connector --- obp-api/src/main/protobuf/connector.proto | 16 + .../scala/code/bankconnectors/Connector.scala | 2 + .../grpc/GrpcConnectorBuilder.scala | 13 + .../grpc/GrpcConnector_vFeb2026.scala | 7428 +++++++++++++++++ .../code/bankconnectors/grpc/GrpcUtils.scala | 78 + .../grpc/api/ObpConnectorServiceGrpc.scala | 81 + 6 files changed, 7618 insertions(+) create mode 100644 obp-api/src/main/protobuf/connector.proto create mode 100644 obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala create mode 100644 obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala create mode 100644 obp-api/src/main/scala/code/bankconnectors/grpc/GrpcUtils.scala create mode 100644 obp-api/src/main/scala/code/bankconnectors/grpc/api/ObpConnectorServiceGrpc.scala diff --git a/obp-api/src/main/protobuf/connector.proto b/obp-api/src/main/protobuf/connector.proto new file mode 100644 index 0000000000..074b15bd0b --- /dev/null +++ b/obp-api/src/main/protobuf/connector.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package code.bankconnectors.grpc; + +service ObpConnectorService { + rpc ProcessObpRequest (ObpConnectorRequest) returns (ObpConnectorResponse) {} +} + +message ObpConnectorRequest { + string method_name = 1; // e.g. "obp_get_banks" + string json_payload = 2; // JSON-serialized OutBound DTO +} + +message ObpConnectorResponse { + string json_payload = 1; // JSON-serialized InBound DTO +} diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 0dcae974a6..18dcc9fef8 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -12,6 +12,7 @@ import code.bankattribute.BankAttribute import code.bankconnectors.akka.AkkaConnector_vDec2018 import code.bankconnectors.cardano.CardanoConnector_vJun2025 import code.bankconnectors.ethereum.EthereumConnector_vSept2025 +import code.bankconnectors.grpc.GrpcConnector_vFeb2026 import code.bankconnectors.rabbitmq.RabbitMQConnector_vOct2024 import code.bankconnectors.rest.RestConnector_vMar2019 import code.bankconnectors.storedprocedure.StoredProcedureConnector_vDec2019 @@ -66,6 +67,7 @@ object Connector extends SimpleInjector { "rabbitmq_vOct2024" -> RabbitMQConnector_vOct2024, "cardano_vJun2025" -> CardanoConnector_vJun2025, "ethereum_vSept2025" -> EthereumConnector_vSept2025, + "grpc_vFeb2026" -> GrpcConnector_vFeb2026, // this proxy connector only for unit test, can set connector=proxy in test.default.props, but never set it in default.props "proxy" -> ConnectorUtils.proxyConnector, // internal is the dynamic connector, the developers can upload the source code and override connector method themselves. diff --git a/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala new file mode 100644 index 0000000000..7522f412b1 --- /dev/null +++ b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala @@ -0,0 +1,13 @@ +package code.bankconnectors.grpc + +import code.bankconnectors.generator.ConnectorBuilderUtil._ +import net.liftweb.util.StringHelpers + +import scala.language.postfixOps + +object GrpcConnectorBuilder extends App { + + buildMethods(commonMethodNames.diff(omitMethods), + "src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala", + methodName => s"""sendRequest[InBound]("obp_${StringHelpers.snakify(methodName)}", req, callContext)""") +} diff --git a/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala new file mode 100644 index 0000000000..f8f1939554 --- /dev/null +++ b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala @@ -0,0 +1,7428 @@ +package code.bankconnectors.grpc + +/* +Open Bank Project - API +Copyright (C) 2011-2017, 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 http://www.gnu.org/licenses/. + +Email: contact@tesobe.com +TESOBE GmbH +Osloerstrasse 16/17 +Berlin 13359, Germany +*/ + +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.{CallContext, OBPQueryParam} +import code.bankconnectors._ +import code.util.Helper +import code.util.Helper.MdcLoggable +import com.openbankproject.commons.ExecutionContext.Implicits.global +import com.openbankproject.commons.dto._ +import com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.SCAStatus +import com.openbankproject.commons.model.enums._ +import com.openbankproject.commons.model.{Meta, _} +import net.liftweb.common._ +import net.liftweb.json._ +import net.liftweb.util.StringHelpers + +import java.util.Date +import scala.collection.mutable.ArrayBuffer +import scala.concurrent.Future +import scala.language.postfixOps +import scala.reflect.runtime.universe._ + +trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { + //this one import is for implicit convert, don't delete + import com.openbankproject.commons.model.{AmountOfMoney, CreditLimit, CreditRating, CustomerFaceImage} + + implicit override val nameOfConnector = GrpcConnector_vFeb2026.toString + + val messageFormat: String = "grpc_vFeb2026" + + override val messageDocs = ArrayBuffer[MessageDoc]() + + val authInfoExample = AuthInfo(userId = "userId", username = "username", cbsToken = "cbsToken") + val errorCodeExample = "INTERNAL-OBP-ADAPTER-6001: ..." + +//---------------- dynamic start -------------------please don't modify this line +// ---------- created on 2025-06-10T12:05:04Z + + messageDocs += getAdapterInfoDoc + def getAdapterInfoDoc = MessageDoc( + process = "obp.getAdapterInfo", + messageFormat = messageFormat, + description = "Get Adapter Info", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAdapterInfo(MessageDocsSwaggerDefinitions.outboundAdapterCallContext) + ), + exampleInboundMessage = ( + InBoundGetAdapterInfo(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= InboundAdapterInfoInternal(errorCode=inboundAdapterInfoInternalErrorCodeExample.value, + backendMessages=List( InboundStatusMessage(source=sourceExample.value, + status=inboundStatusMessageStatusExample.value, + errorCode=inboundStatusMessageErrorCodeExample.value, + text=inboundStatusMessageTextExample.value, + duration=Some(BigDecimal(durationExample.value)))), + name=inboundAdapterInfoInternalNameExample.value, + version=inboundAdapterInfoInternalVersionExample.value, + git_commit=inboundAdapterInfoInternalGit_commitExample.value, + date=inboundAdapterInfoInternalDateExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAdapterInfo(callContext: Option[CallContext]): Future[Box[(InboundAdapterInfoInternal, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetAdapterInfo => InBound, OutBoundGetAdapterInfo => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_adapter_info", req, callContext) + response.map(convertToTuple[InboundAdapterInfoInternal](callContext)) + } + + messageDocs += validateAndCheckIbanNumberDoc + def validateAndCheckIbanNumberDoc = MessageDoc( + process = "obp.validateAndCheckIbanNumber", + messageFormat = messageFormat, + description = "Validate And Check Iban Number", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundValidateAndCheckIbanNumber(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + iban=ibanExample.value) + ), + exampleInboundMessage = ( + InBoundValidateAndCheckIbanNumber(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= IbanChecker(isValid=true, + details=Some( IbanDetails(bic=bicExample.value, + bank=bankExample.value, + branch="string", + address=addressExample.value, + city=cityExample.value, + zip="string", + phone=phoneExample.value, + country=countryExample.value, + countryIso="string", + sepaCreditTransfer=sepaCreditTransferExample.value, + sepaDirectDebit=sepaDirectDebitExample.value, + sepaSddCore=sepaSddCoreExample.value, + sepaB2b=sepaB2bExample.value, + sepaCardClearing=sepaCardClearingExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def validateAndCheckIbanNumber(iban: String, callContext: Option[CallContext]): OBPReturnType[Box[IbanChecker]] = { + import com.openbankproject.commons.dto.{InBoundValidateAndCheckIbanNumber => InBound, OutBoundValidateAndCheckIbanNumber => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, iban) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_validate_and_check_iban_number", req, callContext) + response.map(convertToTuple[IbanChecker](callContext)) + } + + messageDocs += getChallengeThresholdDoc + def getChallengeThresholdDoc = MessageDoc( + process = "obp.getChallengeThreshold", + messageFormat = messageFormat, + description = "Get Challenge Threshold", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChallengeThreshold(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + accountId=accountIdExample.value, + viewId=viewIdExample.value, + transactionRequestType=transactionRequestTypeExample.value, + currency=currencyExample.value, + userId=userIdExample.value, + username=usernameExample.value) + ), + exampleInboundMessage = ( + InBoundGetChallengeThreshold(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChallengeThreshold(bankId: String, accountId: String, viewId: String, transactionRequestType: String, currency: String, userId: String, username: String, callContext: Option[CallContext]): OBPReturnType[Box[AmountOfMoney]] = { + import com.openbankproject.commons.dto.{InBoundGetChallengeThreshold => InBound, OutBoundGetChallengeThreshold => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, viewId, transactionRequestType, currency, userId, username) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_challenge_threshold", req, callContext) + response.map(convertToTuple[AmountOfMoney](callContext)) + } + + messageDocs += getChargeLevelDoc + def getChargeLevelDoc = MessageDoc( + process = "obp.getChargeLevel", + messageFormat = messageFormat, + description = "Get Charge Level", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChargeLevel(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + viewId=ViewId(viewIdExample.value), + userId=userIdExample.value, + username=usernameExample.value, + transactionRequestType=transactionRequestTypeExample.value, + currency=currencyExample.value) + ), + exampleInboundMessage = ( + InBoundGetChargeLevel(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChargeLevel(bankId: BankId, accountId: AccountId, viewId: ViewId, userId: String, username: String, transactionRequestType: String, currency: String, callContext: Option[CallContext]): OBPReturnType[Box[AmountOfMoney]] = { + import com.openbankproject.commons.dto.{InBoundGetChargeLevel => InBound, OutBoundGetChargeLevel => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, viewId, userId, username, transactionRequestType, currency) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_charge_level", req, callContext) + response.map(convertToTuple[AmountOfMoney](callContext)) + } + + messageDocs += getChargeLevelC2Doc + def getChargeLevelC2Doc = MessageDoc( + process = "obp.getChargeLevelC2", + messageFormat = messageFormat, + description = "Get Charge Level C2", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChargeLevelC2(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + viewId=ViewId(viewIdExample.value), + userId=userIdExample.value, + username=usernameExample.value, + transactionRequestType=transactionRequestTypeExample.value, + currency=currencyExample.value, + amount=amountExample.value, + toAccountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + customAttributes=List( CustomAttribute(name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.AttributeType.example, + value=valueExample.value))) + ), + exampleInboundMessage = ( + InBoundGetChargeLevelC2(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChargeLevelC2(bankId: BankId, accountId: AccountId, viewId: ViewId, userId: String, username: String, transactionRequestType: String, currency: String, amount: String, toAccountRoutings: List[AccountRouting], customAttributes: List[CustomAttribute], callContext: Option[CallContext]): OBPReturnType[Box[AmountOfMoney]] = { + import com.openbankproject.commons.dto.{InBoundGetChargeLevelC2 => InBound, OutBoundGetChargeLevelC2 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, viewId, userId, username, transactionRequestType, currency, amount, toAccountRoutings, customAttributes) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_charge_level_c2", req, callContext) + response.map(convertToTuple[AmountOfMoney](callContext)) + } + + messageDocs += createChallengeDoc + def createChallengeDoc = MessageDoc( + process = "obp.createChallenge", + messageFormat = messageFormat, + description = "Create Challenge", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateChallenge(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + userId=userIdExample.value, + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value), + transactionRequestId=transactionRequestIdExample.value, + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS)) + ), + exampleInboundMessage = ( + InBoundCreateChallenge(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data="string") + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createChallenge(bankId: BankId, accountId: AccountId, userId: String, transactionRequestType: TransactionRequestType, transactionRequestId: String, scaMethod: Option[StrongCustomerAuthentication.SCA], callContext: Option[CallContext]): OBPReturnType[Box[String]] = { + import com.openbankproject.commons.dto.{InBoundCreateChallenge => InBound, OutBoundCreateChallenge => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, userId, transactionRequestType, transactionRequestId, scaMethod) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_challenge", req, callContext) + response.map(convertToTuple[String](callContext)) + } + + messageDocs += createChallengesDoc + def createChallengesDoc = MessageDoc( + process = "obp.createChallenges", + messageFormat = messageFormat, + description = "Create Challenges", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateChallenges(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + userIds=listExample.value.replace("[","").replace("]","").split(",").toList, + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value), + transactionRequestId=transactionRequestIdExample.value, + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS)) + ), + exampleInboundMessage = ( + InBoundCreateChallenges(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=listExample.value.replace("[","").replace("]","").split(",").toList) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createChallenges(bankId: BankId, accountId: AccountId, userIds: List[String], transactionRequestType: TransactionRequestType, transactionRequestId: String, scaMethod: Option[StrongCustomerAuthentication.SCA], callContext: Option[CallContext]): OBPReturnType[Box[List[String]]] = { + import com.openbankproject.commons.dto.{InBoundCreateChallenges => InBound, OutBoundCreateChallenges => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, userIds, transactionRequestType, transactionRequestId, scaMethod) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_challenges", req, callContext) + response.map(convertToTuple[List[String]](callContext)) + } + + messageDocs += createChallengesC2Doc + def createChallengesC2Doc = MessageDoc( + process = "obp.createChallengesC2", + messageFormat = messageFormat, + description = "Create Challenges C2", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateChallengesC2(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userIds=listExample.value.replace("[","").replace("]","").split(",").toList, + challengeType=com.openbankproject.commons.model.enums.ChallengeType.example, + transactionRequestId=Some(transactionRequestIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + consentId=Some(consentIdExample.value), + authenticationMethodId=Some("string")) + ), + exampleInboundMessage = ( + InBoundCreateChallengesC2(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createChallengesC2(userIds: List[String], challengeType: ChallengeType.Value, transactionRequestId: Option[String], scaMethod: Option[StrongCustomerAuthentication.SCA], scaStatus: Option[SCAStatus], consentId: Option[String], authenticationMethodId: Option[String], callContext: Option[CallContext]): OBPReturnType[Box[List[ChallengeTrait]]] = { + import com.openbankproject.commons.dto.{InBoundCreateChallengesC2 => InBound, OutBoundCreateChallengesC2 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userIds, challengeType, transactionRequestId, scaMethod, scaStatus, consentId, authenticationMethodId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_challenges_c2", req, callContext) + response.map(convertToTuple[List[ChallengeCommons]](callContext)) + } + + messageDocs += createChallengesC3Doc + def createChallengesC3Doc = MessageDoc( + process = "obp.createChallengesC3", + messageFormat = messageFormat, + description = "Create Challenges C3", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateChallengesC3(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userIds=listExample.value.replace("[","").replace("]","").split(",").toList, + challengeType=com.openbankproject.commons.model.enums.ChallengeType.example, + transactionRequestId=Some(transactionRequestIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + authenticationMethodId=Some("string")) + ), + exampleInboundMessage = ( + InBoundCreateChallengesC3(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createChallengesC3(userIds: List[String], challengeType: ChallengeType.Value, transactionRequestId: Option[String], scaMethod: Option[StrongCustomerAuthentication.SCA], scaStatus: Option[SCAStatus], consentId: Option[String], basketId: Option[String], authenticationMethodId: Option[String], callContext: Option[CallContext]): OBPReturnType[Box[List[ChallengeTrait]]] = { + import com.openbankproject.commons.dto.{InBoundCreateChallengesC3 => InBound, OutBoundCreateChallengesC3 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userIds, challengeType, transactionRequestId, scaMethod, scaStatus, consentId, basketId, authenticationMethodId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_challenges_c3", req, callContext) + response.map(convertToTuple[List[ChallengeCommons]](callContext)) + } + + messageDocs += validateChallengeAnswerDoc + def validateChallengeAnswerDoc = MessageDoc( + process = "obp.validateChallengeAnswer", + messageFormat = messageFormat, + description = "Validate Challenge Answer", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundValidateChallengeAnswer(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + challengeId=challengeIdExample.value, + hashOfSuppliedAnswer=hashOfSuppliedAnswerExample.value) + ), + exampleInboundMessage = ( + InBoundValidateChallengeAnswer(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def validateChallengeAnswer(challengeId: String, hashOfSuppliedAnswer: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundValidateChallengeAnswer => InBound, OutBoundValidateChallengeAnswer => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, challengeId, hashOfSuppliedAnswer) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_validate_challenge_answer", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += validateChallengeAnswerV2Doc + def validateChallengeAnswerV2Doc = MessageDoc( + process = "obp.validateChallengeAnswerV2", + messageFormat = messageFormat, + description = "Validate Challenge Answer V2", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundValidateChallengeAnswerV2(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + challengeId=challengeIdExample.value, + suppliedAnswer=suppliedAnswerExample.value, + suppliedAnswerType=com.openbankproject.commons.model.enums.SuppliedAnswerType.example) + ), + exampleInboundMessage = ( + InBoundValidateChallengeAnswerV2(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def validateChallengeAnswerV2(challengeId: String, suppliedAnswer: String, suppliedAnswerType: SuppliedAnswerType.Value, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundValidateChallengeAnswerV2 => InBound, OutBoundValidateChallengeAnswerV2 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, challengeId, suppliedAnswer, suppliedAnswerType) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_validate_challenge_answer_v2", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += validateChallengeAnswerC2Doc + def validateChallengeAnswerC2Doc = MessageDoc( + process = "obp.validateChallengeAnswerC2", + messageFormat = messageFormat, + description = "Validate Challenge Answer C2", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundValidateChallengeAnswerC2(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=Some(transactionRequestIdExample.value), + consentId=Some(consentIdExample.value), + challengeId=challengeIdExample.value, + hashOfSuppliedAnswer=hashOfSuppliedAnswerExample.value) + ), + exampleInboundMessage = ( + InBoundValidateChallengeAnswerC2(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def validateChallengeAnswerC2(transactionRequestId: Option[String], consentId: Option[String], challengeId: String, hashOfSuppliedAnswer: String, callContext: Option[CallContext]): OBPReturnType[Box[ChallengeTrait]] = { + import com.openbankproject.commons.dto.{InBoundValidateChallengeAnswerC2 => InBound, OutBoundValidateChallengeAnswerC2 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId, consentId, challengeId, hashOfSuppliedAnswer) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_validate_challenge_answer_c2", req, callContext) + response.map(convertToTuple[ChallengeCommons](callContext)) + } + + messageDocs += validateChallengeAnswerC3Doc + def validateChallengeAnswerC3Doc = MessageDoc( + process = "obp.validateChallengeAnswerC3", + messageFormat = messageFormat, + description = "Validate Challenge Answer C3", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundValidateChallengeAnswerC3(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=Some(transactionRequestIdExample.value), + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + challengeId=challengeIdExample.value, + hashOfSuppliedAnswer=hashOfSuppliedAnswerExample.value) + ), + exampleInboundMessage = ( + InBoundValidateChallengeAnswerC3(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def validateChallengeAnswerC3(transactionRequestId: Option[String], consentId: Option[String], basketId: Option[String], challengeId: String, hashOfSuppliedAnswer: String, callContext: Option[CallContext]): OBPReturnType[Box[ChallengeTrait]] = { + import com.openbankproject.commons.dto.{InBoundValidateChallengeAnswerC3 => InBound, OutBoundValidateChallengeAnswerC3 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId, consentId, basketId, challengeId, hashOfSuppliedAnswer) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_validate_challenge_answer_c3", req, callContext) + response.map(convertToTuple[ChallengeCommons](callContext)) + } + + messageDocs += validateChallengeAnswerC4Doc + def validateChallengeAnswerC4Doc = MessageDoc( + process = "obp.validateChallengeAnswerC4", + messageFormat = messageFormat, + description = "Validate Challenge Answer C4", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundValidateChallengeAnswerC4(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=Some(transactionRequestIdExample.value), + consentId=Some(consentIdExample.value), + challengeId=challengeIdExample.value, + suppliedAnswer=suppliedAnswerExample.value, + suppliedAnswerType=com.openbankproject.commons.model.enums.SuppliedAnswerType.example) + ), + exampleInboundMessage = ( + InBoundValidateChallengeAnswerC4(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def validateChallengeAnswerC4(transactionRequestId: Option[String], consentId: Option[String], challengeId: String, suppliedAnswer: String, suppliedAnswerType: SuppliedAnswerType.Value, callContext: Option[CallContext]): OBPReturnType[Box[ChallengeTrait]] = { + import com.openbankproject.commons.dto.{InBoundValidateChallengeAnswerC4 => InBound, OutBoundValidateChallengeAnswerC4 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId, consentId, challengeId, suppliedAnswer, suppliedAnswerType) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_validate_challenge_answer_c4", req, callContext) + response.map(convertToTuple[ChallengeCommons](callContext)) + } + + messageDocs += validateChallengeAnswerC5Doc + def validateChallengeAnswerC5Doc = MessageDoc( + process = "obp.validateChallengeAnswerC5", + messageFormat = messageFormat, + description = "Validate Challenge Answer C5", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundValidateChallengeAnswerC5(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=Some(transactionRequestIdExample.value), + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + challengeId=challengeIdExample.value, + suppliedAnswer=suppliedAnswerExample.value, + suppliedAnswerType=com.openbankproject.commons.model.enums.SuppliedAnswerType.example) + ), + exampleInboundMessage = ( + InBoundValidateChallengeAnswerC5(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def validateChallengeAnswerC5(transactionRequestId: Option[String], consentId: Option[String], basketId: Option[String], challengeId: String, suppliedAnswer: String, suppliedAnswerType: SuppliedAnswerType.Value, callContext: Option[CallContext]): OBPReturnType[Box[ChallengeTrait]] = { + import com.openbankproject.commons.dto.{InBoundValidateChallengeAnswerC5 => InBound, OutBoundValidateChallengeAnswerC5 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId, consentId, basketId, challengeId, suppliedAnswer, suppliedAnswerType) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_validate_challenge_answer_c5", req, callContext) + response.map(convertToTuple[ChallengeCommons](callContext)) + } + + messageDocs += getChallengesByTransactionRequestIdDoc + def getChallengesByTransactionRequestIdDoc = MessageDoc( + process = "obp.getChallengesByTransactionRequestId", + messageFormat = messageFormat, + description = "Get Challenges By Transaction Request Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChallengesByTransactionRequestId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=transactionRequestIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetChallengesByTransactionRequestId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChallengesByTransactionRequestId(transactionRequestId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[ChallengeTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetChallengesByTransactionRequestId => InBound, OutBoundGetChallengesByTransactionRequestId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_challenges_by_transaction_request_id", req, callContext) + response.map(convertToTuple[List[ChallengeCommons]](callContext)) + } + + messageDocs += getChallengesByConsentIdDoc + def getChallengesByConsentIdDoc = MessageDoc( + process = "obp.getChallengesByConsentId", + messageFormat = messageFormat, + description = "Get Challenges By Consent Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChallengesByConsentId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + consentId=consentIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetChallengesByConsentId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChallengesByConsentId(consentId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[ChallengeTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetChallengesByConsentId => InBound, OutBoundGetChallengesByConsentId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, consentId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_challenges_by_consent_id", req, callContext) + response.map(convertToTuple[List[ChallengeCommons]](callContext)) + } + + messageDocs += getChallengesByBasketIdDoc + def getChallengesByBasketIdDoc = MessageDoc( + process = "obp.getChallengesByBasketId", + messageFormat = messageFormat, + description = "Get Challenges By Basket Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChallengesByBasketId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + basketId=basketIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetChallengesByBasketId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChallengesByBasketId(basketId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[ChallengeTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetChallengesByBasketId => InBound, OutBoundGetChallengesByBasketId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, basketId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_challenges_by_basket_id", req, callContext) + response.map(convertToTuple[List[ChallengeCommons]](callContext)) + } + + messageDocs += getChallengeDoc + def getChallengeDoc = MessageDoc( + process = "obp.getChallenge", + messageFormat = messageFormat, + description = "Get Challenge", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChallenge(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + challengeId=challengeIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetChallenge(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ChallengeCommons(challengeId=challengeIdExample.value, + transactionRequestId=transactionRequestIdExample.value, + expectedAnswer="string", + expectedUserId="string", + salt="string", + successful=true, + challengeType=challengeTypeExample.value, + consentId=Some(consentIdExample.value), + basketId=Some(basketIdExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), + authenticationMethodId=Some("string"), + attemptCounter=123)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChallenge(challengeId: String, callContext: Option[CallContext]): OBPReturnType[Box[ChallengeTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetChallenge => InBound, OutBoundGetChallenge => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, challengeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_challenge", req, callContext) + response.map(convertToTuple[ChallengeCommons](callContext)) + } + + messageDocs += getBankDoc + def getBankDoc = MessageDoc( + process = "obp.getBank", + messageFormat = messageFormat, + description = "Get Bank", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBank(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetBank(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankCommons(bankId=BankId(bankIdExample.value), + shortName=bankShortNameExample.value, + fullName=bankFullNameExample.value, + logoUrl=bankLogoUrlExample.value, + websiteUrl=bankWebsiteUrlExample.value, + bankRoutingScheme=bankRoutingSchemeExample.value, + bankRoutingAddress=bankRoutingAddressExample.value, + swiftBic=bankSwiftBicExample.value, + nationalIdentifier=bankNationalIdentifierExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBank(bankId: BankId, callContext: Option[CallContext]): Future[Box[(Bank, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetBank => InBound, OutBoundGetBank => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank", req, callContext) + response.map(convertToTuple[BankCommons](callContext)) + } + + messageDocs += getBanksDoc + def getBanksDoc = MessageDoc( + process = "obp.getBanks", + messageFormat = messageFormat, + description = "Get Banks", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBanks(MessageDocsSwaggerDefinitions.outboundAdapterCallContext) + ), + exampleInboundMessage = ( + InBoundGetBanks(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BankCommons(bankId=BankId(bankIdExample.value), + shortName=bankShortNameExample.value, + fullName=bankFullNameExample.value, + logoUrl=bankLogoUrlExample.value, + websiteUrl=bankWebsiteUrlExample.value, + bankRoutingScheme=bankRoutingSchemeExample.value, + bankRoutingAddress=bankRoutingAddressExample.value, + swiftBic=bankSwiftBicExample.value, + nationalIdentifier=bankNationalIdentifierExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBanks(callContext: Option[CallContext]): Future[Box[(List[Bank], Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetBanks => InBound, OutBoundGetBanks => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_banks", req, callContext) + response.map(convertToTuple[List[BankCommons]](callContext)) + } + + messageDocs += getBankAccountsForUserDoc + def getBankAccountsForUserDoc = MessageDoc( + process = "obp.getBankAccountsForUser", + messageFormat = messageFormat, + description = "Get Bank Accounts For User", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountsForUser(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + provider=providerExample.value, + username=usernameExample.value) + ), + exampleInboundMessage = ( + InBoundGetBankAccountsForUser(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( InboundAccountCommons(bankId=bankIdExample.value, + branchId=branchIdExample.value, + accountId=accountIdExample.value, + accountNumber=accountNumberExample.value, + accountType=accountTypeExample.value, + balanceAmount=balanceAmountExample.value, + balanceCurrency=balanceCurrencyExample.value, + owners=inboundAccountOwnersExample.value.replace("[","").replace("]","").split(",").toList, + viewsToGenerate=inboundAccountViewsToGenerateExample.value.replace("[","").replace("]","").split(",").toList, + bankRoutingScheme=bankRoutingSchemeExample.value, + bankRoutingAddress=bankRoutingAddressExample.value, + branchRoutingScheme=branchRoutingSchemeExample.value, + branchRoutingAddress=branchRoutingAddressExample.value, + accountRoutingScheme=accountRoutingSchemeExample.value, + accountRoutingAddress=accountRoutingAddressExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountsForUser(provider: String, username: String, callContext: Option[CallContext]): Future[Box[(List[InboundAccount], Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountsForUser => InBound, OutBoundGetBankAccountsForUser => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, provider, username) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_accounts_for_user", req, callContext) + response.map(convertToTuple[List[InboundAccountCommons]](callContext)) + } + + messageDocs += getBankAccountByIbanDoc + def getBankAccountByIbanDoc = MessageDoc( + process = "obp.getBankAccountByIban", + messageFormat = messageFormat, + description = "Get Bank Account By Iban", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountByIban(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + iban=ibanExample.value) + ), + exampleInboundMessage = ( + InBoundGetBankAccountByIban(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountByIban(iban: String, callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountByIban => InBound, OutBoundGetBankAccountByIban => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, iban) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_account_by_iban", req, callContext) + response.map(convertToTuple[BankAccountCommons](callContext)) + } + + messageDocs += getBankAccountByRoutingDoc + def getBankAccountByRoutingDoc = MessageDoc( + process = "obp.getBankAccountByRouting", + messageFormat = messageFormat, + description = "Get Bank Account By Routing", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountByRouting(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=Some(BankId(bankIdExample.value)), + scheme=schemeExample.value, + address=addressExample.value) + ), + exampleInboundMessage = ( + InBoundGetBankAccountByRouting(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountByRouting => InBound, OutBoundGetBankAccountByRouting => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, scheme, address) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_account_by_routing", req, callContext) + response.map(convertToTuple[BankAccountCommons](callContext)) + } + + messageDocs += getBankAccountsDoc + def getBankAccountsDoc = MessageDoc( + process = "obp.getBankAccounts", + messageFormat = messageFormat, + description = "Get Bank Accounts", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccounts(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankIdAccountIds=List( BankIdAccountId(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)))) + ), + exampleInboundMessage = ( + InBoundGetBankAccounts(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]): OBPReturnType[Box[List[BankAccount]]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccounts => InBound, OutBoundGetBankAccounts => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankIdAccountIds) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_accounts", req, callContext) + response.map(convertToTuple[List[BankAccountCommons]](callContext)) + } + + messageDocs += getBankAccountsBalancesDoc + def getBankAccountsBalancesDoc = MessageDoc( + process = "obp.getBankAccountsBalances", + messageFormat = messageFormat, + description = "Get Bank Accounts Balances", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountsBalances(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankIdAccountIds=List( BankIdAccountId(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)))) + ), + exampleInboundMessage = ( + InBoundGetBankAccountsBalances(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AccountsBalances(accounts=List( AccountBalance(id=idExample.value, + label=labelExample.value, + bankId=bankIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + balance= AmountOfMoney(currency=balanceCurrencyExample.value, + amount=balanceAmountExample.value))), + overallBalance= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value), + overallBalanceDate=toDate(overallBalanceDateExample))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountsBalances(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]): OBPReturnType[Box[AccountsBalances]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountsBalances => InBound, OutBoundGetBankAccountsBalances => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankIdAccountIds) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_accounts_balances", req, callContext) + response.map(convertToTuple[AccountsBalances](callContext)) + } + + messageDocs += getBankAccountBalancesDoc + def getBankAccountBalancesDoc = MessageDoc( + process = "obp.getBankAccountBalances", + messageFormat = messageFormat, + description = "Get Bank Account Balances", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountBalances(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankIdAccountId= BankIdAccountId(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value))) + ), + exampleInboundMessage = ( + InBoundGetBankAccountBalances(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AccountBalances(id=idExample.value, + label=labelExample.value, + bankId=bankIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + balances=List( BankAccountBalance(balance= AmountOfMoney(currency=balanceCurrencyExample.value, + amount=balanceAmountExample.value), + balanceType=balanceTypeExample.value)), + overallBalance= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value), + overallBalanceDate=toDate(overallBalanceDateExample))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountBalances(bankIdAccountId: BankIdAccountId, callContext: Option[CallContext]): OBPReturnType[Box[AccountBalances]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountBalances => InBound, OutBoundGetBankAccountBalances => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankIdAccountId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_account_balances", req, callContext) + response.map(convertToTuple[AccountBalances](callContext)) + } + + messageDocs += getCoreBankAccountsDoc + def getCoreBankAccountsDoc = MessageDoc( + process = "obp.getCoreBankAccounts", + messageFormat = messageFormat, + description = "Get Core Bank Accounts", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCoreBankAccounts(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankIdAccountIds=List( BankIdAccountId(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)))) + ), + exampleInboundMessage = ( + InBoundGetCoreBankAccounts(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CoreAccount(id=accountIdExample.value, + label=labelExample.value, + bankId=bankIdExample.value, + accountType=accountTypeExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCoreBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]): Future[Box[(List[CoreAccount], Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetCoreBankAccounts => InBound, OutBoundGetCoreBankAccounts => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankIdAccountIds) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_core_bank_accounts", req, callContext) + response.map(convertToTuple[List[CoreAccount]](callContext)) + } + + messageDocs += getBankAccountsHeldDoc + def getBankAccountsHeldDoc = MessageDoc( + process = "obp.getBankAccountsHeld", + messageFormat = messageFormat, + description = "Get Bank Accounts Held", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountsHeld(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankIdAccountIds=List( BankIdAccountId(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)))) + ), + exampleInboundMessage = ( + InBoundGetBankAccountsHeld(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( AccountHeld(id=idExample.value, + label=labelExample.value, + bankId=bankIdExample.value, + number=numberExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountsHeld(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]): OBPReturnType[Box[List[AccountHeld]]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountsHeld => InBound, OutBoundGetBankAccountsHeld => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankIdAccountIds) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_accounts_held", req, callContext) + response.map(convertToTuple[List[AccountHeld]](callContext)) + } + + messageDocs += getAccountsHeldDoc + def getAccountsHeldDoc = MessageDoc( + process = "obp.getAccountsHeld", + messageFormat = messageFormat, + description = "Get Accounts Held", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAccountsHeld(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + user= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample)))) + ), + exampleInboundMessage = ( + InBoundGetAccountsHeld(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BankIdAccountId(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAccountsHeld(bankId: BankId, user: User, callContext: Option[CallContext]): OBPReturnType[Box[List[BankIdAccountId]]] = { + import com.openbankproject.commons.dto.{InBoundGetAccountsHeld => InBound, OutBoundGetAccountsHeld => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, user) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_accounts_held", req, callContext) + response.map(convertToTuple[List[BankIdAccountId]](callContext)) + } + + messageDocs += getAccountsHeldByUserDoc + def getAccountsHeldByUserDoc = MessageDoc( + process = "obp.getAccountsHeldByUser", + messageFormat = messageFormat, + description = "Get Accounts Held By User", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAccountsHeldByUser(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + user= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample)))) + ), + exampleInboundMessage = ( + InBoundGetAccountsHeldByUser(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BankIdAccountId(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAccountsHeldByUser(user: User, callContext: Option[CallContext]): OBPReturnType[Box[List[BankIdAccountId]]] = { + import com.openbankproject.commons.dto.{InBoundGetAccountsHeldByUser => InBound, OutBoundGetAccountsHeldByUser => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, user) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_accounts_held_by_user", req, callContext) + response.map(convertToTuple[List[BankIdAccountId]](callContext)) + } + + messageDocs += checkBankAccountExistsDoc + def checkBankAccountExistsDoc = MessageDoc( + process = "obp.checkBankAccountExists", + messageFormat = messageFormat, + description = "Check Bank Account Exists", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCheckBankAccountExists(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)) + ), + exampleInboundMessage = ( + InBoundCheckBankAccountExists(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def checkBankAccountExists(bankId: BankId, accountId: AccountId, callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = { + import com.openbankproject.commons.dto.{InBoundCheckBankAccountExists => InBound, OutBoundCheckBankAccountExists => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_check_bank_account_exists", req, callContext) + response.map(convertToTuple[BankAccountCommons](callContext)) + } + + messageDocs += getCounterpartyTraitDoc + def getCounterpartyTraitDoc = MessageDoc( + process = "obp.getCounterpartyTrait", + messageFormat = messageFormat, + description = "Get Counterparty Trait", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCounterpartyTrait(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + couterpartyId="string") + ), + exampleInboundMessage = ( + InBoundGetCounterpartyTrait(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=nameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCounterpartyTrait(bankId: BankId, accountId: AccountId, couterpartyId: String, callContext: Option[CallContext]): OBPReturnType[Box[CounterpartyTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetCounterpartyTrait => InBound, OutBoundGetCounterpartyTrait => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, couterpartyId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_counterparty_trait", req, callContext) + response.map(convertToTuple[CounterpartyTraitCommons](callContext)) + } + + messageDocs += getCounterpartyByCounterpartyIdDoc + def getCounterpartyByCounterpartyIdDoc = MessageDoc( + process = "obp.getCounterpartyByCounterpartyId", + messageFormat = messageFormat, + description = "Get Counterparty By Counterparty Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCounterpartyByCounterpartyId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + counterpartyId=CounterpartyId(counterpartyIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetCounterpartyByCounterpartyId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=nameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCounterpartyByCounterpartyId(counterpartyId: CounterpartyId, callContext: Option[CallContext]): OBPReturnType[Box[CounterpartyTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetCounterpartyByCounterpartyId => InBound, OutBoundGetCounterpartyByCounterpartyId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, counterpartyId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_counterparty_by_counterparty_id", req, callContext) + response.map(convertToTuple[CounterpartyTraitCommons](callContext)) + } + + messageDocs += getCounterpartyByIbanDoc + def getCounterpartyByIbanDoc = MessageDoc( + process = "obp.getCounterpartyByIban", + messageFormat = messageFormat, + description = "Get Counterparty By Iban", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCounterpartyByIban(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + iban=ibanExample.value) + ), + exampleInboundMessage = ( + InBoundGetCounterpartyByIban(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=nameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCounterpartyByIban(iban: String, callContext: Option[CallContext]): OBPReturnType[Box[CounterpartyTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetCounterpartyByIban => InBound, OutBoundGetCounterpartyByIban => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, iban) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_counterparty_by_iban", req, callContext) + response.map(convertToTuple[CounterpartyTraitCommons](callContext)) + } + + messageDocs += getCounterpartyByIbanAndBankAccountIdDoc + def getCounterpartyByIbanAndBankAccountIdDoc = MessageDoc( + process = "obp.getCounterpartyByIbanAndBankAccountId", + messageFormat = messageFormat, + description = "Get Counterparty By Iban And Bank Account Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCounterpartyByIbanAndBankAccountId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + iban=ibanExample.value, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetCounterpartyByIbanAndBankAccountId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=nameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCounterpartyByIbanAndBankAccountId(iban: String, bankId: BankId, accountId: AccountId, callContext: Option[CallContext]): OBPReturnType[Box[CounterpartyTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetCounterpartyByIbanAndBankAccountId => InBound, OutBoundGetCounterpartyByIbanAndBankAccountId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, iban, bankId, accountId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_counterparty_by_iban_and_bank_account_id", req, callContext) + response.map(convertToTuple[CounterpartyTraitCommons](callContext)) + } + + messageDocs += getCounterpartiesDoc + def getCounterpartiesDoc = MessageDoc( + process = "obp.getCounterparties", + messageFormat = messageFormat, + description = "Get Counterparties", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCounterparties(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + thisBankId=BankId(thisBankIdExample.value), + thisAccountId=AccountId(thisAccountIdExample.value), + viewId=ViewId(viewIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetCounterparties(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=nameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCounterparties(thisBankId: BankId, thisAccountId: AccountId, viewId: ViewId, callContext: Option[CallContext]): OBPReturnType[Box[List[CounterpartyTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetCounterparties => InBound, OutBoundGetCounterparties => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, thisBankId, thisAccountId, viewId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_counterparties", req, callContext) + response.map(convertToTuple[List[CounterpartyTraitCommons]](callContext)) + } + + messageDocs += getTransactionsDoc + def getTransactionsDoc = MessageDoc( + process = "obp.getTransactions", + messageFormat = messageFormat, + description = "Get Transactions", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactions(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + limit=limitExample.value.toInt, + offset=offsetExample.value.toInt, + fromDate=outBoundGetTransactionsFromDateExample.value, + toDate=outBoundGetTransactionsToDateExample.value) + ), + exampleInboundMessage = ( + InBoundGetTransactions(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( Transaction(uuid=transactionUuidExample.value, + id=TransactionId(transactionIdExample.value), + thisAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + otherAccount= Counterparty(nationalIdentifier=counterpartyNationalIdentifierExample.value, + kind=counterpartyKindExample.value, + counterpartyId=counterpartyIdExample.value, + counterpartyName=counterpartyNameExample.value, + thisBankId=BankId(thisBankIdExample.value), + thisAccountId=AccountId(thisAccountIdExample.value), + otherBankRoutingScheme=counterpartyOtherBankRoutingSchemeExample.value, + otherBankRoutingAddress=Some(counterpartyOtherBankRoutingAddressExample.value), + otherAccountRoutingScheme=counterpartyOtherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=Some(counterpartyOtherAccountRoutingAddressExample.value), + otherAccountProvider=counterpartyOtherAccountProviderExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean), + transactionType=transactionTypeExample.value, + amount=BigDecimal(transactionAmountExample.value), + currency=currencyExample.value, + description=Some(transactionDescriptionExample.value), + startDate=toDate(transactionStartDateExample), + finishDate=Some(toDate(transactionFinishDateExample)), + balance=BigDecimal(balanceExample.value), + status=Some(transactionStatusExample.value) + ))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactions(bankId: BankId, accountId: AccountId, callContext: Option[CallContext], queryParams: List[OBPQueryParam]): OBPReturnType[Box[List[Transaction]]] = { + import com.openbankproject.commons.dto.{InBoundGetTransactions => InBound, OutBoundGetTransactions => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams)) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transactions", req, callContext) + response.map(convertToTuple[List[Transaction]](callContext)) + } + + messageDocs += getTransactionsCoreDoc + def getTransactionsCoreDoc = MessageDoc( + process = "obp.getTransactionsCore", + messageFormat = messageFormat, + description = "Get Transactions Core", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionsCore(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + limit=limitExample.value.toInt, + offset=offsetExample.value.toInt, + fromDate=fromDateExample.value, + toDate=toDateExample.value) + ), + exampleInboundMessage = ( + InBoundGetTransactionsCore(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( TransactionCore(id=TransactionId(idExample.value), + thisAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + otherAccount= CounterpartyCore(kind=kindExample.value, + counterpartyId=counterpartyIdExample.value, + counterpartyName=counterpartyNameExample.value, + thisBankId=BankId(thisBankIdExample.value), + thisAccountId=AccountId(thisAccountIdExample.value), + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=Some(otherBankRoutingAddressExample.value), + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=Some(otherAccountRoutingAddressExample.value), + otherAccountProvider=otherAccountProviderExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean), + transactionType=transactionTypeExample.value, + amount=BigDecimal(amountExample.value), + currency=currencyExample.value, + description=Some(descriptionExample.value), + startDate=toDate(startDateExample), + finishDate=toDate(finishDateExample), + balance=BigDecimal(balanceExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionsCore(bankId: BankId, accountId: AccountId, queryParams: List[OBPQueryParam], callContext: Option[CallContext]): OBPReturnType[Box[List[TransactionCore]]] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionsCore => InBound, OutBoundGetTransactionsCore => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams)) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transactions_core", req, callContext) + response.map(convertToTuple[List[TransactionCore]](callContext)) + } + + messageDocs += getTransactionDoc + def getTransactionDoc = MessageDoc( + process = "obp.getTransaction", + messageFormat = messageFormat, + description = "Get Transaction", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransaction(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + transactionId=TransactionId(transactionIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetTransaction(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= Transaction(uuid=transactionUuidExample.value, + id=TransactionId(transactionIdExample.value), + thisAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + otherAccount= Counterparty(nationalIdentifier=counterpartyNationalIdentifierExample.value, + kind=counterpartyKindExample.value, + counterpartyId=counterpartyIdExample.value, + counterpartyName=counterpartyNameExample.value, + thisBankId=BankId(thisBankIdExample.value), + thisAccountId=AccountId(thisAccountIdExample.value), + otherBankRoutingScheme=counterpartyOtherBankRoutingSchemeExample.value, + otherBankRoutingAddress=Some(counterpartyOtherBankRoutingAddressExample.value), + otherAccountRoutingScheme=counterpartyOtherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=Some(counterpartyOtherAccountRoutingAddressExample.value), + otherAccountProvider=counterpartyOtherAccountProviderExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean), + transactionType=transactionTypeExample.value, + amount=BigDecimal(transactionAmountExample.value), + currency=currencyExample.value, + description=Some(transactionDescriptionExample.value), + startDate=toDate(transactionStartDateExample), + finishDate=Some(toDate(transactionFinishDateExample)), + balance=BigDecimal(balanceExample.value), + status=Some(transactionStatusExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransaction(bankId: BankId, accountId: AccountId, transactionId: TransactionId, callContext: Option[CallContext]): OBPReturnType[Box[Transaction]] = { + import com.openbankproject.commons.dto.{InBoundGetTransaction => InBound, OutBoundGetTransaction => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, transactionId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction", req, callContext) + response.map(convertToTuple[Transaction](callContext)) + } + + messageDocs += getPhysicalCardsForUserDoc + def getPhysicalCardsForUserDoc = MessageDoc( + process = "obp.getPhysicalCardsForUser", + messageFormat = messageFormat, + description = "Get Physical Cards For User", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetPhysicalCardsForUser(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + user= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample)))) + ), + exampleInboundMessage = ( + InBoundGetPhysicalCardsForUser(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( PhysicalCard(cardId=cardIdExample.value, + bankId=bankIdExample.value, + bankCardNumber=bankCardNumberExample.value, + cardType=cardTypeExample.value, + nameOnCard=nameOnCardExample.value, + issueNumber=issueNumberExample.value, + serialNumber=serialNumberExample.value, + validFrom=toDate(validFromExample), + expires=toDate(expiresDateExample), + enabled=enabledExample.value.toBoolean, + cancelled=cancelledExample.value.toBoolean, + onHotList=onHotListExample.value.toBoolean, + technology=technologyExample.value, + networks=networksExample.value.replace("[","").replace("]","").split(",").toList, + allows=List(com.openbankproject.commons.model.CardAction.DEBIT), + account= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=accountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + replacement=Some( CardReplacementInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.CardReplacementReason.FIRST)), + pinResets=List( PinResetInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)), + collected=Some(CardCollectionInfo(toDate(collectedExample))), + posted=Some(CardPostedInfo(toDate(postedExample))), + customerId=customerIdExample.value, + cvv=Some(cvvExample.value), + brand=Some(brandExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getPhysicalCardsForUser(user: User, callContext: Option[CallContext]): OBPReturnType[Box[List[PhysicalCard]]] = { + import com.openbankproject.commons.dto.{InBoundGetPhysicalCardsForUser => InBound, OutBoundGetPhysicalCardsForUser => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, user) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_physical_cards_for_user", req, callContext) + response.map(convertToTuple[List[PhysicalCard]](callContext)) + } + + messageDocs += getPhysicalCardForBankDoc + def getPhysicalCardForBankDoc = MessageDoc( + process = "obp.getPhysicalCardForBank", + messageFormat = messageFormat, + description = "Get Physical Card For Bank", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetPhysicalCardForBank(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + cardId=cardIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetPhysicalCardForBank(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= PhysicalCard(cardId=cardIdExample.value, + bankId=bankIdExample.value, + bankCardNumber=bankCardNumberExample.value, + cardType=cardTypeExample.value, + nameOnCard=nameOnCardExample.value, + issueNumber=issueNumberExample.value, + serialNumber=serialNumberExample.value, + validFrom=toDate(validFromExample), + expires=toDate(expiresDateExample), + enabled=enabledExample.value.toBoolean, + cancelled=cancelledExample.value.toBoolean, + onHotList=onHotListExample.value.toBoolean, + technology=technologyExample.value, + networks=networksExample.value.replace("[","").replace("]","").split(",").toList, + allows=List(com.openbankproject.commons.model.CardAction.DEBIT), + account= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=accountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + replacement=Some( CardReplacementInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.CardReplacementReason.FIRST)), + pinResets=List( PinResetInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)), + collected=Some(CardCollectionInfo(toDate(collectedExample))), + posted=Some(CardPostedInfo(toDate(postedExample))), + customerId=customerIdExample.value, + cvv=Some(cvvExample.value), + brand=Some(brandExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getPhysicalCardForBank(bankId: BankId, cardId: String, callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCardTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetPhysicalCardForBank => InBound, OutBoundGetPhysicalCardForBank => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, cardId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_physical_card_for_bank", req, callContext) + response.map(convertToTuple[PhysicalCard](callContext)) + } + + messageDocs += deletePhysicalCardForBankDoc + def deletePhysicalCardForBankDoc = MessageDoc( + process = "obp.deletePhysicalCardForBank", + messageFormat = messageFormat, + description = "Delete Physical Card For Bank", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeletePhysicalCardForBank(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + cardId=cardIdExample.value) + ), + exampleInboundMessage = ( + InBoundDeletePhysicalCardForBank(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deletePhysicalCardForBank(bankId: BankId, cardId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeletePhysicalCardForBank => InBound, OutBoundDeletePhysicalCardForBank => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, cardId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_physical_card_for_bank", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += getPhysicalCardsForBankDoc + def getPhysicalCardsForBankDoc = MessageDoc( + process = "obp.getPhysicalCardsForBank", + messageFormat = messageFormat, + description = "Get Physical Cards For Bank", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetPhysicalCardsForBank(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bank= BankCommons(bankId=BankId(bankIdExample.value), + shortName=bankShortNameExample.value, + fullName=bankFullNameExample.value, + logoUrl=bankLogoUrlExample.value, + websiteUrl=bankWebsiteUrlExample.value, + bankRoutingScheme=bankRoutingSchemeExample.value, + bankRoutingAddress=bankRoutingAddressExample.value, + swiftBic=bankSwiftBicExample.value, + nationalIdentifier=bankNationalIdentifierExample.value), + user= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + limit=limitExample.value.toInt, + offset=offsetExample.value.toInt, + fromDate=fromDateExample.value, + toDate=toDateExample.value) + ), + exampleInboundMessage = ( + InBoundGetPhysicalCardsForBank(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( PhysicalCard(cardId=cardIdExample.value, + bankId=bankIdExample.value, + bankCardNumber=bankCardNumberExample.value, + cardType=cardTypeExample.value, + nameOnCard=nameOnCardExample.value, + issueNumber=issueNumberExample.value, + serialNumber=serialNumberExample.value, + validFrom=toDate(validFromExample), + expires=toDate(expiresDateExample), + enabled=enabledExample.value.toBoolean, + cancelled=cancelledExample.value.toBoolean, + onHotList=onHotListExample.value.toBoolean, + technology=technologyExample.value, + networks=networksExample.value.replace("[","").replace("]","").split(",").toList, + allows=List(com.openbankproject.commons.model.CardAction.DEBIT), + account= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=accountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + replacement=Some( CardReplacementInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.CardReplacementReason.FIRST)), + pinResets=List( PinResetInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)), + collected=Some(CardCollectionInfo(toDate(collectedExample))), + posted=Some(CardPostedInfo(toDate(postedExample))), + customerId=customerIdExample.value, + cvv=Some(cvvExample.value), + brand=Some(brandExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getPhysicalCardsForBank(bank: Bank, user: User, queryParams: List[OBPQueryParam], callContext: Option[CallContext]): OBPReturnType[Box[List[PhysicalCard]]] = { + import com.openbankproject.commons.dto.{InBoundGetPhysicalCardsForBank => InBound, OutBoundGetPhysicalCardsForBank => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bank, user, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams)) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_physical_cards_for_bank", req, callContext) + response.map(convertToTuple[List[PhysicalCard]](callContext)) + } + + messageDocs += createPhysicalCardDoc + def createPhysicalCardDoc = MessageDoc( + process = "obp.createPhysicalCard", + messageFormat = messageFormat, + description = "Create Physical Card", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreatePhysicalCard(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankCardNumber=bankCardNumberExample.value, + nameOnCard=nameOnCardExample.value, + cardType=cardTypeExample.value, + issueNumber=issueNumberExample.value, + serialNumber=serialNumberExample.value, + validFrom=toDate(validFromExample), + expires=toDate(expiresDateExample), + enabled=enabledExample.value.toBoolean, + cancelled=cancelledExample.value.toBoolean, + onHotList=onHotListExample.value.toBoolean, + technology=technologyExample.value, + networks=networksExample.value.replace("[","").replace("]","").split(",").toList, + allows=allowsExample.value.replace("[","").replace("]","").split(",").toList, + accountId=accountIdExample.value, + bankId=bankIdExample.value, + replacement=Some( CardReplacementInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.CardReplacementReason.FIRST)), + pinResets=List( PinResetInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)), + collected=Some(CardCollectionInfo(toDate(collectedExample))), + posted=Some(CardPostedInfo(toDate(postedExample))), + customerId=customerIdExample.value, + cvv=cvvExample.value, + brand=brandExample.value) + ), + exampleInboundMessage = ( + InBoundCreatePhysicalCard(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= PhysicalCard(cardId=cardIdExample.value, + bankId=bankIdExample.value, + bankCardNumber=bankCardNumberExample.value, + cardType=cardTypeExample.value, + nameOnCard=nameOnCardExample.value, + issueNumber=issueNumberExample.value, + serialNumber=serialNumberExample.value, + validFrom=toDate(validFromExample), + expires=toDate(expiresDateExample), + enabled=enabledExample.value.toBoolean, + cancelled=cancelledExample.value.toBoolean, + onHotList=onHotListExample.value.toBoolean, + technology=technologyExample.value, + networks=networksExample.value.replace("[","").replace("]","").split(",").toList, + allows=List(com.openbankproject.commons.model.CardAction.DEBIT), + account= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=accountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + replacement=Some( CardReplacementInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.CardReplacementReason.FIRST)), + pinResets=List( PinResetInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)), + collected=Some(CardCollectionInfo(toDate(collectedExample))), + posted=Some(CardPostedInfo(toDate(postedExample))), + customerId=customerIdExample.value, + cvv=Some(cvvExample.value), + brand=Some(brandExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createPhysicalCard(bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String, serialNumber: String, validFrom: Date, expires: Date, enabled: Boolean, cancelled: Boolean, onHotList: Boolean, technology: String, networks: List[String], allows: List[String], accountId: String, bankId: String, replacement: Option[CardReplacementInfo], pinResets: List[PinResetInfo], collected: Option[CardCollectionInfo], posted: Option[CardPostedInfo], customerId: String, cvv: String, brand: String, callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = { + import com.openbankproject.commons.dto.{InBoundCreatePhysicalCard => InBound, OutBoundCreatePhysicalCard => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankCardNumber, nameOnCard, cardType, issueNumber, serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId, cvv, brand) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_physical_card", req, callContext) + response.map(convertToTuple[PhysicalCard](callContext)) + } + + messageDocs += updatePhysicalCardDoc + def updatePhysicalCardDoc = MessageDoc( + process = "obp.updatePhysicalCard", + messageFormat = messageFormat, + description = "Update Physical Card", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdatePhysicalCard(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + cardId=cardIdExample.value, + bankCardNumber=bankCardNumberExample.value, + nameOnCard=nameOnCardExample.value, + cardType=cardTypeExample.value, + issueNumber=issueNumberExample.value, + serialNumber=serialNumberExample.value, + validFrom=toDate(validFromExample), + expires=toDate(expiresDateExample), + enabled=enabledExample.value.toBoolean, + cancelled=cancelledExample.value.toBoolean, + onHotList=onHotListExample.value.toBoolean, + technology=technologyExample.value, + networks=networksExample.value.replace("[","").replace("]","").split(",").toList, + allows=allowsExample.value.replace("[","").replace("]","").split(",").toList, + accountId=accountIdExample.value, + bankId=bankIdExample.value, + replacement=Some( CardReplacementInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.CardReplacementReason.FIRST)), + pinResets=List( PinResetInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)), + collected=Some(CardCollectionInfo(toDate(collectedExample))), + posted=Some(CardPostedInfo(toDate(postedExample))), + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundUpdatePhysicalCard(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= PhysicalCard(cardId=cardIdExample.value, + bankId=bankIdExample.value, + bankCardNumber=bankCardNumberExample.value, + cardType=cardTypeExample.value, + nameOnCard=nameOnCardExample.value, + issueNumber=issueNumberExample.value, + serialNumber=serialNumberExample.value, + validFrom=toDate(validFromExample), + expires=toDate(expiresDateExample), + enabled=enabledExample.value.toBoolean, + cancelled=cancelledExample.value.toBoolean, + onHotList=onHotListExample.value.toBoolean, + technology=technologyExample.value, + networks=networksExample.value.replace("[","").replace("]","").split(",").toList, + allows=List(com.openbankproject.commons.model.CardAction.DEBIT), + account= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=accountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + replacement=Some( CardReplacementInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.CardReplacementReason.FIRST)), + pinResets=List( PinResetInfo(requestedDate=toDate(requestedDateExample), + reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)), + collected=Some(CardCollectionInfo(toDate(collectedExample))), + posted=Some(CardPostedInfo(toDate(postedExample))), + customerId=customerIdExample.value, + cvv=Some(cvvExample.value), + brand=Some(brandExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updatePhysicalCard(cardId: String, bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String, serialNumber: String, validFrom: Date, expires: Date, enabled: Boolean, cancelled: Boolean, onHotList: Boolean, technology: String, networks: List[String], allows: List[String], accountId: String, bankId: String, replacement: Option[CardReplacementInfo], pinResets: List[PinResetInfo], collected: Option[CardCollectionInfo], posted: Option[CardPostedInfo], customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCardTrait]] = { + import com.openbankproject.commons.dto.{InBoundUpdatePhysicalCard => InBound, OutBoundUpdatePhysicalCard => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, cardId, bankCardNumber, nameOnCard, cardType, issueNumber, serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_physical_card", req, callContext) + response.map(convertToTuple[PhysicalCard](callContext)) + } + + messageDocs += makePaymentv210Doc + def makePaymentv210Doc = MessageDoc( + process = "obp.makePaymentv210", + messageFormat = messageFormat, + description = "Make Paymentv210", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundMakePaymentv210(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + transactionRequestId=TransactionRequestId(transactionRequestIdExample.value), + transactionRequestCommonBody= TransactionRequestCommonBodyJSONCommons(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value), + amount=BigDecimal(amountExample.value), + description=descriptionExample.value, + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value), + chargePolicy=chargePolicyExample.value) + ), + exampleInboundMessage = ( + InBoundMakePaymentv210(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=TransactionId(transactionIdExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def makePaymentv210(fromAccount: BankAccount, toAccount: BankAccount, transactionRequestId: TransactionRequestId, transactionRequestCommonBody: TransactionRequestCommonBodyJSON, amount: BigDecimal, description: String, transactionRequestType: TransactionRequestType, chargePolicy: String, callContext: Option[CallContext]): OBPReturnType[Box[TransactionId]] = { + import com.openbankproject.commons.dto.{InBoundMakePaymentv210 => InBound, OutBoundMakePaymentv210 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, fromAccount, toAccount, transactionRequestId, transactionRequestCommonBody, amount, description, transactionRequestType, chargePolicy) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_make_paymentv210", req, callContext) + response.map(convertToTuple[TransactionId](callContext)) + } + + messageDocs += getChargeValueDoc + def getChargeValueDoc = MessageDoc( + process = "obp.getChargeValue", + messageFormat = messageFormat, + description = "Get Charge Value", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetChargeValue(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + chargeLevelAmount=BigDecimal("123.321"), + transactionRequestCommonBodyAmount=BigDecimal("123.321")) + ), + exampleInboundMessage = ( + InBoundGetChargeValue(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data="string") + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getChargeValue(chargeLevelAmount: BigDecimal, transactionRequestCommonBodyAmount: BigDecimal, callContext: Option[CallContext]): OBPReturnType[Box[String]] = { + import com.openbankproject.commons.dto.{InBoundGetChargeValue => InBound, OutBoundGetChargeValue => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, chargeLevelAmount, transactionRequestCommonBodyAmount) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_charge_value", req, callContext) + response.map(convertToTuple[String](callContext)) + } + + messageDocs += createTransactionRequestv210Doc + def createTransactionRequestv210Doc = MessageDoc( + process = "obp.createTransactionRequestv210", + messageFormat = messageFormat, + description = "Create Transaction Requestv210", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTransactionRequestv210(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + viewId=ViewId(viewIdExample.value), + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value), + transactionRequestCommonBody= TransactionRequestCommonBodyJSONCommons(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value), + detailsPlain="string", + chargePolicy=chargePolicyExample.value, + challengeType=Some(challengeTypeExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS)) + ), + exampleInboundMessage = ( + InBoundCreateTransactionRequestv210(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTransactionRequestv210(initiator: User, viewId: ViewId, fromAccount: BankAccount, toAccount: BankAccount, transactionRequestType: TransactionRequestType, transactionRequestCommonBody: TransactionRequestCommonBodyJSON, detailsPlain: String, chargePolicy: String, challengeType: Option[String], scaMethod: Option[StrongCustomerAuthentication.SCA], callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequest]] = { + import com.openbankproject.commons.dto.{InBoundCreateTransactionRequestv210 => InBound, OutBoundCreateTransactionRequestv210 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, viewId, fromAccount, toAccount, transactionRequestType, transactionRequestCommonBody, detailsPlain, chargePolicy, challengeType, scaMethod) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_transaction_requestv210", req, callContext) + response.map(convertToTuple[TransactionRequest](callContext)) + } + + messageDocs += createTransactionRequestv400Doc + def createTransactionRequestv400Doc = MessageDoc( + process = "obp.createTransactionRequestv400", + messageFormat = messageFormat, + description = "Create Transaction Requestv400", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTransactionRequestv400(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + viewId=ViewId(viewIdExample.value), + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value), + transactionRequestCommonBody= TransactionRequestCommonBodyJSONCommons(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value), + detailsPlain="string", + chargePolicy=chargePolicyExample.value, + challengeType=Some(challengeTypeExample.value), + scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), + reasons=Some(List( TransactionRequestReason(code=codeExample.value, + documentNumber=Some(documentNumberExample.value), + amount=Some(amountExample.value), + currency=Some(currencyExample.value), + description=Some(descriptionExample.value))))) + ), + exampleInboundMessage = ( + InBoundCreateTransactionRequestv400(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTransactionRequestv400(initiator: User, viewId: ViewId, fromAccount: BankAccount, toAccount: BankAccount, transactionRequestType: TransactionRequestType, transactionRequestCommonBody: TransactionRequestCommonBodyJSON, detailsPlain: String, chargePolicy: String, challengeType: Option[String], scaMethod: Option[StrongCustomerAuthentication.SCA], reasons: Option[List[TransactionRequestReason]], callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequest]] = { + import com.openbankproject.commons.dto.{InBoundCreateTransactionRequestv400 => InBound, OutBoundCreateTransactionRequestv400 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, viewId, fromAccount, toAccount, transactionRequestType, transactionRequestCommonBody, detailsPlain, chargePolicy, challengeType, scaMethod, reasons) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_transaction_requestv400", req, callContext) + response.map(convertToTuple[TransactionRequest](callContext)) + } + + messageDocs += createTransactionRequestSepaCreditTransfersBGV1Doc + def createTransactionRequestSepaCreditTransfersBGV1Doc = MessageDoc( + process = "obp.createTransactionRequestSepaCreditTransfersBGV1", + messageFormat = messageFormat, + description = "Create Transaction Request Sepa Credit Transfers BG V1", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTransactionRequestSepaCreditTransfersBGV1(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= Some(UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample)))), + paymentServiceType=com.openbankproject.commons.model.enums.PaymentServiceTypes.example, + transactionRequestType=com.openbankproject.commons.model.enums.TransactionRequestTypes.example, + transactionRequestBody= SepaCreditTransfersBerlinGroupV13(endToEndIdentification=Some("string"), + instructionIdentification=Some("string"), + debtorName=Some("string"), + debtorAccount=PaymentAccount("string"), + debtorId=Some("string"), + ultimateDebtor=Some("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + currencyOfTransfer=Some("string"), + exchangeRateInformation=Some("string"), + creditorAccount=PaymentAccount("string"), + creditorAgent=Some("string"), + creditorAgentName=Some("string"), + creditorName="string", + creditorId=Some("string"), + creditorAddress=Some("string"), + creditorNameAndAddress=Some("string"), + ultimateCreditor=Some("string"), + purposeCode=Some("string"), + chargeBearer=Some("string"), + serviceLevel=Some("string"), + remittanceInformationUnstructured=Some("string"), + remittanceInformationUnstructuredArray=Some("string"), + remittanceInformationStructured=Some("string"), + remittanceInformationStructuredArray=Some("string"), + requestedExecutionDate=Some("string"), + requestedExecutionTime=Some("string"))) + ), + exampleInboundMessage = ( + InBoundCreateTransactionRequestSepaCreditTransfersBGV1(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequestBGV1(id=TransactionRequestId(idExample.value), + status=statusExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTransactionRequestSepaCreditTransfersBGV1(initiator: Option[User], paymentServiceType: PaymentServiceTypes, transactionRequestType: TransactionRequestTypes, transactionRequestBody: SepaCreditTransfersBerlinGroupV13, callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequestBGV1]] = { + import com.openbankproject.commons.dto.{InBoundCreateTransactionRequestSepaCreditTransfersBGV1 => InBound, OutBoundCreateTransactionRequestSepaCreditTransfersBGV1 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, paymentServiceType, transactionRequestType, transactionRequestBody) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_transaction_request_sepa_credit_transfers_bgv1", req, callContext) + response.map(convertToTuple[TransactionRequestBGV1](callContext)) + } + + messageDocs += createTransactionRequestPeriodicSepaCreditTransfersBGV1Doc + def createTransactionRequestPeriodicSepaCreditTransfersBGV1Doc = MessageDoc( + process = "obp.createTransactionRequestPeriodicSepaCreditTransfersBGV1", + messageFormat = messageFormat, + description = "Create Transaction Request Periodic Sepa Credit Transfers BG V1", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTransactionRequestPeriodicSepaCreditTransfersBGV1(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= Some(UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample)))), + paymentServiceType=com.openbankproject.commons.model.enums.PaymentServiceTypes.example, + transactionRequestType=com.openbankproject.commons.model.enums.TransactionRequestTypes.example, + transactionRequestBody= PeriodicSepaCreditTransfersBerlinGroupV13(endToEndIdentification=Some("string"), + instructionIdentification=Some("string"), + debtorName=Some("string"), + debtorAccount=PaymentAccount("string"), + debtorId=Some("string"), + ultimateDebtor=Some("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + currencyOfTransfer=Some("string"), + exchangeRateInformation=Some("string"), + creditorAccount=PaymentAccount("string"), + creditorAgent=Some("string"), + creditorAgentName=Some("string"), + creditorName="string", + creditorId=Some("string"), + creditorAddress=Some("string"), + creditorNameAndAddress=Some("string"), + ultimateCreditor=Some("string"), + purposeCode=Some("string"), + chargeBearer=Some("string"), + serviceLevel=Some("string"), + remittanceInformationUnstructured=Some("string"), + remittanceInformationUnstructuredArray=Some("string"), + remittanceInformationStructured=Some("string"), + remittanceInformationStructuredArray=Some("string"), + requestedExecutionDate=Some("string"), + requestedExecutionTime=Some("string"), + startDate=startDateExample.value, + executionRule=Some("string"), + endDate=Some(endDateExample.value), + frequency=frequencyExample.value, + dayOfExecution=Some("string"))) + ), + exampleInboundMessage = ( + InBoundCreateTransactionRequestPeriodicSepaCreditTransfersBGV1(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequestBGV1(id=TransactionRequestId(idExample.value), + status=statusExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTransactionRequestPeriodicSepaCreditTransfersBGV1(initiator: Option[User], paymentServiceType: PaymentServiceTypes, transactionRequestType: TransactionRequestTypes, transactionRequestBody: PeriodicSepaCreditTransfersBerlinGroupV13, callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequestBGV1]] = { + import com.openbankproject.commons.dto.{InBoundCreateTransactionRequestPeriodicSepaCreditTransfersBGV1 => InBound, OutBoundCreateTransactionRequestPeriodicSepaCreditTransfersBGV1 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, paymentServiceType, transactionRequestType, transactionRequestBody) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_transaction_request_periodic_sepa_credit_transfers_bgv1", req, callContext) + response.map(convertToTuple[TransactionRequestBGV1](callContext)) + } + + messageDocs += saveTransactionRequestTransactionDoc + def saveTransactionRequestTransactionDoc = MessageDoc( + process = "obp.saveTransactionRequestTransaction", + messageFormat = messageFormat, + description = "Save Transaction Request Transaction", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundSaveTransactionRequestTransaction(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=TransactionRequestId(transactionRequestIdExample.value), + transactionId=TransactionId(transactionIdExample.value)) + ), + exampleInboundMessage = ( + InBoundSaveTransactionRequestTransaction(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def saveTransactionRequestTransaction(transactionRequestId: TransactionRequestId, transactionId: TransactionId, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundSaveTransactionRequestTransaction => InBound, OutBoundSaveTransactionRequestTransaction => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId, transactionId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_save_transaction_request_transaction", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += saveTransactionRequestChallengeDoc + def saveTransactionRequestChallengeDoc = MessageDoc( + process = "obp.saveTransactionRequestChallenge", + messageFormat = messageFormat, + description = "Save Transaction Request Challenge", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundSaveTransactionRequestChallenge(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=TransactionRequestId(transactionRequestIdExample.value), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string")) + ), + exampleInboundMessage = ( + InBoundSaveTransactionRequestChallenge(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def saveTransactionRequestChallenge(transactionRequestId: TransactionRequestId, challenge: TransactionRequestChallenge, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundSaveTransactionRequestChallenge => InBound, OutBoundSaveTransactionRequestChallenge => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId, challenge) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_save_transaction_request_challenge", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += saveTransactionRequestStatusImplDoc + def saveTransactionRequestStatusImplDoc = MessageDoc( + process = "obp.saveTransactionRequestStatusImpl", + messageFormat = messageFormat, + description = "Save Transaction Request Status Impl", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundSaveTransactionRequestStatusImpl(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=TransactionRequestId(transactionRequestIdExample.value), + status=statusExample.value) + ), + exampleInboundMessage = ( + InBoundSaveTransactionRequestStatusImpl(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def saveTransactionRequestStatusImpl(transactionRequestId: TransactionRequestId, status: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundSaveTransactionRequestStatusImpl => InBound, OutBoundSaveTransactionRequestStatusImpl => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId, status) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_save_transaction_request_status_impl", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += getTransactionRequests210Doc + def getTransactionRequests210Doc = MessageDoc( + process = "obp.getTransactionRequests210", + messageFormat = messageFormat, + description = "Get Transaction Requests210", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionRequests210(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value))))) + ), + exampleInboundMessage = ( + InBoundGetTransactionRequests210(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string")))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionRequests210(initiator: User, fromAccount: BankAccount, callContext: Option[CallContext]): Box[(List[TransactionRequest], Option[CallContext])] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionRequests210 => InBound, OutBoundGetTransactionRequests210 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, fromAccount) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction_requests210", req, callContext) + response.map(convertToTuple[List[TransactionRequest]](callContext)) + } + + messageDocs += getTransactionRequestImplDoc + def getTransactionRequestImplDoc = MessageDoc( + process = "obp.getTransactionRequestImpl", + messageFormat = messageFormat, + description = "Get Transaction Request Impl", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionRequestImpl(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequestId=TransactionRequestId(transactionRequestIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetTransactionRequestImpl(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionRequestImpl(transactionRequestId: TransactionRequestId, callContext: Option[CallContext]): Box[(TransactionRequest, Option[CallContext])] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionRequestImpl => InBound, OutBoundGetTransactionRequestImpl => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequestId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction_request_impl", req, callContext) + response.map(convertToTuple[TransactionRequest](callContext)) + } + + messageDocs += getTransactionRequestTypesDoc + def getTransactionRequestTypesDoc = MessageDoc( + process = "obp.getTransactionRequestTypes", + messageFormat = messageFormat, + description = "Get Transaction Request Types", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionRequestTypes(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value))))) + ), + exampleInboundMessage = ( + InBoundGetTransactionRequestTypes(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List(TransactionRequestType(transactionRequestTypeExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionRequestTypes(initiator: User, fromAccount: BankAccount, callContext: Option[CallContext]): Box[(List[TransactionRequestType], Option[CallContext])] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionRequestTypes => InBound, OutBoundGetTransactionRequestTypes => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, fromAccount) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction_request_types", req, callContext) + response.map(convertToTuple[List[TransactionRequestType]](callContext)) + } + + messageDocs += createTransactionAfterChallengeV210Doc + def createTransactionAfterChallengeV210Doc = MessageDoc( + process = "obp.createTransactionAfterChallengeV210", + messageFormat = messageFormat, + description = "Create Transaction After Challenge V210", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTransactionAfterChallengeV210(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + transactionRequest= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string"))) + ), + exampleInboundMessage = ( + InBoundCreateTransactionAfterChallengeV210(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTransactionAfterChallengeV210(fromAccount: BankAccount, transactionRequest: TransactionRequest, callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequest]] = { + import com.openbankproject.commons.dto.{InBoundCreateTransactionAfterChallengeV210 => InBound, OutBoundCreateTransactionAfterChallengeV210 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, fromAccount, transactionRequest) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_transaction_after_challenge_v210", req, callContext) + response.map(convertToTuple[TransactionRequest](callContext)) + } + + messageDocs += updateBankAccountDoc + def updateBankAccountDoc = MessageDoc( + process = "obp.updateBankAccount", + messageFormat = messageFormat, + description = "Update Bank Account", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdateBankAccount(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + accountLabel="string", + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value))) + ), + exampleInboundMessage = ( + InBoundUpdateBankAccount(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updateBankAccount(bankId: BankId, accountId: AccountId, accountType: String, accountLabel: String, branchId: String, accountRoutings: List[AccountRouting], callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = { + import com.openbankproject.commons.dto.{InBoundUpdateBankAccount => InBound, OutBoundUpdateBankAccount => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, accountType, accountLabel, branchId, accountRoutings) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_bank_account", req, callContext) + response.map(convertToTuple[BankAccountCommons](callContext)) + } + + messageDocs += createBankAccountDoc + def createBankAccountDoc = MessageDoc( + process = "obp.createBankAccount", + messageFormat = messageFormat, + description = "Create Bank Account", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateBankAccount(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + accountLabel="string", + currency=currencyExample.value, + initialBalance=BigDecimal("123.321"), + accountHolderName="string", + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value))) + ), + exampleInboundMessage = ( + InBoundCreateBankAccount(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createBankAccount(bankId: BankId, accountId: AccountId, accountType: String, accountLabel: String, currency: String, initialBalance: BigDecimal, accountHolderName: String, branchId: String, accountRoutings: List[AccountRouting], callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = { + import com.openbankproject.commons.dto.{InBoundCreateBankAccount => InBound, OutBoundCreateBankAccount => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, accountType, accountLabel, currency, initialBalance, accountHolderName, branchId, accountRoutings) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_bank_account", req, callContext) + response.map(convertToTuple[BankAccountCommons](callContext)) + } + + messageDocs += updateAccountLabelDoc + def updateAccountLabelDoc = MessageDoc( + process = "obp.updateAccountLabel", + messageFormat = messageFormat, + description = "Update Account Label", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdateAccountLabel(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + label=labelExample.value) + ), + exampleInboundMessage = ( + InBoundUpdateAccountLabel(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updateAccountLabel(bankId: BankId, accountId: AccountId, label: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundUpdateAccountLabel => InBound, OutBoundUpdateAccountLabel => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, label) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_account_label", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += getProductsDoc + def getProductsDoc = MessageDoc( + process = "obp.getProducts", + messageFormat = messageFormat, + description = "Get Products", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetProducts(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + params=List( GetProductsParam(name=nameExample.value, + value=valueExample.value.replace("[","").replace("]","").split(",").toList))) + ), + exampleInboundMessage = ( + InBoundGetProducts(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ProductCommons( + bankId=BankId(bankIdExample.value), + code=ProductCode(productCodeExample.value), + parentProductCode=ProductCode(parentProductCodeExample.value), + name=productNameExample.value, + category=categoryExample.value, + family=familyExample.value, + superFamily=superFamilyExample.value, + moreInfoUrl=moreInfoUrlExample.value, + termsAndConditionsUrl=termsAndConditionsUrlExample.value, + details=detailsExample.value, + description=descriptionExample.value, + meta=Meta( License(id=licenseIdExample.value, + name=licenseNameExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getProducts(bankId: BankId, params: List[GetProductsParam], callContext: Option[CallContext]): OBPReturnType[Box[List[Product]]] = { + import com.openbankproject.commons.dto.{InBoundGetProducts => InBound, OutBoundGetProducts => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, params) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_products", req, callContext) + response.map(convertToTuple[List[ProductCommons]](callContext)) + } + + messageDocs += getProductDoc + def getProductDoc = MessageDoc( + process = "obp.getProduct", + messageFormat = messageFormat, + description = "Get Product", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetProduct(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + productCode=ProductCode(productCodeExample.value)) + ), + exampleInboundMessage = ( + InBoundGetProduct(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ProductCommons( + bankId=BankId(bankIdExample.value), + code=ProductCode(productCodeExample.value), + parentProductCode=ProductCode(parentProductCodeExample.value), + name=productNameExample.value, + category=categoryExample.value, + family=familyExample.value, + superFamily=superFamilyExample.value, + moreInfoUrl=moreInfoUrlExample.value, + termsAndConditionsUrl=termsAndConditionsUrlExample.value, + details=detailsExample.value, + description=descriptionExample.value, + meta=Meta( License(id=licenseIdExample.value, + name=licenseNameExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getProduct(bankId: BankId, productCode: ProductCode, callContext: Option[CallContext]): OBPReturnType[Box[Product]] = { + import com.openbankproject.commons.dto.{InBoundGetProduct => InBound, OutBoundGetProduct => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, productCode) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_product", req, callContext) + response.map(convertToTuple[ProductCommons](callContext)) + } + + messageDocs += getBranchDoc + def getBranchDoc = MessageDoc( + process = "obp.getBranch", + messageFormat = messageFormat, + description = "Get Branch", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBranch(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + branchId=BranchId(branchIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetBranch(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BranchTCommons(branchId=BranchId(branchIdExample.value), + bankId=BankId(bankIdExample.value), + name=nameExample.value, + address= Address(line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=Some(countyExample.value), + state=stateExample.value, + postCode=postCodeExample.value, + countryCode=countryCodeExample.value), + location= Location(latitude=latitudeExample.value.toDouble, + longitude=longitudeExample.value.toDouble, + date=Some(toDate(dateExample)), + user=Some( BasicResourceUser(userId=userIdExample.value, + provider=providerExample.value, + username=usernameExample.value))), + lobbyString=Some(LobbyString("string")), + driveUpString=Some(DriveUpString("string")), + meta=Meta( License(id=licenseIdExample.value, + name=licenseNameExample.value)), + branchRouting=Some( Routing(scheme=branchRoutingSchemeExample.value, + address=branchRoutingAddressExample.value)), + lobby=Some( Lobby(monday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + tuesday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + wednesday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + thursday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + friday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + saturday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + sunday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)))), + driveUp=Some( DriveUp(monday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + tuesday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + wednesday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + thursday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + friday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + saturday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + sunday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value))), + isAccessible=Some(isAccessibleExample.value.toBoolean), + accessibleFeatures=Some("string"), + branchType=Some(branchTypeExample.value), + moreInfo=Some(moreInfoExample.value), + phoneNumber=Some(phoneNumberExample.value), + isDeleted=Some(true))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBranch(bankId: BankId, branchId: BranchId, callContext: Option[CallContext]): Future[Box[(BranchT, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetBranch => InBound, OutBoundGetBranch => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, branchId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_branch", req, callContext) + response.map(convertToTuple[BranchTCommons](callContext)) + } + + messageDocs += getBranchesDoc + def getBranchesDoc = MessageDoc( + process = "obp.getBranches", + messageFormat = messageFormat, + description = "Get Branches", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBranches(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + limit=limitExample.value.toInt, + offset=offsetExample.value.toInt, + fromDate=fromDateExample.value, + toDate=toDateExample.value) + ), + exampleInboundMessage = ( + InBoundGetBranches(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BranchTCommons(branchId=BranchId(branchIdExample.value), + bankId=BankId(bankIdExample.value), + name=nameExample.value, + address= Address(line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=Some(countyExample.value), + state=stateExample.value, + postCode=postCodeExample.value, + countryCode=countryCodeExample.value), + location= Location(latitude=latitudeExample.value.toDouble, + longitude=longitudeExample.value.toDouble, + date=Some(toDate(dateExample)), + user=Some( BasicResourceUser(userId=userIdExample.value, + provider=providerExample.value, + username=usernameExample.value))), + lobbyString=Some(LobbyString("string")), + driveUpString=Some(DriveUpString("string")), + meta=Meta( License(id=licenseIdExample.value, + name=licenseNameExample.value)), + branchRouting=Some( Routing(scheme=branchRoutingSchemeExample.value, + address=branchRoutingAddressExample.value)), + lobby=Some( Lobby(monday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + tuesday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + wednesday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + thursday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + friday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + saturday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)), + sunday=List( OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value)))), + driveUp=Some( DriveUp(monday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + tuesday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + wednesday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + thursday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + friday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + saturday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value), + sunday= OpeningTimes(openingTime=openingTimeExample.value, + closingTime=closingTimeExample.value))), + isAccessible=Some(isAccessibleExample.value.toBoolean), + accessibleFeatures=Some("string"), + branchType=Some(branchTypeExample.value), + moreInfo=Some(moreInfoExample.value), + phoneNumber=Some(phoneNumberExample.value), + isDeleted=Some(true)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBranches(bankId: BankId, callContext: Option[CallContext], queryParams: List[OBPQueryParam]): Future[Box[(List[BranchT], Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetBranches => InBound, OutBoundGetBranches => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams)) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_branches", req, callContext) + response.map(convertToTuple[List[BranchTCommons]](callContext)) + } + + messageDocs += getAtmDoc + def getAtmDoc = MessageDoc( + process = "obp.getAtm", + messageFormat = messageFormat, + description = "Get Atm", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAtm(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + atmId=AtmId(atmIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetAtm(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AtmTCommons(atmId=AtmId(atmIdExample.value), + bankId=BankId(bankIdExample.value), + name=nameExample.value, + address= Address(line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=Some(countyExample.value), + state=stateExample.value, + postCode=postCodeExample.value, + countryCode=countryCodeExample.value), + location= Location(latitude=latitudeExample.value.toDouble, + longitude=longitudeExample.value.toDouble, + date=Some(toDate(dateExample)), + user=Some( BasicResourceUser(userId=userIdExample.value, + provider=providerExample.value, + username=usernameExample.value))), + meta=Meta( License(id=licenseIdExample.value, + name=licenseNameExample.value)), + OpeningTimeOnMonday=Some("string"), + ClosingTimeOnMonday=Some("string"), + OpeningTimeOnTuesday=Some("string"), + ClosingTimeOnTuesday=Some("string"), + OpeningTimeOnWednesday=Some("string"), + ClosingTimeOnWednesday=Some("string"), + OpeningTimeOnThursday=Some("string"), + ClosingTimeOnThursday=Some("string"), + OpeningTimeOnFriday=Some("string"), + ClosingTimeOnFriday=Some("string"), + OpeningTimeOnSaturday=Some("string"), + ClosingTimeOnSaturday=Some("string"), + OpeningTimeOnSunday=Some("string"), + ClosingTimeOnSunday=Some("string"), + isAccessible=Some(isAccessibleExample.value.toBoolean), + locatedAt=Some(locatedAtExample.value), + moreInfo=Some(moreInfoExample.value), + hasDepositCapability=Some(hasDepositCapabilityExample.value.toBoolean), + supportedLanguages=Some(supportedLanguagesExample.value.replace("[","").replace("]","").split(",").toList), + services=Some(servicesExample.value.replace("[","").replace("]","").split(",").toList), + accessibilityFeatures=Some(accessibilityFeaturesExample.value.replace("[","").replace("]","").split(",").toList), + supportedCurrencies=Some(supportedCurrenciesExample.value.replace("[","").replace("]","").split(",").toList), + notes=Some(listExample.value.replace("[","").replace("]","").split(",").toList), + locationCategories=Some(listExample.value.replace("[","").replace("]","").split(",").toList), + minimumWithdrawal=Some("string"), + branchIdentification=Some("string"), + siteIdentification=Some(siteIdentification.value), + siteName=Some("string"), + cashWithdrawalNationalFee=Some(cashWithdrawalNationalFeeExample.value), + cashWithdrawalInternationalFee=Some(cashWithdrawalInternationalFeeExample.value), + balanceInquiryFee=Some(balanceInquiryFeeExample.value), + atmType=Some(atmTypeExample.value), + phone=Some(phoneExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAtm(bankId: BankId, atmId: AtmId, callContext: Option[CallContext]): Future[Box[(AtmT, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetAtm => InBound, OutBoundGetAtm => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, atmId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_atm", req, callContext) + response.map(convertToTuple[AtmTCommons](callContext)) + } + + messageDocs += getAtmsDoc + def getAtmsDoc = MessageDoc( + process = "obp.getAtms", + messageFormat = messageFormat, + description = "Get Atms", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAtms(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + limit=limitExample.value.toInt, + offset=offsetExample.value.toInt, + fromDate=fromDateExample.value, + toDate=toDateExample.value) + ), + exampleInboundMessage = ( + InBoundGetAtms(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( AtmTCommons(atmId=AtmId(atmIdExample.value), + bankId=BankId(bankIdExample.value), + name=nameExample.value, + address= Address(line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=Some(countyExample.value), + state=stateExample.value, + postCode=postCodeExample.value, + countryCode=countryCodeExample.value), + location= Location(latitude=latitudeExample.value.toDouble, + longitude=longitudeExample.value.toDouble, + date=Some(toDate(dateExample)), + user=Some( BasicResourceUser(userId=userIdExample.value, + provider=providerExample.value, + username=usernameExample.value))), + meta=Meta( License(id=licenseIdExample.value, + name=licenseNameExample.value)), + OpeningTimeOnMonday=Some("string"), + ClosingTimeOnMonday=Some("string"), + OpeningTimeOnTuesday=Some("string"), + ClosingTimeOnTuesday=Some("string"), + OpeningTimeOnWednesday=Some("string"), + ClosingTimeOnWednesday=Some("string"), + OpeningTimeOnThursday=Some("string"), + ClosingTimeOnThursday=Some("string"), + OpeningTimeOnFriday=Some("string"), + ClosingTimeOnFriday=Some("string"), + OpeningTimeOnSaturday=Some("string"), + ClosingTimeOnSaturday=Some("string"), + OpeningTimeOnSunday=Some("string"), + ClosingTimeOnSunday=Some("string"), + isAccessible=Some(isAccessibleExample.value.toBoolean), + locatedAt=Some(locatedAtExample.value), + moreInfo=Some(moreInfoExample.value), + hasDepositCapability=Some(hasDepositCapabilityExample.value.toBoolean), + supportedLanguages=Some(supportedLanguagesExample.value.replace("[","").replace("]","").split(",").toList), + services=Some(servicesExample.value.replace("[","").replace("]","").split(",").toList), + accessibilityFeatures=Some(accessibilityFeaturesExample.value.replace("[","").replace("]","").split(",").toList), + supportedCurrencies=Some(supportedCurrenciesExample.value.replace("[","").replace("]","").split(",").toList), + notes=Some(listExample.value.replace("[","").replace("]","").split(",").toList), + locationCategories=Some(listExample.value.replace("[","").replace("]","").split(",").toList), + minimumWithdrawal=Some("string"), + branchIdentification=Some("string"), + siteIdentification=Some(siteIdentification.value), + siteName=Some("string"), + cashWithdrawalNationalFee=Some(cashWithdrawalNationalFeeExample.value), + cashWithdrawalInternationalFee=Some(cashWithdrawalInternationalFeeExample.value), + balanceInquiryFee=Some(balanceInquiryFeeExample.value), + atmType=Some(atmTypeExample.value), + phone=Some(phoneExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAtms(bankId: BankId, callContext: Option[CallContext], queryParams: List[OBPQueryParam]): Future[Box[(List[AtmT], Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetAtms => InBound, OutBoundGetAtms => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams)) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_atms", req, callContext) + response.map(convertToTuple[List[AtmTCommons]](callContext)) + } + + messageDocs += createTransactionAfterChallengev300Doc + def createTransactionAfterChallengev300Doc = MessageDoc( + process = "obp.createTransactionAfterChallengev300", + messageFormat = messageFormat, + description = "Create Transaction After Challengev300", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTransactionAfterChallengev300(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + transReqId=TransactionRequestId(transactionRequestIdExample.value), + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value)) + ), + exampleInboundMessage = ( + InBoundCreateTransactionAfterChallengev300(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTransactionAfterChallengev300(initiator: User, fromAccount: BankAccount, transReqId: TransactionRequestId, transactionRequestType: TransactionRequestType, callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequest]] = { + import com.openbankproject.commons.dto.{InBoundCreateTransactionAfterChallengev300 => InBound, OutBoundCreateTransactionAfterChallengev300 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, fromAccount, transReqId, transactionRequestType) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_transaction_after_challengev300", req, callContext) + response.map(convertToTuple[TransactionRequest](callContext)) + } + + messageDocs += makePaymentv300Doc + def makePaymentv300Doc = MessageDoc( + process = "obp.makePaymentv300", + messageFormat = messageFormat, + description = "Make Paymentv300", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundMakePaymentv300(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toCounterparty= CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=counterpartyNameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=counterpartyOtherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=counterpartyOtherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=counterpartyOtherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=counterpartyOtherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=counterpartyOtherBankRoutingSchemeExample.value, + otherBankRoutingAddress=counterpartyOtherBankRoutingAddressExample.value, + otherBranchRoutingScheme=counterpartyOtherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=counterpartyOtherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value))), + transactionRequestCommonBody= TransactionRequestCommonBodyJSONCommons(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value), + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value), + chargePolicy=chargePolicyExample.value) + ), + exampleInboundMessage = ( + InBoundMakePaymentv300(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=TransactionId(transactionIdExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def makePaymentv300(initiator: User, fromAccount: BankAccount, toAccount: BankAccount, toCounterparty: CounterpartyTrait, transactionRequestCommonBody: TransactionRequestCommonBodyJSON, transactionRequestType: TransactionRequestType, chargePolicy: String, callContext: Option[CallContext]): Future[Box[(TransactionId, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundMakePaymentv300 => InBound, OutBoundMakePaymentv300 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, fromAccount, toAccount, toCounterparty, transactionRequestCommonBody, transactionRequestType, chargePolicy) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_make_paymentv300", req, callContext) + response.map(convertToTuple[TransactionId](callContext)) + } + + messageDocs += createTransactionRequestv300Doc + def createTransactionRequestv300Doc = MessageDoc( + process = "obp.createTransactionRequestv300", + messageFormat = messageFormat, + description = "Create Transaction Requestv300", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTransactionRequestv300(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + initiator= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + viewId=ViewId(viewIdExample.value), + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toCounterparty= CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=counterpartyNameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=counterpartyOtherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=counterpartyOtherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=counterpartyOtherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=counterpartyOtherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=counterpartyOtherBankRoutingSchemeExample.value, + otherBankRoutingAddress=counterpartyOtherBankRoutingAddressExample.value, + otherBranchRoutingScheme=counterpartyOtherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=counterpartyOtherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value))), + transactionRequestType=TransactionRequestType(transactionRequestTypeExample.value), + transactionRequestCommonBody= TransactionRequestCommonBodyJSONCommons(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value), + detailsPlain="string", + chargePolicy=chargePolicyExample.value) + ), + exampleInboundMessage = ( + InBoundCreateTransactionRequestv300(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTransactionRequestv300(initiator: User, viewId: ViewId, fromAccount: BankAccount, toAccount: BankAccount, toCounterparty: CounterpartyTrait, transactionRequestType: TransactionRequestType, transactionRequestCommonBody: TransactionRequestCommonBodyJSON, detailsPlain: String, chargePolicy: String, callContext: Option[CallContext]): Future[Box[(TransactionRequest, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundCreateTransactionRequestv300 => InBound, OutBoundCreateTransactionRequestv300 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, initiator, viewId, fromAccount, toAccount, toCounterparty, transactionRequestType, transactionRequestCommonBody, detailsPlain, chargePolicy) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_transaction_requestv300", req, callContext) + response.map(convertToTuple[TransactionRequest](callContext)) + } + + messageDocs += makePaymentV400Doc + def makePaymentV400Doc = MessageDoc( + process = "obp.makePaymentV400", + messageFormat = messageFormat, + description = "Make Payment V400", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundMakePaymentV400(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionRequest= TransactionRequest(id=TransactionRequestId(transactionRequestIdExample.value), + `type`=transactionRequestTypeExample.value, + from= TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value), + body= TransactionRequestBodyAllTypes(to_sandbox_tan=Some( TransactionRequestAccount(bank_id=bank_idExample.value, + account_id=account_idExample.value)), + to_sepa=Some(TransactionRequestIban(transactionRequestIban.value)), + to_counterparty=Some(TransactionRequestCounterpartyId(transactionRequestCounterpartyIdExample.value)), + to_simple=Some( TransactionRequestSimple(otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value)), + to_transfer_to_phone=Some( TransactionRequestTransferToPhone(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to=ToAccountTransferToPhone(toExample.value))), + to_transfer_to_atm=Some( TransactionRequestTransferToAtm(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + message=messageExample.value, + from= FromAccountTransfer(mobile_phone_number="string", + nickname=nicknameExample.value), + to= ToAccountTransferToAtm(legal_name="string", + date_of_birth="string", + mobile_phone_number="string", + kyc_document= ToAccountTransferToAtmKycDocument(`type`=typeExample.value, + number=numberExample.value)))), + to_transfer_to_account=Some( TransactionRequestTransferToAccount(value= AmountOfMoneyJsonV121(currency=currencyExample.value, + amount=amountExample.value), + description=descriptionExample.value, + transfer_type="string", + future_date="string", + to= ToAccountTransferToAccount(name=nameExample.value, + bank_code="string", + branch_number="string", + account= ToAccountTransferToAccountAccount(number=accountNumberExample.value, + iban=ibanExample.value)))), + to_sepa_credit_transfers=Some( SepaCreditTransfers(debtorAccount=PaymentAccount("string"), + instructedAmount= AmountOfMoneyJsonV121(currency=currencyExample.value, + 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), + transaction_ids="string", + status=statusExample.value, + start_date=toDate(transactionRequestStartDateExample), + end_date=toDate(transactionRequestEndDateExample), + challenge= TransactionRequestChallenge(id=challengeIdExample.value, + allowed_attempts=123, + challenge_type="string"), + charge= TransactionRequestCharge(summary=summaryExample.value, + value= AmountOfMoney(currency=currencyExample.value, + amount=amountExample.value)), + charge_policy="string", + counterparty_id=CounterpartyId(transactionRequestCounterpartyIdExample.value), + name=nameExample.value, + this_bank_id=BankId(bankIdExample.value), + this_account_id=AccountId(accountIdExample.value), + this_view_id=ViewId(viewIdExample.value), + other_account_routing_scheme="string", + other_account_routing_address="string", + other_bank_routing_scheme="string", + other_bank_routing_address="string", + is_beneficiary=true, + future_date=Some("string"), + payment_start_date=Some(toDate(dateExample)), + payment_end_date=Some(toDate(dateExample)), + payment_execution_Rule=Some("string"), + payment_frequency=Some("string"), + payment_day_of_execution=Some("string")), + reasons=Some(List( TransactionRequestReason(code=codeExample.value, + documentNumber=Some(documentNumberExample.value), + amount=Some(amountExample.value), + currency=Some(currencyExample.value), + description=Some(descriptionExample.value))))) + ), + exampleInboundMessage = ( + InBoundMakePaymentV400(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=TransactionId(transactionIdExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def makePaymentV400(transactionRequest: TransactionRequest, reasons: Option[List[TransactionRequestReason]], callContext: Option[CallContext]): Future[Box[(TransactionId, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundMakePaymentV400 => InBound, OutBoundMakePaymentV400 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionRequest, reasons) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_make_payment_v400", req, callContext) + response.map(convertToTuple[TransactionId](callContext)) + } + + messageDocs += cancelPaymentV400Doc + def cancelPaymentV400Doc = MessageDoc( + process = "obp.cancelPaymentV400", + messageFormat = messageFormat, + description = "Cancel Payment V400", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCancelPaymentV400(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionId=TransactionId(transactionIdExample.value)) + ), + exampleInboundMessage = ( + InBoundCancelPaymentV400(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CancelPayment(canBeCancelled=true, + startSca=Some(true))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def cancelPaymentV400(transactionId: TransactionId, callContext: Option[CallContext]): OBPReturnType[Box[CancelPayment]] = { + import com.openbankproject.commons.dto.{InBoundCancelPaymentV400 => InBound, OutBoundCancelPaymentV400 => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_cancel_payment_v400", req, callContext) + response.map(convertToTuple[CancelPayment](callContext)) + } + + messageDocs += getTransactionRequestTypeChargesDoc + def getTransactionRequestTypeChargesDoc = MessageDoc( + process = "obp.getTransactionRequestTypeCharges", + messageFormat = messageFormat, + description = "Get Transaction Request Type Charges", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionRequestTypeCharges(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + viewId=ViewId(viewIdExample.value), + transactionRequestTypes=List(TransactionRequestType(transactionRequestTypesExample.value))) + ), + exampleInboundMessage = ( + InBoundGetTransactionRequestTypeCharges(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( TransactionRequestTypeChargeCommons(transactionRequestTypeId="string", + bankId=bankIdExample.value, + chargeCurrency="string", + chargeAmount="string", + chargeSummary="string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionRequestTypeCharges(bankId: BankId, accountId: AccountId, viewId: ViewId, transactionRequestTypes: List[TransactionRequestType], callContext: Option[CallContext]): OBPReturnType[Box[List[TransactionRequestTypeCharge]]] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionRequestTypeCharges => InBound, OutBoundGetTransactionRequestTypeCharges => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, viewId, transactionRequestTypes) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction_request_type_charges", req, callContext) + response.map(convertToTuple[List[TransactionRequestTypeChargeCommons]](callContext)) + } + + messageDocs += createCounterpartyDoc + def createCounterpartyDoc = MessageDoc( + process = "obp.createCounterparty", + messageFormat = messageFormat, + description = "Create Counterparty", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateCounterparty(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + name=nameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + createdByUserId=createdByUserIdExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value))) + ), + exampleInboundMessage = ( + InBoundCreateCounterparty(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CounterpartyTraitCommons(createdByUserId=createdByUserIdExample.value, + name=nameExample.value, + description=descriptionExample.value, + currency=currencyExample.value, + thisBankId=thisBankIdExample.value, + thisAccountId=thisAccountIdExample.value, + thisViewId=thisViewIdExample.value, + counterpartyId=counterpartyIdExample.value, + otherAccountRoutingScheme=otherAccountRoutingSchemeExample.value, + otherAccountRoutingAddress=otherAccountRoutingAddressExample.value, + otherAccountSecondaryRoutingScheme=otherAccountSecondaryRoutingSchemeExample.value, + otherAccountSecondaryRoutingAddress=otherAccountSecondaryRoutingAddressExample.value, + otherBankRoutingScheme=otherBankRoutingSchemeExample.value, + otherBankRoutingAddress=otherBankRoutingAddressExample.value, + otherBranchRoutingScheme=otherBranchRoutingSchemeExample.value, + otherBranchRoutingAddress=otherBranchRoutingAddressExample.value, + isBeneficiary=isBeneficiaryExample.value.toBoolean, + bespoke=List( CounterpartyBespoke(key=keyExample.value, + value=valueExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createCounterparty(name: String, description: String, currency: String, createdByUserId: String, thisBankId: String, thisAccountId: String, thisViewId: String, otherAccountRoutingScheme: String, otherAccountRoutingAddress: String, otherAccountSecondaryRoutingScheme: String, otherAccountSecondaryRoutingAddress: String, otherBankRoutingScheme: String, otherBankRoutingAddress: String, otherBranchRoutingScheme: String, otherBranchRoutingAddress: String, isBeneficiary: Boolean, bespoke: List[CounterpartyBespoke], callContext: Option[CallContext]): Box[(CounterpartyTrait, Option[CallContext])] = { + import com.openbankproject.commons.dto.{InBoundCreateCounterparty => InBound, OutBoundCreateCounterparty => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, name, description, currency, createdByUserId, thisBankId, thisAccountId, thisViewId, otherAccountRoutingScheme, otherAccountRoutingAddress, otherAccountSecondaryRoutingScheme, otherAccountSecondaryRoutingAddress, otherBankRoutingScheme, otherBankRoutingAddress, otherBranchRoutingScheme, otherBranchRoutingAddress, isBeneficiary, bespoke) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_counterparty", req, callContext) + response.map(convertToTuple[CounterpartyTraitCommons](callContext)) + } + + messageDocs += checkCustomerNumberAvailableDoc + def checkCustomerNumberAvailableDoc = MessageDoc( + process = "obp.checkCustomerNumberAvailable", + messageFormat = messageFormat, + description = "Check Customer Number Available", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCheckCustomerNumberAvailable(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + customerNumber=customerNumberExample.value) + ), + exampleInboundMessage = ( + InBoundCheckCustomerNumberAvailable(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def checkCustomerNumberAvailable(bankId: BankId, customerNumber: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundCheckCustomerNumberAvailable => InBound, OutBoundCheckCustomerNumberAvailable => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, customerNumber) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_check_customer_number_available", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += createCustomerDoc + def createCustomerDoc = MessageDoc( + process = "obp.createCustomer", + messageFormat = messageFormat, + description = "Create Customer", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateCustomer(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(outBoundCreateCustomerLastOkDateExample), + creditRating=Some( CreditRating(rating=ratingExample.value, + source=sourceExample.value)), + creditLimit=Some( AmountOfMoney(currency=currencyExample.value, + amount=creditLimitAmountExample.value)), + title=titleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value) + ), + exampleInboundMessage = ( + InBoundCreateCustomer(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some(""))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createCustomer(bankId: BankId, legalName: String, mobileNumber: String, email: String, faceImage: CustomerFaceImageTrait, dateOfBirth: Date, relationshipStatus: String, dependents: Int, dobOfDependents: List[Date], highestEducationAttained: String, employmentStatus: String, kycStatus: Boolean, lastOkDate: Date, creditRating: Option[CreditRatingTrait], creditLimit: Option[AmountOfMoneyTrait], title: String, branchId: String, nameSuffix: String, callContext: Option[CallContext]): OBPReturnType[Box[Customer]] = { + import com.openbankproject.commons.dto.{InBoundCreateCustomer => InBound, OutBoundCreateCustomer => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, legalName, mobileNumber, email, faceImage, dateOfBirth, relationshipStatus, dependents, dobOfDependents, highestEducationAttained, employmentStatus, kycStatus, lastOkDate, creditRating, creditLimit, title, branchId, nameSuffix) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_customer", req, callContext) + response.map(convertToTuple[CustomerCommons](callContext)) + } + + messageDocs += updateCustomerScaDataDoc + def updateCustomerScaDataDoc = MessageDoc( + process = "obp.updateCustomerScaData", + messageFormat = messageFormat, + description = "Update Customer Sca Data", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdateCustomerScaData(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value, + mobileNumber=Some(mobileNumberExample.value), + email=Some(emailExample.value), + customerNumber=Some(customerNumberExample.value)) + ), + exampleInboundMessage = ( + InBoundUpdateCustomerScaData(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some(""))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updateCustomerScaData(customerId: String, mobileNumber: Option[String], email: Option[String], customerNumber: Option[String], callContext: Option[CallContext]): OBPReturnType[Box[Customer]] = { + import com.openbankproject.commons.dto.{InBoundUpdateCustomerScaData => InBound, OutBoundUpdateCustomerScaData => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId, mobileNumber, email, customerNumber) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_customer_sca_data", req, callContext) + response.map(convertToTuple[CustomerCommons](callContext)) + } + + messageDocs += updateCustomerCreditDataDoc + def updateCustomerCreditDataDoc = MessageDoc( + process = "obp.updateCustomerCreditData", + messageFormat = messageFormat, + description = "Update Customer Credit Data", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdateCustomerCreditData(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value, + creditRating=Some(creditRatingExample.value), + creditSource=Some("string"), + creditLimit=Some( AmountOfMoney(currency=currencyExample.value, + amount=creditLimitAmountExample.value))) + ), + exampleInboundMessage = ( + InBoundUpdateCustomerCreditData(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some(""))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updateCustomerCreditData(customerId: String, creditRating: Option[String], creditSource: Option[String], creditLimit: Option[AmountOfMoney], callContext: Option[CallContext]): OBPReturnType[Box[Customer]] = { + import com.openbankproject.commons.dto.{InBoundUpdateCustomerCreditData => InBound, OutBoundUpdateCustomerCreditData => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId, creditRating, creditSource, creditLimit) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_customer_credit_data", req, callContext) + response.map(convertToTuple[CustomerCommons](callContext)) + } + + messageDocs += updateCustomerGeneralDataDoc + def updateCustomerGeneralDataDoc = MessageDoc( + process = "obp.updateCustomerGeneralData", + messageFormat = messageFormat, + description = "Update Customer General Data", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdateCustomerGeneralData(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value, + legalName=Some(legalNameExample.value), + faceImage=Some( CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value)), + dateOfBirth=Some(toDate(dateOfBirthExample)), + relationshipStatus=Some(relationshipStatusExample.value), + dependents=Some(dependentsExample.value.toInt), + highestEducationAttained=Some(highestEducationAttainedExample.value), + employmentStatus=Some(employmentStatusExample.value), + title=Some(titleExample.value), + branchId=Some(branchIdExample.value), + nameSuffix=Some(nameSuffixExample.value), + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value)) + ), + exampleInboundMessage = ( + InBoundUpdateCustomerGeneralData(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some(""))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updateCustomerGeneralData(customerId: String, legalName: Option[String], faceImage: Option[CustomerFaceImageTrait], dateOfBirth: Option[Date], relationshipStatus: Option[String], dependents: Option[Int], highestEducationAttained: Option[String], employmentStatus: Option[String], title: Option[String], branchId: Option[String], nameSuffix: Option[String], customerType: Option[String] = None, parentCustomerId: Option[String] = None, callContext: Option[CallContext]): OBPReturnType[Box[Customer]] = { + import com.openbankproject.commons.dto.{InBoundUpdateCustomerGeneralData => InBound, OutBoundUpdateCustomerGeneralData => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId, legalName, faceImage, dateOfBirth, relationshipStatus, dependents, highestEducationAttained, employmentStatus, title, branchId, nameSuffix, customerType, parentCustomerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_customer_general_data", req, callContext) + response.map(convertToTuple[CustomerCommons](callContext)) + } + + messageDocs += getCustomersByUserIdDoc + def getCustomersByUserIdDoc = MessageDoc( + process = "obp.getCustomersByUserId", + messageFormat = messageFormat, + description = "Get Customers By User Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomersByUserId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userId=userIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetCustomersByUserId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some("")))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomersByUserId(userId: String, callContext: Option[CallContext]): Future[Box[(List[Customer], Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomersByUserId => InBound, OutBoundGetCustomersByUserId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customers_by_user_id", req, callContext) + response.map(convertToTuple[List[CustomerCommons]](callContext)) + } + + messageDocs += getCustomerByCustomerIdDoc + def getCustomerByCustomerIdDoc = MessageDoc( + process = "obp.getCustomerByCustomerId", + messageFormat = messageFormat, + description = "Get Customer By Customer Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomerByCustomerId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetCustomerByCustomerId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some(""))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomerByCustomerId(customerId: String, callContext: Option[CallContext]): Future[Box[(Customer, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomerByCustomerId => InBound, OutBoundGetCustomerByCustomerId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customer_by_customer_id", req, callContext) + response.map(convertToTuple[CustomerCommons](callContext)) + } + + messageDocs += getCustomerByCustomerNumberDoc + def getCustomerByCustomerNumberDoc = MessageDoc( + process = "obp.getCustomerByCustomerNumber", + messageFormat = messageFormat, + description = "Get Customer By Customer Number", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomerByCustomerNumber(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerNumber=customerNumberExample.value, + bankId=BankId(bankIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetCustomerByCustomerNumber(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some(""))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomerByCustomerNumber(customerNumber: String, bankId: BankId, callContext: Option[CallContext]): Future[Box[(Customer, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomerByCustomerNumber => InBound, OutBoundGetCustomerByCustomerNumber => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerNumber, bankId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customer_by_customer_number", req, callContext) + response.map(convertToTuple[CustomerCommons](callContext)) + } + + messageDocs += getCustomerAddressDoc + def getCustomerAddressDoc = MessageDoc( + process = "obp.getCustomerAddress", + messageFormat = messageFormat, + description = "Get Customer Address", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomerAddress(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetCustomerAddress(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CustomerAddressCommons(customerId=customerIdExample.value, + customerAddressId=customerAddressIdExample.value, + line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=countyExample.value, + state=stateExample.value, + postcode=postcodeExample.value, + countryCode=countryCodeExample.value, + status=statusExample.value, + tags=tagsExample.value, + insertDate=toDate(insertDateExample)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomerAddress(customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[CustomerAddress]]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomerAddress => InBound, OutBoundGetCustomerAddress => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customer_address", req, callContext) + response.map(convertToTuple[List[CustomerAddressCommons]](callContext)) + } + + messageDocs += createCustomerAddressDoc + def createCustomerAddressDoc = MessageDoc( + process = "obp.createCustomerAddress", + messageFormat = messageFormat, + description = "Create Customer Address", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateCustomerAddress(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value, + line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=countyExample.value, + state=stateExample.value, + postcode=postcodeExample.value, + countryCode=countryCodeExample.value, + tags=tagsExample.value, + status=statusExample.value) + ), + exampleInboundMessage = ( + InBoundCreateCustomerAddress(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerAddressCommons(customerId=customerIdExample.value, + customerAddressId=customerAddressIdExample.value, + line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=countyExample.value, + state=stateExample.value, + postcode=postcodeExample.value, + countryCode=countryCodeExample.value, + status=statusExample.value, + tags=tagsExample.value, + insertDate=toDate(insertDateExample))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createCustomerAddress(customerId: String, line1: String, line2: String, line3: String, city: String, county: String, state: String, postcode: String, countryCode: String, tags: String, status: String, callContext: Option[CallContext]): OBPReturnType[Box[CustomerAddress]] = { + import com.openbankproject.commons.dto.{InBoundCreateCustomerAddress => InBound, OutBoundCreateCustomerAddress => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId, line1, line2, line3, city, county, state, postcode, countryCode, tags, status) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_customer_address", req, callContext) + response.map(convertToTuple[CustomerAddressCommons](callContext)) + } + + messageDocs += updateCustomerAddressDoc + def updateCustomerAddressDoc = MessageDoc( + process = "obp.updateCustomerAddress", + messageFormat = messageFormat, + description = "Update Customer Address", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdateCustomerAddress(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerAddressId=customerAddressIdExample.value, + line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=countyExample.value, + state=stateExample.value, + postcode=postcodeExample.value, + countryCode=countryCodeExample.value, + tags=tagsExample.value, + status=statusExample.value) + ), + exampleInboundMessage = ( + InBoundUpdateCustomerAddress(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerAddressCommons(customerId=customerIdExample.value, + customerAddressId=customerAddressIdExample.value, + line1=line1Example.value, + line2=line2Example.value, + line3=line3Example.value, + city=cityExample.value, + county=countyExample.value, + state=stateExample.value, + postcode=postcodeExample.value, + countryCode=countryCodeExample.value, + status=statusExample.value, + tags=tagsExample.value, + insertDate=toDate(insertDateExample))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updateCustomerAddress(customerAddressId: String, line1: String, line2: String, line3: String, city: String, county: String, state: String, postcode: String, countryCode: String, tags: String, status: String, callContext: Option[CallContext]): OBPReturnType[Box[CustomerAddress]] = { + import com.openbankproject.commons.dto.{InBoundUpdateCustomerAddress => InBound, OutBoundUpdateCustomerAddress => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerAddressId, line1, line2, line3, city, county, state, postcode, countryCode, tags, status) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_customer_address", req, callContext) + response.map(convertToTuple[CustomerAddressCommons](callContext)) + } + + messageDocs += deleteCustomerAddressDoc + def deleteCustomerAddressDoc = MessageDoc( + process = "obp.deleteCustomerAddress", + messageFormat = messageFormat, + description = "Delete Customer Address", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeleteCustomerAddress(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerAddressId=customerAddressIdExample.value) + ), + exampleInboundMessage = ( + InBoundDeleteCustomerAddress(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deleteCustomerAddress(customerAddressId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeleteCustomerAddress => InBound, OutBoundDeleteCustomerAddress => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerAddressId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_customer_address", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += createTaxResidenceDoc + def createTaxResidenceDoc = MessageDoc( + process = "obp.createTaxResidence", + messageFormat = messageFormat, + description = "Create Tax Residence", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateTaxResidence(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value, + domain=domainExample.value, + taxNumber=taxNumberExample.value) + ), + exampleInboundMessage = ( + InBoundCreateTaxResidence(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TaxResidenceCommons(customerId=customerIdExample.value, + taxResidenceId=taxResidenceIdExample.value, + domain=domainExample.value, + taxNumber=taxNumberExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createTaxResidence(customerId: String, domain: String, taxNumber: String, callContext: Option[CallContext]): OBPReturnType[Box[TaxResidence]] = { + import com.openbankproject.commons.dto.{InBoundCreateTaxResidence => InBound, OutBoundCreateTaxResidence => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId, domain, taxNumber) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_tax_residence", req, callContext) + response.map(convertToTuple[TaxResidenceCommons](callContext)) + } + + messageDocs += getTaxResidenceDoc + def getTaxResidenceDoc = MessageDoc( + process = "obp.getTaxResidence", + messageFormat = messageFormat, + description = "Get Tax Residence", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTaxResidence(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetTaxResidence(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( TaxResidenceCommons(customerId=customerIdExample.value, + taxResidenceId=taxResidenceIdExample.value, + domain=domainExample.value, + taxNumber=taxNumberExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTaxResidence(customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[TaxResidence]]] = { + import com.openbankproject.commons.dto.{InBoundGetTaxResidence => InBound, OutBoundGetTaxResidence => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_tax_residence", req, callContext) + response.map(convertToTuple[List[TaxResidenceCommons]](callContext)) + } + + messageDocs += deleteTaxResidenceDoc + def deleteTaxResidenceDoc = MessageDoc( + process = "obp.deleteTaxResidence", + messageFormat = messageFormat, + description = "Delete Tax Residence", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeleteTaxResidence(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + taxResourceId="string") + ), + exampleInboundMessage = ( + InBoundDeleteTaxResidence(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deleteTaxResidence(taxResourceId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeleteTaxResidence => InBound, OutBoundDeleteTaxResidence => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, taxResourceId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_tax_residence", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += getCustomersDoc + def getCustomersDoc = MessageDoc( + process = "obp.getCustomers", + messageFormat = messageFormat, + description = "Get Customers", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomers(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + limit=limitExample.value.toInt, + offset=offsetExample.value.toInt, + fromDate=fromDateExample.value, + toDate=toDateExample.value) + ), + exampleInboundMessage = ( + InBoundGetCustomers(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some("")))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomers(bankId: BankId, callContext: Option[CallContext], queryParams: List[OBPQueryParam]): Future[Box[List[Customer]]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomers => InBound, OutBoundGetCustomers => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams)) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customers", req, callContext) + response.map(convertToTuple[List[CustomerCommons]](callContext)) + } + + messageDocs += getCustomersByCustomerPhoneNumberDoc + def getCustomersByCustomerPhoneNumberDoc = MessageDoc( + process = "obp.getCustomersByCustomerPhoneNumber", + messageFormat = messageFormat, + description = "Get Customers By Customer Phone Number", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomersByCustomerPhoneNumber(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + phoneNumber=phoneNumberExample.value) + ), + exampleInboundMessage = ( + InBoundGetCustomersByCustomerPhoneNumber(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some("")))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomersByCustomerPhoneNumber(bankId: BankId, phoneNumber: String, callContext: Option[CallContext]): OBPReturnType[Box[List[Customer]]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomersByCustomerPhoneNumber => InBound, OutBoundGetCustomersByCustomerPhoneNumber => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, phoneNumber) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customers_by_customer_phone_number", req, callContext) + response.map(convertToTuple[List[CustomerCommons]](callContext)) + } + + messageDocs += getCheckbookOrdersDoc + def getCheckbookOrdersDoc = MessageDoc( + process = "obp.getCheckbookOrders", + messageFormat = messageFormat, + description = "Get Checkbook Orders", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCheckbookOrders(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + accountId=accountIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetCheckbookOrders(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CheckbookOrdersJson(account= AccountV310Json(bank_id=bank_idExample.value, + account_id=account_idExample.value, + account_type="string", + account_routings=List( AccountRoutingJsonV121(scheme=schemeExample.value, + address=addressExample.value)), + branch_routings=List( BranchRoutingJsonV141(scheme=schemeExample.value, + address=addressExample.value))), + orders=List(OrderJson( OrderObjectJson(order_id="string", + order_date="string", + number_of_checkbooks="string", + distribution_channel="string", + status=statusExample.value, + first_check_number="string", + shipping_code="string"))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCheckbookOrders(bankId: String, accountId: String, callContext: Option[CallContext]): Future[Box[(CheckbookOrdersJson, Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetCheckbookOrders => InBound, OutBoundGetCheckbookOrders => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_checkbook_orders", req, callContext) + response.map(convertToTuple[CheckbookOrdersJson](callContext)) + } + + messageDocs += getStatusOfCreditCardOrderDoc + def getStatusOfCreditCardOrderDoc = MessageDoc( + process = "obp.getStatusOfCreditCardOrder", + messageFormat = messageFormat, + description = "Get Status Of Credit Card Order", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetStatusOfCreditCardOrder(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + accountId=accountIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetStatusOfCreditCardOrder(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CardObjectJson(card_type="string", + card_description="string", + use_type="string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getStatusOfCreditCardOrder(bankId: String, accountId: String, callContext: Option[CallContext]): Future[Box[(List[CardObjectJson], Option[CallContext])]] = { + import com.openbankproject.commons.dto.{InBoundGetStatusOfCreditCardOrder => InBound, OutBoundGetStatusOfCreditCardOrder => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_status_of_credit_card_order", req, callContext) + response.map(convertToTuple[List[CardObjectJson]](callContext)) + } + + messageDocs += createUserAuthContextDoc + def createUserAuthContextDoc = MessageDoc( + process = "obp.createUserAuthContext", + messageFormat = messageFormat, + description = "Create User Auth Context", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateUserAuthContext(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userId=userIdExample.value, + key=keyExample.value, + value=valueExample.value) + ), + exampleInboundMessage = ( + InBoundCreateUserAuthContext(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= UserAuthContextCommons(userAuthContextId=userAuthContextIdExample.value, + userId=userIdExample.value, + key=keyExample.value, + value=valueExample.value, + timeStamp=toDate(timeStampExample), + consumerId=consumerIdExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createUserAuthContext(userId: String, key: String, value: String, callContext: Option[CallContext]): OBPReturnType[Box[UserAuthContext]] = { + import com.openbankproject.commons.dto.{InBoundCreateUserAuthContext => InBound, OutBoundCreateUserAuthContext => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userId, key, value) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_user_auth_context", req, callContext) + response.map(convertToTuple[UserAuthContextCommons](callContext)) + } + + messageDocs += createUserAuthContextUpdateDoc + def createUserAuthContextUpdateDoc = MessageDoc( + process = "obp.createUserAuthContextUpdate", + messageFormat = messageFormat, + description = "Create User Auth Context Update", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateUserAuthContextUpdate(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userId=userIdExample.value, + key=keyExample.value, + value=valueExample.value) + ), + exampleInboundMessage = ( + InBoundCreateUserAuthContextUpdate(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= UserAuthContextUpdateCommons(userAuthContextUpdateId=userAuthContextUpdateIdExample.value, + userId=userIdExample.value, + key=keyExample.value, + value=valueExample.value, + challenge=challengeExample.value, + status=statusExample.value, + consumerId=consumerIdExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createUserAuthContextUpdate(userId: String, key: String, value: String, callContext: Option[CallContext]): OBPReturnType[Box[UserAuthContextUpdate]] = { + import com.openbankproject.commons.dto.{InBoundCreateUserAuthContextUpdate => InBound, OutBoundCreateUserAuthContextUpdate => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userId, key, value) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_user_auth_context_update", req, callContext) + response.map(convertToTuple[UserAuthContextUpdateCommons](callContext)) + } + + messageDocs += deleteUserAuthContextsDoc + def deleteUserAuthContextsDoc = MessageDoc( + process = "obp.deleteUserAuthContexts", + messageFormat = messageFormat, + description = "Delete User Auth Contexts", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeleteUserAuthContexts(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userId=userIdExample.value) + ), + exampleInboundMessage = ( + InBoundDeleteUserAuthContexts(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deleteUserAuthContexts(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeleteUserAuthContexts => InBound, OutBoundDeleteUserAuthContexts => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_user_auth_contexts", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += deleteUserAuthContextByIdDoc + def deleteUserAuthContextByIdDoc = MessageDoc( + process = "obp.deleteUserAuthContextById", + messageFormat = messageFormat, + description = "Delete User Auth Context By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeleteUserAuthContextById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userAuthContextId=userAuthContextIdExample.value) + ), + exampleInboundMessage = ( + InBoundDeleteUserAuthContextById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deleteUserAuthContextById(userAuthContextId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeleteUserAuthContextById => InBound, OutBoundDeleteUserAuthContextById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userAuthContextId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_user_auth_context_by_id", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += getUserAuthContextsDoc + def getUserAuthContextsDoc = MessageDoc( + process = "obp.getUserAuthContexts", + messageFormat = messageFormat, + description = "Get User Auth Contexts", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetUserAuthContexts(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + userId=userIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetUserAuthContexts(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( UserAuthContextCommons(userAuthContextId=userAuthContextIdExample.value, + userId=userIdExample.value, + key=keyExample.value, + value=valueExample.value, + timeStamp=toDate(timeStampExample), + consumerId=consumerIdExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getUserAuthContexts(userId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[UserAuthContext]]] = { + import com.openbankproject.commons.dto.{InBoundGetUserAuthContexts => InBound, OutBoundGetUserAuthContexts => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, userId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_user_auth_contexts", req, callContext) + response.map(convertToTuple[List[UserAuthContextCommons]](callContext)) + } + + messageDocs += createOrUpdateProductAttributeDoc + def createOrUpdateProductAttributeDoc = MessageDoc( + process = "obp.createOrUpdateProductAttribute", + messageFormat = messageFormat, + description = "Create Or Update Product Attribute", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateProductAttribute(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + productCode=ProductCode(productCodeExample.value), + productAttributeId=Some(productAttributeIdExample.value), + name=nameExample.value, + productAttributeType=com.openbankproject.commons.model.enums.ProductAttributeType.example, + value=valueExample.value, + isActive=Some(isActiveExample.value.toBoolean)) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateProductAttribute(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ProductAttributeCommons(bankId=BankId(bankIdExample.value), + productCode=ProductCode(productCodeExample.value), + productAttributeId=productAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.ProductAttributeType.example, + value=valueExample.value, + isActive=Some(isActiveExample.value.toBoolean))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateProductAttribute(bankId: BankId, productCode: ProductCode, productAttributeId: Option[String], name: String, productAttributeType: ProductAttributeType.Value, value: String, isActive: Option[Boolean], callContext: Option[CallContext]): OBPReturnType[Box[ProductAttribute]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateProductAttribute => InBound, OutBoundCreateOrUpdateProductAttribute => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, productCode, productAttributeId, name, productAttributeType, value, isActive) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_product_attribute", req, callContext) + 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( BankAttributeTraitCommons(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[BankAttributeTraitCommons]](callContext)) + } + + messageDocs += getProductAttributeByIdDoc + def getProductAttributeByIdDoc = MessageDoc( + process = "obp.getProductAttributeById", + messageFormat = messageFormat, + description = "Get Product Attribute By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetProductAttributeById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + productAttributeId=productAttributeIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetProductAttributeById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= ProductAttributeCommons(bankId=BankId(bankIdExample.value), + productCode=ProductCode(productCodeExample.value), + productAttributeId=productAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.ProductAttributeType.example, + value=valueExample.value, + isActive=Some(isActiveExample.value.toBoolean))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getProductAttributeById(productAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[ProductAttribute]] = { + import com.openbankproject.commons.dto.{InBoundGetProductAttributeById => InBound, OutBoundGetProductAttributeById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, productAttributeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_product_attribute_by_id", req, callContext) + response.map(convertToTuple[ProductAttributeCommons](callContext)) + } + + messageDocs += getProductAttributesByBankAndCodeDoc + def getProductAttributesByBankAndCodeDoc = MessageDoc( + process = "obp.getProductAttributesByBankAndCode", + messageFormat = messageFormat, + description = "Get Product Attributes By Bank And Code", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetProductAttributesByBankAndCode(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bank=BankId(bankExample.value), + productCode=ProductCode(productCodeExample.value)) + ), + exampleInboundMessage = ( + InBoundGetProductAttributesByBankAndCode(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ProductAttributeCommons(bankId=BankId(bankIdExample.value), + productCode=ProductCode(productCodeExample.value), + productAttributeId=productAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.ProductAttributeType.example, + value=valueExample.value, + isActive=Some(isActiveExample.value.toBoolean)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getProductAttributesByBankAndCode(bank: BankId, productCode: ProductCode, callContext: Option[CallContext]): OBPReturnType[Box[List[ProductAttribute]]] = { + import com.openbankproject.commons.dto.{InBoundGetProductAttributesByBankAndCode => InBound, OutBoundGetProductAttributesByBankAndCode => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bank, productCode) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_product_attributes_by_bank_and_code", req, callContext) + response.map(convertToTuple[List[ProductAttributeCommons]](callContext)) + } + + messageDocs += deleteProductAttributeDoc + def deleteProductAttributeDoc = MessageDoc( + process = "obp.deleteProductAttribute", + messageFormat = messageFormat, + description = "Delete Product Attribute", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeleteProductAttribute(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + productAttributeId=productAttributeIdExample.value) + ), + exampleInboundMessage = ( + InBoundDeleteProductAttribute(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deleteProductAttribute(productAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeleteProductAttribute => InBound, OutBoundDeleteProductAttribute => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, productAttributeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_product_attribute", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += getAccountAttributeByIdDoc + def getAccountAttributeByIdDoc = MessageDoc( + process = "obp.getAccountAttributeById", + messageFormat = messageFormat, + description = "Get Account Attribute By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAccountAttributeById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + accountAttributeId=accountAttributeIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetAccountAttributeById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AccountAttributeCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + productCode=ProductCode(productCodeExample.value), + accountAttributeId=accountAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.AccountAttributeType.example, + value=valueExample.value, + productInstanceCode=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAccountAttributeById(accountAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[AccountAttribute]] = { + import com.openbankproject.commons.dto.{InBoundGetAccountAttributeById => InBound, OutBoundGetAccountAttributeById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, accountAttributeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_account_attribute_by_id", req, callContext) + response.map(convertToTuple[AccountAttributeCommons](callContext)) + } + + messageDocs += getTransactionAttributeByIdDoc + def getTransactionAttributeByIdDoc = MessageDoc( + process = "obp.getTransactionAttributeById", + messageFormat = messageFormat, + description = "Get Transaction Attribute By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionAttributeById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + transactionAttributeId=transactionAttributeIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetTransactionAttributeById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionAttributeCommons(bankId=BankId(bankIdExample.value), + transactionId=TransactionId(transactionIdExample.value), + transactionAttributeId=transactionAttributeIdExample.value, + attributeType=com.openbankproject.commons.model.enums.TransactionAttributeType.example, + name=transactionAttributeNameExample.value, + value=transactionAttributeValueExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionAttributeById(transactionAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[TransactionAttribute]] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionAttributeById => InBound, OutBoundGetTransactionAttributeById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, transactionAttributeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction_attribute_by_id", req, callContext) + response.map(convertToTuple[TransactionAttributeCommons](callContext)) + } + + messageDocs += createOrUpdateAccountAttributeDoc + def createOrUpdateAccountAttributeDoc = MessageDoc( + process = "obp.createOrUpdateAccountAttribute", + messageFormat = messageFormat, + description = "Create Or Update Account Attribute", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateAccountAttribute(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + productCode=ProductCode(productCodeExample.value), + productAttributeId=Some(productAttributeIdExample.value), + name=nameExample.value, + accountAttributeType=com.openbankproject.commons.model.enums.AccountAttributeType.example, + value=valueExample.value, + productInstanceCode=Some("string")) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateAccountAttribute(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AccountAttributeCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + productCode=ProductCode(productCodeExample.value), + accountAttributeId=accountAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.AccountAttributeType.example, + value=valueExample.value, + productInstanceCode=Some("string"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateAccountAttribute(bankId: BankId, accountId: AccountId, productCode: ProductCode, productAttributeId: Option[String], name: String, accountAttributeType: AccountAttributeType.Value, value: String, productInstanceCode: Option[String], callContext: Option[CallContext]): OBPReturnType[Box[AccountAttribute]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateAccountAttribute => InBound, OutBoundCreateOrUpdateAccountAttribute => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, productCode, productAttributeId, name, accountAttributeType, value, productInstanceCode) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_account_attribute", req, callContext) + response.map(convertToTuple[AccountAttributeCommons](callContext)) + } + + messageDocs += createOrUpdateCustomerAttributeDoc + def createOrUpdateCustomerAttributeDoc = MessageDoc( + process = "obp.createOrUpdateCustomerAttribute", + messageFormat = messageFormat, + description = "Create Or Update Customer Attribute", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateCustomerAttribute(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + customerId=CustomerId(customerIdExample.value), + customerAttributeId=Some(customerAttributeIdExample.value), + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.CustomerAttributeType.example, + value=valueExample.value) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateCustomerAttribute(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerAttributeCommons(bankId=BankId(bankIdExample.value), + customerId=CustomerId(customerIdExample.value), + customerAttributeId=customerAttributeIdExample.value, + attributeType=com.openbankproject.commons.model.enums.CustomerAttributeType.example, + name=customerAttributeNameExample.value, + value=customerAttributeValueExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateCustomerAttribute(bankId: BankId, customerId: CustomerId, customerAttributeId: Option[String], name: String, attributeType: CustomerAttributeType.Value, value: String, callContext: Option[CallContext]): OBPReturnType[Box[CustomerAttribute]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateCustomerAttribute => InBound, OutBoundCreateOrUpdateCustomerAttribute => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, customerId, customerAttributeId, name, attributeType, value) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_customer_attribute", req, callContext) + response.map(convertToTuple[CustomerAttributeCommons](callContext)) + } + + messageDocs += createOrUpdateTransactionAttributeDoc + def createOrUpdateTransactionAttributeDoc = MessageDoc( + process = "obp.createOrUpdateTransactionAttribute", + messageFormat = messageFormat, + description = "Create Or Update Transaction Attribute", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateTransactionAttribute(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + transactionId=TransactionId(transactionIdExample.value), + transactionAttributeId=Some(transactionAttributeIdExample.value), + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.TransactionAttributeType.example, + value=valueExample.value) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateTransactionAttribute(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= TransactionAttributeCommons(bankId=BankId(bankIdExample.value), + transactionId=TransactionId(transactionIdExample.value), + transactionAttributeId=transactionAttributeIdExample.value, + attributeType=com.openbankproject.commons.model.enums.TransactionAttributeType.example, + name=transactionAttributeNameExample.value, + value=transactionAttributeValueExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateTransactionAttribute(bankId: BankId, transactionId: TransactionId, transactionAttributeId: Option[String], name: String, attributeType: TransactionAttributeType.Value, value: String, callContext: Option[CallContext]): OBPReturnType[Box[TransactionAttribute]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateTransactionAttribute => InBound, OutBoundCreateOrUpdateTransactionAttribute => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, transactionId, transactionAttributeId, name, attributeType, value) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_transaction_attribute", req, callContext) + response.map(convertToTuple[TransactionAttributeCommons](callContext)) + } + + messageDocs += createAccountAttributesDoc + def createAccountAttributesDoc = MessageDoc( + process = "obp.createAccountAttributes", + messageFormat = messageFormat, + description = "Create Account Attributes", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateAccountAttributes(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + productCode=ProductCode(productCodeExample.value), + accountAttributes=List( ProductAttributeCommons(bankId=BankId(bankIdExample.value), + productCode=ProductCode(productCodeExample.value), + productAttributeId=productAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.ProductAttributeType.example, + value=valueExample.value, + isActive=Some(isActiveExample.value.toBoolean))), + productInstanceCode=Some("string")) + ), + exampleInboundMessage = ( + InBoundCreateAccountAttributes(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( AccountAttributeCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + productCode=ProductCode(productCodeExample.value), + accountAttributeId=accountAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.AccountAttributeType.example, + value=valueExample.value, + productInstanceCode=Some("string")))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createAccountAttributes(bankId: BankId, accountId: AccountId, productCode: ProductCode, accountAttributes: List[ProductAttribute], productInstanceCode: Option[String], callContext: Option[CallContext]): OBPReturnType[Box[List[AccountAttribute]]] = { + import com.openbankproject.commons.dto.{InBoundCreateAccountAttributes => InBound, OutBoundCreateAccountAttributes => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, productCode, accountAttributes, productInstanceCode) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_account_attributes", req, callContext) + response.map(convertToTuple[List[AccountAttributeCommons]](callContext)) + } + + messageDocs += getAccountAttributesByAccountDoc + def getAccountAttributesByAccountDoc = MessageDoc( + process = "obp.getAccountAttributesByAccount", + messageFormat = messageFormat, + description = "Get Account Attributes By Account", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAccountAttributesByAccount(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetAccountAttributesByAccount(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( AccountAttributeCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + productCode=ProductCode(productCodeExample.value), + accountAttributeId=accountAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.AccountAttributeType.example, + value=valueExample.value, + productInstanceCode=Some("string")))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAccountAttributesByAccount(bankId: BankId, accountId: AccountId, callContext: Option[CallContext]): OBPReturnType[Box[List[AccountAttribute]]] = { + import com.openbankproject.commons.dto.{InBoundGetAccountAttributesByAccount => InBound, OutBoundGetAccountAttributesByAccount => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_account_attributes_by_account", req, callContext) + response.map(convertToTuple[List[AccountAttributeCommons]](callContext)) + } + + messageDocs += getCustomerAttributesDoc + def getCustomerAttributesDoc = MessageDoc( + process = "obp.getCustomerAttributes", + messageFormat = messageFormat, + description = "Get Customer Attributes", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomerAttributes(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + customerId=CustomerId(customerIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetCustomerAttributes(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CustomerAttributeCommons(bankId=BankId(bankIdExample.value), + customerId=CustomerId(customerIdExample.value), + customerAttributeId=customerAttributeIdExample.value, + attributeType=com.openbankproject.commons.model.enums.CustomerAttributeType.example, + name=customerAttributeNameExample.value, + value=customerAttributeValueExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomerAttributes(bankId: BankId, customerId: CustomerId, callContext: Option[CallContext]): OBPReturnType[Box[List[CustomerAttribute]]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomerAttributes => InBound, OutBoundGetCustomerAttributes => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customer_attributes", req, callContext) + response.map(convertToTuple[List[CustomerAttributeCommons]](callContext)) + } + + messageDocs += getCustomerIdsByAttributeNameValuesDoc + def getCustomerIdsByAttributeNameValuesDoc = MessageDoc( + process = "obp.getCustomerIdsByAttributeNameValues", + messageFormat = messageFormat, + description = "Get Customer Ids By Attribute Name Values", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomerIdsByAttributeNameValues(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + nameValues=Map("some_name" -> List("name1", "name2"))) + ), + exampleInboundMessage = ( + InBoundGetCustomerIdsByAttributeNameValues(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=listExample.value.replace("[","").replace("]","").split(",").toList) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomerIdsByAttributeNameValues(bankId: BankId, nameValues: Map[String,List[String]], callContext: Option[CallContext]): OBPReturnType[Box[List[String]]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomerIdsByAttributeNameValues => InBound, OutBoundGetCustomerIdsByAttributeNameValues => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, nameValues) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customer_ids_by_attribute_name_values", req, callContext) + response.map(convertToTuple[List[String]](callContext)) + } + + messageDocs += getCustomerAttributesForCustomersDoc + def getCustomerAttributesForCustomersDoc = MessageDoc( + process = "obp.getCustomerAttributesForCustomers", + messageFormat = messageFormat, + description = "Get Customer Attributes For Customers", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomerAttributesForCustomers(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customers=List( CustomerCommons(customerId=customerIdExample.value, + bankId=bankIdExample.value, + number=customerNumberExample.value, + legalName=legalNameExample.value, + mobileNumber=mobileNumberExample.value, + email=emailExample.value, + faceImage= CustomerFaceImage(date=toDate(customerFaceImageDateExample), + url=urlExample.value), + dateOfBirth=toDate(dateOfBirthExample), + relationshipStatus=relationshipStatusExample.value, + dependents=dependentsExample.value.toInt, + dobOfDependents=dobOfDependentsExample.value.replace("[","").replace("]","").split(",").map(parseDate).flatMap(_.toSeq).toList, + highestEducationAttained=highestEducationAttainedExample.value, + employmentStatus=employmentStatusExample.value, + creditRating= CreditRating(rating=ratingExample.value, + source=sourceExample.value), + creditLimit= CreditLimit(currency=currencyExample.value, + amount=creditLimitAmountExample.value), + kycStatus=kycStatusExample.value.toBoolean, + lastOkDate=toDate(customerLastOkDateExample), + title=customerTitleExample.value, + branchId=branchIdExample.value, + nameSuffix=nameSuffixExample.value, + customerType=Some("INDIVIDUAL"), + parentCustomerId=Some("")))) + ), + exampleInboundMessage = ( + InBoundGetCustomerAttributesForCustomers(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= List( + CustomerAndAttribute( + MessageDocsSwaggerDefinitions.customerCommons, + List(MessageDocsSwaggerDefinitions.customerAttribute) + ) + ) + ) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomerAttributesForCustomers(customers: List[Customer], callContext: Option[CallContext]): OBPReturnType[Box[List[CustomerAndAttribute]]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomerAttributesForCustomers => InBound, OutBoundGetCustomerAttributesForCustomers => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customers) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customer_attributes_for_customers", req, callContext) + response.map(convertToTuple[List[CustomerAndAttribute]](callContext)) + } + + messageDocs += getTransactionIdsByAttributeNameValuesDoc + def getTransactionIdsByAttributeNameValuesDoc = MessageDoc( + process = "obp.getTransactionIdsByAttributeNameValues", + messageFormat = messageFormat, + description = "Get Transaction Ids By Attribute Name Values", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionIdsByAttributeNameValues(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + nameValues=Map("some_name" -> List("name1", "name2"))) + ), + exampleInboundMessage = ( + InBoundGetTransactionIdsByAttributeNameValues(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=listExample.value.replace("[","").replace("]","").split(",").toList) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionIdsByAttributeNameValues(bankId: BankId, nameValues: Map[String,List[String]], callContext: Option[CallContext]): OBPReturnType[Box[List[String]]] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionIdsByAttributeNameValues => InBound, OutBoundGetTransactionIdsByAttributeNameValues => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, nameValues) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction_ids_by_attribute_name_values", req, callContext) + response.map(convertToTuple[List[String]](callContext)) + } + + messageDocs += getTransactionAttributesDoc + def getTransactionAttributesDoc = MessageDoc( + process = "obp.getTransactionAttributes", + messageFormat = messageFormat, + description = "Get Transaction Attributes", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetTransactionAttributes(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + transactionId=TransactionId(transactionIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetTransactionAttributes(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( TransactionAttributeCommons(bankId=BankId(bankIdExample.value), + transactionId=TransactionId(transactionIdExample.value), + transactionAttributeId=transactionAttributeIdExample.value, + attributeType=com.openbankproject.commons.model.enums.TransactionAttributeType.example, + name=transactionAttributeNameExample.value, + value=transactionAttributeValueExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getTransactionAttributes(bankId: BankId, transactionId: TransactionId, callContext: Option[CallContext]): OBPReturnType[Box[List[TransactionAttribute]]] = { + import com.openbankproject.commons.dto.{InBoundGetTransactionAttributes => InBound, OutBoundGetTransactionAttributes => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, transactionId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_transaction_attributes", req, callContext) + response.map(convertToTuple[List[TransactionAttributeCommons]](callContext)) + } + + messageDocs += getCustomerAttributeByIdDoc + def getCustomerAttributeByIdDoc = MessageDoc( + process = "obp.getCustomerAttributeById", + messageFormat = messageFormat, + description = "Get Customer Attribute By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCustomerAttributeById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerAttributeId=customerAttributeIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetCustomerAttributeById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerAttributeCommons(bankId=BankId(bankIdExample.value), + customerId=CustomerId(customerIdExample.value), + customerAttributeId=customerAttributeIdExample.value, + attributeType=com.openbankproject.commons.model.enums.CustomerAttributeType.example, + name=customerAttributeNameExample.value, + value=customerAttributeValueExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCustomerAttributeById(customerAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[CustomerAttribute]] = { + import com.openbankproject.commons.dto.{InBoundGetCustomerAttributeById => InBound, OutBoundGetCustomerAttributeById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerAttributeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_customer_attribute_by_id", req, callContext) + response.map(convertToTuple[CustomerAttributeCommons](callContext)) + } + + messageDocs += createOrUpdateCardAttributeDoc + def createOrUpdateCardAttributeDoc = MessageDoc( + process = "obp.createOrUpdateCardAttribute", + messageFormat = messageFormat, + description = "Create Or Update Card Attribute", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateCardAttribute(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=Some(BankId(bankIdExample.value)), + cardId=Some(cardIdExample.value), + cardAttributeId=Some(cardAttributeIdExample.value), + name=nameExample.value, + cardAttributeType=com.openbankproject.commons.model.enums.CardAttributeType.example, + value=valueExample.value) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateCardAttribute(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CardAttributeCommons(bankId=Some(BankId(bankIdExample.value)), + cardId=Some(cardIdExample.value), + cardAttributeId=Some(cardAttributeIdExample.value), + name=cardAttributeNameExample.value, + attributeType=com.openbankproject.commons.model.enums.CardAttributeType.example, + value=cardAttributeValueExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateCardAttribute(bankId: Option[BankId], cardId: Option[String], cardAttributeId: Option[String], name: String, cardAttributeType: CardAttributeType.Value, value: String, callContext: Option[CallContext]): OBPReturnType[Box[CardAttribute]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateCardAttribute => InBound, OutBoundCreateOrUpdateCardAttribute => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, cardId, cardAttributeId, name, cardAttributeType, value) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_card_attribute", req, callContext) + response.map(convertToTuple[CardAttributeCommons](callContext)) + } + + messageDocs += getCardAttributeByIdDoc + def getCardAttributeByIdDoc = MessageDoc( + process = "obp.getCardAttributeById", + messageFormat = messageFormat, + description = "Get Card Attribute By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCardAttributeById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + cardAttributeId=cardAttributeIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetCardAttributeById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CardAttributeCommons(bankId=Some(BankId(bankIdExample.value)), + cardId=Some(cardIdExample.value), + cardAttributeId=Some(cardAttributeIdExample.value), + name=cardAttributeNameExample.value, + attributeType=com.openbankproject.commons.model.enums.CardAttributeType.example, + value=cardAttributeValueExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCardAttributeById(cardAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[CardAttribute]] = { + import com.openbankproject.commons.dto.{InBoundGetCardAttributeById => InBound, OutBoundGetCardAttributeById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, cardAttributeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_card_attribute_by_id", req, callContext) + response.map(convertToTuple[CardAttributeCommons](callContext)) + } + + messageDocs += getCardAttributesFromProviderDoc + def getCardAttributesFromProviderDoc = MessageDoc( + process = "obp.getCardAttributesFromProvider", + messageFormat = messageFormat, + description = "Get Card Attributes From Provider", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCardAttributesFromProvider(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + cardId=cardIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetCardAttributesFromProvider(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( CardAttributeCommons(bankId=Some(BankId(bankIdExample.value)), + cardId=Some(cardIdExample.value), + cardAttributeId=Some(cardAttributeIdExample.value), + name=cardAttributeNameExample.value, + attributeType=com.openbankproject.commons.model.enums.CardAttributeType.example, + value=cardAttributeValueExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCardAttributesFromProvider(cardId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[CardAttribute]]] = { + import com.openbankproject.commons.dto.{InBoundGetCardAttributesFromProvider => InBound, OutBoundGetCardAttributesFromProvider => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, cardId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_card_attributes_from_provider", req, callContext) + response.map(convertToTuple[List[CardAttributeCommons]](callContext)) + } + + messageDocs += createAccountApplicationDoc + def createAccountApplicationDoc = MessageDoc( + process = "obp.createAccountApplication", + messageFormat = messageFormat, + description = "Create Account Application", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateAccountApplication(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + productCode=ProductCode(productCodeExample.value), + userId=Some(userIdExample.value), + customerId=Some(customerIdExample.value)) + ), + exampleInboundMessage = ( + InBoundCreateAccountApplication(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AccountApplicationCommons(accountApplicationId=accountApplicationIdExample.value, + productCode=ProductCode(productCodeExample.value), + userId=userIdExample.value, + customerId=customerIdExample.value, + dateOfApplication=toDate(dateOfApplicationExample), + status=statusExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createAccountApplication(productCode: ProductCode, userId: Option[String], customerId: Option[String], callContext: Option[CallContext]): OBPReturnType[Box[AccountApplication]] = { + import com.openbankproject.commons.dto.{InBoundCreateAccountApplication => InBound, OutBoundCreateAccountApplication => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, productCode, userId, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_account_application", req, callContext) + response.map(convertToTuple[AccountApplicationCommons](callContext)) + } + + messageDocs += getAllAccountApplicationDoc + def getAllAccountApplicationDoc = MessageDoc( + process = "obp.getAllAccountApplication", + messageFormat = messageFormat, + description = "Get All Account Application", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAllAccountApplication(MessageDocsSwaggerDefinitions.outboundAdapterCallContext) + ), + exampleInboundMessage = ( + InBoundGetAllAccountApplication(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( AccountApplicationCommons(accountApplicationId=accountApplicationIdExample.value, + productCode=ProductCode(productCodeExample.value), + userId=userIdExample.value, + customerId=customerIdExample.value, + dateOfApplication=toDate(dateOfApplicationExample), + status=statusExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAllAccountApplication(callContext: Option[CallContext]): OBPReturnType[Box[List[AccountApplication]]] = { + import com.openbankproject.commons.dto.{InBoundGetAllAccountApplication => InBound, OutBoundGetAllAccountApplication => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_all_account_application", req, callContext) + response.map(convertToTuple[List[AccountApplicationCommons]](callContext)) + } + + messageDocs += getAccountApplicationByIdDoc + def getAccountApplicationByIdDoc = MessageDoc( + process = "obp.getAccountApplicationById", + messageFormat = messageFormat, + description = "Get Account Application By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetAccountApplicationById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + accountApplicationId=accountApplicationIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetAccountApplicationById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AccountApplicationCommons(accountApplicationId=accountApplicationIdExample.value, + productCode=ProductCode(productCodeExample.value), + userId=userIdExample.value, + customerId=customerIdExample.value, + dateOfApplication=toDate(dateOfApplicationExample), + status=statusExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getAccountApplicationById(accountApplicationId: String, callContext: Option[CallContext]): OBPReturnType[Box[AccountApplication]] = { + import com.openbankproject.commons.dto.{InBoundGetAccountApplicationById => InBound, OutBoundGetAccountApplicationById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, accountApplicationId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_account_application_by_id", req, callContext) + response.map(convertToTuple[AccountApplicationCommons](callContext)) + } + + messageDocs += updateAccountApplicationStatusDoc + def updateAccountApplicationStatusDoc = MessageDoc( + process = "obp.updateAccountApplicationStatus", + messageFormat = messageFormat, + description = "Update Account Application Status", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundUpdateAccountApplicationStatus(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + accountApplicationId=accountApplicationIdExample.value, + status=statusExample.value) + ), + exampleInboundMessage = ( + InBoundUpdateAccountApplicationStatus(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= AccountApplicationCommons(accountApplicationId=accountApplicationIdExample.value, + productCode=ProductCode(productCodeExample.value), + userId=userIdExample.value, + customerId=customerIdExample.value, + dateOfApplication=toDate(dateOfApplicationExample), + status=statusExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def updateAccountApplicationStatus(accountApplicationId: String, status: String, callContext: Option[CallContext]): OBPReturnType[Box[AccountApplication]] = { + import com.openbankproject.commons.dto.{InBoundUpdateAccountApplicationStatus => InBound, OutBoundUpdateAccountApplicationStatus => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, accountApplicationId, status) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_account_application_status", req, callContext) + response.map(convertToTuple[AccountApplicationCommons](callContext)) + } + + messageDocs += getOrCreateProductCollectionDoc + def getOrCreateProductCollectionDoc = MessageDoc( + process = "obp.getOrCreateProductCollection", + messageFormat = messageFormat, + description = "Get Or Create Product Collection", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetOrCreateProductCollection(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + collectionCode=collectionCodeExample.value, + productCodes=listExample.value.replace("[","").replace("]","").split(",").toList) + ), + exampleInboundMessage = ( + InBoundGetOrCreateProductCollection(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ProductCollectionCommons(collectionCode=collectionCodeExample.value, + productCode=productCodeExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getOrCreateProductCollection(collectionCode: String, productCodes: List[String], callContext: Option[CallContext]): OBPReturnType[Box[List[ProductCollection]]] = { + import com.openbankproject.commons.dto.{InBoundGetOrCreateProductCollection => InBound, OutBoundGetOrCreateProductCollection => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, collectionCode, productCodes) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_or_create_product_collection", req, callContext) + response.map(convertToTuple[List[ProductCollectionCommons]](callContext)) + } + + messageDocs += getProductCollectionDoc + def getProductCollectionDoc = MessageDoc( + process = "obp.getProductCollection", + messageFormat = messageFormat, + description = "Get Product Collection", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetProductCollection(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + collectionCode=collectionCodeExample.value) + ), + exampleInboundMessage = ( + InBoundGetProductCollection(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ProductCollectionCommons(collectionCode=collectionCodeExample.value, + productCode=productCodeExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getProductCollection(collectionCode: String, callContext: Option[CallContext]): OBPReturnType[Box[List[ProductCollection]]] = { + import com.openbankproject.commons.dto.{InBoundGetProductCollection => InBound, OutBoundGetProductCollection => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, collectionCode) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_product_collection", req, callContext) + response.map(convertToTuple[List[ProductCollectionCommons]](callContext)) + } + + messageDocs += getOrCreateProductCollectionItemDoc + def getOrCreateProductCollectionItemDoc = MessageDoc( + process = "obp.getOrCreateProductCollectionItem", + messageFormat = messageFormat, + description = "Get Or Create Product Collection Item", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetOrCreateProductCollectionItem(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + collectionCode=collectionCodeExample.value, + memberProductCodes=listExample.value.replace("[","").replace("]","").split(",").toList) + ), + exampleInboundMessage = ( + InBoundGetOrCreateProductCollectionItem(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ProductCollectionItemCommons(collectionCode=collectionCodeExample.value, + memberProductCode=memberProductCodeExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getOrCreateProductCollectionItem(collectionCode: String, memberProductCodes: List[String], callContext: Option[CallContext]): OBPReturnType[Box[List[ProductCollectionItem]]] = { + import com.openbankproject.commons.dto.{InBoundGetOrCreateProductCollectionItem => InBound, OutBoundGetOrCreateProductCollectionItem => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, collectionCode, memberProductCodes) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_or_create_product_collection_item", req, callContext) + response.map(convertToTuple[List[ProductCollectionItemCommons]](callContext)) + } + + messageDocs += getProductCollectionItemDoc + def getProductCollectionItemDoc = MessageDoc( + process = "obp.getProductCollectionItem", + messageFormat = messageFormat, + description = "Get Product Collection Item", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetProductCollectionItem(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + collectionCode=collectionCodeExample.value) + ), + exampleInboundMessage = ( + InBoundGetProductCollectionItem(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ProductCollectionItemCommons(collectionCode=collectionCodeExample.value, + memberProductCode=memberProductCodeExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getProductCollectionItem(collectionCode: String, callContext: Option[CallContext]): OBPReturnType[Box[List[ProductCollectionItem]]] = { + import com.openbankproject.commons.dto.{InBoundGetProductCollectionItem => InBound, OutBoundGetProductCollectionItem => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, collectionCode) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_product_collection_item", req, callContext) + response.map(convertToTuple[List[ProductCollectionItemCommons]](callContext)) + } + + messageDocs += getProductCollectionItemsTreeDoc + def getProductCollectionItemsTreeDoc = MessageDoc( + process = "obp.getProductCollectionItemsTree", + messageFormat = messageFormat, + description = "Get Product Collection Items Tree", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetProductCollectionItemsTree(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + collectionCode=collectionCodeExample.value, + bankId=bankIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetProductCollectionItemsTree(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( ProductCollectionItemsTree(productCollectionItem= ProductCollectionItemCommons(collectionCode=collectionCodeExample.value, + memberProductCode=memberProductCodeExample.value), + product= ProductCommons( + bankId=BankId(bankIdExample.value), + code=ProductCode(productCodeExample.value), + parentProductCode=ProductCode(parentProductCodeExample.value), + name=productNameExample.value, + category=categoryExample.value, + family=familyExample.value, + superFamily=superFamilyExample.value, + moreInfoUrl=moreInfoUrlExample.value, + termsAndConditionsUrl=termsAndConditionsUrlExample.value, + details=detailsExample.value, + description=descriptionExample.value, + meta=Meta( License(id=licenseIdExample.value, + name=licenseNameExample.value))), + attributes=List( ProductAttributeCommons(bankId=BankId(bankIdExample.value), + productCode=ProductCode(productCodeExample.value), + productAttributeId=productAttributeIdExample.value, + name=nameExample.value, + attributeType=com.openbankproject.commons.model.enums.ProductAttributeType.example, + value=valueExample.value, + isActive=Some(isActiveExample.value.toBoolean)))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getProductCollectionItemsTree(collectionCode: String, bankId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[ProductCollectionItemsTree]]] = { + import com.openbankproject.commons.dto.{InBoundGetProductCollectionItemsTree => InBound, OutBoundGetProductCollectionItemsTree => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, collectionCode, bankId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_product_collection_items_tree", req, callContext) + response.map(convertToTuple[List[ProductCollectionItemsTree]](callContext)) + } + + messageDocs += createMeetingDoc + def createMeetingDoc = MessageDoc( + process = "obp.createMeeting", + messageFormat = messageFormat, + description = "Create Meeting", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateMeeting(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + staffUser= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + customerUser= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + providerId=providerIdExample.value, + purposeId=purposeIdExample.value, + when=toDate(whenExample), + sessionId=sessionIdExample.value, + customerToken=customerTokenExample.value, + staffToken=staffTokenExample.value, + creator= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + invitees=List( Invitee(contactDetails= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + status=statusExample.value))) + ), + exampleInboundMessage = ( + InBoundCreateMeeting(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= MeetingCommons(meetingId=meetingIdExample.value, + providerId=providerIdExample.value, + purposeId=purposeIdExample.value, + bankId=bankIdExample.value, + present= MeetingPresent(staffUserId=staffUserIdExample.value, + customerUserId=customerUserIdExample.value), + keys= MeetingKeys(sessionId=sessionIdExample.value, + customerToken=customerTokenExample.value, + staffToken=staffTokenExample.value), + when=toDate(whenExample), + creator= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + invitees=List( Invitee(contactDetails= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + status=statusExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createMeeting(bankId: BankId, staffUser: User, customerUser: User, providerId: String, purposeId: String, when: Date, sessionId: String, customerToken: String, staffToken: String, creator: ContactDetails, invitees: List[Invitee], callContext: Option[CallContext]): OBPReturnType[Box[Meeting]] = { + import com.openbankproject.commons.dto.{InBoundCreateMeeting => InBound, OutBoundCreateMeeting => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, staffUser, customerUser, providerId, purposeId, when, sessionId, customerToken, staffToken, creator, invitees) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_meeting", req, callContext) + response.map(convertToTuple[MeetingCommons](callContext)) + } + + messageDocs += getMeetingsDoc + def getMeetingsDoc = MessageDoc( + process = "obp.getMeetings", + messageFormat = messageFormat, + description = "Get Meetings", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetMeetings(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + user= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample)))) + ), + exampleInboundMessage = ( + InBoundGetMeetings(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( MeetingCommons(meetingId=meetingIdExample.value, + providerId=providerIdExample.value, + purposeId=purposeIdExample.value, + bankId=bankIdExample.value, + present= MeetingPresent(staffUserId=staffUserIdExample.value, + customerUserId=customerUserIdExample.value), + keys= MeetingKeys(sessionId=sessionIdExample.value, + customerToken=customerTokenExample.value, + staffToken=staffTokenExample.value), + when=toDate(whenExample), + creator= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + invitees=List( Invitee(contactDetails= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + status=statusExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getMeetings(bankId: BankId, user: User, callContext: Option[CallContext]): OBPReturnType[Box[List[Meeting]]] = { + import com.openbankproject.commons.dto.{InBoundGetMeetings => InBound, OutBoundGetMeetings => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, user) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_meetings", req, callContext) + response.map(convertToTuple[List[MeetingCommons]](callContext)) + } + + messageDocs += getMeetingDoc + def getMeetingDoc = MessageDoc( + process = "obp.getMeeting", + messageFormat = messageFormat, + description = "Get Meeting", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetMeeting(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + user= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + meetingId=meetingIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetMeeting(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= MeetingCommons(meetingId=meetingIdExample.value, + providerId=providerIdExample.value, + purposeId=purposeIdExample.value, + bankId=bankIdExample.value, + present= MeetingPresent(staffUserId=staffUserIdExample.value, + customerUserId=customerUserIdExample.value), + keys= MeetingKeys(sessionId=sessionIdExample.value, + customerToken=customerTokenExample.value, + staffToken=staffTokenExample.value), + when=toDate(whenExample), + creator= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + invitees=List( Invitee(contactDetails= ContactDetails(name=nameExample.value, + phone=phoneExample.value, + email=emailExample.value), + status=statusExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getMeeting(bankId: BankId, user: User, meetingId: String, callContext: Option[CallContext]): OBPReturnType[Box[Meeting]] = { + import com.openbankproject.commons.dto.{InBoundGetMeeting => InBound, OutBoundGetMeeting => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, user, meetingId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_meeting", req, callContext) + response.map(convertToTuple[MeetingCommons](callContext)) + } + + messageDocs += createOrUpdateKycCheckDoc + def createOrUpdateKycCheckDoc = MessageDoc( + process = "obp.createOrUpdateKycCheck", + messageFormat = messageFormat, + description = "Create Or Update Kyc Check", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateKycCheck(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + customerId=customerIdExample.value, + id=idExample.value, + customerNumber=customerNumberExample.value, + date=toDate(dateExample), + how=howExample.value, + staffUserId=staffUserIdExample.value, + mStaffName="string", + mSatisfied=true, + comments=commentsExample.value) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateKycCheck(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= KycCheckCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + idKycCheck="string", + customerNumber=customerNumberExample.value, + date=toDate(dateExample), + how=howExample.value, + staffUserId=staffUserIdExample.value, + staffName=staffNameExample.value, + satisfied=satisfiedExample.value.toBoolean, + comments=commentsExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateKycCheck(bankId: String, customerId: String, id: String, customerNumber: String, date: Date, how: String, staffUserId: String, mStaffName: String, mSatisfied: Boolean, comments: String, callContext: Option[CallContext]): OBPReturnType[Box[KycCheck]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateKycCheck => InBound, OutBoundCreateOrUpdateKycCheck => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, customerId, id, customerNumber, date, how, staffUserId, mStaffName, mSatisfied, comments) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_kyc_check", req, callContext) + response.map(convertToTuple[KycCheckCommons](callContext)) + } + + messageDocs += createOrUpdateKycDocumentDoc + def createOrUpdateKycDocumentDoc = MessageDoc( + process = "obp.createOrUpdateKycDocument", + messageFormat = messageFormat, + description = "Create Or Update Kyc Document", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateKycDocument(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + customerId=customerIdExample.value, + id=idExample.value, + customerNumber=customerNumberExample.value, + `type`=typeExample.value, + number=numberExample.value, + issueDate=toDate(issueDateExample), + issuePlace=issuePlaceExample.value, + expiryDate=toDate(expiryDateExample)) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateKycDocument(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= KycDocumentCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + idKycDocument="string", + customerNumber=customerNumberExample.value, + `type`=typeExample.value, + number=numberExample.value, + issueDate=toDate(issueDateExample), + issuePlace=issuePlaceExample.value, + expiryDate=toDate(expiryDateExample))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateKycDocument(bankId: String, customerId: String, id: String, customerNumber: String, `type`: String, number: String, issueDate: Date, issuePlace: String, expiryDate: Date, callContext: Option[CallContext]): OBPReturnType[Box[KycDocument]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateKycDocument => InBound, OutBoundCreateOrUpdateKycDocument => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, customerId, id, customerNumber, `type`, number, issueDate, issuePlace, expiryDate) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_kyc_document", req, callContext) + response.map(convertToTuple[KycDocument](callContext)) + } + + messageDocs += createOrUpdateKycMediaDoc + def createOrUpdateKycMediaDoc = MessageDoc( + process = "obp.createOrUpdateKycMedia", + messageFormat = messageFormat, + description = "Create Or Update Kyc Media", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateKycMedia(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + customerId=customerIdExample.value, + id=idExample.value, + customerNumber=customerNumberExample.value, + `type`=typeExample.value, + url=urlExample.value, + date=toDate(dateExample), + relatesToKycDocumentId=relatesToKycDocumentIdExample.value, + relatesToKycCheckId=relatesToKycCheckIdExample.value) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateKycMedia(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= KycMediaCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + idKycMedia="string", + customerNumber=customerNumberExample.value, + `type`=typeExample.value, + url=urlExample.value, + date=toDate(dateExample), + relatesToKycDocumentId=relatesToKycDocumentIdExample.value, + relatesToKycCheckId=relatesToKycCheckIdExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateKycMedia(bankId: String, customerId: String, id: String, customerNumber: String, `type`: String, url: String, date: Date, relatesToKycDocumentId: String, relatesToKycCheckId: String, callContext: Option[CallContext]): OBPReturnType[Box[KycMedia]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateKycMedia => InBound, OutBoundCreateOrUpdateKycMedia => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, customerId, id, customerNumber, `type`, url, date, relatesToKycDocumentId, relatesToKycCheckId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_kyc_media", req, callContext) + response.map(convertToTuple[KycMediaCommons](callContext)) + } + + messageDocs += createOrUpdateKycStatusDoc + def createOrUpdateKycStatusDoc = MessageDoc( + process = "obp.createOrUpdateKycStatus", + messageFormat = messageFormat, + description = "Create Or Update Kyc Status", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateKycStatus(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + customerId=customerIdExample.value, + customerNumber=customerNumberExample.value, + ok=okExample.value.toBoolean, + date=toDate(dateExample)) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateKycStatus(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= KycStatusCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + customerNumber=customerNumberExample.value, + ok=okExample.value.toBoolean, + date=toDate(dateExample))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateKycStatus(bankId: String, customerId: String, customerNumber: String, ok: Boolean, date: Date, callContext: Option[CallContext]): OBPReturnType[Box[KycStatus]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateKycStatus => InBound, OutBoundCreateOrUpdateKycStatus => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, customerId, customerNumber, ok, date) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_kyc_status", req, callContext) + response.map(convertToTuple[KycStatusCommons](callContext)) + } + + messageDocs += getKycChecksDoc + def getKycChecksDoc = MessageDoc( + process = "obp.getKycChecks", + messageFormat = messageFormat, + description = "Get Kyc Checks", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetKycChecks(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetKycChecks(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( KycCheckCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + idKycCheck="string", + customerNumber=customerNumberExample.value, + date=toDate(dateExample), + how=howExample.value, + staffUserId=staffUserIdExample.value, + staffName=staffNameExample.value, + satisfied=satisfiedExample.value.toBoolean, + comments=commentsExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getKycChecks(customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[KycCheck]]] = { + import com.openbankproject.commons.dto.{InBoundGetKycChecks => InBound, OutBoundGetKycChecks => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_kyc_checks", req, callContext) + response.map(convertToTuple[List[KycCheckCommons]](callContext)) + } + + messageDocs += getKycDocumentsDoc + def getKycDocumentsDoc = MessageDoc( + process = "obp.getKycDocuments", + messageFormat = messageFormat, + description = "Get Kyc Documents", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetKycDocuments(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetKycDocuments(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( KycDocumentCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + idKycDocument="string", + customerNumber=customerNumberExample.value, + `type`=typeExample.value, + number=numberExample.value, + issueDate=toDate(issueDateExample), + issuePlace=issuePlaceExample.value, + expiryDate=toDate(expiryDateExample)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getKycDocuments(customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[KycDocument]]] = { + import com.openbankproject.commons.dto.{InBoundGetKycDocuments => InBound, OutBoundGetKycDocuments => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_kyc_documents", req, callContext) + response.map(convertToTuple[List[KycDocumentCommons]](callContext)) + } + + messageDocs += getKycMediasDoc + def getKycMediasDoc = MessageDoc( + process = "obp.getKycMedias", + messageFormat = messageFormat, + description = "Get Kyc Medias", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetKycMedias(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetKycMedias(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( KycMediaCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + idKycMedia="string", + customerNumber=customerNumberExample.value, + `type`=typeExample.value, + url=urlExample.value, + date=toDate(dateExample), + relatesToKycDocumentId=relatesToKycDocumentIdExample.value, + relatesToKycCheckId=relatesToKycCheckIdExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getKycMedias(customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[KycMedia]]] = { + import com.openbankproject.commons.dto.{InBoundGetKycMedias => InBound, OutBoundGetKycMedias => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_kyc_medias", req, callContext) + response.map(convertToTuple[List[KycMediaCommons]](callContext)) + } + + messageDocs += getKycStatusesDoc + def getKycStatusesDoc = MessageDoc( + process = "obp.getKycStatuses", + messageFormat = messageFormat, + description = "Get Kyc Statuses", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetKycStatuses(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerId=customerIdExample.value) + ), + exampleInboundMessage = ( + InBoundGetKycStatuses(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( KycStatusCommons(bankId=bankIdExample.value, + customerId=customerIdExample.value, + customerNumber=customerNumberExample.value, + ok=okExample.value.toBoolean, + date=toDate(dateExample)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getKycStatuses(customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[KycStatus]]] = { + import com.openbankproject.commons.dto.{InBoundGetKycStatuses => InBound, OutBoundGetKycStatuses => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_kyc_statuses", req, callContext) + response.map(convertToTuple[List[KycStatusCommons]](callContext)) + } + + messageDocs += createMessageDoc + def createMessageDoc = MessageDoc( + process = "obp.createMessage", + messageFormat = messageFormat, + description = "Create Message", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateMessage(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + user= UserCommons(userPrimaryKey=UserPrimaryKey(123), + userId=userIdExample.value, + idGivenByProvider="string", + provider=providerExample.value, + emailAddress=emailAddressExample.value, + name=userNameExample.value, + createdByConsentId=Some("string"), + createdByUserInvitationId=Some("string"), + isDeleted=Some(true), + lastMarketingAgreementSignedDate=Some(toDate(dateExample))), + bankId=BankId(bankIdExample.value), + message=messageExample.value, + fromDepartment=fromDepartmentExample.value, + fromPerson=fromPersonExample.value) + ), + exampleInboundMessage = ( + InBoundCreateMessage(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= CustomerMessageCommons(messageId="string", + date=toDate(dateExample), + message=messageExample.value, + fromDepartment=fromDepartmentExample.value, + fromPerson=fromPersonExample.value, + transport=Some(transportExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createMessage(user: User, bankId: BankId, message: String, fromDepartment: String, fromPerson: String, callContext: Option[CallContext]): OBPReturnType[Box[CustomerMessage]] = { + import com.openbankproject.commons.dto.{InBoundCreateMessage => InBound, OutBoundCreateMessage => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, user, bankId, message, fromDepartment, fromPerson) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_message", req, callContext) + response.map(convertToTuple[CustomerMessageCommons](callContext)) + } + + messageDocs += makeHistoricalPaymentDoc + def makeHistoricalPaymentDoc = MessageDoc( + process = "obp.makeHistoricalPayment", + messageFormat = messageFormat, + description = "Make Historical Payment", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundMakeHistoricalPayment(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + fromAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + toAccount= BankAccountCommons(accountId=AccountId(accountIdExample.value), + accountType=accountTypeExample.value, + balance=BigDecimal(balanceExample.value), + currency=currencyExample.value, + name=bankAccountNameExample.value, + label=labelExample.value, + number=bankAccountNumberExample.value, + bankId=BankId(bankIdExample.value), + lastUpdate=toDate(bankAccountLastUpdateExample), + branchId=branchIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + accountRules=List( AccountRule(scheme=accountRuleSchemeExample.value, + value=accountRuleValueExample.value)), + accountHolder=bankAccountAccountHolderExample.value, + attributes=Some(List( Attribute(name=attributeNameExample.value, + `type`=attributeTypeExample.value, + value=attributeValueExample.value)))), + posted=toDate(postedExample), + completed=toDate(completedExample), + amount=BigDecimal(amountExample.value), + currency=currencyExample.value, + description=descriptionExample.value, + transactionRequestType=transactionRequestTypeExample.value, + chargePolicy=chargePolicyExample.value) + ), + exampleInboundMessage = ( + InBoundMakeHistoricalPayment(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=TransactionId(transactionIdExample.value)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def makeHistoricalPayment(fromAccount: BankAccount, toAccount: BankAccount, posted: Date, completed: Date, amount: BigDecimal, currency: String, description: String, transactionRequestType: String, chargePolicy: String, callContext: Option[CallContext]): OBPReturnType[Box[TransactionId]] = { + import com.openbankproject.commons.dto.{InBoundMakeHistoricalPayment => InBound, OutBoundMakeHistoricalPayment => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, fromAccount, toAccount, posted, completed, amount, currency, description, transactionRequestType, chargePolicy) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_make_historical_payment", req, callContext) + response.map(convertToTuple[TransactionId](callContext)) + } + + messageDocs += createDirectDebitDoc + def createDirectDebitDoc = MessageDoc( + process = "obp.createDirectDebit", + messageFormat = messageFormat, + description = "Create Direct Debit", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateDirectDebit(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=bankIdExample.value, + accountId=accountIdExample.value, + customerId=customerIdExample.value, + userId=userIdExample.value, + counterpartyId=counterpartyIdExample.value, + dateSigned=toDate(dateSignedExample), + dateStarts=toDate(dateStartsExample), + dateExpires=Some(toDate(dateExpiresExample))) + ), + exampleInboundMessage = ( + InBoundCreateDirectDebit(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= DirectDebitTraitCommons(directDebitId=directDebitIdExample.value, + bankId=bankIdExample.value, + accountId=accountIdExample.value, + customerId=customerIdExample.value, + userId=userIdExample.value, + counterpartyId=counterpartyIdExample.value, + dateSigned=toDate(dateSignedExample), + dateCancelled=toDate(dateCancelledExample), + dateStarts=toDate(dateStartsExample), + dateExpires=toDate(dateExpiresExample), + active=activeExample.value.toBoolean)) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createDirectDebit(bankId: String, accountId: String, customerId: String, userId: String, counterpartyId: String, dateSigned: Date, dateStarts: Date, dateExpires: Option[Date], callContext: Option[CallContext]): OBPReturnType[Box[DirectDebitTrait]] = { + import com.openbankproject.commons.dto.{InBoundCreateDirectDebit => InBound, OutBoundCreateDirectDebit => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, customerId, userId, counterpartyId, dateSigned, dateStarts, dateExpires) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_direct_debit", req, callContext) + response.map(convertToTuple[DirectDebitTraitCommons](callContext)) + } + + messageDocs += deleteCustomerAttributeDoc + def deleteCustomerAttributeDoc = MessageDoc( + process = "obp.deleteCustomerAttribute", + messageFormat = messageFormat, + description = "Delete Customer Attribute", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeleteCustomerAttribute(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + customerAttributeId=customerAttributeIdExample.value) + ), + exampleInboundMessage = ( + InBoundDeleteCustomerAttribute(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deleteCustomerAttribute(customerAttributeId: String, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeleteCustomerAttribute => InBound, OutBoundDeleteCustomerAttribute => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerAttributeId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_customer_attribute", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + + messageDocs += getRegulatedEntitiesDoc + def getRegulatedEntitiesDoc = MessageDoc( + process = "obp.getRegulatedEntities", + messageFormat = messageFormat, + description = "Get Regulated Entities", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetRegulatedEntities(MessageDocsSwaggerDefinitions.outboundAdapterCallContext) + ), + exampleInboundMessage = ( + InBoundGetRegulatedEntities(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( RegulatedEntityTraitCommons(entityId=entityIdExample.value, + certificateAuthorityCaOwnerId=certificateAuthorityCaOwnerIdExample.value, + entityName=entityNameExample.value, + entityCode=entityCodeExample.value, + entityCertificatePublicKey=entityCertificatePublicKeyExample.value, + entityType=entityTypeExample.value, + entityAddress=entityAddressExample.value, + entityTownCity=entityTownCityExample.value, + entityPostCode=entityPostCodeExample.value, + entityCountry=entityCountryExample.value, + entityWebSite=entityWebSiteExample.value, + services=servicesExample.value, + attributes=Some(List( RegulatedEntityAttributeSimple(attributeType=attributeTypeExample.value, + name=nameExample.value, + value=valueExample.value)))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getRegulatedEntities(callContext: Option[CallContext]): OBPReturnType[Box[List[RegulatedEntityTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetRegulatedEntities => InBound, OutBoundGetRegulatedEntities => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_regulated_entities", req, callContext) + response.map(convertToTuple[List[RegulatedEntityTraitCommons]](callContext)) + } + + messageDocs += getRegulatedEntityByEntityIdDoc + def getRegulatedEntityByEntityIdDoc = MessageDoc( + process = "obp.getRegulatedEntityByEntityId", + messageFormat = messageFormat, + description = "Get Regulated Entity By Entity Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetRegulatedEntityByEntityId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + regulatedEntityId="string") + ), + exampleInboundMessage = ( + InBoundGetRegulatedEntityByEntityId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= RegulatedEntityTraitCommons(entityId=entityIdExample.value, + certificateAuthorityCaOwnerId=certificateAuthorityCaOwnerIdExample.value, + entityName=entityNameExample.value, + entityCode=entityCodeExample.value, + entityCertificatePublicKey=entityCertificatePublicKeyExample.value, + entityType=entityTypeExample.value, + entityAddress=entityAddressExample.value, + entityTownCity=entityTownCityExample.value, + entityPostCode=entityPostCodeExample.value, + entityCountry=entityCountryExample.value, + entityWebSite=entityWebSiteExample.value, + services=servicesExample.value, + attributes=Some(List( RegulatedEntityAttributeSimple(attributeType=attributeTypeExample.value, + name=nameExample.value, + value=valueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getRegulatedEntityByEntityId(regulatedEntityId: String, callContext: Option[CallContext]): OBPReturnType[Box[RegulatedEntityTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetRegulatedEntityByEntityId => InBound, OutBoundGetRegulatedEntityByEntityId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, regulatedEntityId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_regulated_entity_by_entity_id", req, callContext) + response.map(convertToTuple[RegulatedEntityTraitCommons](callContext)) + } + + messageDocs += getBankAccountBalancesByAccountIdDoc + def getBankAccountBalancesByAccountIdDoc = MessageDoc( + process = "obp.getBankAccountBalancesByAccountId", + messageFormat = messageFormat, + description = "Get Bank Account Balances By Account Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountBalancesByAccountId(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + accountId=AccountId(accountIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetBankAccountBalancesByAccountId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BankAccountBalanceTraitCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + balanceId=BalanceId(balanceIdExample.value), + balanceType=balanceTypeExample.value, + balanceAmount=BigDecimal(balanceAmountExample.value), + lastChangeDateTime=Some(toDate(dateExample)), + referenceDate=Some(referenceDateExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountBalancesByAccountId(accountId: AccountId, callContext: Option[CallContext]): OBPReturnType[Box[List[BankAccountBalanceTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountBalancesByAccountId => InBound, OutBoundGetBankAccountBalancesByAccountId => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, accountId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_account_balances_by_account_id", req, callContext) + response.map(convertToTuple[List[BankAccountBalanceTraitCommons]](callContext)) + } + + messageDocs += getBankAccountsBalancesByAccountIdsDoc + def getBankAccountsBalancesByAccountIdsDoc = MessageDoc( + process = "obp.getBankAccountsBalancesByAccountIds", + messageFormat = messageFormat, + description = "Get Bank Accounts Balances By Account Ids", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountsBalancesByAccountIds(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + accountIds=List(AccountId(accountIdExample.value))) + ), + exampleInboundMessage = ( + InBoundGetBankAccountsBalancesByAccountIds(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=List( BankAccountBalanceTraitCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + balanceId=BalanceId(balanceIdExample.value), + balanceType=balanceTypeExample.value, + balanceAmount=BigDecimal(balanceAmountExample.value), + lastChangeDateTime=Some(toDate(dateExample)), + referenceDate=Some(referenceDateExample.value)))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountsBalancesByAccountIds(accountIds: List[AccountId], callContext: Option[CallContext]): OBPReturnType[Box[List[BankAccountBalanceTrait]]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountsBalancesByAccountIds => InBound, OutBoundGetBankAccountsBalancesByAccountIds => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, accountIds) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_accounts_balances_by_account_ids", req, callContext) + response.map(convertToTuple[List[BankAccountBalanceTraitCommons]](callContext)) + } + + messageDocs += getBankAccountBalanceByIdDoc + def getBankAccountBalanceByIdDoc = MessageDoc( + process = "obp.getBankAccountBalanceById", + messageFormat = messageFormat, + description = "Get Bank Account Balance By Id", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetBankAccountBalanceById(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + balanceId=BalanceId(balanceIdExample.value)) + ), + exampleInboundMessage = ( + InBoundGetBankAccountBalanceById(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankAccountBalanceTraitCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + balanceId=BalanceId(balanceIdExample.value), + balanceType=balanceTypeExample.value, + balanceAmount=BigDecimal(balanceAmountExample.value), + lastChangeDateTime=Some(toDate(dateExample)), + referenceDate=Some(referenceDateExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getBankAccountBalanceById(balanceId: BalanceId, callContext: Option[CallContext]): OBPReturnType[Box[BankAccountBalanceTrait]] = { + import com.openbankproject.commons.dto.{InBoundGetBankAccountBalanceById => InBound, OutBoundGetBankAccountBalanceById => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, balanceId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_bank_account_balance_by_id", req, callContext) + response.map(convertToTuple[BankAccountBalanceTraitCommons](callContext)) + } + + messageDocs += createOrUpdateBankAccountBalanceDoc + def createOrUpdateBankAccountBalanceDoc = MessageDoc( + process = "obp.createOrUpdateBankAccountBalance", + messageFormat = messageFormat, + description = "Create Or Update Bank Account Balance", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCreateOrUpdateBankAccountBalance(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + balanceId=Some(BalanceId(balanceIdExample.value)), + balanceType=balanceTypeExample.value, + balanceAmount=BigDecimal(balanceAmountExample.value)) + ), + exampleInboundMessage = ( + InBoundCreateOrUpdateBankAccountBalance(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= BankAccountBalanceTraitCommons(bankId=BankId(bankIdExample.value), + accountId=AccountId(accountIdExample.value), + balanceId=BalanceId(balanceIdExample.value), + balanceType=balanceTypeExample.value, + balanceAmount=BigDecimal(balanceAmountExample.value), + lastChangeDateTime=Some(toDate(dateExample)), + referenceDate=Some(referenceDateExample.value))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def createOrUpdateBankAccountBalance(bankId: BankId, accountId: AccountId, balanceId: Option[BalanceId], balanceType: String, balanceAmount: BigDecimal, callContext: Option[CallContext]): OBPReturnType[Box[BankAccountBalanceTrait]] = { + import com.openbankproject.commons.dto.{InBoundCreateOrUpdateBankAccountBalance => InBound, OutBoundCreateOrUpdateBankAccountBalance => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, accountId, balanceId, balanceType, balanceAmount) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_or_update_bank_account_balance", req, callContext) + response.map(convertToTuple[BankAccountBalanceTraitCommons](callContext)) + } + + messageDocs += deleteBankAccountBalanceDoc + def deleteBankAccountBalanceDoc = MessageDoc( + process = "obp.deleteBankAccountBalance", + messageFormat = messageFormat, + description = "Delete Bank Account Balance", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDeleteBankAccountBalance(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + balanceId=BalanceId(balanceIdExample.value)) + ), + exampleInboundMessage = ( + InBoundDeleteBankAccountBalance(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data=true) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def deleteBankAccountBalance(balanceId: BalanceId, callContext: Option[CallContext]): OBPReturnType[Box[Boolean]] = { + import com.openbankproject.commons.dto.{InBoundDeleteBankAccountBalance => InBound, OutBoundDeleteBankAccountBalance => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, balanceId) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_delete_bank_account_balance", req, callContext) + response.map(convertToTuple[Boolean](callContext)) + } + +// ---------- created on 2025-06-10T12:05:04Z +//---------------- dynamic end ---------------------please don't modify this line + + private val availableOperation = DynamicEntityOperation.values.map(it => s""""$it"""").mkString("[", ", ", "]") + + messageDocs += dynamicEntityProcessDoc + def dynamicEntityProcessDoc = MessageDoc( + process = "obp.dynamicEntityProcess", + messageFormat = messageFormat, + description = s"operate committed dynamic entity data, the available value of 'operation' can be: ${availableOperation}", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundDynamicEntityProcessDoc(outboundAdapterCallContext = OutboundAdapterCallContext(correlationId=correlationIdExample.value, + sessionId=Some(sessionIdExample.value), + consumerId=Some(consumerIdExample.value), + generalContext=Some(List( BasicGeneralContext(key=keyExample.value, + value=valueExample.value))), + outboundAdapterAuthInfo=Some( OutboundAdapterAuthInfo(userId=Some(userIdExample.value), + username=Some(usernameExample.value), + linkedCustomers=Some(List( BasicLinkedCustomer(customerId=customerIdExample.value, + customerNumber=customerNumberExample.value, + legalName=legalNameExample.value))), + userAuthContext=Some(List( BasicUserAuthContext(key=keyExample.value, + value=valueExample.value))), + authViews=Some(List( AuthView(view= ViewBasic(id=viewIdExample.value, + name=viewNameExample.value, + description=viewDescriptionExample.value), + account= AccountBasic(id=accountIdExample.value, + accountRoutings=List( AccountRouting(scheme=accountRoutingSchemeExample.value, + address=accountRoutingAddressExample.value)), + customerOwners=List( InternalBasicCustomer(bankId=bankIdExample.value, + customerId=customerIdExample.value, + customerNumber=customerNumberExample.value, + legalName=legalNameExample.value, + dateOfBirth=parseDate(dateOfBirthExample.value).getOrElse(sys.error("dateOfBirthExample.value is not validate date format.")))), + userOwners=List( InternalBasicUser(userId=userIdExample.value, + emailAddress=emailExample.value, + name=usernameExample.value))))))))), + operation = DynamicEntityOperation.UPDATE, + entityName = "FooBar", + requestBody = Some(FooBar(name = "James Brown", number = 1234567890)), + entityId = Some("foobar-id-value")) + ), + exampleInboundMessage = ( + InBoundDynamicEntityProcessDoc(inboundAdapterCallContext= InboundAdapterCallContext(correlationId=correlationIdExample.value, + sessionId=Some(sessionIdExample.value), + generalContext=Some(List( BasicGeneralContext(key=keyExample.value, + value=valueExample.value)))), + status= Status(errorCode=statusErrorCodeExample.value, + backendMessages=List( InboundStatusMessage(source=sourceExample.value, + status=inboundStatusMessageStatusExample.value, + errorCode=inboundStatusMessageErrorCodeExample.value, + text=inboundStatusMessageTextExample.value))), + data=FooBar(name = "James Brown", number = 1234567890, fooBarId = Some("foobar-id-value"))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def dynamicEntityProcess(operation: DynamicEntityOperation, + entityName: String, + requestBody: Option[JObject], + entityId: Option[String], + bankId: Option[String], + queryParameters: Option[Map[String, List[String]]], + userId: Option[String], + isPersonalEntity: Boolean, + callContext: Option[CallContext]): OBPReturnType[Box[JValue]] = { + import com.openbankproject.commons.dto.{InBoundDynamicEntityProcess => InBound, OutBoundDynamicEntityProcess => OutBound} + val procedureName = StringHelpers.snakify("dynamicEntityProcess") + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull , operation, entityName, requestBody, entityId, bankId, queryParameters, userId, isPersonalEntity) + val result: OBPReturnType[Box[JValue]] = sendRequest[InBound](procedureName, req, callContext).map(convertToTuple(callContext)) + result + } + + private[this] def sendRequest[T <: InBoundTrait[_]: TypeTag : Manifest](process: String, outBound: TopicTrait, callContext: Option[CallContext]): Future[Box[T]] = { + //transfer accountId to accountReference and customerId to customerReference in outBound + Helper.convertToReference(outBound) + GrpcUtils + .sendRequest[T](process, outBound) + .map(Helper.convertToId(_)) + .recoverWith { + case e: Exception => Future(Failure(s"$AdapterUnknownError Please Check Adapter Side! Details: ${e.getMessage}")) + } + } + + + //-----helper methods + + //TODO hongwei confirm the third value: OutboundAdapterCallContext#adapterAuthInfo + private[this] def buildCallContext(inboundAdapterCallContext: InboundAdapterCallContext, callContext: Option[CallContext]): Option[CallContext] = + for (cc <- callContext) + yield cc.copy(correlationId = inboundAdapterCallContext.correlationId, sessionId = inboundAdapterCallContext.sessionId) + + private[this] def buildCallContext(boxedInboundAdapterCallContext: Box[InboundAdapterCallContext], callContext: Option[CallContext]): Option[CallContext] = boxedInboundAdapterCallContext match { + case Full(inboundAdapterCallContext) => buildCallContext(inboundAdapterCallContext, callContext) + case _ => callContext + } + +} +object GrpcConnector_vFeb2026 extends GrpcConnector_vFeb2026 diff --git a/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcUtils.scala b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcUtils.scala new file mode 100644 index 0000000000..60b726be67 --- /dev/null +++ b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcUtils.scala @@ -0,0 +1,78 @@ +package code.bankconnectors.grpc + +import code.api.util.APIUtil +import code.api.util.ErrorMessages.AdapterUnknownError +import code.bankconnectors.Connector +import code.bankconnectors.grpc.api.{ObpConnectorRequest, ObpConnectorServiceGrpc} +import code.util.Helper.MdcLoggable +import com.openbankproject.commons.model.TopicTrait +import io.grpc.netty.{GrpcSslContexts, NettyChannelBuilder} +import io.netty.handler.ssl.SslContextBuilder +import net.liftweb.common.{Box, Empty} +import net.liftweb.json.Serialization.write + +import java.io.File +import java.util.concurrent.TimeUnit +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.Future + +/** + * gRPC utils for the connector. + * Manages the ManagedChannel lifecycle and executes gRPC calls. + * The reason for extracting this util: if not using the gRPC connector, + * the gRPC channel will not be initialized. + */ +object GrpcUtils extends MdcLoggable { + + private implicit val formats = code.api.util.CustomJsonFormats.nullTolerateFormats + + val host: String = APIUtil.getPropsValue("grpc_connector.host", "localhost") + val port: Int = APIUtil.getPropsAsIntValue("grpc_connector.port", 50051) + val deadlineMs: Long = APIUtil.getPropsAsLongValue("grpc_connector.deadline_ms", 30000L) + val useTls: Boolean = APIUtil.getPropsAsBoolValue("grpc_connector.use_tls", false) + + lazy val channel: io.grpc.ManagedChannel = { + val builder = NettyChannelBuilder.forAddress(host, port) + if (useTls) { + val sslBuilder = SslContextBuilder.forClient() + val trustCertFile = APIUtil.getPropsValue("grpc_connector.tls.trust_cert_collection_file", "") + if (trustCertFile.nonEmpty) sslBuilder.trustManager(new File(trustCertFile)) + val clientCertFile = APIUtil.getPropsValue("grpc_connector.tls.client_cert_chain_file", "") + val clientKeyFile = APIUtil.getPropsValue("grpc_connector.tls.client_private_key_file", "") + if (clientCertFile.nonEmpty && clientKeyFile.nonEmpty) { + sslBuilder.keyManager(new File(clientCertFile), new File(clientKeyFile)) + } + builder.sslContext(GrpcSslContexts.configure(sslBuilder).build()) + } else { + builder.usePlaintext() + } + val ch = builder.build() + logger.info(s"gRPC channel created: $host:$port (tls=$useTls)") + // Register shutdown hook for clean teardown + sys.addShutdownHook { + logger.info("Shutting down gRPC channel...") + ch.shutdown() + if (!ch.awaitTermination(5, TimeUnit.SECONDS)) { + ch.shutdownNow() + } + } + ch + } + + lazy val blockingStub: ObpConnectorServiceGrpc.ObpConnectorServiceBlockingStub = + ObpConnectorServiceGrpc.blockingStub(channel) + + def sendRequest[T: Manifest](processName: String, outBound: TopicTrait): Future[Box[T]] = { + val outBoundJson: String = write(outBound) + logger.debug(s"${GrpcConnector_vFeb2026.toString} outBoundJson: $processName = $outBoundJson") + + Future { + val request = ObpConnectorRequest(methodName = processName, jsonPayload = outBoundJson) + val response = blockingStub.processObpRequest(request) + response.jsonPayload + }.map { responseJson => + logger.debug(s"${GrpcConnector_vFeb2026.toString} inBoundJson: $processName = $responseJson") + Connector.extractAdapterResponse[T](responseJson, Empty) + } + } +} diff --git a/obp-api/src/main/scala/code/bankconnectors/grpc/api/ObpConnectorServiceGrpc.scala b/obp-api/src/main/scala/code/bankconnectors/grpc/api/ObpConnectorServiceGrpc.scala new file mode 100644 index 0000000000..b75e9dd518 --- /dev/null +++ b/obp-api/src/main/scala/code/bankconnectors/grpc/api/ObpConnectorServiceGrpc.scala @@ -0,0 +1,81 @@ +// Hand-written gRPC stubs for connector.proto +// Uses raw io.grpc API with protobuf wire format for full compatibility +// with any gRPC server implementing the same proto definition. + +package code.bankconnectors.grpc.api + +case class ObpConnectorRequest(methodName: String = "", jsonPayload: String = "") +case class ObpConnectorResponse(jsonPayload: String = "") + +object ObpConnectorServiceGrpc { + + private val requestMarshaller: _root_.io.grpc.MethodDescriptor.Marshaller[ObpConnectorRequest] = + new _root_.io.grpc.MethodDescriptor.Marshaller[ObpConnectorRequest] { + override def stream(value: ObpConnectorRequest): java.io.InputStream = { + val baos = new java.io.ByteArrayOutputStream() + val cos = _root_.com.google.protobuf.CodedOutputStream.newInstance(baos) + if (value.methodName.nonEmpty) cos.writeString(1, value.methodName) + if (value.jsonPayload.nonEmpty) cos.writeString(2, value.jsonPayload) + cos.flush() + new java.io.ByteArrayInputStream(baos.toByteArray) + } + override def parse(stream: java.io.InputStream): ObpConnectorRequest = { + val cis = _root_.com.google.protobuf.CodedInputStream.newInstance(stream) + var methodName = "" + var jsonPayload = "" + var done = false + while (!done) { + val tag = cis.readTag() + tag match { + case 0 => done = true + case 10 => methodName = cis.readString() + case 18 => jsonPayload = cis.readString() + case other => cis.skipField(other) + } + } + ObpConnectorRequest(methodName, jsonPayload) + } + } + + private val responseMarshaller: _root_.io.grpc.MethodDescriptor.Marshaller[ObpConnectorResponse] = + new _root_.io.grpc.MethodDescriptor.Marshaller[ObpConnectorResponse] { + override def stream(value: ObpConnectorResponse): java.io.InputStream = { + val baos = new java.io.ByteArrayOutputStream() + val cos = _root_.com.google.protobuf.CodedOutputStream.newInstance(baos) + if (value.jsonPayload.nonEmpty) cos.writeString(1, value.jsonPayload) + cos.flush() + new java.io.ByteArrayInputStream(baos.toByteArray) + } + override def parse(stream: java.io.InputStream): ObpConnectorResponse = { + val cis = _root_.com.google.protobuf.CodedInputStream.newInstance(stream) + var jsonPayload = "" + var done = false + while (!done) { + val tag = cis.readTag() + tag match { + case 0 => done = true + case 10 => jsonPayload = cis.readString() + case other => cis.skipField(other) + } + } + ObpConnectorResponse(jsonPayload) + } + } + + val METHOD_PROCESS_OBP_REQUEST: _root_.io.grpc.MethodDescriptor[ObpConnectorRequest, ObpConnectorResponse] = + _root_.io.grpc.MethodDescriptor.newBuilder() + .setType(_root_.io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(_root_.io.grpc.MethodDescriptor.generateFullMethodName("code.bankconnectors.grpc.ObpConnectorService", "ProcessObpRequest")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(requestMarshaller) + .setResponseMarshaller(responseMarshaller) + .build() + + class ObpConnectorServiceBlockingStub(channel: _root_.io.grpc.Channel, options: _root_.io.grpc.CallOptions = _root_.io.grpc.CallOptions.DEFAULT) { + def processObpRequest(request: ObpConnectorRequest): ObpConnectorResponse = { + _root_.io.grpc.stub.ClientCalls.blockingUnaryCall(channel.newCall(METHOD_PROCESS_OBP_REQUEST, options), request) + } + } + + def blockingStub(channel: _root_.io.grpc.Channel): ObpConnectorServiceBlockingStub = new ObpConnectorServiceBlockingStub(channel) +} From 10f1203aa61b66bfe532aab342dbc63d3aba7cb7 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Fri, 27 Feb 2026 06:29:12 +0100 Subject: [PATCH 04/19] grpc connector regenerated --- .../grpc/GrpcConnectorBuilder.scala | 12 + .../grpc/GrpcConnector_vFeb2026.scala | 220 ++++++++++++++---- 2 files changed, 188 insertions(+), 44 deletions(-) diff --git a/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala index 7522f412b1..1dc3749719 100644 --- a/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala +++ b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnectorBuilder.scala @@ -5,6 +5,18 @@ import net.liftweb.util.StringHelpers import scala.language.postfixOps +// To regenerate the dynamic region in GrpcConnector_vFeb2026.scala, run: +// MAVEN_OPTS="--add-opens java.base/java.lang=ALL-UNNAMED" \ +// mvn exec:java -pl obp-api -Dexec.mainClass="code.bankconnectors.grpc.GrpcConnectorBuilder" -Dexec.classpathScope=compile +// +// Notes: +// - The --add-opens flag is needed on Java 17+ because ConnectorBuilderUtil uses javassist +// to rewrite MappedWebUiPropsProvider, which requires reflective access to java.lang.ClassLoader. +// - If you see "unsafe symbol X (child of package model)", run `mvn install -pl obp-commons` +// first. The exec:java plugin resolves classpath from the local Maven repo, so newly added +// commons types won't be found until the commons JAR is reinstalled. +// - The process may hang after completion due to a non-daemon thread; it is safe to kill it +// once the file has been updated (check the "created on" timestamp in the dynamic region). object GrpcConnectorBuilder extends App { buildMethods(commonMethodNames.diff(omitMethods), diff --git a/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala index f8f1939554..9fbe22a600 100644 --- a/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala +++ b/obp-api/src/main/scala/code/bankconnectors/grpc/GrpcConnector_vFeb2026.scala @@ -60,7 +60,7 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { val errorCodeExample = "INTERNAL-OBP-ADAPTER-6001: ..." //---------------- dynamic start -------------------please don't modify this line -// ---------- created on 2025-06-10T12:05:04Z +// ---------- created on 2026-02-27T05:54:48Z messageDocs += getAdapterInfoDoc def getAdapterInfoDoc = MessageDoc( @@ -335,7 +335,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123))) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string")))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -380,7 +383,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123))) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string")))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -476,7 +482,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123)) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string"))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -518,7 +527,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123)) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string"))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -560,7 +572,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123)) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string"))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -603,7 +618,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123)) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string"))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -641,7 +659,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123))) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string")))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -679,7 +700,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123))) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string")))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -717,7 +741,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123))) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string")))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -755,7 +782,10 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { scaMethod=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SMS), scaStatus=Some(com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.example), authenticationMethodId=Some("string"), - attemptCounter=123)) + attemptCounter=123, + challengePurpose=Some("string"), + challengeContextHash=Some("string"), + challengeContextStructure=Some("string"))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -875,6 +905,79 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { response.map(convertToTuple[List[InboundAccountCommons]](callContext)) } + messageDocs += checkExternalUserCredentialsDoc + def checkExternalUserCredentialsDoc = MessageDoc( + process = "obp.checkExternalUserCredentials", + messageFormat = messageFormat, + description = "Check External User Credentials", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCheckExternalUserCredentials(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + username=usernameExample.value, + password=passwordExample.value) + ), + exampleInboundMessage = ( + InBoundCheckExternalUserCredentials(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= InboundExternalUser(aud=audExample.value, + exp=expExample.value, + iat=iatExample.value, + iss=issExample.value, + sub=subExample.value, + azp=Some("string"), + email=Some(emailExample.value), + emailVerified=Some(emailVerifiedExample.value), + name=Some(userNameExample.value), + userAuthContext=Some(List( BasicUserAuthContext(key=keyExample.value, + value=valueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def checkExternalUserCredentials(username: String, password: String, callContext: Option[CallContext]): Box[InboundExternalUser] = { + import com.openbankproject.commons.dto.{InBoundCheckExternalUserCredentials => InBound, OutBoundCheckExternalUserCredentials => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, username, password) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_check_external_user_credentials", req, callContext) + response.map(convertToTuple[InboundExternalUser](callContext)) + } + + messageDocs += checkExternalUserExistsDoc + def checkExternalUserExistsDoc = MessageDoc( + process = "obp.checkExternalUserExists", + messageFormat = messageFormat, + description = "Check External User Exists", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundCheckExternalUserExists(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + username=usernameExample.value) + ), + exampleInboundMessage = ( + InBoundCheckExternalUserExists(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= InboundExternalUser(aud=audExample.value, + exp=expExample.value, + iat=iatExample.value, + iss=issExample.value, + sub=subExample.value, + azp=Some("string"), + email=Some(emailExample.value), + emailVerified=Some(emailVerifiedExample.value), + name=Some(userNameExample.value), + userAuthContext=Some(List( BasicUserAuthContext(key=keyExample.value, + value=valueExample.value))))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def checkExternalUserExists(username: String, callContext: Option[CallContext]): Box[InboundExternalUser] = { + import com.openbankproject.commons.dto.{InBoundCheckExternalUserExists => InBound, OutBoundCheckExternalUserExists => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, username) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_check_external_user_exists", req, callContext) + response.map(convertToTuple[InboundExternalUser](callContext)) + } + messageDocs += getBankAccountByIbanDoc def getBankAccountByIbanDoc = MessageDoc( process = "obp.getBankAccountByIban", @@ -1545,8 +1648,7 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { startDate=toDate(transactionStartDateExample), finishDate=Some(toDate(transactionFinishDateExample)), balance=BigDecimal(balanceExample.value), - status=Some(transactionStatusExample.value) - ))) + status=Some(transactionStatusExample.value)))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -2561,7 +2663,7 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { inboundTopic = None, exampleOutboundMessage = ( OutBoundCreateTransactionRequestSepaCreditTransfersBGV1(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, - initiator= Some(UserCommons(userPrimaryKey=UserPrimaryKey(123), + initiator=Some( UserCommons(userPrimaryKey=UserPrimaryKey(123), userId=userIdExample.value, idGivenByProvider="string", provider=providerExample.value, @@ -2626,7 +2728,7 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { inboundTopic = None, exampleOutboundMessage = ( OutBoundCreateTransactionRequestPeriodicSepaCreditTransfersBGV1(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, - initiator= Some(UserCommons(userPrimaryKey=UserPrimaryKey(123), + initiator=Some( UserCommons(userPrimaryKey=UserPrimaryKey(123), userId=userIdExample.value, idGivenByProvider="string", provider=providerExample.value, @@ -3411,8 +3513,7 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { exampleInboundMessage = ( InBoundGetProducts(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, status=MessageDocsSwaggerDefinitions.inboundStatus, - data=List( ProductCommons( - bankId=BankId(bankIdExample.value), + data=List( ProductCommons(bankId=BankId(bankIdExample.value), code=ProductCode(productCodeExample.value), parentProductCode=ProductCode(parentProductCodeExample.value), name=productNameExample.value, @@ -3451,8 +3552,7 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { exampleInboundMessage = ( InBoundGetProduct(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, status=MessageDocsSwaggerDefinitions.inboundStatus, - data= ProductCommons( - bankId=BankId(bankIdExample.value), + data= ProductCommons(bankId=BankId(bankIdExample.value), code=ProductCode(productCodeExample.value), parentProductCode=ProductCode(parentProductCodeExample.value), name=productNameExample.value, @@ -3804,6 +3904,39 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { response.map(convertToTuple[List[AtmTCommons]](callContext)) } + messageDocs += getCurrentFxRateDoc + def getCurrentFxRateDoc = MessageDoc( + process = "obp.getCurrentFxRate", + messageFormat = messageFormat, + description = "Get Current Fx Rate", + outboundTopic = None, + inboundTopic = None, + exampleOutboundMessage = ( + OutBoundGetCurrentFxRate(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext, + bankId=BankId(bankIdExample.value), + fromCurrencyCode=fromCurrencyCodeExample.value, + toCurrencyCode=toCurrencyCodeExample.value) + ), + exampleInboundMessage = ( + InBoundGetCurrentFxRate(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, + status=MessageDocsSwaggerDefinitions.inboundStatus, + data= FXRateCommons(bankId=BankId(bankIdExample.value), + fromCurrencyCode=fromCurrencyCodeExample.value, + toCurrencyCode=toCurrencyCodeExample.value, + conversionValue=conversionValueExample.value.toDouble, + inverseConversionValue=inverseConversionValueExample.value.toDouble, + effectiveDate=toDate(effectiveDateExample))) + ), + adapterImplementation = Some(AdapterImplementation("- Core", 1)) + ) + + override def getCurrentFxRate(bankId: BankId, fromCurrencyCode: String, toCurrencyCode: String, callContext: Option[CallContext]): Box[FXRate] = { + import com.openbankproject.commons.dto.{InBoundGetCurrentFxRate => InBound, OutBoundGetCurrentFxRate => OutBound} + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, fromCurrencyCode, toCurrencyCode) + val response: Future[Box[InBound]] = sendRequest[InBound]("obp_get_current_fx_rate", req, callContext) + response.map(convertToTuple[FXRateCommons](callContext)) + } + messageDocs += createTransactionAfterChallengev300Doc def createTransactionAfterChallengev300Doc = MessageDoc( process = "obp.createTransactionAfterChallengev300", @@ -4527,8 +4660,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some(""))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -4580,8 +4713,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some(""))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -4634,8 +4767,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some(""))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -4697,13 +4830,13 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some(""))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) - override def updateCustomerGeneralData(customerId: String, legalName: Option[String], faceImage: Option[CustomerFaceImageTrait], dateOfBirth: Option[Date], relationshipStatus: Option[String], dependents: Option[Int], highestEducationAttained: Option[String], employmentStatus: Option[String], title: Option[String], branchId: Option[String], nameSuffix: Option[String], customerType: Option[String] = None, parentCustomerId: Option[String] = None, callContext: Option[CallContext]): OBPReturnType[Box[Customer]] = { + override def updateCustomerGeneralData(customerId: String, legalName: Option[String], faceImage: Option[CustomerFaceImageTrait], dateOfBirth: Option[Date], relationshipStatus: Option[String], dependents: Option[Int], highestEducationAttained: Option[String], employmentStatus: Option[String], title: Option[String], branchId: Option[String], nameSuffix: Option[String], customerType: Option[String], parentCustomerId: Option[String], callContext: Option[CallContext]): OBPReturnType[Box[Customer]] = { import com.openbankproject.commons.dto.{InBoundUpdateCustomerGeneralData => InBound, OutBoundUpdateCustomerGeneralData => OutBound} val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, customerId, legalName, faceImage, dateOfBirth, relationshipStatus, dependents, highestEducationAttained, employmentStatus, title, branchId, nameSuffix, customerType, parentCustomerId) val response: Future[Box[InBound]] = sendRequest[InBound]("obp_update_customer_general_data", req, callContext) @@ -4747,8 +4880,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some("")))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value)))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -4797,8 +4930,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some(""))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -4848,8 +4981,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some(""))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -5148,8 +5281,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some("")))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value)))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -5199,8 +5332,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some("")))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value)))) ), adapterImplementation = Some(AdapterImplementation("- Core", 1)) ) @@ -5935,8 +6068,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { title=customerTitleExample.value, branchId=branchIdExample.value, nameSuffix=nameSuffixExample.value, - customerType=Some("INDIVIDUAL"), - parentCustomerId=Some("")))) + customerType=Some(customerTypeExample.value), + parentCustomerId=Some(parentCustomerIdExample.value)))) ), exampleInboundMessage = ( InBoundGetCustomerAttributesForCustomers(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext, @@ -6400,8 +6533,7 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { status=MessageDocsSwaggerDefinitions.inboundStatus, data=List( ProductCollectionItemsTree(productCollectionItem= ProductCollectionItemCommons(collectionCode=collectionCodeExample.value, memberProductCode=memberProductCodeExample.value), - product= ProductCommons( - bankId=BankId(bankIdExample.value), + product= ProductCommons(bankId=BankId(bankIdExample.value), code=ProductCode(productCodeExample.value), parentProductCode=ProductCode(parentProductCodeExample.value), name=productNameExample.value, @@ -7325,8 +7457,8 @@ trait GrpcConnector_vFeb2026 extends Connector with MdcLoggable { response.map(convertToTuple[Boolean](callContext)) } -// ---------- created on 2025-06-10T12:05:04Z -//---------------- dynamic end ---------------------please don't modify this line +// ---------- created on 2026-02-27T05:54:48Z +//---------------- dynamic end ---------------------please don't modify this line private val availableOperation = DynamicEntityOperation.values.map(it => s""""$it"""").mkString("[", ", ", "]") From e86ed6710098d185d6ca899957e1ae2b6874469b Mon Sep 17 00:00:00 2001 From: simonredfern Date: Sat, 28 Feb 2026 06:08:11 +0100 Subject: [PATCH 05/19] Adding Get Users With Account Access endpoint --- .../scala/code/api/v6_0_0/APIMethods600.scala | 165 +++++++++++++++++- .../code/api/v6_0_0/JSONFactory6.0.0.scala | 20 +++ 2 files changed, 184 insertions(+), 1 deletion(-) diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 328b832fe9..0203676e00 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -30,7 +30,7 @@ import code.api.v5_0_0.JSONFactory500 import code.api.v5_0_0.{ViewJsonV500, ViewsJsonV500} import code.api.v5_1_0.{JSONFactory510, PostCustomerLegalNameJsonV510} import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo} -import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, CleanupOrphanedDynamicEntityResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, OrphanedDynamicEntityJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PostResetPasswordUrlAnonymousJsonV600, PostResetPasswordCompleteJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, ResetPasswordUrlAnonymousResponseJsonV600, ResetPasswordCompleteResponseJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600} +import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, CleanupOrphanedDynamicEntityResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, OrphanedDynamicEntityJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PostResetPasswordUrlAnonymousJsonV600, PostResetPasswordCompleteJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, ResetPasswordUrlAnonymousResponseJsonV600, ResetPasswordCompleteResponseJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, UserViewAccessJsonV600, UserWithAccountAccessJsonV600, UsersWithAccountAccessJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600} import code.api.v6_0_0.OBPAPI6_0_0 import code.abacrule.{AbacRuleEngine, MappedAbacRuleProvider} import code.metrics.{APIMetrics, ConnectorCountsRedis, ConnectorTraceProvider} @@ -10965,6 +10965,169 @@ trait APIMethods600 { } } + staticResourceDocs += ResourceDoc( + getUsersWithAccountAccess, + implementedInApiVersion, + nameOf(getUsersWithAccountAccess), + "GET", + "/banks/BANK_ID/accounts/ACCOUNT_ID/users-with-access", + "Get Users With Account Access", + s"""Get all users who have access to a specific account, along with their views and access sources. + | + |This endpoint combines both traditional AccountAccess records and ABAC (Attribute-Based Access Control) + |evaluation to provide a complete picture of who can access the account. + | + |Each user entry includes the list of views they can access and how that access was granted + |(either "ACCOUNT_ACCESS" for direct grants or "ABAC" for rule-based access). + | + |Public views are listed separately since they are accessible by everyone. + | + |Authentication is Required + | + |""".stripMargin, + EmptyBody, + UsersWithAccountAccessJsonV600( + users = List(UserWithAccountAccessJsonV600( + user_id = ExampleValue.userIdExample.value, + username = "robert.x.smith.test", + email = "robert.x@example.com", + provider = "https://apisandbox.openbankproject.com", + views = List(UserViewAccessJsonV600( + view_id = "owner", + access_source = "ACCOUNT_ACCESS" + )) + )), + has_public_view = false, + public_views = List.empty[String], + abac_enabled = false + ), + List( + $BankNotFound, + BankAccountNotFound, + UnknownError + ), + List(apiTagAccount, apiTagView), + Some(List(canSeeAccountAccessForAnyUser)) + ) + + lazy val getUsersWithAccountAccess: OBPEndpoint = { + case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "users-with-access" :: Nil JsonGet _ => { + cc => implicit val ec = EndpointContext(Some(cc)) + for { + (Full(u), callContext) <- authenticatedAccess(cc) + (_, callContext) <- NewStyle.function.getBank(bankId, callContext) + (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext) + bankIdAccountId = BankIdAccountId(bankId, accountId) + + // Step A: Get all views for the account, split into public and private + allViews <- Future(Views.views.vend.assignedViewsForAccount(bankIdAccountId)) + publicViewIds = allViews.filter(_.isPublic).map(_.viewId.value) + privateViews = allViews.filter(_.isPrivate) + + // Step B: Get traditional AccountAccess permissions (all users with direct access) + permissions <- Future(Views.views.vend.permissions(bankIdAccountId)) + accountAccessResults = permissions.map { perm => + val privateViewAccesses = perm.views.filter(_.isPrivate).map { v => + UserViewAccessJsonV600( + view_id = v.viewId.value, + access_source = "ACCOUNT_ACCESS" + ) + } + perm.user.userId -> (perm.user, privateViewAccesses) + }.toMap + + // Step C: ABAC evaluation (only if enabled) + abacEnabled = allowAbacAccountAccess + abacResults <- { + if (!abacEnabled || privateViews.isEmpty) { + Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) + } else { + // Find users with CanExecuteAbacRule entitlement + val abacEntitlements = Entitlement.entitlement.vend.getEntitlementsByRole(canExecuteAbacRule.toString) + .getOrElse(Nil) + val abacUserIds = abacEntitlements.map(_.userId).distinct + + if (abacUserIds.isEmpty) { + Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) + } else { + for { + abacUsers <- Users.users.vend.getUsersByUserIdsFuture(abacUserIds) + abacUserMap = abacUsers.map(u => u.userId -> u).toMap + + // For each (user, view) pair, skip if already has AccountAccess, otherwise evaluate ABAC + evaluationPairs = for { + user <- abacUsers + view <- privateViews + existingViews = accountAccessResults.get(user.userId).map(_._2).getOrElse(Nil) + if !existingViews.exists(_.view_id == view.viewId.value) + } yield (user, view) + + abacEvaluations <- Future.sequence( + evaluationPairs.map { case (user, view) => + callContext match { + case Some(cc) => + AbacRuleEngine.executeRulesByPolicyDetailed( + policy = ABAC_POLICY_ACCOUNT_ACCESS, + authenticatedUserId = user.userId, + callContext = cc, + bankId = Some(bankId.value), + accountId = Some(accountId.value), + viewId = Some(view.viewId.value) + ).map { + case Full((true, _)) => Some((user, view)) + case _ => None + }.recover { case _ => None } + case None => + Future.successful(None) + } + } + ) + + passingPairs = abacEvaluations.flatten + } yield { + passingPairs.groupBy(_._1.userId).map { case (userId, pairs) => + val user = pairs.head._1 + val viewAccesses = pairs.map { case (_, view) => + UserViewAccessJsonV600( + view_id = view.viewId.value, + access_source = "ABAC" + ) + } + userId -> (user, viewAccesses) + } + } + } + } + } + } yield { + // Step D: Merge accountAccessResults + abacResults by userId + val allUserIds = (accountAccessResults.keySet ++ abacResults.keySet).toList + val mergedUsers = allUserIds.map { userId => + val (user, views1) = accountAccessResults.getOrElse(userId, { + val (u, _) = abacResults(userId) + (u, Nil) + }) + val views2 = abacResults.get(userId).map(_._2).getOrElse(Nil) + UserWithAccountAccessJsonV600( + user_id = user.userId, + username = user.name, + email = user.emailAddress, + provider = user.provider, + views = views1 ++ views2 + ) + }.filter(_.views.nonEmpty) + + val response = UsersWithAccountAccessJsonV600( + users = mergedUsers, + has_public_view = publicViewIds.nonEmpty, + public_views = publicViewIds, + abac_enabled = abacEnabled + ) + (response, HttpCode.`200`(callContext)) + } + } + } + } } diff --git a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala index 8038a00059..7c2b6298ce 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala @@ -2415,4 +2415,24 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable { abac_rule_id: String ) + case class UserViewAccessJsonV600( + view_id: String, + access_source: String // "ACCOUNT_ACCESS" or "ABAC" + ) + + case class UserWithAccountAccessJsonV600( + user_id: String, + username: String, + email: String, + provider: String, + views: List[UserViewAccessJsonV600] + ) + + case class UsersWithAccountAccessJsonV600( + users: List[UserWithAccountAccessJsonV600], + has_public_view: Boolean, + public_views: List[String], + abac_enabled: Boolean + ) + } From cf43f7b5ed0effdd6229fd00e84ece86a951186d Mon Sep 17 00:00:00 2001 From: simonredfern Date: Sat, 28 Feb 2026 06:14:26 +0100 Subject: [PATCH 06/19] Updating README regarding use of http4s and liftweb --- LIFT_HTTP4S_COEXISTENCE.md | 1014 +++--------------------------------- README.md | 35 +- 2 files changed, 89 insertions(+), 960 deletions(-) diff --git a/LIFT_HTTP4S_COEXISTENCE.md b/LIFT_HTTP4S_COEXISTENCE.md index 33d41adb38..2d171cfe8f 100644 --- a/LIFT_HTTP4S_COEXISTENCE.md +++ b/LIFT_HTTP4S_COEXISTENCE.md @@ -1,973 +1,103 @@ -# Lift and http4s Coexistence Strategy +# Architecture: http4s and Lift Coexistence -## Question -Can http4s and Lift coexist in the same project to convert endpoints one by one? +## Current State -## Answer: Yes, on Different Ports +OBP-API runs as a **single http4s Ember server** (single process, single port). The application entry point is a Cats Effect `IOApp` (`Http4sServer`). Lift is no longer used as an HTTP server — Jetty and the servlet container have been removed. -## OBP-API-Dispatch +Lift still plays two roles: -OBP-API-Dispatch already exists: +1. **ORM / Database** — Lift Mapper manages schema creation, migrations, and data access. +2. **Legacy endpoint dispatch** — Older API versions are handled through a bridge (`Http4sLiftWebBridge`) that converts http4s requests into Lift requests, runs them through Lift's dispatch tables, and converts the responses back. -- **Location:** `workspace_2024/OBP-API-Dispatch` -- **GitHub:** https://github.com/OpenBankProject/OBP-API-Dispatch -- **Technology:** http4s (Cats Effect 3, Ember server) -- **Purpose:** Routes requests between different OBP-API backends -- **Current routing:** Based on API version (v1.3.0 → backend 2, others → backend 1) +New API versions are implemented as native http4s routes and do not pass through the Lift bridge. -It needs minor enhancements to support version-based routing for the Lift → http4s migration. +## How It Works -## Answers to Your Three Questions +### Entry Point — `Http4sServer.scala` -### Q1: Could we use OBP-API-Dispatch to route between two ports? +`Http4sServer` extends `IOApp`. On startup it: -**YES - it already exists** +1. Calls `bootstrap.liftweb.Boot().boot()` to initialise Lift Mapper, connectors, and OBP configuration. +2. Parses the configured `hostname` and `dev.port` props (defaults: `127.0.0.1`, `8080`). +3. Starts an http4s Ember server with the application defined in `Http4sApp.httpApp`. -OBP-API-Dispatch can be used for this: -- Single entry point for clients -- Route by API version: v4/v5 → Lift, v6/v7 → http4s (might want to route based on resource docs but not sure if we really need this - NGINX might therefore be an alternative but OBP-Dispatch would have OBP specific routing out of the box and potentially other features) -- No client configuration changes needed -- Rollback by changing routing config +### Priority Routing — `Http4sApp.scala` -### Q2: Running http4s in Jetty until migration complete? +`Http4sApp` builds the `HttpApp[IO]` that the Ember server uses. Routes are tried in priority order: -**Possible but not recommended** +| Priority | Routes | Source | +|----------|--------|--------| +| 1 | v5.0.0 native http4s endpoints | `Http4s500.wrappedRoutesV500Services` | +| 2 | v7.0.0 native http4s endpoints | `Http4s700.wrappedRoutesV700Services` | +| 3 | Berlin Group v2 endpoints | `Http4sBGv2.wrappedRoutes` | +| 4 | **Lift bridge fallback** | `Http4sLiftWebBridge.routes` | -Running http4s in Jetty (servlet mode) loses: -- True non-blocking I/O -- HTTP/2, WebSockets, efficient streaming -- Would need to refactor again later to standalone +If none of the above match, a 404 is returned. The routing uses `OptionT`-based `orElse` chaining so that each layer can decline a request and pass it to the next. -Use standalone http4s on port 8081 from the start. +Standard security headers (Cache-Control, X-Frame-Options, Correlation-Id, etc.) are applied to every response via `Http4sLiftWebBridge.withStandardHeaders`. -### Q3: How would the developer experience be? +### Lift Bridge — `Http4sLiftWebBridge.scala` -**IDE and Project Setup:** +The bridge handles any request that is not matched by a native http4s route. It: -You'll work in **one IDE window** with the OBP-API codebase: -- Same project structure -- Same database (Lift Boot continues to handle DB creation/migrations) -- Both Lift and http4s code in the same `obp-api` module -- Edit both Lift endpoints and http4s endpoints in the same IDE +1. Reads the http4s request body. +2. Constructs a Lift `Req` object from the http4s `Request[IO]`. +3. Creates a stateless Lift session. +4. Initialises a Lift `S` context and runs `LiftRules.statelessDispatch` / `LiftRules.dispatch` handlers. +5. Handles Lift's `ContinuationException` pattern for async responses (configurable timeout via `http4s.continuation.timeout.ms`, default 60 s). +6. Converts the Lift response back to an http4s `Response[IO]`. -**Running the Servers:** - -You'll run **three separate terminal processes**: - -**Terminal 1: Lift Server (existing)** -```bash -cd workspace_2024/OBP-API-C/OBP-API -sbt "project obp-api" run -``` -- Runs Lift Boot (handles DB initialization) -- Starts on port 8080 -- Keep this running as long as you have Lift endpoints - -**Terminal 2: http4s Server (new)** -```bash -cd workspace_2024/OBP-API-C/OBP-API -sbt "project obp-api" "runMain code.api.http4s.Http4sMain" -``` -- Starts on port 8081 -- Separate process from Lift -- Uses same database connection pool - -**Terminal 3: OBP-API-Dispatch (separate project)** -```bash -cd workspace_2024/OBP-API-Dispatch -mvn clean package -java -jar target/OBP-API-Dispatch-1.0-SNAPSHOT-jar-with-dependencies.jar -``` -- Separate IDE window or just a terminal -- Routes requests between Lift (8080) and http4s (8081) -- Runs on port 8088 - -**Editing Workflow:** - -1. **Adding new http4s endpoint:** - - Create endpoint in `obp-api/src/main/scala/code/api/http4s/` - - Edit in same IDE as Lift code - - Restart Terminal 2 only (http4s server) - -2. **Fixing Lift endpoint:** - - Edit existing Lift code in `obp-api/src/main/scala/code/api/` - - Restart Terminal 1 only (Lift server) - -3. **Updating routing (which endpoints go where):** - - Edit `OBP-API-Dispatch/src/main/resources/application.conf` - - Restart Terminal 3 only (Dispatch) - -**Database:** - -Lift Boot continues to handle: -- Database connection setup -- Schema migrations -- Table creation - -Both Lift and http4s use the same database connection pool and Mapper classes. - -### Architecture with OBP-API-Dispatch - -``` -┌────────────────────────────────────────────┐ -│ API Clients │ -└────────────────────────────────────────────┘ - ↓ - Port 8088/443 - ↓ -┌────────────────────────────────────────────┐ -│ OBP-API-Dispatch (http4s) │ -│ │ -│ Routing Rules: │ -│ • /obp/v4.0.0/* → Lift (8080) │ -│ • /obp/v5.0.0/* → Lift (8080) │ -│ • /obp/v5.1.0/* → Lift (8080) │ -│ • /obp/v6.0.0/* → http4s (8081) ✨ │ -│ • /obp/v7.0.0/* → http4s (8081) ✨ │ -└────────────────────────────────────────────┘ - ↓ ↓ - ┌─────────┐ ┌─────────┐ - │ Lift │ │ http4s │ - │ :8080 │ │ :8081 │ - └─────────┘ └─────────┘ - ↓ ↓ - ┌────────────────────────────────┐ - │ Shared Resources: │ - │ - Database │ - │ - Business Logic │ - │ - Authentication │ - │ - ResourceDocs │ - └────────────────────────────────┘ -``` - -### How It Works - -1. **Two HTTP Servers Running Simultaneously** - - Lift/Jetty continues on port 8080 - - http4s starts on port 8081 - - Both run in the same JVM process - -2. **Shared Components** - - Database connections - - Business logic layer - - Authentication/authorization - - Configuration - - Connector layer - -3. **Gradual Migration** - - Start: All endpoints on Lift (port 8080) - - During: Some on Lift, some on http4s - - End: All on http4s (port 8081), Lift removed - -## Using OBP-API-Dispatch for Routing - -### Current Status - -OBP-API-Dispatch already exists and is functional: -- **Location:** `workspace_2024/OBP-API-Dispatch` -- **GitHub:** https://github.com/OpenBankProject/OBP-API-Dispatch -- **Build:** Maven-based -- **Technology:** http4s with Ember server -- **Current routing:** Routes v1.3.0 to backend 2, others to backend 1 - -### Current Configuration - -```hocon -# application.conf -app { - dispatch_host = "127.0.0.1" - dispatch_dev_port = 8088 - obp_api_1_base_uri = "http://localhost:8080" - obp_api_2_base_uri = "http://localhost:8086" -} -``` - -### Enhancement for Migration - -Update configuration to support version-based routing: - -```hocon -# application.conf -app { - dispatch_host = "0.0.0.0" - dispatch_port = 8088 - - # Lift backend (legacy endpoints) - lift_backend_uri = "http://localhost:8080" - lift_backend_uri = ${?LIFT_BACKEND_URI} - - # http4s backend (modern endpoints) - http4s_backend_uri = "http://localhost:8081" - http4s_backend_uri = ${?HTTP4S_BACKEND_URI} - - # Routing strategy - routing { - # API versions that go to http4s backend - http4s_versions = ["v6.0.0", "v7.0.0"] - - # Specific endpoint overrides (optional) - overrides = [ - # Example: migrate specific v5.1.0 endpoints early - # { path = "/obp/v5.1.0/banks", target = "http4s" } - ] - } -} -``` - -### Enhanced Routing Logic - -Update `ObpApiDispatch.scala` to support version-based routing: - -```scala -private def selectBackend(path: String, method: Method): String = { - // Extract API version from path: /obp/v{version}/... - val versionPattern = """/obp/(v\d+\.\d+\.\d+)/.*""".r - - path match { - case versionPattern(version) => - if (http4sVersions.contains(version)) { - logger.info(s"Version $version routed to http4s") - "http4s" - } else { - logger.info(s"Version $version routed to Lift") - "lift" - } - case _ => - logger.debug(s"Path $path routing to Lift (default)") - "lift" - } -} -``` - -### Local Development Workflow - -**Terminal 1: Start Lift** -```bash -cd workspace_2024/OBP-API-C/OBP-API -sbt "project obp-api" run -# Starts on port 8080 -``` - -**Terminal 2: Start http4s** -```bash -cd workspace_2024/OBP-API-C/OBP-API -sbt "project obp-api" "runMain code.api.http4s.Http4sMain" -# Starts on port 8081 -``` - -**Terminal 3: Start OBP-API-Dispatch** -```bash -cd workspace_2024/OBP-API-Dispatch -mvn clean package -java -jar target/OBP-API-Dispatch-1.0-SNAPSHOT-jar-with-dependencies.jar -# Starts on port 8088 -``` - -**Terminal 4: Test** -```bash -# Old endpoint (goes to Lift) -curl http://localhost:8088/obp/v5.1.0/banks - -# New endpoint (goes to http4s) -curl http://localhost:8088/obp/v6.0.0/banks - -# Health checks -curl http://localhost:8088/health -``` - -## Implementation Approach - -### Step 1: Add http4s to Project - -```scala -// build.sbt -libraryDependencies ++= Seq( - "org.http4s" %% "http4s-dsl" % "0.23.x", - "org.http4s" %% "http4s-ember-server" % "0.23.x", - "org.http4s" %% "http4s-ember-client" % "0.23.x", - "org.http4s" %% "http4s-circe" % "0.23.x" -) -``` - -### Step 2: Create http4s Server - -```scala -// code/api/http4s/Http4sServer.scala -package code.api.http4s - -import cats.effect._ -import org.http4s.ember.server.EmberServerBuilder -import com.comcast.ip4s._ - -object Http4sServer { - - def start(port: Int = 8081): IO[Unit] = { - EmberServerBuilder - .default[IO] - .withHost(ipv4"0.0.0.0") - .withPort(Port.fromInt(port).get) - .withHttpApp(routes.orNotFound) - .build - .useForever - } - - def routes = ??? // Define routes here -} -``` - -### Step 3: THE JETTY PROBLEM - -If you start http4s from Lift's Bootstrap, it runs INSIDE Jetty's servlet container. This defeats the purpose of using http4s. - -``` -❌ WRONG APPROACH: -┌─────────────────────────────┐ -│ Jetty Servlet Container │ -│ ├─ Lift (port 8080) │ -│ └─ http4s (port 8081) │ ← Still requires Jetty -└─────────────────────────────┘ -``` - -**The Problem:** -- http4s would still require Jetty to run -- Can't remove servlet container later -- Defeats the goal of eliminating Jetty - -### Step 3: CORRECT APPROACH - Separate Main - -**Solution:** Start http4s as a STANDALONE server, NOT from Lift Bootstrap. - -``` -✓ CORRECT APPROACH: -┌──────────────────┐ ┌─────────────────┐ -│ Jetty Container │ │ http4s Server │ -│ └─ Lift │ │ (standalone) │ -│ Port 8080 │ │ Port 8081 │ -└──────────────────┘ └─────────────────┘ - Same JVM Process -``` - -#### Option A: Two Separate Processes (Simpler) - -```scala -// Run Lift as usual -sbt "jetty:start" // Port 8080 - -// Run http4s separately -sbt "runMain code.api.http4s.Http4sMain" // Port 8081 -``` - -**Deployment:** -```bash -# Start Lift/Jetty -java -jar obp-api-jetty.jar & - -# Start http4s standalone -java -jar obp-api-http4s.jar & -``` - -**Pros:** -- Complete separation -- Easy to understand -- Can stop/restart independently -- No Jetty dependency for http4s - -**Cons:** -- Two separate processes to manage -- Two JVMs (more memory) - -### Two Separate Processes - -For actual migration: - -1. **Keep Lift/Jetty running as-is** on port 8080 -2. **Create standalone http4s server** on port 8081 with its own Main class -3. **Use reverse proxy** (nginx/HAProxy) to route requests -4. **Migrate endpoints one by one** to http4s -5. **Eventually remove Lift/Jetty** completely - -``` -Phase 1-3 (Migration): -┌─────────────┐ -│ Nginx │ Port 443 -│ (Proxy) │ -└──────┬──────┘ - │ - ├──→ Jetty/Lift (Process 1) Port 8080 ← Old endpoints - └──→ http4s standalone (Process 2) Port 8081 ← New endpoints - -Phase 4 (Complete): -┌─────────────┐ -│ Nginx │ Port 443 -│ (Proxy) │ -└──────┬──────┘ - │ - └──→ http4s standalone Port 8080 ← All endpoints - (Jetty removed) ``` - -**This way http4s is NEVER dependent on Jetty.** - -### Is http4s Non-Blocking? - -**YES - http4s is fully non-blocking and asynchronous.** - -#### Architecture Comparison - -**Lift/Jetty (Blocking):** -``` -Thread-per-request model: -┌─────────────────────────────┐ -│ Request 1 → Thread 1 (busy) │ Blocks waiting for DB -│ Request 2 → Thread 2 (busy) │ Blocks waiting for HTTP call -│ Request 3 → Thread 3 (busy) │ Blocks waiting for file I/O -│ Request 4 → Thread 4 (busy) │ -│ ... │ -│ Request N → Thread pool full │ ← New requests wait -└─────────────────────────────┘ - -Problem: -- 1 thread per request -- Thread blocks on I/O -- Limited by thread pool size (e.g., 200 threads) -- More requests = more memory -``` - -**http4s (Non-Blocking):** +HTTP Request + | + v +Http4sServer (IOApp / Ember) + | + v +Http4sApp.httpApp — priority router + standard headers + | + |---> v5.0.0 native routes + |---> v7.0.0 native routes + |---> Berlin Group v2 routes + |---> Http4sLiftWebBridge (fallback) + | | + | +---> Lift statelessDispatch handlers + | +---> Lift dispatch handlers (REST API) + | + v +HTTP Response (with standard headers) ``` -Async/Effect model: -┌─────────────────────────────┐ -│ Thread 1: │ -│ Request 1 → DB call (IO) │ ← Doesn't block - Fiber suspended -│ Request 2 → API call (IO) │ ← Continues processing -│ Request 3 → Processing │ -│ Request N → ... │ -└─────────────────────────────┘ -Benefits: -- Few threads (typically = CPU cores) -- Thousands of concurrent requests -- Much lower memory usage -- Scales better -``` +## What Lift Still Does -#### Performance Impact +| Area | Role | +|------|------| +| **Mapper ORM** | Database schema creation, migrations, and all data access (`MappedBank`, `AuthUser`, etc.) | +| **Boot** | `bootstrap.liftweb.Boot` initialises OBP configuration, connectors, resource docs, and Mapper schemifier | +| **Dispatch tables** | `LiftRules.statelessDispatch` / `LiftRules.dispatch` hold the endpoint definitions for API versions not yet ported to native http4s | +| **JSON utilities** | Some serialisation helpers from `net.liftweb.json` are still in use | -**Lift/Jetty:** -- 200 threads × ~1MB stack = ~200MB just for threads -- Max ~200 concurrent blocking requests -- Each blocked thread = wasted resources +## Why http4s? -**http4s:** -- 8 threads (on 8-core machine) × ~1MB = ~8MB for threads -- Can handle 10,000+ concurrent requests -- Threads never block, always doing work +- **Non-blocking I/O** — http4s with Cats Effect uses a small, fixed thread pool (typically equal to CPU cores) and suspends fibres on I/O instead of blocking threads. This allows thousands of concurrent requests without thread-pool tuning. +- **Lower memory** — No thread-per-request overhead. +- **Modern Scala ecosystem** — First-class support for Cats Effect, fs2 streaming, and functional programming patterns. +- **No servlet container** — Removes the Jetty dependency and WAR packaging. -#### Code Example - Blocking vs Non-Blocking +## Future Direction -**Lift (Blocking):** -```scala -// This BLOCKS the thread while waiting for DB -lazy val getBank: OBPEndpoint = { - case "banks" :: bankId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - // Thread blocks here waiting for database - bank <- Future { Connector.connector.vend.getBank(BankId(bankId)) } - } yield { - (bank, HttpCode.`200`(cc)) - } - } -} +The plan is to gradually port remaining Lift-dispatched endpoints to native http4s routes. As each API version is migrated: -// Under the hood: -// Thread 1: Wait for DB... (blocked, not doing anything else) -// Thread 2: Wait for DB... (blocked) -// Thread 3: Wait for DB... (blocked) -// Eventually: No threads left → requests queue up -``` +1. New native http4s routes are added to `Http4sApp` at a higher priority than the bridge. +2. The corresponding Lift dispatch registrations can be removed. +3. Once all endpoints are native, the Lift bridge and Lift dispatch dependencies can be removed entirely (Lift Mapper may remain for ORM). -**http4s (Non-Blocking):** -```scala -// This NEVER blocks - thread is freed while waiting -def getBank[F[_]: Concurrent](bankId: String): F[Response[F]] = { - for { - // Thread is released while waiting for DB - // Can handle other requests in the meantime - bank <- getBankFromDB(bankId) // Returns F[Bank], doesn't block - response <- Ok(bank.asJson) - } yield response -} +## Running -// Under the hood: -// Thread 1: Start DB call → release thread → handle other requests -// DB returns → pick up continuation → send response -// Same thread handles 100s of requests while others wait for I/O +```sh +MAVEN_OPTS="-Xms3G -Xmx6G -XX:MaxMetaspaceSize=2G" \ + mvn -pl obp-api -am clean package -DskipTests=true -Dmaven.test.skip=true && \ + java -jar obp-api/target/obp-api.jar ``` -#### Real-World Impact - -**Scenario:** 1000 concurrent requests, each needs 100ms of DB time - -**Lift/Jetty (200 thread pool):** -- First 200 requests: start immediately -- Requests 201-1000: wait in queue -- Total time: ~500ms (because of queuing) -- Memory: 200MB for threads - -**http4s (8 threads):** -- All 1000 requests: start immediately -- Process concurrently on 8 threads -- Total time: ~100ms (no queuing) -- Memory: 8MB for threads - -#### Why This Matters for Migration - -1. **Better Resource Usage** - - Same machine can handle more requests - - Lower memory footprint - - Can scale vertically better - -2. **No Thread Pool Tuning** - - Lift: Need to tune thread pool size (too small = slow, too large = OOM) - - http4s: Set to CPU cores, done - -3. **Database Connections** - - Lift: Need thread pool ≤ DB connections (e.g., 200 threads = 200 DB connections) - - http4s: 8 threads can share smaller DB pool (e.g., 20 connections) - -4. **Modern Architecture** - - http4s uses cats-effect (like Akka, ZIO, Monix) - - Industry standard for Scala backends - - Better ecosystem and tooling - -#### The Blocking Problem in Current OBP-API - -```scala -// Common pattern in OBP-API - BLOCKS thread -for { - bank <- Future { /* Get from DB - BLOCKS */ } - accounts <- Future { /* Get from DB - BLOCKS */ } - transactions <- Future { /* Get from Connector - BLOCKS */ } -} yield result - -// Each Future ties up a thread waiting -// If 200 requests do this, 200 threads blocked -``` - -#### http4s Solution - Truly Async - -```scala -// Non-blocking version -for { - bank <- IO { /* Get from DB - thread released */ } - accounts <- IO { /* Get from DB - thread released */ } - transactions <- IO { /* Get from Connector - thread released */ } -} yield result - -// IO suspends computation, releases thread -// Thread can handle other work while waiting -// 8 threads can handle 1000s of these concurrently -``` - -### Conclusion on Non-Blocking - -**Yes, http4s is non-blocking and this is a MAJOR reason to migrate:** - -- Better performance (10-50x more concurrent requests) -- Lower memory usage -- Better resource utilization -- Scales much better -- Removes need for thread pool tuning - -**However:** To get full benefits, you'll need to: -1. Use `IO` or `F[_]` instead of blocking `Future` -2. Use non-blocking database libraries (Doobie, Skunk) -3. Use non-blocking HTTP clients (http4s client) - -But the migration can be gradual - even blocking code in http4s is still better than Lift/Jetty's servlet model. - -### Step 4: Shared Business Logic - -```scala -// Keep business logic separate from HTTP layer -package code.api.service - -object UserService { - // Pure business logic - no Lift or http4s dependencies - def createUser(username: String, email: String, password: String): Box[User] = { - // Implementation - } -} - -// Use in Lift endpoint -class LiftEndpoints extends RestHelper { - serve("obp" / "v6.0.0" prefix) { - case "users" :: Nil JsonPost json -> _ => { - val result = UserService.createUser(...) - // Return Lift response - } - } -} - -// Use in http4s endpoint -class Http4sEndpoints[F[_]: Concurrent] { - def routes: HttpRoutes[F] = HttpRoutes.of[F] { - case req @ POST -> Root / "obp" / "v6.0.0" / "users" => - val result = UserService.createUser(...) - // Return http4s response - } -} -``` - -## Migration Strategy - -### Phase 1: Setup -- Add http4s dependencies -- Create http4s server infrastructure -- Start http4s on port 8081 -- Keep all endpoints on Lift - -### Phase 2: Convert New Endpoints -- All NEW endpoints go to http4s only -- Existing endpoints stay on Lift -- Share business logic between both - -### Phase 3: Migrate Existing Endpoints -Priority order: -1. Simple GET endpoints (read-only, no sessions) -2. POST endpoints with simple authentication -3. Endpoints with complex authorization -4. Admin/management endpoints -5. OAuth/authentication endpoints (last) - -### Phase 4: Deprecation -- Announce Lift endpoints deprecated -- Run both servers (port 8080 and 8081) -- Redirect/proxy 8080 -> 8081 -- Update documentation - -### Phase 5: Removal -- Remove Lift dependencies -- Remove Jetty dependency -- Single http4s server on port 8080 -- No servlet container needed - -## Request Routing During Migration - -### OBP-API-Dispatch - -``` -Clients → OBP-API-Dispatch (8088/443) - ├─→ Lift (8080) - v4, v5, v5.1 - └─→ http4s (8081) - v6, v7 -``` - -**OBP-API-Dispatch:** -- Already exists in workspace -- Already http4s-based -- Designed for routing between backends -- Has error handling, logging -- Needs routing logic updates -- Single entry point -- Route by version or endpoint - -**Migration Phases:** - -**Phase 1: Setup** -```hocon -routing { - http4s_versions = [] # All traffic to Lift -} -``` - -**Phase 2: First Migration** -```hocon -routing { - http4s_versions = ["v6.0.0"] # v6 to http4s -} -``` - -**Phase 3: Progressive** -```hocon -routing { - http4s_versions = ["v5.1.0", "v6.0.0", "v7.0.0"] -} -``` - -**Phase 4: Complete** -```hocon -routing { - http4s_versions = ["v4.0.0", "v5.0.0", "v5.1.0", "v6.0.0", "v7.0.0"] -} -``` - -### Alternative: Two Separate Ports - -``` -Clients → Load Balancer - ├─→ Port 8080 (Lift) - └─→ Port 8081 (http4s) -``` -Clients need to know which port to use - -## Database Access Migration - -### Current: Lift Mapper -```scala -class AuthUser extends MegaProtoUser[AuthUser] { - // Mapper ORM -} -``` - -### During Migration: Keep Mapper -```scala -// Both Lift and http4s use Mapper -// No need to migrate DB layer immediately -import code.model.dataAccess.AuthUser - -// In http4s endpoint -def getUser(id: String): IO[Option[User]] = IO { - AuthUser.find(By(AuthUser.id, id)).map(_.toUser) -} -``` - -### Future: Replace Mapper (Optional) -```scala -// Use Doobie or Skunk -import doobie._ -import doobie.implicits._ - -def getUser(id: String): ConnectionIO[Option[User]] = { - sql"SELECT * FROM authuser WHERE id = $id" - .query[User] - .option -} -``` - -## Configuration - -```properties -# props/default.props - -# Enable http4s server -http4s.enabled=true -http4s.port=8081 - -# Lift/Jetty (keep running) -jetty.port=8080 - -# Migration mode -# - "dual" = both servers running -# - "http4s-only" = only http4s -migration.mode=dual -``` - -## Testing Strategy - -### Test Both Implementations -```scala -class UserEndpointTest extends ServerSetup { - - // Test Lift version - scenario("Create user via Lift (port 8080)") { - val request = (v6_0_0_Request / "users").POST - val response = makePostRequest(request, userJson) - response.code should equal(201) - } - - // Test http4s version - scenario("Create user via http4s (port 8081)") { - val request = (http4s_v6_0_0_Request / "users").POST - val response = makePostRequest(request, userJson) - response.code should equal(201) - } - - // Test both give same result - scenario("Both implementations return same result") { - val liftResult = makeLiftRequest(...) - val http4sResult = makeHttp4sRequest(...) - liftResult should equal(http4sResult) - } -} -``` - -## Resource Docs Compatibility - -### Keep Same ResourceDoc Structure -```scala -// Shared ResourceDoc definition -val createUserDoc = ResourceDoc( - createUser, - implementedInApiVersion, - "createUser", - "POST", - "/users", - "Create User", - """Creates a new user...""", - postUserJson, - userResponseJson, - List(UserNotLoggedIn, InvalidJsonFormat) -) - -// Lift endpoint references it -lazy val createUserLift: OBPEndpoint = { - case "users" :: Nil JsonPost json -> _ => { - // implementation - } -} - -// http4s endpoint references same doc -def createUserHttp4s[F[_]: Concurrent]: HttpRoutes[F] = { - case req @ POST -> Root / "users" => { - // implementation - } -} -``` - -## Advantages of Coexistence Approach - -1. **Zero Downtime Migration** - - Old endpoints keep working - - New endpoints added incrementally - - No big-bang rewrite - -2. **Risk Mitigation** - - Test new framework alongside old - - Easy rollback per endpoint - - Gradual learning curve - -3. **Business Continuity** - - No disruption to users - - Features can still be added - - Migration in background - -4. **Shared Resources** - - Same database - - Same business logic - - Same configuration - - - -## Challenges and Solutions - -### Challenge 1: Port Management -**Solution:** Use property files to configure ports, allow override - -### Challenge 2: Session/State Sharing -**Solution:** Use stateless JWT tokens, shared Redis for sessions - -### Challenge 3: Authentication -**Solution:** Keep auth logic separate, callable from both frameworks - -### Challenge 4: Database Connections -**Solution:** Shared connection pool, configure max connections appropriately - -### Challenge 5: Monitoring -**Solution:** Separate metrics for each server, aggregate in monitoring system - -### Challenge 6: Deployment -**Solution:** Single JAR with both servers, configure which to start - -## Deployment Considerations - -### Development -```bash -# Start with both servers -sbt run -# Lift on :8080, http4s on :8081 -``` - -### Production - Transition Period -``` -# Run both servers -java -Dhttp4s.enabled=true \ - -Dhttp4s.port=8081 \ - -Djetty.port=8080 \ - -jar obp-api.jar -``` - -### Production - After Migration -``` -# Only http4s -java -Dhttp4s.enabled=true \ - -Dhttp4s.port=8080 \ - -Dlift.enabled=false \ - -jar obp-api.jar -``` - -## Example: First Endpoint Migration - -### 1. Existing Lift Endpoint -```scala -// APIMethods600.scala -lazy val getBank: OBPEndpoint = { - case "banks" :: bankId :: Nil JsonGet _ => { - cc => implicit val ec = EndpointContext(Some(cc)) - for { - bank <- Future { Connector.connector.vend.getBank(BankId(bankId)) } - } yield { - (bank, HttpCode.`200`(cc)) - } - } -} -``` - -### 2. Create http4s Version -```scala -// code/api/http4s/endpoints/BankEndpoints.scala -class BankEndpoints[F[_]: Concurrent] { - - def routes: HttpRoutes[F] = HttpRoutes.of[F] { - case GET -> Root / "obp" / "v6.0.0" / "banks" / bankId => - // Same business logic - val bankBox = Connector.connector.vend.getBank(BankId(bankId)) - - bankBox match { - case Full(bank) => Ok(bank.toJson) - case Empty => NotFound() - case Failure(msg, _, _) => BadRequest(msg) - } - } -} -``` - -### 3. Both Available -- Lift: `http://localhost:8080/obp/v6.0.0/banks/{bankId}` -- http4s: `http://localhost:8081/obp/v6.0.0/banks/{bankId}` - -### 4. Test Both -```scala -scenario("Get bank - Lift version") { - val response = makeGetRequest(v6_0_0_Request / "banks" / testBankId.value) - response.code should equal(200) -} - -scenario("Get bank - http4s version") { - val response = makeGetRequest(http4s_v6_0_0_Request / "banks" / testBankId.value) - response.code should equal(200) -} -``` - -### 5. Deprecate Lift Version -- Add deprecation warning to Lift endpoint -- Update docs to point to http4s version -- Monitor usage - -### 6. Remove Lift Version -- Delete Lift endpoint code -- All traffic to http4s - -## Conclusion - -**Yes, Lift and http4s can coexist** by running on different ports (8080 and 8081) within the same application. This allows for: - -- Gradual, low-risk migration -- Endpoint-by-endpoint conversion -- Shared business logic and resources -- Zero downtime -- Flexible migration pace - -The key is to **keep HTTP layer separate from business logic** so both frameworks can call the same underlying functions. - -Start with simple read-only endpoints, then gradually migrate more complex ones, finally removing Lift when all endpoints are converted. +The server binds to the `hostname` / `dev.port` values in your props file (defaults: `127.0.0.1:8080`). diff --git a/README.md b/README.md index 2099a44f08..ea4e4ea0d1 100644 --- a/README.md +++ b/README.md @@ -211,9 +211,9 @@ db.driver=org.h2.Driver db.url=jdbc:h2:./obp_api.db;DB_CLOSE_ON_EXIT=FALSE ``` -In order to start H2 web console go to [http://127.0.0.1:8080/console](http://127.0.0.1:8080/console) and you will see a login screen. -Please use the following values: -Note: make sure the JDBC URL used matches your Props value! +**Note:** The H2 web console at `/console` was available when OBP-API ran on Jetty but is no longer served by the http4s server. To inspect the H2 database, connect directly using the [H2 Shell](https://h2database.com/html/tutorial.html#console_settings) or a database tool such as DBeaver. + +Use the following connection values (make sure the JDBC URL matches your Props value): ``` Driver Class: org.h2.Driver @@ -388,16 +388,7 @@ To populate the OBP database with sandbox data: ## Production Options -- set the status of HttpOnly and Secure cookie flags for production, uncomment the following lines of `webapp/WEB-INF/web.xml`: - -```XML - - - true - true - - -``` +OBP-API runs on http4s Ember. Standard security headers (Cache-Control, X-Frame-Options, Correlation-Id, etc.) are applied automatically by `Http4sLiftWebBridge.withStandardHeaders` to all responses. Cookie flags and other session-related settings can be configured via the props file. ## Server Mode Configuration (Removed) @@ -754,14 +745,22 @@ There is a video about the detail: [demonstrate the detail of the feature](https The same as `Frozen APIs`, if a related unit test fails, make sure whether the modification is required, if yes, run frozen util to re-generate frozen types metadata file. take `RestConnector_vMar2019` as an example, the corresponding util is `RestConnector_vMar2019_FrozenUtil`, the corresponding unit test is `RestConnector_vMar2019_FrozenTest` -## Scala / Lift +## Technology Stack + +OBP-API uses the following core technologies: + +- **HTTP Server:** [http4s](https://http4s.org/) with [Cats Effect](https://typelevel.org/cats-effect/) (`IOApp`). The server runs on http4s Ember in a single process on a single port. +- **Routing:** Priority-based routing defined in `Http4sApp.scala`: + 1. Native http4s routes for v5.0.0, v7.0.0, and Berlin Group v2 + 2. A Lift bridge fallback (`Http4sLiftWebBridge`) for all other API versions +- **ORM / Database:** [Lift Mapper](http://www.liftweb.net/) for database access and schema management. +- **JSON:** Lift JSON utilities are used in some areas alongside native http4s JSON handling. -- We use scala and liftweb: [http://www.liftweb.net/](http://www.liftweb.net/). +For details on how the http4s and Lift layers coexist, see [LIFT_HTTP4S_COEXISTENCE.md](LIFT_HTTP4S_COEXISTENCE.md). -- Advanced architecture: [http://exploring.liftweb.net/master/index-9.html - ](http://exploring.liftweb.net/master/index-9.html). +Liftweb architecture: [http://exploring.liftweb.net/master/index-9.html](http://exploring.liftweb.net/master/index-9.html). -- A good book on Lift: "Lift in Action" by Timothy Perrett published by Manning. +A good book on Lift: "Lift in Action" by Timothy Perrett published by Manning. ## Endpoint Request and Response Example From 34c628974955aca1dc5e34bf040ed390b2969c92 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Sat, 28 Feb 2026 06:33:59 +0100 Subject: [PATCH 07/19] Users with Account Access --- obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala | 6 ++---- .../src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 0203676e00..66a403a566 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -10998,8 +10998,7 @@ trait APIMethods600 { )) )), has_public_view = false, - public_views = List.empty[String], - abac_enabled = false + public_views = List.empty[String] ), List( $BankNotFound, @@ -11120,8 +11119,7 @@ trait APIMethods600 { val response = UsersWithAccountAccessJsonV600( users = mergedUsers, has_public_view = publicViewIds.nonEmpty, - public_views = publicViewIds, - abac_enabled = abacEnabled + public_views = publicViewIds ) (response, HttpCode.`200`(callContext)) } diff --git a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala index 7c2b6298ce..e5a36aaee0 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala @@ -2431,8 +2431,7 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable { case class UsersWithAccountAccessJsonV600( users: List[UserWithAccountAccessJsonV600], has_public_view: Boolean, - public_views: List[String], - abac_enabled: Boolean + public_views: List[String] ) } From c9814117ba757e8a4bd8ff054382e849d80344fa Mon Sep 17 00:00:00 2001 From: simonredfern Date: Sat, 28 Feb 2026 06:35:05 +0100 Subject: [PATCH 08/19] remoteJWKSetCache so we don't have to call OIDC provider all the time. --- .../main/scala/code/api/util/JwtUtil.scala | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/JwtUtil.scala b/obp-api/src/main/scala/code/api/util/JwtUtil.scala index 2300ecf4ea..8a07f724ca 100644 --- a/obp-api/src/main/scala/code/api/util/JwtUtil.scala +++ b/obp-api/src/main/scala/code/api/util/JwtUtil.scala @@ -3,6 +3,7 @@ package code.api.util import java.net.{URI, URL} import java.nio.file.{Files, Paths} import java.text.ParseException +import java.util.concurrent.ConcurrentHashMap import code.api.util.RSAUtil.logger import code.util.Helper.MdcLoggable import com.nimbusds.jose.JWSAlgorithm @@ -18,6 +19,25 @@ import dispatch.Future import net.liftweb.common.{Box, Empty, Failure, Full} object JwtUtil extends MdcLoggable { + + // Shared resource retriever for all remote JWK set fetches (thread-safe). + // Parameters: connectTimeout=2000ms, readTimeout=2000ms, maxContentLength=50KB + private val sharedResourceRetriever = new DefaultResourceRetriever(2000, 2000, 50 * 1024) + + // TODO: Marko_review + // Cache of RemoteJWKSet instances keyed by URL string. + // RemoteJWKSet is thread-safe and caches fetched keys internally, + // so reusing instances avoids redundant HTTP requests to the OIDC provider + // and allows validation to succeed using cached keys even if the provider + // is temporarily unreachable. + private val remoteJWKSetCache = new ConcurrentHashMap[String, RemoteJWKSet[SecurityContext]]() + + private def getOrCreateRemoteJWKSet(remoteJWKSetUrl: String): JWKSource[SecurityContext] = { + remoteJWKSetCache.computeIfAbsent(remoteJWKSetUrl, url => { + logger.debug(s"Creating new RemoteJWKSet for URL: $url") + new RemoteJWKSet[SecurityContext](new URL(url), sharedResourceRetriever) + }) + } def checkIfStringIsJWTValue(jwtToken: String): Box[String] = { try { @@ -198,7 +218,7 @@ object JwtUtil extends MdcLoggable { // OAuth 2.0 server's JWK set, published at a well-known URL. The RemoteJWKSet // object caches the retrieved keys to speed up subsequent look-ups and can // also gracefully handle key-rollover - val keySource: JWKSource[SecurityContext] = new RemoteJWKSet(new URL(remoteJWKSetUrl)) + val keySource: JWKSource[SecurityContext] = getOrCreateRemoteJWKSet(remoteJWKSetUrl) // The JWS algorithm of the access tokens val jwsAlg: JWSAlgorithm = getAlgorithm(accessToken).getOrElse(JWSAlgorithm.RS256) @@ -236,18 +256,17 @@ object JwtUtil extends MdcLoggable { import com.nimbusds.jose._ import com.nimbusds.oauth2.sdk.id._ import com.nimbusds.openid.connect.sdk.validators._ - - val resourceRetriever = new DefaultResourceRetriever(1000, 1000, 50 * 1024) // The required parameters val iss: Issuer = new Issuer(getIssuer(idToken).getOrElse("")) val aud = getAudience(idToken).headOption.getOrElse("") val clientID: ClientID = new ClientID(aud) val jwsAlg: JWSAlgorithm = getAlgorithm(idToken).getOrElse(JWSAlgorithm.RS256) - val jwkSetURL: URL = new URL(remoteJWKSetUrl) + val jwkSetSource = getOrCreateRemoteJWKSet(remoteJWKSetUrl) - // Create validator for signed ID tokens - val validator: IDTokenValidator = new IDTokenValidator(iss, clientID, jwsAlg, jwkSetURL, resourceRetriever) + // Create validator for signed ID tokens using the cached JWK source + val keySelector = new JWSVerificationKeySelector[SecurityContext](jwsAlg, jwkSetSource) + val validator: IDTokenValidator = new IDTokenValidator(iss, clientID, keySelector, null) import com.nimbusds.jose.JOSEException import com.nimbusds.jose.proc.BadJOSEException From 64b83cee929df7fdecd8dcc8efc9187afd813f63 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Sun, 1 Mar 2026 23:47:11 +0100 Subject: [PATCH 09/19] App Directory test, search Users by Role --- .../resources/props/sample.props.template | 17 ++++++- .../SwaggerDefinitionsJSON.scala | 11 ++++- .../main/scala/code/api/util/APIUtil.scala | 41 ++++++++++++----- .../main/scala/code/api/util/OBPParam.scala | 1 + .../scala/code/api/v6_0_0/APIMethods600.scala | 37 ++++++++++++---- .../src/main/scala/code/users/LiftUsers.scala | 13 +++++- .../code/api/v6_0_0/AppDirectoryTest.scala | 44 ++++++++++++++----- 7 files changed, 131 insertions(+), 33 deletions(-) diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index 43b99b6102..7e2014a802 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -293,6 +293,21 @@ hostname=http://127.0.0.1 # Set this to your frontend/portal URL so that emails contain the correct link. portal_external_url=http://localhost:5174 +# Public app URLs for the App Directory endpoint (GET /app-directory). +# Any props starting with public_ and ending with _url are returned by that endpoint. +# Defaults are localhost development ports. Override for production deployments. +# Set to empty string to indicate to calling applications they should not display. +public_obp_api_url=http://localhost:8080 +public_obp_portal_url=http://localhost:5174 +public_obp_api_explorer_url=http://localhost:5173 +public_obp_api_manager_url=http://localhost:3003 +public_obp_sandbox_populator_url=http://localhost:5178 +public_obp_oidc_url=http://localhost:9000 +public_keycloak_url=http://localhost:7787 +public_obp_hola_url=http://localhost:8087 +public_obp_mcp_url=http://localhost:9100 +public_obp_opey_url=http://localhost:5000 + ## This port is used for local development ## Note: OBP-API now uses http4s server ## To start the server, use: java -jar obp-api/target/obp-api.jar @@ -1725,4 +1740,4 @@ securelogging_mask_email=true # Signal Channels (Redis-backed ephemeral channels for AI agent coordination) ############################################ # messaging.channel.ttl.seconds=3600 -# messaging.channel.max.messages=1000 \ No newline at end of file +# messaging.channel.max.messages=1000 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 fb19884adb..16ecda95a6 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 @@ -6149,7 +6149,16 @@ object SwaggerDefinitionsJSON { lazy val appDirectoryJsonV600 = ListResult( "app_directory", List( - ConfigPropJsonV600("portal_external_url", "https://portal.openbankproject.com") + ConfigPropJsonV600("public_obp_api_url", "http://localhost:8080"), + ConfigPropJsonV600("public_obp_portal_url", "http://localhost:5174"), + ConfigPropJsonV600("public_obp_api_explorer_url", "http://localhost:5173"), + ConfigPropJsonV600("public_obp_api_manager_url", "http://localhost:3003"), + ConfigPropJsonV600("public_obp_sandbox_populator_url", "http://localhost:5178"), + ConfigPropJsonV600("public_obp_oidc_url", "http://localhost:9000"), + ConfigPropJsonV600("public_keycloak_url", "http://localhost:7787"), + ConfigPropJsonV600("public_obp_hola_url", "http://localhost:8087"), + ConfigPropJsonV600("public_obp_mcp_url", "http://localhost:9100"), + ConfigPropJsonV600("public_obp_opey_url", "http://localhost:5000") ) ) diff --git a/obp-api/src/main/scala/code/api/util/APIUtil.scala b/obp-api/src/main/scala/code/api/util/APIUtil.scala index ecd4512946..7cc228882e 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -1219,6 +1219,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ case "connector_name" => Full(OBPConnectorName(values.head)) case "customer_id" => Full(OBPCustomerId(values.head)) case "locked_status" => Full(OBPLockedStatus(values.head)) + case "role_name" => Full(OBPRoleName(values.head)) case _ => Full(OBPEmpty()) } } yield @@ -1267,6 +1268,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ functionName <- getHttpParamValuesByName(httpParams, "function_name") customerId <- getHttpParamValuesByName(httpParams, "customer_id") lockedStatus <- getHttpParamValuesByName(httpParams, "locked_status") + roleName <- getHttpParamValuesByName(httpParams, "role_name") httpStatusCode <- getHttpParamValuesByName(httpParams, "http_status_code") }yield{ /** @@ -1287,7 +1289,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ anon, status, consumerId, azp, iss, consentId, userId, providerProviderId, url, appName, implementedByPartialFunction, implementedInVersion, verb, correlationId, duration, httpStatusCode, excludeAppNames, excludeUrlPattern, excludeImplementedByPartialfunctions, includeAppNames, includeUrlPattern, includeImplementedByPartialfunctions, - connectorName,functionName, bankId, accountId, customerId, lockedStatus, deletedStatus + connectorName,functionName, bankId, accountId, customerId, lockedStatus, roleName, deletedStatus ).filter(_ != OBPEmpty()) } } @@ -1341,6 +1343,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ val amount = getHttpRequestUrlParam(httpRequestUrl, "amount") val customerId = getHttpRequestUrlParam(httpRequestUrl, "customer_id") val lockedStatus = getHttpRequestUrlParam(httpRequestUrl, "locked_status") + val roleName = getHttpRequestUrlParam(httpRequestUrl, "role_name") //The following three are not a string, it should be List of String //eg: exclude_app_names=A,B,C --> List(A,B,C) @@ -1373,7 +1376,8 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ HTTPParam("connector_name", connectorName), HTTPParam("customer_id", customerId), HTTPParam("is_deleted", isDeleted), - HTTPParam("locked_status", lockedStatus) + HTTPParam("locked_status", lockedStatus), + HTTPParam("role_name", roleName) ).filter(_.values.head != ""))//Here filter the field when value = "". } @@ -3979,18 +3983,35 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ else value } - // Explicit whitelist of prop keys for the app discovery endpoint. - // Add new keys here as needed. Only exact matches are exposed. - val appDiscoveryWhitelist = List( - "portal_external_url" + // Convention-based public app URL props. + // Any prop starting with "public_" and ending with "_url" is included in the App Directory. + // Register known defaults so they appear in getConfigPropsPairs when set. + // Note: public_obp_api_url falls back to hostname prop if not explicitly set. + // Note: public_obp_portal_url falls back to portal_external_url if not explicitly set. + val publicAppUrlDefaults: Map[String, String] = Map( + "public_obp_api_url" -> getPropsValue("public_obp_api_url").openOr(getPropsValue("hostname").openOr("http://localhost:8080")), + "public_obp_portal_url" -> getPropsValue("public_obp_portal_url").openOr(getPropsValue("portal_external_url").openOr("http://localhost:5174")), + "public_obp_api_explorer_url" -> getPropsValue("public_obp_api_explorer_url").openOr("http://localhost:5173"), + "public_obp_api_manager_url" -> getPropsValue("public_obp_api_manager_url").openOr("http://localhost:3003"), + "public_obp_sandbox_populator_url" -> getPropsValue("public_obp_sandbox_populator_url").openOr("http://localhost:5178"), + "public_obp_oidc_url" -> getPropsValue("public_obp_oidc_url").openOr("http://localhost:9000"), + "public_keycloak_url" -> getPropsValue("public_keycloak_url").openOr("http://localhost:7787"), + "public_obp_hola_url" -> getPropsValue("public_obp_hola_url").openOr("http://localhost:8087"), + "public_obp_mcp_url" -> getPropsValue("public_obp_mcp_url").openOr("http://localhost:9100"), + "public_obp_opey_url" -> getPropsValue("public_obp_opey_url").openOr("http://localhost:5000") ) + val publicAppUrlPropNames: List[String] = publicAppUrlDefaults.keys.toList.sorted + // Register defaults so they appear in getConfigPropsPairs + publicAppUrlDefaults.foreach { case (key, default) => getPropsValue(key, default) } - // Returns config props filtered to only explicitly whitelisted keys. - // Chain: registeredDefaults (sensitive excluded) → getConfigPropsPairs (runtime values) - // → explicit whitelist filter → maskSensitivePropValue safety net + // Returns config props matching the public_*_url convention. + // Empty values are excluded (prop not configured). def getAppDiscoveryPairs: List[(String, String)] = { getConfigPropsPairs - .filter { case (key, _) => appDiscoveryWhitelist.contains(key) } + .filter { case (key, _) => + key.startsWith("public_") && key.endsWith("_url") + } + .filter { case (_, value) => value.nonEmpty } .map { case (key, value) => (key, maskSensitivePropValue(key, value)) } } diff --git a/obp-api/src/main/scala/code/api/util/OBPParam.scala b/obp-api/src/main/scala/code/api/util/OBPParam.scala index d0ba9aa7aa..4a8cf115ba 100644 --- a/obp-api/src/main/scala/code/api/util/OBPParam.scala +++ b/obp-api/src/main/scala/code/api/util/OBPParam.scala @@ -56,6 +56,7 @@ case class OBPEmpty() extends OBPQueryParam case class OBPCustomerId(value: String) extends OBPQueryParam case class OBPLockedStatus(value: String) extends OBPQueryParam case class OBPIsDeleted(value: Boolean) extends OBPQueryParam +case class OBPRoleName(value: String) extends OBPQueryParam object OBPQueryParam { val LIMIT = "limit" diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 66a403a566..262fefbcf7 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -1735,6 +1735,8 @@ trait APIMethods600 { |${urlParametersDocument(false, false)} |* locked_status (if null ignore) |* is_deleted (default: false) + |* role_name (if null ignore) - filter by entitlement/role name e.g. CanCreateAccount + |* bank_id (if null ignore) - when used with role_name, filter entitlements by bank_id | """.stripMargin, EmptyBody, @@ -9753,11 +9755,16 @@ trait APIMethods600 { "Get App Directory", s"""Get connectivity information for apps in the OBP ecosystem. | - |Returns configuration properties that apps (Explorer, Portal, OIDC, Hola, - |Sandbox Generator) and agents can use to discover endpoints in the OBP ecosystem. + |Returns configuration properties that apps (Portal, API Explorer, API Manager, + |Sandbox Populator, OIDC, Keycloak, Hola, MCP, Opey) and agents can use to discover + |endpoints in the OBP ecosystem. | - |Only explicitly whitelisted property keys are included: - |${APIUtil.appDiscoveryWhitelist.mkString(", ")} + |Any props starting with public_ and ending with _url are included automatically. + | + |Known public app URL props: + |${APIUtil.publicAppUrlPropNames.mkString(", ")} + | + |Empty (unconfigured) values are excluded from the response. | |Authentication is NOT Required. | @@ -11038,19 +11045,24 @@ trait APIMethods600 { // Step C: ABAC evaluation (only if enabled) abacEnabled = allowAbacAccountAccess abacResults <- { + logger.info(s"ABAC DEBUG: abacEnabled=$abacEnabled, privateViews=${privateViews.map(_.viewId.value)}") if (!abacEnabled || privateViews.isEmpty) { + logger.info(s"ABAC DEBUG: Skipping ABAC evaluation (abacEnabled=$abacEnabled, privateViews.isEmpty=${privateViews.isEmpty})") Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) } else { // Find users with CanExecuteAbacRule entitlement val abacEntitlements = Entitlement.entitlement.vend.getEntitlementsByRole(canExecuteAbacRule.toString) .getOrElse(Nil) val abacUserIds = abacEntitlements.map(_.userId).distinct + logger.info(s"ABAC DEBUG: Found ${abacEntitlements.size} CanExecuteAbacRule entitlements, ${abacUserIds.size} distinct users: $abacUserIds") if (abacUserIds.isEmpty) { + logger.info("ABAC DEBUG: No users with CanExecuteAbacRule entitlement, skipping ABAC") Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) } else { for { abacUsers <- Users.users.vend.getUsersByUserIdsFuture(abacUserIds) + _ = logger.info(s"ABAC DEBUG: Resolved ${abacUsers.size} ABAC users: ${abacUsers.map(u => s"${u.userId}/${u.name}").mkString(", ")}") abacUserMap = abacUsers.map(u => u.userId -> u).toMap // For each (user, view) pair, skip if already has AccountAccess, otherwise evaluate ABAC @@ -11060,11 +11072,13 @@ trait APIMethods600 { existingViews = accountAccessResults.get(user.userId).map(_._2).getOrElse(Nil) if !existingViews.exists(_.view_id == view.viewId.value) } yield (user, view) + _ = logger.info(s"ABAC DEBUG: ${evaluationPairs.size} (user, view) pairs to evaluate (after filtering out existing AccountAccess)") abacEvaluations <- Future.sequence( evaluationPairs.map { case (user, view) => callContext match { case Some(cc) => + logger.info(s"ABAC DEBUG: Evaluating user=${user.userId}/${user.name} view=${view.viewId.value} bank=${bankId.value} account=${accountId.value}") AbacRuleEngine.executeRulesByPolicyDetailed( policy = ABAC_POLICY_ACCOUNT_ACCESS, authenticatedUserId = user.userId, @@ -11072,11 +11086,18 @@ trait APIMethods600 { bankId = Some(bankId.value), accountId = Some(accountId.value), viewId = Some(view.viewId.value) - ).map { - case Full((true, _)) => Some((user, view)) - case _ => None - }.recover { case _ => None } + ).map { result => + logger.info(s"ABAC DEBUG: user=${user.userId}/${user.name} view=${view.viewId.value} result=$result") + result match { + case Full((true, _)) => Some((user, view)) + case _ => None + } + }.recover { case ex => + logger.error(s"ABAC DEBUG: user=${user.userId}/${user.name} view=${view.viewId.value} EXCEPTION: ${ex.getMessage}", ex) + None + } case None => + logger.warn("ABAC DEBUG: callContext is None, skipping ABAC evaluation") Future.successful(None) } } diff --git a/obp-api/src/main/scala/code/users/LiftUsers.scala b/obp-api/src/main/scala/code/users/LiftUsers.scala index 39ae2f690a..3012940271 100644 --- a/obp-api/src/main/scala/code/users/LiftUsers.scala +++ b/obp-api/src/main/scala/code/users/LiftUsers.scala @@ -201,11 +201,22 @@ object LiftUsers extends Users with MdcLoggable{ override def getUsers(queryParams: List[OBPQueryParam]): Future[List[(ResourceUser, Box[List[Entitlement]], Option[List[UserAgreement]])]] = { Future { + val roleName: Option[String] = queryParams.collect { case OBPRoleName(value) => value }.headOption + val bankId: Option[String] = queryParams.collect { case OBPBankId(value) => value }.headOption + val roleUserIds: Option[Set[String]] = roleName.map { rn => + val entitlements = Entitlement.entitlement.vend.getEntitlementsByRole(rn) + .getOrElse(Nil) + val filtered = bankId match { + case Some(bid) => entitlements.filter(_.bankId == bid) + case None => entitlements + } + filtered.map(_.userId).toSet + } for { user <- getUsersCommon(queryParams) + if roleUserIds.forall(_.contains(user.userId)) } yield { val entitlements = Entitlement.entitlement.vend.getEntitlementsByUserId(user.userId).map(_.sortWith(_.roleName < _.roleName)) - // val agreements = getUserAgreements(user) (user, entitlements, None) } } diff --git a/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala index 9711738582..7328b81e95 100644 --- a/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala +++ b/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala @@ -58,7 +58,7 @@ class AppDirectoryTest extends V600ServerSetup { response.code should equal(200) } - scenario("Response only contains explicitly whitelisted keys", VersionOfApi, ApiEndpoint) { + scenario("Response only contains public_*_url keys", VersionOfApi, ApiEndpoint) { When("We call the apps-directory endpoint") val request = (v6_0_0_Request / "app-directory").GET val response = makeGetRequest(request) @@ -66,12 +66,13 @@ class AppDirectoryTest extends V600ServerSetup { Then("We should get a 200") response.code should equal(200) - And("Every returned key should be in the explicit whitelist") + And("Every returned key should match public_*_url pattern") val props = (response.body \ "app_directory").children props.foreach { prop => val name = (prop \ "name").extract[String] - withClue(s"Key '$name' should be in appDiscoveryWhitelist: ") { - APIUtil.appDiscoveryWhitelist should contain(name) + withClue(s"Key '$name' should match public_*_url: ") { + name should startWith("public_") + name should endWith("_url") } } } @@ -158,11 +159,12 @@ class AppDirectoryTest extends V600ServerSetup { APIUtil.maskSensitivePropValue("api_port", "8080") should equal("8080") } - scenario("getAppDiscoveryPairs only returns explicitly whitelisted keys", VersionOfApi, ApiEndpoint) { + scenario("getAppDiscoveryPairs only returns public_*_url keys", VersionOfApi, ApiEndpoint) { val pairs = APIUtil.getAppDiscoveryPairs pairs.foreach { case (key, _) => - withClue(s"Key '$key' should be in appDiscoveryWhitelist: ") { - APIUtil.appDiscoveryWhitelist should contain(key) + withClue(s"Key '$key' should match public_*_url: ") { + key should startWith("public_") + key should endWith("_url") } } } @@ -191,14 +193,32 @@ class AppDirectoryTest extends V600ServerSetup { } } - scenario("appDiscoveryWhitelist contains portal_external_url", VersionOfApi, ApiEndpoint) { - APIUtil.appDiscoveryWhitelist should contain("portal_external_url") + scenario("publicAppUrlPropNames contains expected app URLs", VersionOfApi, ApiEndpoint) { + APIUtil.publicAppUrlPropNames should contain("public_obp_api_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_portal_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_api_explorer_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_api_manager_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_sandbox_populator_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_oidc_url") + APIUtil.publicAppUrlPropNames should contain("public_keycloak_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_hola_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_mcp_url") + APIUtil.publicAppUrlPropNames should contain("public_obp_opey_url") } - scenario("appDiscoveryWhitelist does not include sensitive keys", VersionOfApi, ApiEndpoint) { - APIUtil.appDiscoveryWhitelist.foreach { key => + scenario("all publicAppUrlPropNames follow public_*_url convention", VersionOfApi, ApiEndpoint) { + APIUtil.publicAppUrlPropNames.foreach { key => + withClue(s"Key '$key' should start with public_ and end with _url: ") { + key should startWith("public_") + key should endWith("_url") + } + } + } + + scenario("publicAppUrlPropNames do not include sensitive keys", VersionOfApi, ApiEndpoint) { + APIUtil.publicAppUrlPropNames.foreach { key => APIUtil.sensitiveKeywords.foreach { keyword => - withClue(s"Whitelisted key '$key' should not contain sensitive keyword '$keyword': ") { + withClue(s"Public URL key '$key' should not contain sensitive keyword '$keyword': ") { key.toLowerCase should not include(keyword) } } From 41c3004439b50b88858baf9ff9aa1740230af5b6 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Mon, 2 Mar 2026 05:55:34 +0100 Subject: [PATCH 10/19] logfix in getUsersWithAccountAccess --- .../resources/props/sample.props.template | 5 ++++ .../scala/code/api/v6_0_0/APIMethods600.scala | 29 ++++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index 7e2014a802..f7c65840a7 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -858,6 +858,11 @@ password_reset_token_expiry_minutes=120 # control the create and access to public views. # allow_public_views=false +# Enable ABAC (Attribute-Based Access Control) for account access. +# When true, users with CanExecuteAbacRule entitlement can gain access +# to accounts via ABAC rules with the "account-access" policy. +# allow_abac_account_access=false + # control access to account firehose. # allow_account_firehose=false # control access to customer firehose. diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 262fefbcf7..3b73acf43c 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -8717,7 +8717,7 @@ trait APIMethods600 { json.extract[PostVerifyUserCredentialsJsonV600] } // Validate credentials using the existing AuthUser mechanism - resourceUserIdBox = //we first try to get the userId from local, if not find, we try to get it from external + resourceUserIdBox = //we first try to get the userId from local, if not find, we try to get it from external code.model.dataAccess.AuthUser.getResourceUserId(postedData.username, postedData.password) .or(code.model.dataAccess.AuthUser.externalUserHelper(postedData.username, postedData.password).map(_.user.get)) // Check if account is locked @@ -11042,27 +11042,28 @@ trait APIMethods600 { perm.user.userId -> (perm.user, privateViewAccesses) }.toMap - // Step C: ABAC evaluation (only if enabled) - abacEnabled = allowAbacAccountAccess + // Step C: ABAC evaluation — always report ABAC access regardless of + // allow_abac_account_access prop. This endpoint reports the truth about + // who has access, it does not enforce access. abacResults <- { - logger.info(s"ABAC DEBUG: abacEnabled=$abacEnabled, privateViews=${privateViews.map(_.viewId.value)}") - if (!abacEnabled || privateViews.isEmpty) { - logger.info(s"ABAC DEBUG: Skipping ABAC evaluation (abacEnabled=$abacEnabled, privateViews.isEmpty=${privateViews.isEmpty})") + logger.info(s"getUsersWithAccountAccess says: privateViews=${privateViews.map(_.viewId.value)}") + if (privateViews.isEmpty) { + logger.info(s"getUsersWithAccountAccess says: Skipping ABAC evaluation (privateViews.isEmpty=${privateViews.isEmpty})") Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) } else { // Find users with CanExecuteAbacRule entitlement val abacEntitlements = Entitlement.entitlement.vend.getEntitlementsByRole(canExecuteAbacRule.toString) .getOrElse(Nil) val abacUserIds = abacEntitlements.map(_.userId).distinct - logger.info(s"ABAC DEBUG: Found ${abacEntitlements.size} CanExecuteAbacRule entitlements, ${abacUserIds.size} distinct users: $abacUserIds") + logger.info(s"getUsersWithAccountAccess says: Found ${abacEntitlements.size} CanExecuteAbacRule entitlements, ${abacUserIds.size} distinct users: $abacUserIds") if (abacUserIds.isEmpty) { - logger.info("ABAC DEBUG: No users with CanExecuteAbacRule entitlement, skipping ABAC") + logger.info("getUsersWithAccountAccess says: No users with CanExecuteAbacRule entitlement, skipping ABAC") Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) } else { for { abacUsers <- Users.users.vend.getUsersByUserIdsFuture(abacUserIds) - _ = logger.info(s"ABAC DEBUG: Resolved ${abacUsers.size} ABAC users: ${abacUsers.map(u => s"${u.userId}/${u.name}").mkString(", ")}") + _ = logger.info(s"getUsersWithAccountAccess says: Resolved ${abacUsers.size} ABAC users: ${abacUsers.map(u => s"${u.userId}/${u.name}").mkString(", ")}") abacUserMap = abacUsers.map(u => u.userId -> u).toMap // For each (user, view) pair, skip if already has AccountAccess, otherwise evaluate ABAC @@ -11072,13 +11073,13 @@ trait APIMethods600 { existingViews = accountAccessResults.get(user.userId).map(_._2).getOrElse(Nil) if !existingViews.exists(_.view_id == view.viewId.value) } yield (user, view) - _ = logger.info(s"ABAC DEBUG: ${evaluationPairs.size} (user, view) pairs to evaluate (after filtering out existing AccountAccess)") + _ = logger.info(s"getUsersWithAccountAccess says: ${evaluationPairs.size} (user, view) pairs to evaluate (after filtering out existing AccountAccess)") abacEvaluations <- Future.sequence( evaluationPairs.map { case (user, view) => callContext match { case Some(cc) => - logger.info(s"ABAC DEBUG: Evaluating user=${user.userId}/${user.name} view=${view.viewId.value} bank=${bankId.value} account=${accountId.value}") + logger.info(s"getUsersWithAccountAccess says: Evaluating user=${user.userId}/${user.name} view=${view.viewId.value} bank=${bankId.value} account=${accountId.value}") AbacRuleEngine.executeRulesByPolicyDetailed( policy = ABAC_POLICY_ACCOUNT_ACCESS, authenticatedUserId = user.userId, @@ -11087,17 +11088,17 @@ trait APIMethods600 { accountId = Some(accountId.value), viewId = Some(view.viewId.value) ).map { result => - logger.info(s"ABAC DEBUG: user=${user.userId}/${user.name} view=${view.viewId.value} result=$result") + logger.info(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${view.viewId.value} result=$result") result match { case Full((true, _)) => Some((user, view)) case _ => None } }.recover { case ex => - logger.error(s"ABAC DEBUG: user=${user.userId}/${user.name} view=${view.viewId.value} EXCEPTION: ${ex.getMessage}", ex) + logger.error(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${view.viewId.value} EXCEPTION: ${ex.getMessage}", ex) None } case None => - logger.warn("ABAC DEBUG: callContext is None, skipping ABAC evaluation") + logger.warn("getUsersWithAccountAccess says: callContext is None, skipping ABAC evaluation") Future.successful(None) } } From 07a509e45d2d9dc66c0f4ca7b8318d9adb42c54a Mon Sep 17 00:00:00 2001 From: simonredfern Date: Mon, 2 Mar 2026 06:24:44 +0100 Subject: [PATCH 11/19] getUsersWithAccountAccess operates on view level --- .../scala/code/api/v6_0_0/APIMethods600.scala | 202 +++++++----------- .../code/api/v6_0_0/JSONFactory6.0.0.scala | 15 +- 2 files changed, 85 insertions(+), 132 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 3b73acf43c..ce8ada32cd 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -30,7 +30,7 @@ import code.api.v5_0_0.JSONFactory500 import code.api.v5_0_0.{ViewJsonV500, ViewsJsonV500} import code.api.v5_1_0.{JSONFactory510, PostCustomerLegalNameJsonV510} import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo} -import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, CleanupOrphanedDynamicEntityResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, OrphanedDynamicEntityJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PostResetPasswordUrlAnonymousJsonV600, PostResetPasswordCompleteJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, ResetPasswordUrlAnonymousResponseJsonV600, ResetPasswordCompleteResponseJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, UserViewAccessJsonV600, UserWithAccountAccessJsonV600, UsersWithAccountAccessJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600} +import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, CleanupOrphanedDynamicEntityResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, OrphanedDynamicEntityJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PostResetPasswordUrlAnonymousJsonV600, PostResetPasswordCompleteJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, ResetPasswordUrlAnonymousResponseJsonV600, ResetPasswordCompleteResponseJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, UserWithViewAccessJsonV600, UsersWithViewAccessJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600} import code.api.v6_0_0.OBPAPI6_0_0 import code.abacrule.{AbacRuleEngine, MappedAbacRuleProvider} import code.metrics.{APIMetrics, ConnectorCountsRedis, ConnectorTraceProvider} @@ -10977,35 +10977,28 @@ trait APIMethods600 { implementedInApiVersion, nameOf(getUsersWithAccountAccess), "GET", - "/banks/BANK_ID/accounts/ACCOUNT_ID/users-with-access", + "/banks/BANK_ID/accounts/ACCOUNT_ID/views/VIEW_ID/users-with-access", "Get Users With Account Access", - s"""Get all users who have access to a specific account, along with their views and access sources. + s"""Get all users who have access to a specific view on a specific account, and how that access was granted. | |This endpoint combines both traditional AccountAccess records and ABAC (Attribute-Based Access Control) - |evaluation to provide a complete picture of who can access the account. + |evaluation to provide a complete picture of who can access the specified view. | - |Each user entry includes the list of views they can access and how that access was granted + |Each user entry includes an access_source indicating how access was granted |(either "ACCOUNT_ACCESS" for direct grants or "ABAC" for rule-based access). | - |Public views are listed separately since they are accessible by everyone. - | |Authentication is Required | |""".stripMargin, EmptyBody, - UsersWithAccountAccessJsonV600( - users = List(UserWithAccountAccessJsonV600( + UsersWithViewAccessJsonV600( + users = List(UserWithViewAccessJsonV600( user_id = ExampleValue.userIdExample.value, username = "robert.x.smith.test", email = "robert.x@example.com", provider = "https://apisandbox.openbankproject.com", - views = List(UserViewAccessJsonV600( - view_id = "owner", - access_source = "ACCOUNT_ACCESS" - )) - )), - has_public_view = false, - public_views = List.empty[String] + access_source = "ACCOUNT_ACCESS" + )) ), List( $BankNotFound, @@ -11017,7 +11010,7 @@ trait APIMethods600 { ) lazy val getUsersWithAccountAccess: OBPEndpoint = { - case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "users-with-access" :: Nil JsonGet _ => { + case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: "users-with-access" :: Nil JsonGet _ => { cc => implicit val ec = EndpointContext(Some(cc)) for { (Full(u), callContext) <- authenticatedAccess(cc) @@ -11025,123 +11018,90 @@ trait APIMethods600 { (_, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext) bankIdAccountId = BankIdAccountId(bankId, accountId) - // Step A: Get all views for the account, split into public and private - allViews <- Future(Views.views.vend.assignedViewsForAccount(bankIdAccountId)) - publicViewIds = allViews.filter(_.isPublic).map(_.viewId.value) - privateViews = allViews.filter(_.isPrivate) + // Validate the view exists + _ <- Future { + Views.views.vend.customViewFuture(viewId, bankIdAccountId).flatMap { + case Full(v) => Future.successful(Full(v)) + case _ => Views.views.vend.systemViewFuture(viewId) + } + }.flatten.map { + unboxFullOrFail(_, callContext, s"$ViewNotFound Current ViewId is ${viewId.value}") + } - // Step B: Get traditional AccountAccess permissions (all users with direct access) + // Step A: Get traditional AccountAccess users for this view permissions <- Future(Views.views.vend.permissions(bankIdAccountId)) - accountAccessResults = permissions.map { perm => - val privateViewAccesses = perm.views.filter(_.isPrivate).map { v => - UserViewAccessJsonV600( - view_id = v.viewId.value, + accountAccessUsers: List[UserWithViewAccessJsonV600] = permissions.flatMap { perm => + if (perm.views.exists(_.viewId == viewId)) { + Some(UserWithViewAccessJsonV600( + user_id = perm.user.userId, + username = perm.user.name, + email = perm.user.emailAddress, + provider = perm.user.provider, access_source = "ACCOUNT_ACCESS" - ) - } - perm.user.userId -> (perm.user, privateViewAccesses) - }.toMap + )) + } else None + } + accountAccessUserIds = accountAccessUsers.map(_.user_id).toSet - // Step C: ABAC evaluation — always report ABAC access regardless of + // Step B: ABAC evaluation — always report ABAC access regardless of // allow_abac_account_access prop. This endpoint reports the truth about // who has access, it does not enforce access. - abacResults <- { - logger.info(s"getUsersWithAccountAccess says: privateViews=${privateViews.map(_.viewId.value)}") - if (privateViews.isEmpty) { - logger.info(s"getUsersWithAccountAccess says: Skipping ABAC evaluation (privateViews.isEmpty=${privateViews.isEmpty})") - Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) + abacUsers <- { + // Find users with CanExecuteAbacRule entitlement + val abacEntitlements = Entitlement.entitlement.vend.getEntitlementsByRole(canExecuteAbacRule.toString) + .getOrElse(Nil) + val abacUserIds = abacEntitlements.map(_.userId).distinct + .filterNot(accountAccessUserIds.contains) // Skip users already covered by AccountAccess + logger.info(s"getUsersWithAccountAccess says: view=${viewId.value} abacUserIds to evaluate=$abacUserIds") + + if (abacUserIds.isEmpty) { + logger.info("getUsersWithAccountAccess says: No ABAC users to evaluate") + Future.successful(List.empty[UserWithViewAccessJsonV600]) } else { - // Find users with CanExecuteAbacRule entitlement - val abacEntitlements = Entitlement.entitlement.vend.getEntitlementsByRole(canExecuteAbacRule.toString) - .getOrElse(Nil) - val abacUserIds = abacEntitlements.map(_.userId).distinct - logger.info(s"getUsersWithAccountAccess says: Found ${abacEntitlements.size} CanExecuteAbacRule entitlements, ${abacUserIds.size} distinct users: $abacUserIds") - - if (abacUserIds.isEmpty) { - logger.info("getUsersWithAccountAccess says: No users with CanExecuteAbacRule entitlement, skipping ABAC") - Future.successful(Map.empty[String, (User, List[UserViewAccessJsonV600])]) - } else { - for { - abacUsers <- Users.users.vend.getUsersByUserIdsFuture(abacUserIds) - _ = logger.info(s"getUsersWithAccountAccess says: Resolved ${abacUsers.size} ABAC users: ${abacUsers.map(u => s"${u.userId}/${u.name}").mkString(", ")}") - abacUserMap = abacUsers.map(u => u.userId -> u).toMap - - // For each (user, view) pair, skip if already has AccountAccess, otherwise evaluate ABAC - evaluationPairs = for { - user <- abacUsers - view <- privateViews - existingViews = accountAccessResults.get(user.userId).map(_._2).getOrElse(Nil) - if !existingViews.exists(_.view_id == view.viewId.value) - } yield (user, view) - _ = logger.info(s"getUsersWithAccountAccess says: ${evaluationPairs.size} (user, view) pairs to evaluate (after filtering out existing AccountAccess)") - - abacEvaluations <- Future.sequence( - evaluationPairs.map { case (user, view) => - callContext match { - case Some(cc) => - logger.info(s"getUsersWithAccountAccess says: Evaluating user=${user.userId}/${user.name} view=${view.viewId.value} bank=${bankId.value} account=${accountId.value}") - AbacRuleEngine.executeRulesByPolicyDetailed( - policy = ABAC_POLICY_ACCOUNT_ACCESS, - authenticatedUserId = user.userId, - callContext = cc, - bankId = Some(bankId.value), - accountId = Some(accountId.value), - viewId = Some(view.viewId.value) - ).map { result => - logger.info(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${view.viewId.value} result=$result") - result match { - case Full((true, _)) => Some((user, view)) - case _ => None - } - }.recover { case ex => - logger.error(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${view.viewId.value} EXCEPTION: ${ex.getMessage}", ex) - None + for { + users <- Users.users.vend.getUsersByUserIdsFuture(abacUserIds) + _ = logger.info(s"getUsersWithAccountAccess says: Resolved ${users.size} ABAC users: ${users.map(u => s"${u.userId}/${u.name}").mkString(", ")}") + + abacEvaluations <- Future.sequence( + users.map { user => + callContext match { + case Some(cc) => + logger.info(s"getUsersWithAccountAccess says: Evaluating user=${user.userId}/${user.name} view=${viewId.value} bank=${bankId.value} account=${accountId.value}") + AbacRuleEngine.executeRulesByPolicyDetailed( + policy = ABAC_POLICY_ACCOUNT_ACCESS, + authenticatedUserId = user.userId, + callContext = cc, + bankId = Some(bankId.value), + accountId = Some(accountId.value), + viewId = Some(viewId.value) + ).map { result => + logger.info(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${viewId.value} result=$result") + result match { + case Full((true, _)) => Some(UserWithViewAccessJsonV600( + user_id = user.userId, + username = user.name, + email = user.emailAddress, + provider = user.provider, + access_source = "ABAC" + )) + case _ => None } - case None => - logger.warn("getUsersWithAccountAccess says: callContext is None, skipping ABAC evaluation") - Future.successful(None) - } - } - ) - - passingPairs = abacEvaluations.flatten - } yield { - passingPairs.groupBy(_._1.userId).map { case (userId, pairs) => - val user = pairs.head._1 - val viewAccesses = pairs.map { case (_, view) => - UserViewAccessJsonV600( - view_id = view.viewId.value, - access_source = "ABAC" - ) + }.recover { case ex => + logger.error(s"getUsersWithAccountAccess says: user=${user.userId}/${user.name} view=${viewId.value} EXCEPTION: ${ex.getMessage}", ex) + None + } + case None => + logger.warn("getUsersWithAccountAccess says: callContext is None, skipping ABAC evaluation") + Future.successful(None) } - userId -> (user, viewAccesses) } - } - } + ) + } yield abacEvaluations.flatten } } } yield { - // Step D: Merge accountAccessResults + abacResults by userId - val allUserIds = (accountAccessResults.keySet ++ abacResults.keySet).toList - val mergedUsers = allUserIds.map { userId => - val (user, views1) = accountAccessResults.getOrElse(userId, { - val (u, _) = abacResults(userId) - (u, Nil) - }) - val views2 = abacResults.get(userId).map(_._2).getOrElse(Nil) - UserWithAccountAccessJsonV600( - user_id = user.userId, - username = user.name, - email = user.emailAddress, - provider = user.provider, - views = views1 ++ views2 - ) - }.filter(_.views.nonEmpty) - - val response = UsersWithAccountAccessJsonV600( - users = mergedUsers, - has_public_view = publicViewIds.nonEmpty, - public_views = publicViewIds + val response = UsersWithViewAccessJsonV600( + users = accountAccessUsers ++ abacUsers ) (response, HttpCode.`200`(callContext)) } diff --git a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala index e5a36aaee0..54e9ea7044 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala @@ -2415,23 +2415,16 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable { abac_rule_id: String ) - case class UserViewAccessJsonV600( - view_id: String, - access_source: String // "ACCOUNT_ACCESS" or "ABAC" - ) - - case class UserWithAccountAccessJsonV600( + case class UserWithViewAccessJsonV600( user_id: String, username: String, email: String, provider: String, - views: List[UserViewAccessJsonV600] + access_source: String // "ACCOUNT_ACCESS" or "ABAC" ) - case class UsersWithAccountAccessJsonV600( - users: List[UserWithAccountAccessJsonV600], - has_public_view: Boolean, - public_views: List[String] + case class UsersWithViewAccessJsonV600( + users: List[UserWithViewAccessJsonV600] ) } From 3290c1a66f24f0f7db781109366905619c95b711 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Mon, 2 Mar 2026 06:41:59 +0100 Subject: [PATCH 12/19] rule.policy exists check --- obp-api/src/main/scala/code/abacrule/AbacRuleTrait.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/abacrule/AbacRuleTrait.scala b/obp-api/src/main/scala/code/abacrule/AbacRuleTrait.scala index 9e9a228857..8a0e995f99 100644 --- a/obp-api/src/main/scala/code/abacrule/AbacRuleTrait.scala +++ b/obp-api/src/main/scala/code/abacrule/AbacRuleTrait.scala @@ -96,13 +96,13 @@ object MappedAbacRuleProvider extends AbacRuleProvider { override def getAbacRulesByPolicy(policy: String): List[AbacRuleTrait] = { AbacRule.findAll().filter { rule => - rule.policy.split(",").map(_.trim).contains(policy) + Option(rule.policy).exists(_.split(",").map(_.trim).contains(policy)) } } override def getActiveAbacRulesByPolicy(policy: String): List[AbacRuleTrait] = { AbacRule.findAll(By(AbacRule.IsActive, true)).filter { rule => - rule.policy.split(",").map(_.trim).contains(policy) + Option(rule.policy).exists(_.split(",").map(_.trim).contains(policy)) } } From a815177b9bc7cffdebb922ba6154f3e633a6301f Mon Sep 17 00:00:00 2001 From: simonredfern Date: Mon, 2 Mar 2026 09:02:04 +0100 Subject: [PATCH 13/19] getPrivateAccountByIdFull v6.0.0 list of allowed permissions rather than hardcoded list of boolean flags --- .../scala/code/api/v6_0_0/APIMethods600.scala | 104 +++++++++++++++++- .../code/api/v6_0_0/JSONFactory6.0.0.scala | 43 +++++++- 2 files changed, 144 insertions(+), 3 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index ce8ada32cd..645dee2626 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -30,7 +30,8 @@ import code.api.v5_0_0.JSONFactory500 import code.api.v5_0_0.{ViewJsonV500, ViewsJsonV500} import code.api.v5_1_0.{JSONFactory510, PostCustomerLegalNameJsonV510} import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo} -import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, CleanupOrphanedDynamicEntityResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, OrphanedDynamicEntityJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PostResetPasswordUrlAnonymousJsonV600, PostResetPasswordCompleteJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, ResetPasswordUrlAnonymousResponseJsonV600, ResetPasswordCompleteResponseJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, UserWithViewAccessJsonV600, UsersWithViewAccessJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600} +import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, CleanupOrphanedDynamicEntityResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, OrphanedDynamicEntityJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, ModeratedAccountJSON600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PostResetPasswordUrlAnonymousJsonV600, PostResetPasswordCompleteJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, ResetPasswordUrlAnonymousResponseJsonV600, ResetPasswordCompleteResponseJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, UserWithViewAccessJsonV600, UsersWithViewAccessJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createActiveRateLimitsJsonV600FromCallLimit, createBankAccountJSON600, createCallLimitJsonV600, createConsumerJsonV600, createRedisCallCountersJson, createFeaturedApiCollectionJsonV600, createFeaturedApiCollectionsJsonV600} +import code.metadata.tags.Tags import code.api.v6_0_0.OBPAPI6_0_0 import code.abacrule.{AbacRuleEngine, MappedAbacRuleProvider} import code.metrics.{APIMetrics, ConnectorCountsRedis, ConnectorTraceProvider} @@ -11108,6 +11109,107 @@ trait APIMethods600 { } } + staticResourceDocs += ResourceDoc( + getPrivateAccountByIdFull, + implementedInApiVersion, + nameOf(getPrivateAccountByIdFull), + "GET", + "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account", + "Get Account by Id (Full)", + """Information returned about an account specified by ACCOUNT_ID as moderated by the view (VIEW_ID): + | + |* Number + |* Owners + |* Type + |* Balance + |* Available views (sorted by short_name) + | + |More details about the data moderation by the view [here](#1_2_1-getViewsForBankAccount). + | + |PSD2 Context: PSD2 requires customers to have access to their account information via third party applications. + |This call provides balance and other account information via delegated authentication using OAuth. + | + |Authentication is required if the 'is_public' field in view (VIEW_ID) is not set to `true`. + |""".stripMargin, + EmptyBody, + ModeratedAccountJSON600( + id = "5995d6a2-01b3-423c-a173-5481df49bdaf", + label = "NoneLabel", + number = "123", + owners = List(userJSONV121), + product_code = ExampleValue.productCodeExample.value, + balance = amountOfMoneyJsonV121, + views_available = List(ViewJsonV600( + view_id = "owner", + short_name = "Owner", + description = "The owner of the account", + metadata_view = "owner", + is_public = false, + is_system = true, + is_firehose = Some(false), + alias = "private", + hide_metadata_if_alias_used = false, + can_grant_access_to_views = List("owner"), + can_revoke_access_to_views = List("owner"), + allowed_actions = List("can_see_transaction_amount", "can_see_bank_account_balance") + )), + bank_id = ExampleValue.bankIdExample.value, + account_routings = List(accountRoutingJsonV121), + account_attributes = List(accountAttributeResponseJson), + tags = List(accountTagJSON) + ), + List( + $AuthenticatedUserIsRequired, + $BankNotFound, + $BankAccountNotFound, + $UserNoPermissionAccessView, + UnknownError + ), + apiTagAccount :: Nil + ) + + lazy val getPrivateAccountByIdFull: OBPEndpoint = { + case "banks" :: BankId(bankId) :: "accounts" :: AccountId( + accountId + ) :: ViewId(viewId) :: "account" :: Nil JsonGet req => { cc => + implicit val ec = EndpointContext(Some(cc)) + for { + (user @ Full(u), _, account, view, callContext) <- + SS.userBankAccountView + moderatedAccount <- NewStyle.function.moderatedBankAccountCore( + account, + view, + user, + callContext + ) + (accountAttributes, callContext) <- NewStyle.function + .getAccountAttributesByAccount( + bankId, + accountId, + callContext: Option[CallContext] + ) + } yield { + val availableViews = + Views.views.vend.privateViewsUserCanAccessForAccount( + u, + BankIdAccountId(account.bankId, account.accountId) + ) + val viewsAvailable = + availableViews.map(JSONFactory600.createViewJsonV600).sortBy(_.short_name) + val tags = Tags.tags.vend.getTagsOnAccount(bankId, accountId)(viewId) + ( + createBankAccountJSON600( + moderatedAccount, + viewsAvailable, + accountAttributes, + tags + ), + HttpCode.`200`(callContext) + ) + } + } + } + } } diff --git a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala index 54e9ea7044..5e341d95d6 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala @@ -17,7 +17,7 @@ import code.api.util.APIUtil.stringOrNull import code.metrics.ConnectorTrace import code.api.util.RateLimitingPeriod.LimitCallPeriod import code.api.util._ -import code.api.v1_2_1.{AccountHolderJSON, BankRoutingJsonV121, OtherAccountMetadataJSON, TransactionDetailsJSON, TransactionMetadataJSON} +import code.api.v1_2_1.{AccountHolderJSON, BankRoutingJsonV121, OtherAccountMetadataJSON, TransactionDetailsJSON, TransactionMetadataJSON, UserJSONV121} import code.api.v1_4_0.JSONFactory1_4_0.{CustomerFaceImageJson, MetaJsonV140, createMetaJson} import code.api.v2_0_0.{BasicViewJson, EntitlementJSONs, JSONFactory200} import code.api.v2_1_0.CustomerCreditRatingJSON @@ -30,7 +30,7 @@ import code.api.v3_0_0.{ } import code.api.v3_1_0.{AccountAttributeResponseJson, ProductAttributeResponseWithoutBankIdJson, RateLimit, RedisCallLimitJson} import code.api.v3_1_0.JSONFactory310.createProductAttributesJson -import code.api.v4_0_0.{BankAttributeBankResponseJsonV400, ProductFeeJsonV400, ProductFeeValueJsonV400, TransactionAttributeResponseJson, UserAgreementJson} +import code.api.v4_0_0.{AccountTagJSON, BankAttributeBankResponseJsonV400, ProductFeeJsonV400, ProductFeeValueJsonV400, TransactionAttributeResponseJson, UserAgreementJson} import code.entitlement.Entitlement import code.apiproduct.ApiProductTrait import code.apiproductattribute.ApiProductAttributeTrait @@ -2427,4 +2427,43 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable { users: List[UserWithViewAccessJsonV600] ) + case class ModeratedAccountJSON600( + id: String, + label: String, + number: String, + owners: List[UserJSONV121], + product_code: String, + balance: AmountOfMoneyJsonV121, + views_available: List[ViewJsonV600], + bank_id: String, + account_routings: List[AccountRoutingJsonV121], + account_attributes: List[AccountAttributeResponseJson], + tags: List[AccountTagJSON] + ) + + def createBankAccountJSON600( + account: ModeratedBankAccountCore, + viewsAvailable: List[ViewJsonV600], + accountAttributes: List[AccountAttribute], + tags: List[TransactionTag] + ): ModeratedAccountJSON600 = { + import code.api.v1_2_1.JSONFactory.{createAmountOfMoneyJSON, createOwnersJSON} + import code.api.v3_0_0.JSONFactory300.createAccountRoutingsJSON + import code.api.v3_1_0.JSONFactory310.createAccountAttributeJson + import code.api.v4_0_0.JSONFactory400.createAccountTagJSON + ModeratedAccountJSON600( + id = account.accountId.value, + label = stringOptionOrNull(account.label), + number = stringOptionOrNull(account.number), + owners = createOwnersJSON(account.owners.getOrElse(Set()), ""), + product_code = stringOptionOrNull(account.accountType), + balance = createAmountOfMoneyJSON(account.currency.getOrElse(""), account.balance.getOrElse("")), + views_available = viewsAvailable, + bank_id = stringOrNull(account.bankId.value), + account_routings = createAccountRoutingsJSON(account.accountRoutings), + account_attributes = accountAttributes.map(createAccountAttributeJson), + tags = tags.map(createAccountTagJSON) + ) + } + } From e35a47ed481c0bcd3f3dd76788f68efb5f3e1f91 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Mon, 2 Mar 2026 12:39:42 +0100 Subject: [PATCH 14/19] Features endpoint --- .../SwaggerDefinitionsJSON.scala | 14 +++++++ .../scala/code/api/v6_0_0/APIMethods600.scala | 39 +++++++++++++++++++ .../code/api/v6_0_0/JSONFactory6.0.0.scala | 14 +++++++ 3 files changed, 67 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 16ecda95a6..0591bd6a1e 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 @@ -5323,6 +5323,20 @@ object SwaggerDefinitionsJSON { ) lazy val apiProductsJsonV600 = ApiProductsJsonV600(List(apiProductJsonV600)) + lazy val featuresJsonV600 = FeaturesJsonV600( + allow_public_views = true, + allow_abac_account_access = false, + allow_account_firehose = false, + allow_customer_firehose = false, + allow_direct_login = true, + allow_gateway_login = false, + allow_oauth2_login = true, + allow_dauth = false, + allow_sandbox_account_creation = false, + allow_sandbox_data_import = false, + allow_account_deletion = false + ) + lazy val jsonScalaConnectorMethod = JsonConnectorMethod(Some(connectorMethodIdExample.value),"getBank", connectorMethodBodyScalaExample.value, "Scala") lazy val jsonScalaConnectorMethodMethodBody = JsonConnectorMethodMethodBody(connectorMethodBodyScalaExample.value, "Scala") diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 645dee2626..3986bc13c4 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -127,6 +127,45 @@ trait APIMethods600 { } } + staticResourceDocs += ResourceDoc( + getFeatures, + implementedInApiVersion, + nameOf(getFeatures), + "GET", + "/features", + "Get Features", + """Returns information about the features enabled on this OBP instance. + | + |No Authentication is Required.""", + EmptyBody, + featuresJsonV600, + List(UnknownError), + apiTagApi :: Nil) + + lazy val getFeatures: OBPEndpoint = { + case "features" :: Nil JsonGet _ => { + cc => implicit val ec = EndpointContext(Some(cc)) + for { + _ <- Future(()) + } yield { + val featuresJson = FeaturesJsonV600( + allow_public_views = APIUtil.getPropsAsBoolValue("allow_public_views", false), + allow_abac_account_access = APIUtil.getPropsAsBoolValue("allow_abac_account_access", false), + allow_account_firehose = APIUtil.getPropsAsBoolValue("allow_account_firehose", false), + allow_customer_firehose = APIUtil.getPropsAsBoolValue("allow_customer_firehose", false), + allow_direct_login = APIUtil.getPropsAsBoolValue("allow_direct_login", true), + allow_gateway_login = APIUtil.getPropsAsBoolValue("allow_gateway_login", false), + allow_oauth2_login = APIUtil.getPropsAsBoolValue("allow_oauth2_login", true), + allow_dauth = APIUtil.getPropsAsBoolValue("allow_dauth", false), + allow_sandbox_account_creation = APIUtil.getPropsAsBoolValue("allow_sandbox_account_creation", false), + allow_sandbox_data_import = APIUtil.getPropsAsBoolValue("allow_sandbox_data_import", false), + allow_account_deletion = APIUtil.getPropsAsBoolValue("allow_account_deletion", false) + ) + (featuresJson, HttpCode.`200`(cc.callContext)) + } + } + } + staticResourceDocs += ResourceDoc( createTransactionRequestHold, implementedInApiVersion, diff --git a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala index 5e341d95d6..5ff232ea5e 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala @@ -50,6 +50,20 @@ import net.liftweb.common.Box import java.util.Date +case class FeaturesJsonV600( + allow_public_views: Boolean, + allow_abac_account_access: Boolean, + allow_account_firehose: Boolean, + allow_customer_firehose: Boolean, + allow_direct_login: Boolean, + allow_gateway_login: Boolean, + allow_oauth2_login: Boolean, + allow_dauth: Boolean, + allow_sandbox_account_creation: Boolean, + allow_sandbox_data_import: Boolean, + allow_account_deletion: Boolean +) + case class CardanoPaymentJsonV600( address: String, amount: CardanoAmountJsonV600, From 8e70c4bd3c5185290b219ff92366f840dc003fe0 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Tue, 3 Mar 2026 22:56:21 +0100 Subject: [PATCH 15/19] If , else instead of .or so we can better log paths. Don't increment bad login attempts if not even validated. Added Verify External User Credentials Test.scala --- .../main/scala/code/api/util/Glossary.scala | 2 +- .../scala/code/api/v6_0_0/APIMethods600.scala | 21 ++++- .../code/model/dataAccess/AuthUser.scala | 70 +++++++++------- .../v6_0_0/VerifyUserCredentialsTest.scala | 80 +++++++++++++++++++ 4 files changed, 138 insertions(+), 35 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/Glossary.scala b/obp-api/src/main/scala/code/api/util/Glossary.scala index 758ab139a4..96952353bf 100644 --- a/obp-api/src/main/scala/code/api/util/Glossary.scala +++ b/obp-api/src/main/scala/code/api/util/Glossary.scala @@ -5237,7 +5237,7 @@ object Glossary extends MdcLoggable { | |1. **Check only** — validates credentials and returns user info, but does not create a session or token |2. **Requires an already-authenticated caller** with `canVerifyUserCredentials` role (or SuperAdmin) - |3. **Does not auto-provision users** — unlike `externalUserHelper()` in the web login flow, this endpoint will not create a new AuthUser if the user doesn't exist locally + |3. **May auto-provision users** — if the local lookup fails and the external fallback via `externalUserHelper()` / `checkExternalUserViaConnector()` succeeds, a new AuthUser and ResourceUser will be created locally (same behaviour as the web login flow) |4. **Provider matching** — optionally verifies the user's provider matches what was posted (skipped if provider is empty) | |### Key Source Files diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 66c33266a3..1bbe46f1d9 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -8758,10 +8758,23 @@ trait APIMethods600 { } // Validate credentials using the existing AuthUser mechanism - resourceUserIdBox = //we first try to get the userId from local, if not find, we try to get it from external - code.model.dataAccess.AuthUser.getResourceUserId(postedData.username, postedData.password, postedData.provider) - - .or(code.model.dataAccess.AuthUser.externalUserHelper(postedData.username, postedData.password).map(_.user.get)) + resourceUserIdBox = + if (postedData.provider == Constant.localIdentityProvider || postedData.provider.isEmpty) { + // Local provider: only check local credentials. No external fallback. + val result = code.model.dataAccess.AuthUser.getResourceUserId( + postedData.username, postedData.password, Constant.localIdentityProvider + ) + logger.info(s"verifyUserCredentials says: local getResourceUserId result: $result") + result + } else { + // External provider: validate via connector. Local DB stores a random UUID + // as password for external users, so getResourceUserId would always fail. + val connectorResult = code.model.dataAccess.AuthUser.externalUserHelper( + postedData.username, postedData.password + ).map(_.user.get) + logger.info(s"verifyUserCredentials says: externalUserHelper result: $connectorResult") + connectorResult + } // Check if account is locked _ <- Helper.booleanToFuture(UsernameHasBeenLocked, 401, callContext) { resourceUserIdBox != Full(code.model.dataAccess.AuthUser.usernameLockedStateCode) diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala index 799769faf1..a7b1a340b6 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala @@ -784,38 +784,27 @@ import net.liftweb.util.Helpers._ def getResourceUserId(username: String, password: String, provider: String = Constant.localIdentityProvider): Box[Long] = { + logger.info(s"getResourceUserId says: starting for username: $username, provider: $provider") findAuthUserByUsernameAndProvider(username, provider) match { // We have a user from the local provider. case Full(user) if (user.getProvider() == Constant.localIdentityProvider) => - if ( - user.validated_? && - // User is NOT locked AND the password is good - ! LoginAttempt.userIsLocked(user.getProvider(), username) && - user.testPassword(Full(password))) - { - // We logged in correctly, so reset badLoginAttempts counter (if it exists) - LoginAttempt.resetBadLoginAttempts(user.getProvider(), username) - Full(user.user.get) // Return the user. - } - // User is unlocked AND password is bad - else if ( - user.validated_? && - ! LoginAttempt.userIsLocked(user.getProvider(), username) && - ! user.testPassword(Full(password)) - ) { - LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username) + if (!user.validated_?) { + logger.info(s"getResourceUserId says: user not validated, username: $username, provider: $provider") Empty } - // User is locked - else if (LoginAttempt.userIsLocked(user.getProvider(), username)) - { + else if (LoginAttempt.userIsLocked(user.getProvider(), username)) { + logger.info(s"getResourceUserId says: user is locked, username: $username, provider: $provider") LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username) - logger.info(ErrorMessages.UsernameHasBeenLocked) //TODO need to fix, use Failure instead, it is used to show the error message to the GUI Full(usernameLockedStateCode) } + else if (user.testPassword(Full(password))) { + logger.info(s"getResourceUserId says: password correct, username: $username, provider: $provider") + LoginAttempt.resetBadLoginAttempts(user.getProvider(), username) + Full(user.user.get) + } else { - // Nothing worked, so just increment bad login attempts + logger.info(s"getResourceUserId says: wrong password, username: $username, provider: $provider") LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username) Empty } @@ -823,6 +812,7 @@ import net.liftweb.util.Helpers._ case Full(user) if (user.getProvider() != Constant.localIdentityProvider) => APIUtil.getPropsAsBoolValue("connector.user.authentication", false) match { case true if !LoginAttempt.userIsLocked(user.getProvider(), username) => + logger.info(s"getResourceUserId says: external user found, checking via connector, username: $username, provider: ${user.getProvider()}") val userId = for { authUser <- checkExternalUserViaConnector(username, password) @@ -834,18 +824,27 @@ import net.liftweb.util.Helpers._ resourceUser.get } userId match { - case Full(l: Long) => Full(l) + case Full(l: Long) => + logger.info(s"getResourceUserId says: external connector auth succeeded, username: $username, provider: ${user.getProvider()}") + Full(l) case _ => + logger.info(s"getResourceUserId says: external connector auth failed, username: $username, provider: ${user.getProvider()}") LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username) Empty } + case true => + logger.info(s"getResourceUserId says: external user is locked, username: $username, provider: ${user.getProvider()}") + LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username) + Empty case false => + logger.info(s"getResourceUserId says: connector.user.authentication is false, username: $username, provider: ${user.getProvider()}") LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username) Empty } - // Everything else. + // Everything else (user not found for this username+provider). case _ => - LoginAttempt.incrementBadLoginAttempts(user.foreign.map(_.provider).getOrElse(Constant.HostName), username) + logger.info(s"getResourceUserId says: user not found, username: $username, provider: $provider") + LoginAttempt.incrementBadLoginAttempts(provider, username) Empty } } @@ -1174,11 +1173,22 @@ def restoreSomeSessions(): Unit = { * This method will update the views and createAccountHolder .... */ def externalUserHelper(name: String, password: String): Box[AuthUser] = { - for { - user <- checkExternalUserViaConnector(name, password) - u <- Users.users.vend.getUserByProviderAndUsername(user.getProvider(), name) - } yield { - user + logger.info(s"externalUserHelper says: starting for username: $name") + val connectorUserBox = checkExternalUserViaConnector(name, password) + logger.info(s"externalUserHelper says: checkExternalUserViaConnector result: ${connectorUserBox.getClass.getSimpleName}") + connectorUserBox match { + case Full(user) => + val providerUserBox = Users.users.vend.getUserByProviderAndUsername(user.getProvider(), name) + logger.info(s"externalUserHelper says: getUserByProviderAndUsername(${user.getProvider()}, $name) result: ${providerUserBox.getClass.getSimpleName}") + providerUserBox match { + case Full(_) => Full(user) + case _ => + logger.warn(s"externalUserHelper says: connector authenticated user but getUserByProviderAndUsername failed for provider: ${user.getProvider()}, username: $name") + Empty + } + case _ => + logger.info(s"externalUserHelper says: checkExternalUserViaConnector failed for username: $name") + Empty } } diff --git a/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala index 2b77b2fb73..06e50c961d 100644 --- a/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala +++ b/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala @@ -202,6 +202,86 @@ class VerifyUserCredentialsTest extends V600ServerSetup with DefaultUsers { response.body.extract[ErrorMessage].message should include("OBP-20004") } + scenario("Wrong password for external provider should not increment local user bad login attempts", ApiEndpoint, VersionOfApi) { + // This test verifies the fix for collateral damage: two users share the same username + // but have different providers. Verifying the external user with wrong credentials + // must NOT increment bad login attempts on the local user. + val sharedUsername = "shared_user_" + randomString(8).toLowerCase + val localPassword = "LocalPassword123!" + val localEmail = sharedUsername + "@local.example.com" + val externalProvider = "external_test_provider" + + // Create a local user + val localUser = AuthUser.create + .email(localEmail) + .username(sharedUsername) + .password(localPassword) + .validated(true) + .firstName("Local") + .lastName("User") + .provider(Constant.localIdentityProvider) + .saveMe() + + // Create an external user with the same username (dummy password, as external users have) + val externalUser = AuthUser.create + .email(sharedUsername + "@external.example.com") + .username(sharedUsername) + .password(net.liftweb.util.Helpers.randomString(40)) // random dummy password + .validated(true) + .firstName("External") + .lastName("User") + .provider(externalProvider) + .saveMe() + + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + // Reset any prior login attempts for both + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, sharedUsername) + LoginAttempt.resetBadLoginAttempts(externalProvider, sharedUsername) + + // Record local user's bad login attempts before the test + val localAttemptsBefore = LoginAttempt.getOrCreateBadLoginStatus( + Constant.localIdentityProvider, sharedUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + + When("We verify credentials with the external provider (which will fail)") + val postJson = Map( + "username" -> sharedUsername, + "password" -> "SomeWrongPassword!", + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + + Then("We should get a 401") + response.code should equal(401) + + And("The local user's bad login attempts should NOT have increased") + val localAttemptsAfter = LoginAttempt.getOrCreateBadLoginStatus( + Constant.localIdentityProvider, sharedUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + localAttemptsAfter should equal(localAttemptsBefore) + + And("The local user should still be able to log in with correct credentials") + val localPostJson = Map( + "username" -> sharedUsername, + "password" -> localPassword, + "provider" -> Constant.localIdentityProvider + ) + val localRequest = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val localResponse = makePostRequest(localRequest, write(localPostJson)) + localResponse.code should equal(200) + } finally { + // Clean up + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, sharedUsername) + LoginAttempt.resetBadLoginAttempts(externalProvider, sharedUsername) + localUser.delete_! + externalUser.delete_! + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + scenario("Fail with invalid JSON format", ApiEndpoint, VersionOfApi) { // Add the required entitlement val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) From c962ee1d1ad8521e3e24762c9ab83b700c882948 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Tue, 3 Mar 2026 22:56:26 +0100 Subject: [PATCH 16/19] Create VerifyExternalUserCredentialsTest.scala --- .../VerifyExternalUserCredentialsTest.scala | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala diff --git a/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala new file mode 100644 index 0000000000..28ecc1fb1a --- /dev/null +++ b/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala @@ -0,0 +1,185 @@ +package code.api.v6_0_0 + +import code.api.Constant +import code.api.util.APIUtil.OAuth._ +import code.api.util.{CallContext, ErrorMessages} +import code.api.util.ApiRole.CanVerifyUserCredentials +import code.api.v6_0_0.APIMethods600.Implementations6_0_0 +import code.bankconnectors.Connector +import code.entitlement.Entitlement +import code.loginattempts.LoginAttempt +import code.model.dataAccess.AuthUser +import code.setup.DefaultUsers +import code.util.Helper.MdcLoggable +import com.github.dwickern.macros.NameOf.nameOf +import com.openbankproject.commons.model.{ErrorMessage, InboundExternalUser} +import com.openbankproject.commons.util.ApiVersion +import net.liftweb.common.{Box, Empty, Full} +import net.liftweb.json.Serialization.write +import net.liftweb.util.Helpers.randomString +import org.scalatest.Tag + +/** + * Test suite for verifying external user credentials via a mocked connector. + * + * This is a separate test class because it swaps the global Connector to mock + * checkExternalUserCredentials — which would interfere with local-auth tests + * in VerifyUserCredentialsTest. + */ +class VerifyExternalUserCredentialsTest extends V600ServerSetup with DefaultUsers { + + object VersionOfApi extends Tag(ApiVersion.v6_0_0.toString) + object ApiEndpoint extends Tag(nameOf(Implementations6_0_0.verifyUserCredentials)) + + val externalProvider = "mock_external_provider" + val externalUsername = "ext_user_" + randomString(8).toLowerCase + val externalPassword = "ExternalPassword123!" + val externalEmail = externalUsername + "@external.example.com" + + // Mock connector that only overrides checkExternalUserCredentials. + // Accepts one known username+password pair; rejects everything else. + object MockExternalAuthConnector extends Connector with MdcLoggable { + implicit override val nameOfConnector = "MockExternalAuthConnector" + + override def checkExternalUserCredentials( + username: String, + password: String, + callContext: Option[CallContext] + ): Box[InboundExternalUser] = { + if (username == externalUsername && password == externalPassword) { + Full(InboundExternalUser( + aud = "", + exp = "", + iat = "", + iss = externalProvider, + sub = externalUsername, + azp = None, + email = Some(externalEmail), + emailVerified = Some("true"), + name = Some("External Test User") + )) + } else { + Empty + } + } + } + + override def beforeAll(): Unit = { + super.beforeAll() + Connector.connector.default.set(MockExternalAuthConnector) + } + + override def afterAll(): Unit = { + Connector.connector.default.set(Connector.buildOne) + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + super.afterAll() + } + + feature(s"Verify External User Credentials - POST /obp/v6.0.0/users/verify-credentials - $VersionOfApi") { + + scenario("Successfully verify external user credentials via connector", ApiEndpoint, VersionOfApi) { + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + When("We verify valid external credentials") + val postJson = Map( + "username" -> externalUsername, + "password" -> externalPassword, + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = try { + makePostRequest(request, write(postJson)) + } finally { + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + + Then("We should get a 200") + response.code should equal(200) + + And("The response should contain the external user details") + val json = response.body + (json \ "username").extract[String] should equal(externalUsername) + (json \ "provider").extract[String] should equal(externalProvider) + } + + scenario("Fail to verify external user with wrong password", ApiEndpoint, VersionOfApi) { + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + When("We verify external credentials with wrong password") + val postJson = Map( + "username" -> externalUsername, + "password" -> "WrongPassword!", + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = try { + makePostRequest(request, write(postJson)) + } finally { + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + + Then("We should get a 401") + response.code should equal(401) + response.body.extract[ErrorMessage].message should include("OBP-20004") + } + + scenario("External auth failure should not affect local user with same username", ApiEndpoint, VersionOfApi) { + // Create a local user with the same username as the external user + val localPassword = "LocalPassword123!" + val localUser = AuthUser.create + .email(externalUsername + "@local.example.com") + .username(externalUsername) + .password(localPassword) + .validated(true) + .firstName("Local") + .lastName("User") + .provider(Constant.localIdentityProvider) + .saveMe() + + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, externalUsername) + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + + val localAttemptsBefore = LoginAttempt.getOrCreateBadLoginStatus( + Constant.localIdentityProvider, externalUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + + When("We fail to verify external credentials with wrong password") + val postJson = Map( + "username" -> externalUsername, + "password" -> "WrongPassword!", + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + + Then("We should get a 401") + response.code should equal(401) + + And("The local user's bad login attempts should NOT have increased") + val localAttemptsAfter = LoginAttempt.getOrCreateBadLoginStatus( + Constant.localIdentityProvider, externalUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + localAttemptsAfter should equal(localAttemptsBefore) + + And("The local user should still authenticate successfully") + val localPostJson = Map( + "username" -> externalUsername, + "password" -> localPassword, + "provider" -> Constant.localIdentityProvider + ) + val localRequest = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val localResponse = makePostRequest(localRequest, write(localPostJson)) + localResponse.code should equal(200) + } finally { + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, externalUsername) + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + localUser.delete_! + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + } +} From 0747b00655a193bf3c8ed82287c0b60db5ca1eb8 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Tue, 3 Mar 2026 23:19:11 +0100 Subject: [PATCH 17/19] Additional tests around login --- .../VerifyExternalUserCredentialsTest.scala | 138 +++++++++ .../v6_0_0/VerifyUserCredentialsTest.scala | 284 ++++++++++++++++++ 2 files changed, 422 insertions(+) diff --git a/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala index 28ecc1fb1a..1570f9ecc7 100644 --- a/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala +++ b/obp-api/src/test/scala/code/api/v6_0_0/VerifyExternalUserCredentialsTest.scala @@ -124,6 +124,144 @@ class VerifyExternalUserCredentialsTest extends V600ServerSetup with DefaultUser response.body.extract[ErrorMessage].message should include("OBP-20004") } + scenario("Successful external login should reset bad login attempts for that provider", ApiEndpoint, VersionOfApi) { + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + + When("We first trigger some failed attempts with wrong password") + for (_ <- 1 to 3) { + val postJson = Map( + "username" -> externalUsername, + "password" -> "WrongPassword!", + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(request, write(postJson)) + } + + Then("Bad login attempts should be > 0") + val attemptsBefore = LoginAttempt.getOrCreateBadLoginStatus( + externalProvider, externalUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + attemptsBefore should be > 0 + + When("We then successfully authenticate with correct credentials") + val postJson = Map( + "username" -> externalUsername, + "password" -> externalPassword, + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + + Then("We should get a 200") + response.code should equal(200) + + And("Bad login attempts should have been reset to zero") + val attemptsAfter = LoginAttempt.getOrCreateBadLoginStatus( + externalProvider, externalUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + attemptsAfter should equal(0) + } finally { + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + + scenario("External user should be locked after too many failed attempts", ApiEndpoint, VersionOfApi) { + // max.bad.login.attempts defaults to 5, locking triggers at > 5 (i.e. 6+). + // After locking, even correct credentials should fail. + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + + When("We fire 7 failed login attempts to exceed the lock threshold") + for (_ <- 1 to 7) { + val postJson = Map( + "username" -> externalUsername, + "password" -> "WrongPassword!", + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(request, write(postJson)) + } + + Then("The external user should now be locked") + LoginAttempt.userIsLocked(externalProvider, externalUsername) should be(true) + + When("We try to authenticate with correct credentials") + val postJson = Map( + "username" -> externalUsername, + "password" -> externalPassword, + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + + Then("We should get a 401 because the account is locked") + response.code should equal(401) + } finally { + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + + scenario("External user locking should not lock local user with same username", ApiEndpoint, VersionOfApi) { + // Lock the external user, then verify the local user is unaffected. + val localPassword = "LocalPassword123!" + val localUser = AuthUser.create + .email(externalUsername + "@local.example.com") + .username(externalUsername) + .password(localPassword) + .validated(true) + .firstName("Local") + .lastName("User") + .provider(Constant.localIdentityProvider) + .saveMe() + + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, externalUsername) + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + + When("We lock the external user by firing 7 failed attempts") + for (_ <- 1 to 7) { + val postJson = Map( + "username" -> externalUsername, + "password" -> "WrongPassword!", + "provider" -> externalProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(request, write(postJson)) + } + + Then("The external user should be locked") + LoginAttempt.userIsLocked(externalProvider, externalUsername) should be(true) + + And("The local user should NOT be locked") + LoginAttempt.userIsLocked(Constant.localIdentityProvider, externalUsername) should be(false) + + And("The local user should still authenticate successfully") + val localPostJson = Map( + "username" -> externalUsername, + "password" -> localPassword, + "provider" -> Constant.localIdentityProvider + ) + val localRequest = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val localResponse = makePostRequest(localRequest, write(localPostJson)) + localResponse.code should equal(200) + } finally { + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, externalUsername) + LoginAttempt.resetBadLoginAttempts(externalProvider, externalUsername) + localUser.delete_! + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + scenario("External auth failure should not affect local user with same username", ApiEndpoint, VersionOfApi) { // Create a local user with the same username as the external user val localPassword = "LocalPassword123!" diff --git a/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala index 06e50c961d..394815ac9b 100644 --- a/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala +++ b/obp-api/src/test/scala/code/api/v6_0_0/VerifyUserCredentialsTest.scala @@ -282,6 +282,290 @@ class VerifyUserCredentialsTest extends V600ServerSetup with DefaultUsers { } } + scenario("Empty provider should be treated as local provider", ApiEndpoint, VersionOfApi) { + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + When("We verify valid credentials with an empty provider string") + val postJson = Map( + "username" -> testUsername, + "password" -> testPassword, + "provider" -> "" + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = try { + makePostRequest(request, write(postJson)) + } finally { + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + + Then("We should get a 200 because empty provider is treated as local") + response.code should equal(200) + + And("The response should contain user details") + (response.body \ "username").extract[String] should equal(testUsername) + } + + scenario("Same username across multiple realistic providers should be fully isolated", ApiEndpoint, VersionOfApi) { + // In production, a single username like "alice" might exist under several providers: + // the local OBP instance, Google OIDC, GitHub, and possibly erroneous entries. + // Each must be completely isolated from the others. + val sharedUsername = "alice_" + randomString(8).toLowerCase + val localPassword = "LocalAlice123!" + + val googleProvider = "https://accounts.google.com" + val githubProvider = "https://github.com/login/oauth" + val erroneousProvider = "https://gogle.com" // typo in production data + + // Create a local user + val localUser = AuthUser.create + .email(sharedUsername + "@openbankproject.com") + .username(sharedUsername) + .password(localPassword) + .validated(true) + .firstName("Alice") + .lastName("Local") + .provider(Constant.localIdentityProvider) + .saveMe() + + // Create external users with the same username under different providers + // (as would exist in production when users sign in via different identity providers) + val googleUser = AuthUser.create + .email(sharedUsername + "@gmail.com") + .username(sharedUsername) + .password(randomString(40)) // dummy password, as with all external users + .validated(true) + .firstName("Alice") + .lastName("Google") + .provider(googleProvider) + .saveMe() + + val githubUser = AuthUser.create + .email(sharedUsername + "@github.com") + .username(sharedUsername) + .password(randomString(40)) + .validated(true) + .firstName("Alice") + .lastName("GitHub") + .provider(githubProvider) + .saveMe() + + val erroneousUser = AuthUser.create + .email(sharedUsername + "@gogle.com") + .username(sharedUsername) + .password(randomString(40)) + .validated(true) + .firstName("Alice") + .lastName("Erroneous") + .provider(erroneousProvider) + .saveMe() + + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + // Reset all login attempt counters + val allProviders = List(Constant.localIdentityProvider, googleProvider, githubProvider, erroneousProvider) + allProviders.foreach(p => LoginAttempt.resetBadLoginAttempts(p, sharedUsername)) + + When("We attempt to verify credentials against the Google provider (will fail, no connector)") + val googlePostJson = Map( + "username" -> sharedUsername, + "password" -> "WrongPassword!", + "provider" -> googleProvider + ) + val googleRequest = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(googleRequest, write(googlePostJson)) + + And("We attempt to verify credentials against the GitHub provider (will fail)") + val githubPostJson = Map( + "username" -> sharedUsername, + "password" -> "WrongPassword!", + "provider" -> githubProvider + ) + val githubRequest = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(githubRequest, write(githubPostJson)) + + And("We attempt to verify credentials against the erroneous provider (will fail)") + val erroneousPostJson = Map( + "username" -> sharedUsername, + "password" -> "WrongPassword!", + "provider" -> erroneousProvider + ) + val erroneousRequest = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(erroneousRequest, write(erroneousPostJson)) + + Then("The local user's bad login attempts should still be zero") + val localAttempts = LoginAttempt.getOrCreateBadLoginStatus( + Constant.localIdentityProvider, sharedUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + localAttempts should equal(0) + + And("The local user should still authenticate successfully") + val localPostJson = Map( + "username" -> sharedUsername, + "password" -> localPassword, + "provider" -> Constant.localIdentityProvider + ) + val localRequest = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val localResponse = makePostRequest(localRequest, write(localPostJson)) + localResponse.code should equal(200) + (localResponse.body \ "username").extract[String] should equal(sharedUsername) + (localResponse.body \ "provider").extract[String] should equal(Constant.localIdentityProvider) + + } finally { + val allProviders = List(Constant.localIdentityProvider, googleProvider, githubProvider, erroneousProvider) + allProviders.foreach(p => LoginAttempt.resetBadLoginAttempts(p, sharedUsername)) + localUser.delete_! + googleUser.delete_! + githubUser.delete_! + erroneousUser.delete_! + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + + scenario("Failed external auth for one provider should not affect a different external provider", ApiEndpoint, VersionOfApi) { + // Providers are independent namespaces. Failing against https://accounts.google.com + // should not increment bad attempts for https://github.com/login/oauth. + val sharedUsername = "multi_ext_" + randomString(8).toLowerCase + val googleProvider = "https://accounts.google.com" + val githubProvider = "https://github.com/login/oauth" + + val googleUser = AuthUser.create + .email(sharedUsername + "@gmail.com") + .username(sharedUsername) + .password(randomString(40)) + .validated(true) + .firstName("Test") + .lastName("Google") + .provider(googleProvider) + .saveMe() + + val githubUser = AuthUser.create + .email(sharedUsername + "@github.com") + .username(sharedUsername) + .password(randomString(40)) + .validated(true) + .firstName("Test") + .lastName("GitHub") + .provider(githubProvider) + .saveMe() + + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + LoginAttempt.resetBadLoginAttempts(googleProvider, sharedUsername) + LoginAttempt.resetBadLoginAttempts(githubProvider, sharedUsername) + + When("We fire multiple failed auth attempts against Google provider") + for (_ <- 1 to 3) { + val postJson = Map( + "username" -> sharedUsername, + "password" -> "WrongPassword!", + "provider" -> googleProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(request, write(postJson)) + } + + Then("GitHub provider's bad login attempts should still be zero") + val githubAttempts = LoginAttempt.getOrCreateBadLoginStatus( + githubProvider, sharedUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + githubAttempts should equal(0) + + } finally { + LoginAttempt.resetBadLoginAttempts(googleProvider, sharedUsername) + LoginAttempt.resetBadLoginAttempts(githubProvider, sharedUsername) + googleUser.delete_! + githubUser.delete_! + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + + scenario("Failed local auth should not affect external users with the same username", ApiEndpoint, VersionOfApi) { + // The reverse of the external→local test: wrong local password should not + // touch the external provider's login attempt counter. + val sharedUsername = "reverse_iso_" + randomString(8).toLowerCase + val localPassword = "LocalPassword123!" + val googleProvider = "https://accounts.google.com" + + val localUser = AuthUser.create + .email(sharedUsername + "@openbankproject.com") + .username(sharedUsername) + .password(localPassword) + .validated(true) + .firstName("Test") + .lastName("Local") + .provider(Constant.localIdentityProvider) + .saveMe() + + val googleUser = AuthUser.create + .email(sharedUsername + "@gmail.com") + .username(sharedUsername) + .password(randomString(40)) + .validated(true) + .firstName("Test") + .lastName("Google") + .provider(googleProvider) + .saveMe() + + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, sharedUsername) + LoginAttempt.resetBadLoginAttempts(googleProvider, sharedUsername) + + When("We fire multiple failed local auth attempts with wrong password") + for (_ <- 1 to 3) { + val postJson = Map( + "username" -> sharedUsername, + "password" -> "WrongPassword!", + "provider" -> Constant.localIdentityProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + makePostRequest(request, write(postJson)) + } + + Then("Google provider's bad login attempts should still be zero") + val googleAttempts = LoginAttempt.getOrCreateBadLoginStatus( + googleProvider, sharedUsername + ).map(_.badAttemptsSinceLastSuccessOrReset).openOr(0) + googleAttempts should equal(0) + + } finally { + LoginAttempt.resetBadLoginAttempts(Constant.localIdentityProvider, sharedUsername) + LoginAttempt.resetBadLoginAttempts(googleProvider, sharedUsername) + localUser.delete_! + googleUser.delete_! + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + + scenario("Non-existent external user should fail cleanly", ApiEndpoint, VersionOfApi) { + // Post a username that has no AuthUser record at all for this external provider. + // Should get 401 without any side effects on other providers. + val nonExistentUsername = "no_such_user_" + randomString(8).toLowerCase + val googleProvider = "https://accounts.google.com" + + val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) + + try { + When("We verify credentials for a non-existent external user") + val postJson = Map( + "username" -> nonExistentUsername, + "password" -> "SomePassword!", + "provider" -> googleProvider + ) + val request = (v6_0_0_Request / "users" / "verify-credentials").POST <@ (user1) + val response = makePostRequest(request, write(postJson)) + + Then("We should get a 401") + response.code should equal(401) + response.body.extract[ErrorMessage].message should include("OBP-20004") + } finally { + Entitlement.entitlement.vend.deleteEntitlement(addedEntitlement) + } + } + scenario("Fail with invalid JSON format", ApiEndpoint, VersionOfApi) { // Add the required entitlement val addedEntitlement = Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanVerifyUserCredentials.toString) From b712ec9bfb65af8b74eec0391a8ea147c7d1d9c0 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Tue, 3 Mar 2026 23:23:29 +0100 Subject: [PATCH 18/19] Whitelist the word keycloak --- .../src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala b/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala index 7328b81e95..479e3fb5cd 100644 --- a/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala +++ b/obp-api/src/test/scala/code/api/v6_0_0/AppDirectoryTest.scala @@ -216,10 +216,15 @@ class AppDirectoryTest extends V600ServerSetup { } scenario("publicAppUrlPropNames do not include sensitive keys", VersionOfApi, ApiEndpoint) { + // Words that contain sensitive substrings but are not themselves sensitive. + // e.g. "keycloak" contains "key" but is just a product name. + val whitelistedWords = List("keycloak") APIUtil.publicAppUrlPropNames.foreach { key => APIUtil.sensitiveKeywords.foreach { keyword => + // Strip whitelisted words before checking for sensitive substrings + val keyToCheck = whitelistedWords.foldLeft(key.toLowerCase) { (k, w) => k.replace(w, "") } withClue(s"Public URL key '$key' should not contain sensitive keyword '$keyword': ") { - key.toLowerCase should not include(keyword) + keyToCheck should not include(keyword) } } } From 4df70fcd84b177aca0d188d8cc7a83dfb297a473 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Wed, 4 Mar 2026 00:21:57 +0100 Subject: [PATCH 19/19] Better calling of externalUserHelper --- .../scala/code/api/v6_0_0/APIMethods600.scala | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 1bbe46f1d9..3105f4cdf0 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -8769,11 +8769,23 @@ trait APIMethods600 { } else { // External provider: validate via connector. Local DB stores a random UUID // as password for external users, so getResourceUserId would always fail. - val connectorResult = code.model.dataAccess.AuthUser.externalUserHelper( - postedData.username, postedData.password - ).map(_.user.get) - logger.info(s"verifyUserCredentials says: externalUserHelper result: $connectorResult") - connectorResult + if (LoginAttempt.userIsLocked(postedData.provider, postedData.username)) { + logger.info(s"verifyUserCredentials says: external user is locked, provider: ${postedData.provider}, username: ${postedData.username}") + Full(code.model.dataAccess.AuthUser.usernameLockedStateCode) + } else { + val connectorResult = code.model.dataAccess.AuthUser.externalUserHelper( + postedData.username, postedData.password + ).map(_.user.get) + logger.info(s"verifyUserCredentials says: externalUserHelper result: $connectorResult") + connectorResult match { + case Full(_) => + LoginAttempt.resetBadLoginAttempts(postedData.provider, postedData.username) + connectorResult + case _ => + LoginAttempt.incrementBadLoginAttempts(postedData.provider, postedData.username) + connectorResult + } + } } // Check if account is locked _ <- Helper.booleanToFuture(UsernameHasBeenLocked, 401, callContext) {