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 41797fa888..24c9bc80e2 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -450,6 +450,13 @@ object NewStyle extends MdcLoggable{ (unboxFullOrFail(i._1, callContext, s"$BankAccountNotFound Current BankId is $bankId and Current AccountNumber is $accountNumber", 404), i._2) } + // This method handles external bank accounts that may not exist in our database. + // If the account is not found, we create an in-memory account using counterparty information for payment processing. + def getOtherBankAccountByNumber(bankId : Option[BankId], accountNumber : String, counterparty: Option[CounterpartyTrait], callContext: Option[CallContext]) : OBPReturnType[(BankAccount)] = { + Connector.connector.vend.getOtherBankAccountByNumber(bankId, accountNumber, counterparty, callContext) } map { i => + (unboxFullOrFail(i._1, callContext, s"$BankAccountNotFound Current BankId is $bankId and Current AccountNumber is $accountNumber", 404), i._2) + } + def getBankSettlementAccounts(bankId: BankId, callContext: Option[CallContext]): OBPReturnType[List[BankAccount]] = { Connector.connector.vend.getBankSettlementAccounts(bankId: BankId, callContext: Option[CallContext]) map { i => (unboxFullOrFail(i._1, callContext,s"$BankNotFound Current BankId is $bankId", 404 ), i._2) diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 2d3a8ae3e7..131e8ed6eb 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -530,6 +530,11 @@ trait Connector extends MdcLoggable { def getBankAccountByNumber(bankId : Option[BankId], accountNumber : String, callContext: Option[CallContext]) : OBPReturnType[Box[(BankAccount)]] = Future {(Failure(setUnimplementedError(nameOf(getBankAccountByNumber _))), callContext)} + // This method handles external bank accounts that may not exist in our database. + // If the account is not found, we create an in-memory account using counterparty information for payment processing. + //TODO understand more about this method. + def getOtherBankAccountByNumber(bankId : Option[BankId], accountNumber : String, counterparty: Option[CounterpartyTrait], callContext: Option[CallContext]) : OBPReturnType[Box[(BankAccount)]] = Future {(Failure(setUnimplementedError(nameOf(getOtherBankAccountByNumber _))), callContext)} + def getBankAccountByRoutings(bankAccountRoutings: BankAccountRoutings, callContext: Option[CallContext]) : OBPReturnType[Box[(BankAccount)]] = Future {(Failure(setUnimplementedError(nameOf(getBankAccountByRoutings _))), callContext)} def getCounterpartyFromTransaction(bankId: BankId, accountId: AccountId, counterpartyId: String, callContext: Option[CallContext]): OBPReturnType[Box[Counterparty]] = Future {(Failure(setUnimplementedError(nameOf(checkBankAccountExists _))), callContext)} diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index 8c112f5eec..0bfe96e38c 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -1026,15 +1026,76 @@ object LocalMappedConnector extends Connector with MdcLoggable { else s"$AccountNumberNotUniqueError, current BankId is ${bankId.head.value}, AccountNumber is $accountNumber" - if(bankAccounts.length > 1){ + if(bankAccounts.length > 1){ // If the account number is not unique, return the error message (Failure(errorMessage), callContext) - }else if (bankAccounts.length == 1){ + }else if (bankAccounts.length == 1){ // If the account number is unique, return the account (Full(bankAccounts.head), callContext) - }else{ - (Failure(errorMessage), callContext) + }else{ // If the account number is not found, return the error message + (Failure(s"$InvalidAccountNumber, current AccountNumber is $accountNumber"), callContext) } } + // This method handles external bank accounts that may not exist in our database. + // If the account is not found, we create an in-memory account using counterparty information for payment processing. + override def getOtherBankAccountByNumber(bankId : Option[BankId], accountNumber : String, counterparty: Option[CounterpartyTrait], callContext: Option[CallContext]) : OBPReturnType[Box[(BankAccount)]] = { + + for { + (existingAccountBox, updatedCallContext) <- getBankAccountByNumber(bankId, accountNumber, callContext) + (finalAccountBox, finalCallContext) <- existingAccountBox match { + case Full(account) => + // If account found in database, return it + Future.successful((Full(account), updatedCallContext)) + case _ => + // If account not found, check if we can create in-memory account + counterparty match { + case Some(cp) => + // Create in-memory account using counterparty information + Future { + val accountRouting1 = + if (cp.otherAccountRoutingScheme.isEmpty) Nil + else List(AccountRouting(cp.otherAccountRoutingScheme, cp.otherAccountRoutingAddress)) + val accountRouting2 = + if (cp.otherAccountSecondaryRoutingScheme.isEmpty) Nil + else List(AccountRouting(cp.otherAccountSecondaryRoutingScheme, cp.otherAccountSecondaryRoutingAddress)) + + // Due to the new field in the database, old counterparty have void currency, so by default, we set it to EUR + val counterpartyCurrency = if (cp.currency.nonEmpty) cp.currency else "EUR" + + val inMemoryAccount = BankAccountCommons( + AccountId(if (cp.otherAccountSecondaryRoutingAddress.nonEmpty) cp.otherAccountSecondaryRoutingAddress else accountNumber), + "", 0, + currency = counterpartyCurrency, + name = cp.name, + "", accountNumber, + BankId(cp.otherBankRoutingAddress), + new Date(), "", + accountRoutings = accountRouting1 ++ accountRouting2, + List.empty, + accountHolder = cp.name, + Some(List(Attribute( + name = "BANK_ROUTING_SCHEME", + `type` = "STRING", + value = cp.otherBankRoutingScheme + ), + Attribute( + name = "BANK_ROUTING_ADDRESS", + `type` = "STRING", + value = cp.otherBankRoutingAddress + ), + )) + ) + (Full(inMemoryAccount), updatedCallContext) + } + case None => + // No counterparty provided, return failure + Future.successful((Failure(s"$InvalidAccountNumber, current AccountNumber is $accountNumber and no counterparty provided for creating in-memory account"), updatedCallContext)) + } + } + } yield { + (finalAccountBox, finalCallContext) + } + } + override def getBankAccountByRoutings( bankAccountRoutings: BankAccountRoutings, callContext: Option[CallContext] diff --git a/obp-api/src/main/scala/code/model/BankingData.scala b/obp-api/src/main/scala/code/model/BankingData.scala index 89d770d978..1976fb38ab 100644 --- a/obp-api/src/main/scala/code/model/BankingData.scala +++ b/obp-api/src/main/scala/code/model/BankingData.scala @@ -476,9 +476,10 @@ object BankAccountX { else if (counterparty.otherAccountRoutingScheme.equalsIgnoreCase("ACCOUNT_NUMBER")|| counterparty.otherAccountRoutingScheme.equalsIgnoreCase("ACCOUNT_NO")){ for{ bankIdOption <- Future.successful(if(counterparty.otherBankRoutingAddress.isEmpty) None else Some(counterparty.otherBankRoutingAddress)) - (account, callContext) <- NewStyle.function.getBankAccountByNumber( + (account, callContext) <- NewStyle.function.getOtherBankAccountByNumber( bankIdOption.map(BankId(_)), counterparty.otherAccountRoutingAddress, + Some(counterparty), callContext) } yield { (Full(account), callContext)