Merge pull request #2523 from hongwei1/develop

refactor/added attributes to messageDoc
This commit is contained in:
Simon Redfern 2025-04-08 15:25:19 +02:00 committed by GitHub
commit 4fac0069a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 317 additions and 39 deletions

View File

@ -133,10 +133,10 @@ import code.views.Views
import code.views.system.{AccountAccess, ViewDefinition, ViewPermission}
import code.webhook.{BankAccountNotificationWebhook, MappedAccountWebhook, SystemAccountNotificationWebhook}
import code.webuiprops.WebUiProps
import code.regulatedentities.attribute.RegulatedEntityAttribute
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.Functions.Implicits._
import com.openbankproject.commons.util.{ApiVersion, Functions}
import javax.mail.internet.MimeMessage
import net.liftweb.common._
import net.liftweb.db.{DB, DBLogEntry}
@ -1124,7 +1124,8 @@ object ToSchemify {
MappedCustomerDependant,
AttributeDefinition,
CustomerAccountLink,
TransactionIdMapping
TransactionIdMapping,
RegulatedEntityAttribute,
)
// start grpc server

View File

@ -60,7 +60,12 @@ object SwaggerDefinitionsJSON {
entity_post_code = "1060",
entity_country = "CY",
entity_web_site = "www.example.com",
services = json.parse("""[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]""")
services = json.parse("""[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]"""),
attributes = Some(List(RegulatedEntityAttributeSimple(
attributeType=attributeTypeExample.value,
name=attributeNameExample.value,
value=attributeValueExample.value)
))
)
lazy val regulatedEntityPostJsonV510: RegulatedEntityPostJsonV510 = RegulatedEntityPostJsonV510(
@ -74,7 +79,12 @@ object SwaggerDefinitionsJSON {
entity_post_code = "1060",
entity_country = "CY",
entity_web_site = "www.example.com",
services = json.parse("""[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]""")
services = json.parse("""[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]"""),
attributes = Some(List(RegulatedEntityAttributeSimple(
attributeType=attributeTypeExample.value,
name=attributeNameExample.value,
value=attributeValueExample.value)
))
)
val license = License(

View File

@ -202,7 +202,7 @@ trait APIMethods510 {
|
|""",
regulatedEntityPostJsonV510,
regulatedEntitiesJsonV510,
regulatedEntityJsonV510,
List(
$UserNotLoggedIn,
UserHasMissingRoles,

View File

@ -83,7 +83,8 @@ case class RegulatedEntityJsonV510(
entity_post_code: String,
entity_country: String,
entity_web_site: String,
services: JValue
services: JValue,
attributes: Option[List[RegulatedEntityAttributeSimple]]
)
case class RegulatedEntityPostJsonV510(
certificate_authority_ca_owner_id: String,
@ -96,7 +97,8 @@ case class RegulatedEntityPostJsonV510(
entity_post_code: String,
entity_country: String,
entity_web_site: String,
services: JValue
services: JValue,
attributes: Option[List[RegulatedEntityAttributeSimple]]
)
case class RegulatedEntitiesJsonV510(entities: List[RegulatedEntityJsonV510])
@ -989,7 +991,8 @@ object JSONFactory510 extends CustomJsonFormats {
entity_post_code = entity.entityPostCode,
entity_country = entity.entityCountry,
entity_web_site = entity.entityWebSite,
services = json.parse(entity.services)
services = json.parse(entity.services),
attributes = entity.attributes
)
}
def createRegulatedEntitiesJson(entities: List[RegulatedEntityTrait]): RegulatedEntitiesJsonV510 = {

View File

@ -77,7 +77,7 @@ class ServerCallback(val ch: Channel) extends DeliverCallback with MdcLoggable{
))
}
//---------------- dynamic start -------------------please don't modify this line
// ---------- created on 2025-01-14T11:53:01Z
// ---------- created on 2025-04-07T14:53:47Z
} else if (obpMessageId.contains("get_adapter_info")) {
val outBound = json.parse(message).extract[OutBoundGetAdapterInfo]
@ -3109,6 +3109,48 @@ class ServerCallback(val ch: Channel) extends DeliverCallback with MdcLoggable{
data = false
))
}
} else if (obpMessageId.contains("get_regulated_entities")) {
val outBound = json.parse(message).extract[OutBoundGetRegulatedEntities]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.getRegulatedEntities(None).map(_._1.head)
obpMappedResponse.map(response => InBoundGetRegulatedEntities(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status("", Nil),
data = response
)).recoverWith {
case e: Exception => Future(InBoundGetRegulatedEntities(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status(e.getMessage, Nil),
data = null
))
}
} else if (obpMessageId.contains("get_regulated_entity_by_entity_id")) {
val outBound = json.parse(message).extract[OutBoundGetRegulatedEntityByEntityId]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.getRegulatedEntityByEntityId(outBound.regulatedEntityId,None).map(_._1.head)
obpMappedResponse.map(response => InBoundGetRegulatedEntityByEntityId(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status("", Nil),
data = response
)).recoverWith {
case e: Exception => Future(InBoundGetRegulatedEntityByEntityId(
inboundAdapterCallContext = InboundAdapterCallContext(
correlationId = outBound.outboundAdapterCallContext.correlationId
),
status = Status(e.getMessage, Nil),
data = null
))
}
} else if (obpMessageId.contains("dynamic_entity_process")) {
val outBound = json.parse(message).extract[OutBoundDynamicEntityProcess]
val obpMappedResponse = code.bankconnectors.LocalMappedConnector.dynamicEntityProcess(outBound.operation,outBound.entityName,outBound.requestBody,outBound.entityId,None,None,None,false,None).map(_._1.head)
@ -3130,8 +3172,8 @@ class ServerCallback(val ch: Channel) extends DeliverCallback with MdcLoggable{
data = null
))
}
// ---------- created on 2025-01-14T11:53:01Z
//---------------- dynamic end ---------------------please don't modify this line
// ---------- created on 2025-04-07T14:53:47Z
//---------------- dynamic end ---------------------please don't modify this line
} else {
Future {
1

View File

@ -36,7 +36,7 @@ import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto.{InBoundTrait, _}
import com.openbankproject.commons.model.enums.StrongCustomerAuthenticationStatus.SCAStatus
import com.openbankproject.commons.model.enums._
import com.openbankproject.commons.model.{TopicTrait, _}
import com.openbankproject.commons.model.{TopicTrait, RegulatedEntityAttributeSimple, _}
import com.openbankproject.commons.util.ReflectUtils
import net.liftweb.common.{Box, _}
import net.liftweb.json._
@ -7081,18 +7081,32 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable {
exampleInboundMessage = (
InBoundGetRegulatedEntities(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext,
status=MessageDocsSwaggerDefinitions.inboundStatus,
data=List( RegulatedEntityTraitCommons(entityId="string",
certificateAuthorityCaOwnerId="string",
entityName="string",
entityCode="string",
entityCertificatePublicKey="string",
entityType="string",
entityAddress="string",
entityTownCity="string",
entityPostCode="string",
entityCountry="string",
entityWebSite="string",
services="string")))
data=List(RegulatedEntityTraitCommons(entityId = "0af807d7-3c39-43ef-9712-82bcfde1b9ca",
certificateAuthorityCaOwnerId = "CY_CBC",
entityName = "EXAMPLE COMPANY LTD",
entityCode = "PSD_PICY_CBC!12345",
entityCertificatePublicKey =
"""-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2
|FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQ
|YJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iRE
|aVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6
|RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aN
|nmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ
|19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQi
|Hnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZ
|LpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE----- """.stripMargin,
entityType = "PSD_PI",
entityAddress = "EXAMPLE COMPANY LTD, 5 SOME STREET",
entityTownCity = "SOME CITY",
entityPostCode = "1060",
entityCountry = "CY",
entityWebSite = "www.example.com",
services = """[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]""",
attributes = Some(List(RegulatedEntityAttributeSimple(
attributeType=attributeTypeExample.value,
name=attributeNameExample.value,
value=attributeValueExample.value)
)))))
),
adapterImplementation = Some(AdapterImplementation("- Core", 1))
)
@ -7118,18 +7132,32 @@ trait RabbitMQConnector_vOct2024 extends Connector with MdcLoggable {
exampleInboundMessage = (
InBoundGetRegulatedEntityByEntityId(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext,
status=MessageDocsSwaggerDefinitions.inboundStatus,
data= RegulatedEntityTraitCommons(entityId="string",
certificateAuthorityCaOwnerId="string",
entityName="string",
entityCode="string",
entityCertificatePublicKey="string",
entityType="string",
entityAddress="string",
entityTownCity="string",
entityPostCode="string",
entityCountry="string",
entityWebSite="string",
services="string"))
data= RegulatedEntityTraitCommons(entityId = "0af807d7-3c39-43ef-9712-82bcfde1b9ca",
certificateAuthorityCaOwnerId = "CY_CBC",
entityName = "EXAMPLE COMPANY LTD",
entityCode = "PSD_PICY_CBC!12345",
entityCertificatePublicKey =
"""-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2
|FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQ
|YJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iRE
|aVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6
|RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aN
|nmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ
|19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQi
|Hnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZ
|LpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE----- """.stripMargin,
entityType = "PSD_PI",
entityAddress = "EXAMPLE COMPANY LTD, 5 SOME STREET",
entityTownCity = "SOME CITY",
entityPostCode = "1060",
entityCountry = "CY",
entityWebSite = "www.example.com",
services = """[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]""",
attributes = Some(List(RegulatedEntityAttributeSimple(
attributeType=attributeTypeExample.value,
name=attributeNameExample.value,
value=attributeValueExample.value)
))))
),
adapterImplementation = Some(AdapterImplementation("- Core", 1))
)

View File

@ -1,7 +1,7 @@
package code.regulatedentities
import code.util.MappedUUID
import com.openbankproject.commons.model.RegulatedEntityTrait
import com.openbankproject.commons.model.{RegulatedEntityTrait,RegulatedEntityAttributeSimple}
import net.liftweb.common.Box
import net.liftweb.common.Box.tryo
import net.liftweb.mapper._
@ -120,7 +120,12 @@ class MappedRegulatedEntity extends RegulatedEntityTrait with LongKeyedMapper[Ma
override def entityCountry: String = EntityCountry.get
override def entityWebSite: String = EntityWebSite.get
override def services: String = Services.get
// override def attributes: Option[List[RegulatedEntityAttributeSimple]] = Some(List(RegulatedEntityAttributeSimple(
// attributeType="attributeTypeExample.value",
// name="attributeNameExample.value",
// value="attributeValueExample.value")
// ))
override def attributes: Option[List[RegulatedEntityAttributeSimple]] = None //not for mapped mode yet, will add it later.
}

View File

@ -0,0 +1,104 @@
package code.regulatedentities.attribute
import code.util.{MappedUUID, UUIDString}
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model.enums.RegulatedEntityAttributeType
import com.openbankproject.commons.model.{RegulatedEntityAttributeTrait, RegulatedEntityId}
import net.liftweb.common.{Box, Empty, Full}
import net.liftweb.mapper.{MappedBoolean, _}
import net.liftweb.util.Helpers.tryo
import scala.concurrent.Future
object RegulatedEntityAttributeProvider extends RegulatedEntityAttributeProviderTrait {
override def getRegulatedEntityAttributesFromProvider(regulatedEntityId: RegulatedEntityId): Future[Box[List[RegulatedEntityAttribute]]] =
Future {
Box !! RegulatedEntityAttribute.findAll(
By(RegulatedEntityAttribute.RegulatedEntityId_, regulatedEntityId.value)
)
}
override def getRegulatedEntityAttributeById(RegulatedEntityAttributeId: String): Future[Box[RegulatedEntityAttribute]] = Future {
RegulatedEntityAttribute.find(By(RegulatedEntityAttribute.RegulatedEntityAttributeId, RegulatedEntityAttributeId))
}
override def createOrUpdateRegulatedEntityAttribute(
regulatedEntityId: RegulatedEntityId,
RegulatedEntityAttributeId: Option[String],
name: String,
attributeType: RegulatedEntityAttributeType.Value,
value: String,
isActive: Option[Boolean]
): Future[Box[RegulatedEntityAttribute]] = {
RegulatedEntityAttributeId match {
case Some(id) => Future {
RegulatedEntityAttribute.find(By(RegulatedEntityAttribute.RegulatedEntityAttributeId, id)) match {
case Full(attribute) => tryo {
attribute
.RegulatedEntityId_(regulatedEntityId.value)
.Name(name)
.Type(attributeType.toString)
.`Value`(value)
.IsActive(isActive.getOrElse(true))
.saveMe()
}
case _ => Empty
}
}
case None => Future {
Full {
RegulatedEntityAttribute.create
.RegulatedEntityId_(regulatedEntityId.value)
.Name(name)
.Type(attributeType.toString())
.`Value`(value)
.IsActive(isActive.getOrElse(true))
.saveMe()
}
}
}
}
override def deleteRegulatedEntityAttribute(RegulatedEntityAttributeId: String): Future[Box[Boolean]] = Future {
tryo (
RegulatedEntityAttribute.bulkDelete_!!(By(RegulatedEntityAttribute.RegulatedEntityAttributeId, RegulatedEntityAttributeId))
)
}
override def deleteRegulatedEntityAttributesByRegulatedEntityId(regulatedEntityId: RegulatedEntityId): Future[Box[Boolean]]= Future {
tryo(
RegulatedEntityAttribute.bulkDelete_!!(By(RegulatedEntityAttribute.RegulatedEntityId_, regulatedEntityId.value))
)
}
}
class RegulatedEntityAttribute extends RegulatedEntityAttributeTrait with LongKeyedMapper[RegulatedEntityAttribute] with IdPK {
override def getSingleton = RegulatedEntityAttribute
object RegulatedEntityId_ extends UUIDString(this) {
override def dbColumnName = "RegulatedEntityId"
}
object RegulatedEntityAttributeId extends MappedUUID(this)
object Name extends MappedString(this, 50)
object Type extends MappedString(this, 50)
object `Value` extends MappedString(this, 255)
object IsActive extends MappedBoolean(this) {
override def defaultValue = true
}
override def regulatedEntityId: RegulatedEntityId = RegulatedEntityId(RegulatedEntityId_.get)
override def regulatedEntityAttributeId: String = RegulatedEntityAttributeId.get
override def name: String = Name.get
override def attributeType: RegulatedEntityAttributeType.Value = RegulatedEntityAttributeType.withName(Type.get)
override def value: String = `Value`.get
override def isActive: Option[Boolean] = if (IsActive.jdbcFriendly(IsActive.calcFieldName) == null) { None } else Some(IsActive.get)
}
object RegulatedEntityAttribute extends RegulatedEntityAttribute with LongKeyedMetaMapper[RegulatedEntityAttribute] {
override def dbIndexes: List[BaseIndex[RegulatedEntityAttribute]] = Index(RegulatedEntityId_) :: super.dbIndexes
}

View File

@ -0,0 +1,50 @@
package code.regulatedentities.attribute
/* For ProductAttribute */
import com.openbankproject.commons.model.{RegulatedEntityId, BankId}
import com.openbankproject.commons.model.enums.RegulatedEntityAttributeType
import net.liftweb.common.{Box, Logger}
import net.liftweb.util.SimpleInjector
import scala.concurrent.Future
object RegulatedEntityAttributeX extends SimpleInjector {
val regulatedEntityAttributeProvider = new Inject(buildOne _) {}
def buildOne: RegulatedEntityAttributeProviderTrait = RegulatedEntityAttributeProvider
// Helper to get the count out of an option
def countOfRegulatedEntityAttribute(listOpt: Option[List[RegulatedEntityAttribute]]): Int = {
val count = listOpt match {
case Some(list) => list.size
case None => 0
}
count
}
}
trait RegulatedEntityAttributeProviderTrait {
private val logger = Logger(classOf[RegulatedEntityAttributeProviderTrait])
def getRegulatedEntityAttributesFromProvider(regulatedEntityId: RegulatedEntityId): Future[Box[List[RegulatedEntityAttribute]]]
def getRegulatedEntityAttributeById(regulatedEntityAttributeId: String): Future[Box[RegulatedEntityAttribute]]
def createOrUpdateRegulatedEntityAttribute(
regulatedEntityId: RegulatedEntityId,
regulatedEntityAttributeId: Option[String],
name: String,
attributeType: RegulatedEntityAttributeType.Value,
value: String,
isActive: Option[Boolean]): Future[Box[RegulatedEntityAttribute]]
def deleteRegulatedEntityAttribute(regulatedEntityAttributeId: String): Future[Box[Boolean]]
def deleteRegulatedEntityAttributesByRegulatedEntityId(regulatedEntityId: RegulatedEntityId): Future[Box[Boolean]]
// End of Trait
}

View File

@ -128,6 +128,13 @@ case class TransactionTypeId(val value : String) {
object TransactionTypeId {
def unapply(id : String) = Some(TransactionTypeId(id))
}
case class RegulatedEntityId(val value : String) {
override def toString = value
}
object RegulatedEntityId {
def unapply(id : String) = Some(RegulatedEntityId(id))
}
case class AccountId(val value : String) {
override def toString = value

View File

@ -902,7 +902,10 @@ case class RegulatedEntityTraitCommons(
entityPostCode :String,
entityCountry :String,
entityWebSite :String,
services :String) extends RegulatedEntityTrait
services :String,
attributes :Option[List[RegulatedEntityAttributeSimple]]
) extends RegulatedEntityTrait
object RegulatedEntityTraitCommons extends Converter[RegulatedEntityTrait, RegulatedEntityTraitCommons]
//For COUNTERPARTY, it needs the counterparty_id to find the toCounterparty--> toBankAccount

View File

@ -114,6 +114,14 @@ trait SigningBasketConsentTrait {
def consentId: String
}
//TODO, this is only from CBS yet, not use mapped mode, may need to be refactor.
case class RegulatedEntityAttributeSimple(
attributeType: String,
name: String,
value: String,
)
trait RegulatedEntityTrait {
def entityId: String
def certificateAuthorityCaOwnerId: String
@ -127,6 +135,7 @@ trait RegulatedEntityTrait {
def entityCountry: String
def entityWebSite: String
def services: String
def attributes: Option[List[RegulatedEntityAttributeSimple]]
}
trait UserAttributeTrait {
@ -532,6 +541,15 @@ trait AtmAttributeTrait {
def isActive: Option[Boolean]
}
trait RegulatedEntityAttributeTrait {
def regulatedEntityId: RegulatedEntityId
def regulatedEntityAttributeId: String
def attributeType: RegulatedEntityAttributeType.Value
def name: String
def value: String
def isActive: Option[Boolean]
}
trait BankAttributeTrait {
def bankId: BankId
def bankAttributeId: String

View File

@ -22,6 +22,13 @@ object AtmAttributeType extends OBPEnumeration[AtmAttributeType]{
object DOUBLE extends Value
object DATE_WITH_DAY extends Value
}
sealed trait RegulatedEntityAttributeType extends EnumValue
object RegulatedEntityAttributeType extends OBPEnumeration[RegulatedEntityAttributeType]{
object STRING extends Value
object INTEGER extends Value
object DOUBLE extends Value
object DATE_WITH_DAY extends Value
}
sealed trait BankAttributeType extends EnumValue
object BankAttributeType extends OBPEnumeration[BankAttributeType]{
object STRING extends Value