feature/Add BankId in account routing unique constraint and add release notes

This commit is contained in:
Guillaume Kergreis 2020-08-11 16:48:16 +02:00
parent a7a3ed0cb4
commit 4a91700841
14 changed files with 42 additions and 23 deletions

View File

@ -428,6 +428,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats {
private def extractAccountData(scheme: String, address: String): (String, String, String, String, String) = {
val (iban: String, bban: String, pan: String, maskedPan: String, currency: String) = Connector.connector.vend.getBankAccountByRouting(
None,
scheme,
address,
None

View File

@ -216,9 +216,9 @@ object NewStyle {
}
}
def getBankAccountByRouting(scheme: String, address: String, callContext: Option[CallContext]) : OBPReturnType[BankAccount] = {
Future(Connector.connector.vend.getBankAccountByRouting(scheme: String, address : String, callContext: Option[CallContext])) map { i =>
unboxFullOrFail(i, callContext,s"$BankAccountNotFoundByAccountRouting Current scheme is $scheme, current address is $address", 404 )
def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]) : OBPReturnType[BankAccount] = {
Future(Connector.connector.vend.getBankAccountByRouting(bankId: Option[BankId], scheme: String, address : String, callContext: Option[CallContext])) map { i =>
unboxFullOrFail(i, callContext,s"$BankAccountNotFoundByAccountRouting Current scheme is $scheme, current address is $address, current bankId is $bankId", 404 )
}
}

View File

@ -4814,7 +4814,7 @@ trait APIMethods310 {
consentJson.account_routings.map(_.scheme).distinct.size == consentJson.account_routings.size
}
alreadyExistAccountRoutings <- Future.sequence(consentJson.account_routings.map(accountRouting =>
NewStyle.function.getBankAccountByRouting(accountRouting.scheme, accountRouting.address, callContext)
NewStyle.function.getBankAccountByRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext)
.map {
// If we find an already existing account routing linked to the account, it just mean we don't want to update it
case bankAccount if !(bankAccount._1.bankId == bankId && bankAccount._1.accountId == accountId) => Some(accountRouting)
@ -4822,7 +4822,7 @@ trait APIMethods310 {
} fallbackTo Future.successful(None)
))
alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect {
case Some(accountRouting) => s"scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
}
_ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})") {
alreadyExistingAccountRouting.isEmpty
@ -5478,10 +5478,10 @@ trait APIMethods310 {
createAccountJson.account_routings.map(_.scheme).distinct.size == createAccountJson.account_routings.size
}
alreadyExistAccountRoutings <- Future.sequence(createAccountJson.account_routings.map(accountRouting =>
NewStyle.function.getBankAccountByRouting(accountRouting.scheme, accountRouting.address, callContext).map(_ => Some(accountRouting)).fallbackTo(Future.successful(None))
NewStyle.function.getBankAccountByRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext).map(_ => Some(accountRouting)).fallbackTo(Future.successful(None))
))
alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect {
case Some(accountRouting) => s"scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
}
_ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})") {
alreadyExistingAccountRouting.isEmpty

View File

@ -1267,10 +1267,10 @@ trait APIMethods400 {
createAccountJson.account_routings.map(_.scheme).distinct.size == createAccountJson.account_routings.size
}
alreadyExistAccountRoutings <- Future.sequence(createAccountJson.account_routings.map(accountRouting =>
NewStyle.function.getBankAccountByRouting(accountRouting.scheme, accountRouting.address, callContext).map(_ => Some(accountRouting)).fallbackTo(Future.successful(None))
NewStyle.function.getBankAccountByRouting(Some(bankId), accountRouting.scheme, accountRouting.address, callContext).map(_ => Some(accountRouting)).fallbackTo(Future.successful(None))
))
alreadyExistingAccountRouting = alreadyExistAccountRoutings.collect {
case Some(accountRouting) => s"scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
case Some(accountRouting) => s"bankId: $bankId, scheme: ${accountRouting.scheme}, address: ${accountRouting.address}"
}
_ <- Helper.booleanToFuture(s"$AccountRoutingAlreadyExist (${alreadyExistingAccountRouting.mkString("; ")})") {
alreadyExistingAccountRouting.isEmpty

View File

@ -447,7 +447,7 @@ trait Connector extends MdcLoggable {
def getBankAccountLegacy(bankId : BankId, accountId : AccountId, callContext: Option[CallContext]) : Box[(BankAccount, Option[CallContext])]= Failure(setUnimplementedError)
def getBankAccountByIban(iban : String, callContext: Option[CallContext]) : OBPReturnType[Box[BankAccount]]= Future{(Failure(setUnimplementedError),callContext)}
def getBankAccountByRouting(scheme : String, address : String, callContext: Option[CallContext]) : Box[(BankAccount, Option[CallContext])]= Failure(setUnimplementedError)
def getBankAccountByRouting(bankId: Option[BankId], scheme : String, address : String, callContext: Option[CallContext]) : Box[(BankAccount, Option[CallContext])]= Failure(setUnimplementedError)
def getBankAccounts(bankIdAccountIds: List[BankIdAccountId], callContext: Option[CallContext]) : OBPReturnType[Box[List[BankAccount]]]= Future{(Failure(setUnimplementedError), callContext)}

View File

@ -511,13 +511,20 @@ object LocalMappedConnector extends Connector with MdcLoggable {
}
override def getBankAccountByIban(iban: String, callContext: Option[CallContext]): OBPReturnType[Box[BankAccount]] = Future {
getBankAccountByRouting("IBAN", iban, callContext)
getBankAccountByRouting(None, "IBAN", iban, callContext)
}
override def getBankAccountByRouting(scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
BankAccountRouting
.find(By(BankAccountRouting.AccountRoutingScheme, scheme), By(BankAccountRouting.AccountRoutingAddress, address))
.flatMap(accountRouting => getBankAccountCommon(accountRouting.bankId, accountRouting.accountId, callContext))
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
bankId match {
case Some(bankId) =>
BankAccountRouting
.find(By(BankAccountRouting.BankId, bankId.value), By(BankAccountRouting.AccountRoutingScheme, scheme), By(BankAccountRouting.AccountRoutingAddress, address))
.flatMap(accountRouting => getBankAccountCommon(accountRouting.bankId, accountRouting.accountId, callContext))
case None =>
BankAccountRouting
.find(By(BankAccountRouting.AccountRoutingScheme, scheme), By(BankAccountRouting.AccountRoutingAddress, address))
.flatMap(accountRouting => getBankAccountCommon(accountRouting.bankId, accountRouting.accountId, callContext))
}
}
def getBankAccountCommon(bankId: BankId, accountId: AccountId, callContext: Option[CallContext]) = {

View File

@ -580,6 +580,7 @@ object AkkaConnector_vDec2018 extends Connector with AkkaConnectorActorInit {
inboundTopic = None,
exampleOutboundMessage = (
OutBoundGetBankAccountByRouting(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext,
bankId=Some(BankId(bankIdExample.value)),
scheme="string",
address="string")
),
@ -605,9 +606,9 @@ object AkkaConnector_vDec2018 extends Connector with AkkaConnectorActorInit {
adapterImplementation = Some(AdapterImplementation("- Core", 1))
)
override def getBankAccountByRouting(scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
import com.openbankproject.commons.dto.{OutBoundGetBankAccountByRouting => OutBound, InBoundGetBankAccountByRouting => InBound}
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, scheme, address)
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, scheme, address)
val response: Future[Box[InBound]] = (southSideActor ? req).mapTo[InBound].recoverWith(recoverFunction).map(Box !! _)
response.map(convertToTuple[BankAccountCommons](callContext))
}

View File

@ -1011,6 +1011,7 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
userOwners=List( InternalBasicUser(userId=userIdExample.value,
emailAddress=emailExample.value,
name=usernameExample.value))))))))),
bankId=Some(BankId(bankIdExample.value)),
scheme="string",
address="string")
),
@ -1043,10 +1044,10 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
adapterImplementation = Some(AdapterImplementation("- Core", 1))
)
// url example: /getBankAccountByRouting
override def getBankAccountByRouting(scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
import com.openbankproject.commons.dto.{OutBoundGetBankAccountByRouting => OutBound, InBoundGetBankAccountByRouting => InBound}
val url = getUrl(callContext, "getBankAccountByRouting")
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull , scheme, address)
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankId, scheme, address)
val result: OBPReturnType[Box[BankAccountCommons]] = sendRequest[InBound](url, HttpMethods.POST, req, callContext).map(convertToTuple(callContext))
result
}

View File

@ -559,6 +559,7 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
inboundTopic = None,
exampleOutboundMessage = (
OutBoundGetBankAccountByRouting(outboundAdapterCallContext=MessageDocsSwaggerDefinitions.outboundAdapterCallContext,
bankId=Some(BankId(bankIdExample.value)),
scheme="string",
address="string")
),
@ -585,9 +586,9 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
adapterImplementation = Some(AdapterImplementation("- Core", 1))
)
override def getBankAccountByRouting(scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
override def getBankAccountByRouting(bankId: Option[BankId], scheme: String, address: String, callContext: Option[CallContext]): Box[(BankAccount, Option[CallContext])] = {
import com.openbankproject.commons.dto.{InBoundGetBankAccountByRouting => InBound, OutBoundGetBankAccountByRouting => OutBound}
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, scheme, address)
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))
}

View File

@ -26,7 +26,7 @@ class BankAccountRouting extends BankAccountRoutingTrait with LongKeyedMapper[Ba
object BankAccountRouting extends BankAccountRouting with LongKeyedMetaMapper[BankAccountRouting] {
override def dbIndexes: List[BaseIndex[BankAccountRouting]] =
UniqueIndex(BankId, AccountId, AccountRoutingScheme) :: UniqueIndex(AccountRoutingScheme, AccountRoutingAddress) :: super.dbIndexes
UniqueIndex(BankId, AccountId, AccountRoutingScheme) :: UniqueIndex(BankId, AccountRoutingScheme, AccountRoutingAddress) :: super.dbIndexes
}

View File

@ -326,7 +326,7 @@ trait OBPDataImport extends MdcLoggable {
val ibans = data.accounts.map(_.IBAN)
val duplicateIbans = ibans diff ibans.distinct
val existingIbans = data.accounts.flatMap(acc => {
Connector.connector.vend.getBankAccountByRouting(AccountRoutingScheme.IBAN.toString, acc.IBAN, None).map(_._1)
Connector.connector.vend.getBankAccountByRouting(Some(BankId(acc.bank)), AccountRoutingScheme.IBAN.toString, acc.IBAN, None).map(_._1)
})
if(!banksNotSpecifiedInImport.isEmpty) {

View File

@ -838,6 +838,7 @@ case class InBoundGetBankAccountLegacy (inboundAdapterCallContext: InboundAdapte
case class OutBoundGetBankAccountByRouting (outboundAdapterCallContext: OutboundAdapterCallContext,
bankId: Option[BankId],
scheme: String,
address: String) extends TopicTrait
case class InBoundGetBankAccountByRouting (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: BankAccountCommons) extends InBoundTrait[BankAccountCommons]

View File

@ -3,6 +3,13 @@
### Most recent changes at top of file
```
Date Commit Action
11/08/2020 5319a5f8 WARNING: Added new account routing system.
- Impacted endpoints: Create Account, Create Account (POST) and Update Account.
multiple account routings can now be put in the "account_routings" field.
- Impacted connector messages: OutBoundUpdateBankAccount, OutBoundCreateBankAccount,
OutBoundCreateBankAccountLegacy, OutBoundAddBankAccount and OutBoundCreateSandboxBankAccount.
Parameters "accountRoutingScheme" and "accountRoutingAddress" have been replaced by a List[AccountRouting].
OutBoundGetBankAccountByRouting message is also impacted with an additionnal parameter: Option[BankId].
14/07/2020 376be727 Added full support for MS SQL as a mapper databas
13/07/2020 d42dda90 Added props: webui_header_content_url. If we set the props, it will override the id ="table-header" content in default.html
19/06/2020 ea819aab Added props: refresh_user.interval. default is 30 minutes.