diff --git a/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala b/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala index edc24e7ca1..b493fd10a0 100644 --- a/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala +++ b/obp-api/src/main/scala/code/api/berlin/group/v1_3/JSONFactory_BERLIN_GROUP_1_3.scala @@ -462,7 +462,7 @@ object JSONFactory_BERLIN_GROUP_1_3 extends CustomJsonFormats with MdcLoggable{ def createTransactionJSON(bankAccount: BankAccount, transaction : ModeratedTransaction) : TransactionJsonV13 = { val bookingDate = transaction.startDate.orNull val valueDate = transaction.finishDate.orNull - val creditorName = bankAccount.label + val creditorName = transaction.otherBankAccount.map(_.label.display).getOrElse(null) TransactionJsonV13( transactionId = transaction.id.value, creditorName = creditorName, diff --git a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala index 2b7b9eb5f1..39adbe5f8e 100644 --- a/obp-api/src/main/scala/code/api/util/ConsentUtil.scala +++ b/obp-api/src/main/scala/code/api/util/ConsentUtil.scala @@ -2,14 +2,11 @@ package code.api.util import code.accountholders.AccountHolders import code.api.berlin.group.ConstantsBG - -import java.text.SimpleDateFormat -import java.util.{Date, UUID} import code.api.berlin.group.v1_3.JSONFactory_BERLIN_GROUP_1_3.{ConsentAccessJson, PostConsentJson} import code.api.util.APIUtil.fullBoxOrException import code.api.util.ApiRole.{canCreateEntitlementAtAnyBank, canCreateEntitlementAtOneBank} import code.api.util.BerlinGroupSigning.getHeaderValue -import code.api.util.ErrorMessages.{CouldNotAssignAccountAccess, InvalidConnectorResponse, NoViewReadAccountsBerlinGroup} +import code.api.util.ErrorMessages._ import code.api.v3_1_0.{PostConsentBodyCommonJson, PostConsentEntitlementJsonV310, PostConsentViewJsonV310} import code.api.v5_0_0.HelperInfoJson import code.api.{APIFailure, APIFailureNewStyle, Constant, RequestHeader} @@ -22,7 +19,6 @@ import code.context.{ConsentAuthContextProvider, UserAuthContextProvider} import code.entitlement.Entitlement import code.model.Consumer import code.model.dataAccess.BankAccountRouting -import code.scheduler.ConsentScheduler.logger import code.users.Users import code.util.Helper.MdcLoggable import code.util.HydraUtil @@ -30,16 +26,16 @@ import code.views.Views import com.nimbusds.jwt.JWTClaimsSet import com.openbankproject.commons.ExecutionContext.Implicits.global import com.openbankproject.commons.model._ -import com.openbankproject.commons.util.ApiVersion -import net.liftweb.common.{Box, Empty, Failure, Full, ParamFailure} +import net.liftweb.common._ import net.liftweb.http.provider.HTTPParam import net.liftweb.json.JsonParser.ParseException import net.liftweb.json.{Extraction, MappingException, compactRender, parse} import net.liftweb.mapper.By -import net.liftweb.util.{ControlHelpers, Props} -import org.apache.commons.lang3.StringUtils +import net.liftweb.util.Props import sh.ory.hydra.model.OAuth2TokenIntrospection +import java.text.SimpleDateFormat +import java.util.Date import scala.collection.immutable.{List, Nil} import scala.concurrent.Future @@ -309,13 +305,13 @@ object Consent extends MdcLoggable { Entitlement.entitlement.vend.addEntitlement(bankId, user.userId, entitlement.role_name) match { case Full(_) => (entitlement, "AddedOrExisted") case _ => - (entitlement, "Cannot add the entitlement: " + entitlement) + (entitlement, CannotAddEntitlement + entitlement) } case true => (entitlement, "AddedOrExisted") } case false => - (entitlement, "There is no entitlement's name: " + entitlement) + (entitlement, InvalidEntitlement + entitlement) } } @@ -331,11 +327,13 @@ object Consent extends MdcLoggable { val failedToAdd: List[(Role, String)] = triedToAdd.filter(_._2 != "AddedOrExisted") failedToAdd match { case Nil => Full(user) - case _ => - Failure("The entitlements cannot be added. " + failedToAdd.map(i => (i._1, i._2)).mkString(", ")) + case _ => + //Here, we do not throw an exception, just log the error. + logger.error(CannotAddEntitlement + failedToAdd.map(i => (i._1, i._2)).mkString(", ")) + Full(user) } case _ => - Failure("Cannot get entitlements for user id: " + user.userId) + Failure(CannotGetEntitlements + user.userId) } } @@ -438,10 +436,10 @@ object Consent extends MdcLoggable { case failure@Failure(msg, exp, chain) => // Handled errors (Failure(msg), Some(cc)) case _ => - (Failure("Cannot add entitlements based on: " + consentAsJwt), Some(cc)) + (Failure(CannotAddEntitlement + consentAsJwt), Some(cc)) } case _ => - (Failure("Cannot create or get the user based on: " + consentAsJwt), Some(cc)) + (Failure(CannotGetOrCreateUser + consentAsJwt), Some(cc)) } } @@ -524,10 +522,10 @@ object Consent extends MdcLoggable { case failure@Failure(msg, exp, chain) => // Handled errors (Failure(msg), Some(cc)) case _ => - (Failure("Cannot add entitlements based on: " + consentId), Some(cc)) + (Failure(CannotAddEntitlement + consentId), Some(cc)) } case _ => - (Failure("Cannot create or get the user based on: " + consentId), Some(cc)) + (Failure(CannotGetOrCreateUser + consentId), Some(cc)) } } 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 27c61a20f0..1104c6f829 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -1,15 +1,12 @@ package code.api.util -import java.util.Objects -import java.util.regex.Pattern - import code.api.APIFailureNewStyle -import com.openbankproject.commons.model.enums.TransactionRequestStatus._ -import code.api.Constant._ import code.api.util.ApiRole.{CanCreateAnyTransactionRequest, canCreateEntitlementAtAnyBank, canCreateEntitlementAtOneBank} -import code.views.system.ViewDefinition +import com.openbankproject.commons.model.enums.TransactionRequestStatus._ import net.liftweb.json.{Extraction, JsonAST} -import net.liftweb.util.StringHelpers + +import java.util.Objects +import java.util.regex.Pattern object ErrorMessages { import code.api.util.APIUtil._ @@ -550,6 +547,10 @@ object ErrorMessages { val AgentNumberAlreadyExists = "OBP-30328: Agent Number already exists. Please specify a different value for BANK_ID or AGENT_NUMBER." val GetAgentAccountLinksError = "OBP-30329: Could not get the agent account links." val AgentBeneficiaryPermit = "OBP-30330: The account can not send money to the Agent. Please set the Agent 'is_confirmed_agent' true and `is_pending_agent` false." + val InvalidEntitlement = "OBP-30331: Invalid Entitlement Name. Please specify a proper name." + val CannotAddEntitlement = "OBP-30332: Failed to add entitlement. Please check the provided details and try again." + val CannotGetEntitlements = "OBP-30333: Cannot get entitlements for user id." + // Branch related messages val BranchesNotFoundLicense = "OBP-32001: No branches available. License may not be set." diff --git a/obp-api/src/main/scala/code/api/util/ExampleValue.scala b/obp-api/src/main/scala/code/api/util/ExampleValue.scala index 4f434cbc3e..ea20307d98 100644 --- a/obp-api/src/main/scala/code/api/util/ExampleValue.scala +++ b/obp-api/src/main/scala/code/api/util/ExampleValue.scala @@ -1460,7 +1460,7 @@ object ExampleValue { lazy val distributionChannelExample = ConnectorField(NoExampleProvided,NoDescriptionProvided) glossaryItems += makeGlossaryItem("distribution_channel", distributionChannelExample) - lazy val otherAccountRoutingSchemeExample = ConnectorField(NoExampleProvided,NoDescriptionProvided) + lazy val otherAccountRoutingSchemeExample = ConnectorField("IBAN","otherAccountRoutingScheme string, eg: IBAN") glossaryItems += makeGlossaryItem("other_account_routing_scheme", otherAccountRoutingSchemeExample) lazy val generateAccountantsViewExample = ConnectorField(NoExampleProvided,NoDescriptionProvided) @@ -1714,7 +1714,7 @@ object ExampleValue { lazy val canAddTransactionRequestToOwnAccountExample = ConnectorField(booleanFalse,NoDescriptionProvided) glossaryItems += makeGlossaryItem("can_add_transaction_request_to_own_account", canAddTransactionRequestToOwnAccountExample) - lazy val otherAccountRoutingAddressExample = ConnectorField(NoExampleProvided,NoDescriptionProvided) + lazy val otherAccountRoutingAddressExample = ConnectorField("DE89370400440532013000","OtherBankRoutingAddress string, eg IBAN value") glossaryItems += makeGlossaryItem("other_account_routing_address", otherAccountRoutingAddressExample) lazy val isFirehoseExample = ConnectorField(NoExampleProvided,NoDescriptionProvided) @@ -2472,8 +2472,8 @@ object ExampleValue { // if these are duplicate with those examples, just delete the follow examples lazy val counterpartyOtherBankRoutingSchemeExample = ConnectorField("OBP" ,"Counterparty otherBankRoutingScheme string") lazy val counterpartyOtherBankRoutingAddressExample = ConnectorField("gh.29.uk", "Counterparty otherBankRoutingAddress string") - lazy val counterpartyOtherAccountRoutingSchemeExample = ConnectorField("OBP", "Counterparty otherAccountRoutingScheme string") - lazy val counterpartyOtherAccountRoutingAddressExample = ConnectorField("36f8a9e6-c2b1-407a-8bd0-421b7119307e", "Counterparty otherAccountRoutingAddress string") + lazy val counterpartyOtherAccountRoutingSchemeExample = ConnectorField("IBAN", "Counterparty otherAccountRoutingScheme string") + lazy val counterpartyOtherAccountRoutingAddressExample = ConnectorField("DE89370400440532013000", "Counterparty otherAccountRoutingAddress string") lazy val counterpartyOtherAccountSecondaryRoutingSchemeExample = ConnectorField("IBAN", "Counterparty otherAccountSecondaryRoutingScheme string") lazy val counterpartyOtherAccountSecondaryRoutingAddressExample = ConnectorField("DE89370400440532013000", "Counterparty otherAccountSecondaryRoutingAddress string") lazy val counterpartyOtherAccountProviderExample = ConnectorField("Counterparty otherAccountProvider string", "fix me") diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 956e70a18d..d964d726b6 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -9,6 +9,7 @@ import code.api.{APIFailure, APIFailureNewStyle} import code.atmattribute.AtmAttribute import code.bankattribute.BankAttribute import code.bankconnectors.akka.AkkaConnector_vDec2018 +import code.bankconnectors.cardano.CardanoConnector_vJun2025 import code.bankconnectors.rabbitmq.RabbitMQConnector_vOct2024 import code.bankconnectors.rest.RestConnector_vMar2019 import code.bankconnectors.storedprocedure.StoredProcedureConnector_vDec2019 @@ -18,7 +19,7 @@ import code.util.Helper._ import com.github.dwickern.macros.NameOf.nameOf import com.openbankproject.commons.ExecutionContext.Implicits.global import com.openbankproject.commons.dto.{CustomerAndAttribute, GetProductsParam, InBoundTrait, ProductCollectionItemsTree} -import com.openbankproject.commons.model.{TransactionRequestStatus, _} +import com.openbankproject.commons.model._ import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA import com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.SCAStatus import com.openbankproject.commons.model.enums._ @@ -61,6 +62,7 @@ object Connector extends SimpleInjector { "rest_vMar2019" -> RestConnector_vMar2019, "stored_procedure_vDec2019" -> StoredProcedureConnector_vDec2019, "rabbitmq_vOct2024" -> RabbitMQConnector_vOct2024, + "cardano_vJun2025" -> CardanoConnector_vJun2025, // 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/cardano/CardanoConnector_vJun2025.scala b/obp-api/src/main/scala/code/bankconnectors/cardano/CardanoConnector_vJun2025.scala new file mode 100644 index 0000000000..7dce2dd035 --- /dev/null +++ b/obp-api/src/main/scala/code/bankconnectors/cardano/CardanoConnector_vJun2025.scala @@ -0,0 +1,76 @@ +package code.bankconnectors.cardano + +/* +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.util.APIUtil._ +import code.api.util.CallContext +import code.bankconnectors._ +import code.util.AkkaHttpClient._ +import code.util.Helper.MdcLoggable +import com.openbankproject.commons.model._ +import net.liftweb.common._ + +import java.util.UUID.randomUUID +import scala.collection.mutable.ArrayBuffer +import scala.concurrent.Future +import scala.language.postfixOps + + +trait CardanoConnector_vJun2025 extends Connector with MdcLoggable { + //this one import is for implicit convert, don't delete + + implicit override val nameOfConnector = CardanoConnector_vJun2025.toString + + val messageFormat: String = "Jun2025" + + override val messageDocs = ArrayBuffer[MessageDoc]() + + + 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]] = { + for { + transactionData <- Future.successful("123|100.50|EUR|2025-03-16 12:30:00") + transactionHash <- Future { + code.cardano.CardanoMetadataWriter.generateHash(transactionData) + } + txIn <- Future.successful("8c293647e5cb51c4d29e57e162a0bb4a0500096560ce6899a4b801f2b69f2813:0") + txOut <- Future.successful("addr_test1qruvtthh7mndxu2ncykn47tksar9yqr3u97dlkq2h2dhzwnf3d755n99t92kp4rydpzgv7wmx4nx2j0zzz0g802qvadqtczjhn:1234") + signingKey <- Future.successful("payment.skey") + network <- Future.successful("--testnet-magic") + _ <- Future { + code.cardano.CardanoMetadataWriter.submitHashToCardano(transactionHash, txIn, txOut, signingKey, network) + } + transactionId <- Future.successful(TransactionId(randomUUID().toString)) + } yield (Full(transactionId), callContext) + } +} + +object CardanoConnector_vJun2025 extends CardanoConnector_vJun2025 diff --git a/obp-api/src/main/scala/code/cardano/cardano.scala b/obp-api/src/main/scala/code/cardano/cardano.scala index 586127c663..2d3bc87861 100644 --- a/obp-api/src/main/scala/code/cardano/cardano.scala +++ b/obp-api/src/main/scala/code/cardano/cardano.scala @@ -1,8 +1,14 @@ +package code.cardano + + +import code.util.Helper.MdcLoggable + import java.io.{File, PrintWriter} -import scala.sys.process._ import java.security.MessageDigest +import scala.sys.process._ -object CardanoMetadataWriter { + +object CardanoMetadataWriter extends MdcLoggable{ // Function to generate SHA-256 hash of a string def generateHash(transactionData: String): String = { @@ -26,7 +32,7 @@ object CardanoMetadataWriter { val writer = new PrintWriter(file) writer.write(jsonContent) writer.close() - println(s"Metadata file written to: $filePath") + logger.debug(s"Metadata file written to: $filePath") } // Function to submit transaction to Cardano @@ -48,7 +54,7 @@ object CardanoMetadataWriter { val submitCommand = s"cardano-cli transaction submit --tx-file tx.signed --$network" submitCommand.! - println("Transaction submitted to Cardano blockchain.") + logger.debug("Transaction submitted to Cardano blockchain.") } // Example Usage @@ -107,7 +113,7 @@ object CardanoMetadataWriter { // Generate hash of transaction data val transactionHash = generateHash(transactionData) - println(s"Generated Hash: $transactionHash") + logger.debug(s"Generated Hash: $transactionHash") // Create metadata object val metadata = new CBORMetadata() @@ -122,7 +128,7 @@ object CardanoMetadataWriter { val utxos: java.util.List[Utxo] = utxoService.getUtxos(account.baseAddress, 1, 10).getValue if (utxos.isEmpty) { - println("No UTXOs found. Please fund your wallet.") + logger.debug("No UTXOs found. Please fund your wallet.") return } @@ -140,7 +146,7 @@ object CardanoMetadataWriter { // Submit transaction val txHash: String = transactionService.submitTransaction(signedTransaction).getValue - println(s"✅ Transaction submitted! TxHash: $txHash") + logger.debug(s"Transaction submitted! TxHash: $txHash") } // Main method diff --git a/obp-api/src/test/scala/code/connector/RestConnector_vMar2019_frozen_meta_data b/obp-api/src/test/scala/code/connector/RestConnector_vMar2019_frozen_meta_data index 8962f6f41e..b34ffc8b51 100644 Binary files a/obp-api/src/test/scala/code/connector/RestConnector_vMar2019_frozen_meta_data and b/obp-api/src/test/scala/code/connector/RestConnector_vMar2019_frozen_meta_data differ diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala index caf5613a12..b70a462967 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala @@ -26,13 +26,11 @@ TESOBE (http://www.tesobe.com/) */ package com.openbankproject.commons.model -import java.util.Date import com.openbankproject.commons.util.{OBPRequired, optional} import java.security.AccessControlContext +import java.util.Date import javax.security.auth.AuthPermission -import scala.collection.immutable.List -import scala.math.BigDecimal trait Bank { @@ -289,9 +287,7 @@ case class Counterparty( val otherBankRoutingScheme: String, // This is the scheme a consumer would use to specify the bank e.g. BIC @optional val otherBankRoutingAddress: Option[String], // The (BIC) value e.g. 67895 - @optional val otherAccountRoutingScheme: String, // This is the scheme a consumer would use to instruct a payment e.g. IBAN - @optional val otherAccountRoutingAddress: Option[String], // The (IBAN) value e.g. 2349870987820374 @optional val otherAccountProvider: String, // hasBankId and hasAccountId would refer to an OBP account