mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:07:02 +00:00
773 lines
30 KiB
Scala
773 lines
30 KiB
Scala
/**
|
|
Open Bank Project - API
|
|
Copyright (C) 2011-2016, TESOBE Ltd
|
|
|
|
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 Ltd
|
|
Osloerstrasse 16/17
|
|
Berlin 13359, Germany
|
|
|
|
This product includes software developed at
|
|
TESOBE (http://www.tesobe.com/)
|
|
by
|
|
Simon Redfern : simon AT tesobe DOT com
|
|
Stefan Bethge : stefan AT tesobe DOT com
|
|
Everett Sochowski : everett AT tesobe DOT com
|
|
Ayoub Benali: ayoub AT tesobe DOT com
|
|
|
|
*/
|
|
package code.model
|
|
|
|
import code.util.Helper
|
|
|
|
import scala.math.BigDecimal
|
|
import java.util.Date
|
|
|
|
import code.accountholder.AccountHolders
|
|
import code.api.util.SessionContext
|
|
import code.bankconnectors.vJune2017.AccountRules
|
|
|
|
import scala.collection.immutable.{List, Set}
|
|
import net.liftweb.json.JObject
|
|
import net.liftweb.json.JsonDSL._
|
|
import net.liftweb.json.JsonAST.JArray
|
|
import net.liftweb.common._
|
|
import code.metadata.comments.Comments
|
|
import code.metadata.tags.Tags
|
|
import code.metadata.transactionimages.TransactionImages
|
|
import code.metadata.wheretags.WhereTags
|
|
import code.bankconnectors.{Connector, OBPQueryParam}
|
|
import code.views.Views
|
|
import code.metadata.narrative.Narrative
|
|
import code.metadata.counterparties.Counterparties
|
|
import code.util.Helper.MdcLoggable
|
|
|
|
import scala.concurrent.Future
|
|
|
|
/**
|
|
* Uniquely identifies a view
|
|
*/
|
|
case class ViewIdBankIdAccountId(viewId : ViewId, bankId : BankId, accountId : AccountId) {
|
|
override def toString = s"view $viewId, for account: $accountId at bank $bankId"
|
|
}
|
|
|
|
/*
|
|
Examples of viewId are "owner", "accountant", "auditor" etc.
|
|
They are only unique for bank and account
|
|
*/
|
|
case class ViewId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object ViewId {
|
|
def unapply(id : String) = Some(ViewId(id))
|
|
}
|
|
|
|
case class TransactionId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object TransactionId {
|
|
def unapply(id : String) = Some(TransactionId(id))
|
|
}
|
|
|
|
case class TransactionRequestType(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object TransactionRequestType {
|
|
def unapply(id : String) = Some(TransactionRequestType(id))
|
|
}
|
|
|
|
//Note: change case class -> trait, for kafka extends it
|
|
trait TransactionRequestStatus{
|
|
def transactionRequestId : String
|
|
def bulkTransactionsStatus: List[TransactionStatus]
|
|
}
|
|
|
|
|
|
trait TransactionStatus{
|
|
def transactionId : String
|
|
def transactionStatus: String
|
|
def transactionTimestamp: String
|
|
}
|
|
|
|
case class TransactionRequestId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object TransactionRequestId {
|
|
def unapply(id : String) = Some(TransactionRequestId(id))
|
|
}
|
|
|
|
case class TransactionTypeId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object TransactionTypeId {
|
|
def unapply(id : String) = Some(TransactionTypeId(id))
|
|
}
|
|
|
|
case class AccountId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object AccountId {
|
|
def unapply(id : String) = Some(AccountId(id))
|
|
}
|
|
|
|
case class BankId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object BankId {
|
|
def unapply(id : String) = Some(BankId(id))
|
|
}
|
|
|
|
case class AccountRoutingAddress(val value: String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object AccountRoutingAddress {
|
|
def unapply(id: String) = Some(AccountRoutingAddress(id))
|
|
}
|
|
|
|
case class CustomerId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object CustomerId {
|
|
def unapply(id : String) = Some(CustomerId(id))
|
|
}
|
|
|
|
|
|
// In preparation for use in Context (api links) To replace OtherAccountId
|
|
case class CounterpartyId(val value : String) {
|
|
override def toString = value
|
|
}
|
|
|
|
object CounterpartyId {
|
|
def unapply(id : String) = Some(CounterpartyId(id))
|
|
}
|
|
|
|
trait Bank {
|
|
def bankId: BankId
|
|
def shortName : String
|
|
def fullName : String
|
|
def logoUrl : String
|
|
def websiteUrl : String
|
|
def bankRoutingScheme: String
|
|
def bankRoutingAddress: String
|
|
|
|
// TODO Add Group ?
|
|
|
|
|
|
//SWIFT BIC banking code (globally unique)
|
|
@deprecated("Please use bankRoutingScheme and bankRoutingAddress instead")
|
|
def swiftBic: String
|
|
|
|
//it's not entirely clear what this is/represents (BLZ in Germany?)
|
|
@deprecated("Please use bankRoutingScheme and bankRoutingAddress instead")
|
|
def nationalIdentifier : String
|
|
|
|
def accounts(user : Box[User]) : List[BankAccount] = {
|
|
Views.views.vend.getAllAccountsUserCanSee(this, user).flatMap { a =>
|
|
BankAccount(a.bankId, a.accountId)
|
|
}
|
|
}
|
|
|
|
//This was the behaviour in v1.2 and earlier which has since been changed
|
|
@deprecated
|
|
def accountv12AndBelow(user: Box[User]) : Box[List[BankAccount]] = {
|
|
user match {
|
|
case Full(u) => {
|
|
Full(privateAccounts(u))
|
|
}
|
|
case _ => {
|
|
Full(publicAccounts)
|
|
}
|
|
}
|
|
}
|
|
|
|
def publicAccounts : List[BankAccount] = {
|
|
Views.views.vend.getPublicBankAccounts(this).flatMap { a =>
|
|
BankAccount(a.bankId, a.accountId)
|
|
}
|
|
}
|
|
|
|
def privateAccounts(user : User) : List[BankAccount] = {
|
|
|
|
Views.views.vend.getPrivateBankAccounts(user, bankId).flatMap { a =>
|
|
BankAccount(a.bankId, a.accountId)
|
|
}
|
|
|
|
// Note: An alternative to the above implmentation (which will call BankAccount (e.g. Kafka) once for each
|
|
// account) - could be:
|
|
// 1) Get the accounts / view the user should have access to:
|
|
// Views.views.vend.getPrivateBankAccounts(user, bankId)
|
|
// 2) Get all accounts for User
|
|
// 3) Return just the accounts found in step 1.
|
|
// 4) If any accounts are missing (because they belong to another user), call BankAccount for the missing accounts.
|
|
}
|
|
|
|
@deprecated(Helper.deprecatedJsonGenerationMessage)
|
|
def detailedJson : JObject = {
|
|
("name" -> shortName) ~
|
|
("website" -> "") ~
|
|
("email" -> "")
|
|
}
|
|
|
|
@deprecated(Helper.deprecatedJsonGenerationMessage)
|
|
def toJson : JObject = {
|
|
("alias" -> bankId.value) ~
|
|
("name" -> shortName) ~
|
|
("logo" -> "") ~
|
|
("links" -> linkJson)
|
|
}
|
|
|
|
@deprecated(Helper.deprecatedJsonGenerationMessage)
|
|
def linkJson : JObject = {
|
|
("rel" -> "bank") ~
|
|
("href" -> {"/" + bankId + "/bank"}) ~
|
|
("method" -> "GET") ~
|
|
("title" -> {"Get information about the bank identified by " + bankId})
|
|
}
|
|
}
|
|
|
|
object Bank {
|
|
def apply(bankId: BankId) : Box[Bank] = {
|
|
Connector.connector.vend.getBank(bankId)
|
|
}
|
|
|
|
def all(): Box[List[Bank]] = Connector.connector.vend.getBanks
|
|
|
|
@deprecated(Helper.deprecatedJsonGenerationMessage)
|
|
def toJson(banks: Seq[Bank]) : JArray =
|
|
banks.map(bank => bank.toJson)
|
|
|
|
}
|
|
|
|
class AccountOwner(
|
|
val id : String,
|
|
val name : String
|
|
)
|
|
|
|
case class BankIdAccountId(bankId : BankId, accountId : AccountId)
|
|
|
|
|
|
|
|
/** Internal model of a Bank Account
|
|
* @define accountType The account type aka financial product name. The customer friendly text that identifies the financial product this account is based on, as given by the bank
|
|
* @define accountId An identifier (no spaces, url friendly, should be a UUID) that hides the actual account number (obp identifier)
|
|
* @define number The actual bank account number as given by the bank to the customer
|
|
* @define bankId The short bank identifier that holds this account (url friendly, usually short name of bank with hyphens)
|
|
* @define label A string that helps identify the account to a customer or the public. Can be updated by the account owner. Default would typically include the owner display name (should be legal entity owner) + accountType + few characters of number
|
|
* @define iban The IBAN (could be empty)
|
|
* @define currency The currency (3 letter code)
|
|
* @define balance The current balance on the account
|
|
*/
|
|
|
|
// TODO Add: @define productCode A code (no spaces, url friendly) that identifies the financial product this account is based on.
|
|
|
|
trait BankAccount extends MdcLoggable {
|
|
|
|
def accountId : AccountId
|
|
def accountType : String // (stored in the field "kind" on Mapper)
|
|
//def productCode : String // TODO Add this shorter code.
|
|
def balance : BigDecimal
|
|
def currency : String
|
|
def name : String // Is this used?
|
|
def label : String
|
|
@deprecated("Used the account scheme and address instead")
|
|
def swift_bic : Option[String] //TODO: deduplication, bank field should not be in account fields
|
|
@deprecated("Used the account scheme and address instead")
|
|
def iban : Option[String]
|
|
def number : String
|
|
def bankId : BankId
|
|
def lastUpdate : Date
|
|
def branchId: String
|
|
def accountRoutingScheme: String
|
|
def accountRoutingAddress: String
|
|
def accountRules: List[AccountRules]
|
|
|
|
@deprecated("Get the account holder(s) via owners")
|
|
def accountHolder : String
|
|
|
|
//TODO: remove?
|
|
final def bankName : String =
|
|
Connector.connector.vend.getBank(bankId).map(_.fullName).getOrElse("")
|
|
//TODO: remove?
|
|
final def nationalIdentifier : String =
|
|
Connector.connector.vend.getBank(bankId).map(_.nationalIdentifier).getOrElse("")
|
|
|
|
//From V300, used scheme, address
|
|
final def bankRoutingScheme : String =
|
|
Connector.connector.vend.getBank(bankId).map(_.bankRoutingScheme).getOrElse("")
|
|
final def bankRoutingAddress : String =
|
|
Connector.connector.vend.getBank(bankId).map(_.bankRoutingAddress).getOrElse("")
|
|
|
|
/*
|
|
* Delete this account (if connector allows it, e.g. local mirror of account data)
|
|
* */
|
|
final def remove(user : User): Box[Boolean] = {
|
|
if(user.ownerAccess(this)){
|
|
Full(Connector.connector.vend.removeAccount(this.bankId, this.accountId).openOrThrowException("Attempted to open an empty Box."))
|
|
} else {
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
}
|
|
|
|
final def updateLabel(user : User, label : String): Box[Boolean] = {
|
|
if(user.ownerAccess(this)){
|
|
Connector.connector.vend.updateAccountLabel(this.bankId, this.accountId, label)
|
|
} else {
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
}
|
|
|
|
final def owners: Set[User] = {
|
|
val accountHolders = AccountHolders.accountHolders.vend.getAccountHolders(bankId, accountId)
|
|
if(accountHolders.isEmpty) {
|
|
//account holders are not all set up in the db yet, so we might not get any back.
|
|
//In this case, we just use the previous behaviour, which did not return very much information at all
|
|
Set(new User {
|
|
val resourceUserId = UserId(-1)
|
|
val userId = ""
|
|
val idGivenByProvider = ""
|
|
val provider = ""
|
|
val emailAddress = ""
|
|
val name : String = accountHolder
|
|
def views = Nil
|
|
})
|
|
} else {
|
|
accountHolders
|
|
}
|
|
}
|
|
|
|
private def viewNotAllowed(view : View ) = Failure("user does not have access to the " + view.name + " view")
|
|
|
|
final def permittedViews(user: Box[User]) : List[View] = {
|
|
user match {
|
|
case Full(u) => u.permittedViews(this)
|
|
case _ =>{
|
|
//logger.debug("No user was passed to permittedViews")
|
|
publicViews
|
|
}
|
|
}
|
|
}
|
|
|
|
final def permittedViewsFuture(user: Box[User]) : Future[List[View]] = {
|
|
val acc = BankIdAccountId(this.bankId, this.accountId)
|
|
user match {
|
|
case Full(u) =>
|
|
Views.views.vend.permittedViewsFuture(u, acc)
|
|
case _ =>
|
|
Views.views.vend.publicViewsFuture(acc)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param view the view that we want test the access to
|
|
* @param user the user that we want to see if he has access to the view or not
|
|
* @return true if the user is allowed to access this view, false otherwise
|
|
*/
|
|
final def authorizedAccess(view: View, user: Option[User]) : Boolean = {
|
|
if(view.isPublic)
|
|
true
|
|
else
|
|
user match {
|
|
case Some(u) => u.permittedView(view)
|
|
case _ => false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param user a user requesting to see the other users' permissions
|
|
* @return a Box of all the users' permissions of this bank account if the user passed as a parameter has access to the owner view (allowed to see this kind of data)
|
|
*/
|
|
final def permissions(user : User) : Box[List[Permission]] = {
|
|
//check if the user have access to the owner view in this the account
|
|
if(user.ownerAccess(this))
|
|
Full(Views.views.vend.permissions(BankIdAccountId(this.bankId,this.accountId)))
|
|
else
|
|
Failure("user " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
|
|
/**
|
|
* @param user the user requesting to see the other users permissions on this account
|
|
* @param otherUserProvider the authentication provider of the user whose permissions will be retrieved
|
|
* @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) whose permissions will be retrieved
|
|
* @return a Box of the user permissions of this bank account if the user passed as a parameter has access to the owner view (allowed to see this kind of data)
|
|
*/
|
|
final def permission(user : User, otherUserProvider : String, otherUserIdGivenByProvider: String) : Box[Permission] = {
|
|
//check if the user have access to the owner view in this the account
|
|
if(user.ownerAccess(this))
|
|
for{
|
|
u <- User.findByProviderId(otherUserProvider, otherUserIdGivenByProvider)
|
|
p <- Views.views.vend.permission(BankIdAccountId(this.bankId,this.accountId), u)
|
|
} yield p
|
|
else
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
|
|
/**
|
|
* @param user the user that wants to grant another user access to a view on this account
|
|
* @param viewUID uid of the view to which we want to grant access
|
|
* @param otherUserProvider the authentication provider of the user to whom access to the view will be granted
|
|
* @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) to whom access to the view will be granted
|
|
* @return a Full(true) if everything is okay, a Failure otherwise
|
|
*/
|
|
final def addPermission(user : User, viewUID : ViewIdBankIdAccountId, otherUserProvider : String, otherUserIdGivenByProvider: String) : Box[View] = {
|
|
//check if the user have access to the owner view in this the account
|
|
if(user.ownerAccess(this))
|
|
for{
|
|
otherUser <- User.findByProviderId(otherUserProvider, otherUserIdGivenByProvider) //check if the userId corresponds to a user
|
|
savedView <- Views.views.vend.addPermission(viewUID, otherUser) ?~ "could not save the privilege"
|
|
} yield savedView
|
|
else
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
|
|
/**
|
|
* @param user the user that wants to grant another user access to a several views on this account
|
|
* @param viewUIDs uids of the views to which we want to grant access
|
|
* @param otherUserProvider the authentication provider of the user to whom access to the views will be granted
|
|
* @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) to whom access to the views will be granted
|
|
* @return a the list of the granted views if everything is okay, a Failure otherwise
|
|
*/
|
|
final def addPermissions(user : User, viewUIDs : List[ViewIdBankIdAccountId], otherUserProvider : String, otherUserIdGivenByProvider: String) : Box[List[View]] = {
|
|
//check if the user have access to the owner view in this the account
|
|
if(user.ownerAccess(this))
|
|
for{
|
|
otherUser <- User.findByProviderId(otherUserProvider, otherUserIdGivenByProvider) //check if the userId corresponds to a user
|
|
grantedViews <- Views.views.vend.addPermissions(viewUIDs, otherUser) ?~ "could not save the privilege"
|
|
} yield grantedViews
|
|
else
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
|
|
/**
|
|
* @param user the user that wants to revoke another user's access to a view on this account
|
|
* @param viewUID uid of the view to which we want to revoke access
|
|
* @param otherUserProvider the authentication provider of the user to whom access to the view will be revoked
|
|
* @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) to whom access to the view will be revoked
|
|
* @return a Full(true) if everything is okay, a Failure otherwise
|
|
*/
|
|
final def revokePermission(user : User, viewUID : ViewIdBankIdAccountId, otherUserProvider : String, otherUserIdGivenByProvider: String) : Box[Boolean] = {
|
|
//check if the user have access to the owner view in this the account
|
|
if(user.ownerAccess(this))
|
|
for{
|
|
otherUser <- User.findByProviderId(otherUserProvider, otherUserIdGivenByProvider) //check if the userId corresponds to a user
|
|
isRevoked <- Views.views.vend.revokePermission(viewUID, otherUser) ?~ "could not revoke the privilege"
|
|
} yield isRevoked
|
|
else
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param user the user that wants to revoke another user's access to all views on this account
|
|
* @param otherUserProvider the authentication provider of the user to whom access to all views will be revoked
|
|
* @param otherUserIdGivenByProvider the id of the user (the one given by their auth provider) to whom access to all views will be revoked
|
|
* @return a Full(true) if everything is okay, a Failure otherwise
|
|
*/
|
|
|
|
final def revokeAllPermissions(user : User, otherUserProvider : String, otherUserIdGivenByProvider: String) : Box[Boolean] = {
|
|
//check if the user have access to the owner view in this the account
|
|
if(user.ownerAccess(this))
|
|
for{
|
|
otherUser <- User.findByProviderId(otherUserProvider, otherUserIdGivenByProvider) //check if the userId corresponds to a user
|
|
isRevoked <- Views.views.vend.revokeAllPermissions(bankId, accountId, otherUser)
|
|
} yield isRevoked
|
|
else
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
|
|
|
|
/*
|
|
views
|
|
*/
|
|
|
|
final def views(user : User) : Box[List[View]] = {
|
|
//check if the user has access to the owner view in this the account
|
|
if(user.ownerAccess(this)) {
|
|
Full(Views.views.vend.views(BankIdAccountId(this.bankId,this.accountId))) }
|
|
else
|
|
Failure("user : " + user.emailAddress + " does not have access to owner view on account " + accountId, Empty, Empty)
|
|
}
|
|
|
|
final def createView(userDoingTheCreate : User,v: CreateViewJson): Box[View] = {
|
|
if(!userDoingTheCreate.ownerAccess(this)) {
|
|
Failure({"user: " + userDoingTheCreate.idGivenByProvider + " at provider " + userDoingTheCreate.provider + " does not have owner access"})
|
|
} else {
|
|
val view = Views.views.vend.createView(BankIdAccountId(this.bankId,this.accountId), v)
|
|
|
|
//if(view.isDefined) {
|
|
// logger.debug("user: " + userDoingTheCreate.idGivenByProvider + " at provider " + userDoingTheCreate.provider + " created view: " + view.get +
|
|
// " for account " + accountId + "at bank " + bankId)
|
|
//}
|
|
|
|
view
|
|
}
|
|
}
|
|
|
|
final def updateView(userDoingTheUpdate : User, viewId : ViewId, v: UpdateViewJSON) : Box[View] = {
|
|
if(!userDoingTheUpdate.ownerAccess(this)) {
|
|
Failure({"user: " + userDoingTheUpdate.idGivenByProvider + " at provider " + userDoingTheUpdate.provider + " does not have owner access"})
|
|
} else {
|
|
val view = Views.views.vend.updateView(BankIdAccountId(this.bankId,this.accountId), viewId, v)
|
|
|
|
//if(view.isDefined) {
|
|
// logger.debug("user: " + userDoingTheUpdate.idGivenByProvider + " at provider " + userDoingTheUpdate.provider + " updated view: " + view.get +
|
|
// " for account " + accountId + "at bank " + bankId)
|
|
//}
|
|
|
|
view
|
|
}
|
|
}
|
|
|
|
final def removeView(userDoingTheRemove : User, viewId: ViewId) : Box[Unit] = {
|
|
if(!userDoingTheRemove.ownerAccess(this)) {
|
|
return Failure({"user: " + userDoingTheRemove.idGivenByProvider + " at provider " + userDoingTheRemove.provider + " does not have owner access"})
|
|
} else {
|
|
val deleted = Views.views.vend.removeView(viewId, BankIdAccountId(this.bankId,this.accountId))
|
|
|
|
//if (deleted.isDefined) {
|
|
// logger.debug("user: " + userDoingTheRemove.idGivenByProvider + " at provider " + userDoingTheRemove.provider + " deleted view: " + viewId +
|
|
// " for account " + accountId + "at bank " + bankId)
|
|
//}
|
|
|
|
deleted
|
|
}
|
|
}
|
|
|
|
final def publicViews : List[View] = Views.views.vend.publicViews(BankIdAccountId(this.bankId,this.accountId))
|
|
|
|
final def moderatedTransaction(transactionId: TransactionId, view: View, user: Box[User]) : Box[ModeratedTransaction] = {
|
|
if(authorizedAccess(view, user))
|
|
Connector.connector.vend.getTransaction(bankId, accountId, transactionId).flatMap(view.moderate)
|
|
else
|
|
viewNotAllowed(view)
|
|
}
|
|
|
|
/*
|
|
end views
|
|
*/
|
|
|
|
// TODO We should extract params (and their defaults) prior to this call, so this whole function can be cached.
|
|
final def getModeratedTransactions(user : Box[User], view : View, queryParams: OBPQueryParam*)(session: Option[SessionContext]): Box[List[ModeratedTransaction]] = {
|
|
if(authorizedAccess(view, user)) {
|
|
for {
|
|
transactions <- Connector.connector.vend.getTransactions(bankId, accountId, session, queryParams: _*)
|
|
moderated <- view.moderateTransactionsWithSameAccount(transactions) ?~! "Server error"
|
|
} yield moderated
|
|
}
|
|
else viewNotAllowed(view)
|
|
}
|
|
|
|
final def moderatedBankAccount(view: View, user: Box[User]) : Box[ModeratedBankAccount] = {
|
|
if(authorizedAccess(view, user))
|
|
//implicit conversion from option to box
|
|
view.moderate(this)
|
|
else
|
|
viewNotAllowed(view)
|
|
}
|
|
|
|
/**
|
|
* @param the view that we will use to get the ModeratedOtherBankAccount list
|
|
* @param the user that want access to the ModeratedOtherBankAccount list
|
|
* @return a Box of a list ModeratedOtherBankAccounts, it the bank
|
|
* accounts that have at least one transaction in common with this bank account
|
|
*/
|
|
final def moderatedOtherBankAccounts(view : View, user : Box[User]) : Box[List[ModeratedOtherBankAccount]] =
|
|
if(authorizedAccess(view, user))
|
|
Full(Connector.connector.vend.getCounterpartiesFromTransaction(bankId, accountId).openOrThrowException("Attempted to open an empty Box.").map(oAcc => view.moderate(oAcc)).flatten)
|
|
else
|
|
viewNotAllowed(view)
|
|
/**
|
|
* @param the ID of the other bank account that the user want have access
|
|
* @param the view that we will use to get the ModeratedOtherBankAccount
|
|
* @param the user that want access to the otherBankAccounts list
|
|
* @return a Box of a ModeratedOtherBankAccounts, it a bank
|
|
* account that have at least one transaction in common with this bank account
|
|
*/
|
|
final def moderatedOtherBankAccount(counterpartyID : String, view : View, user : Box[User]) : Box[ModeratedOtherBankAccount] =
|
|
if(authorizedAccess(view, user))
|
|
Connector.connector.vend.getCounterpartyFromTransaction(bankId, accountId, counterpartyID).flatMap(oAcc => view.moderate(oAcc))
|
|
else
|
|
viewNotAllowed(view)
|
|
|
|
@deprecated(Helper.deprecatedJsonGenerationMessage)
|
|
final def overviewJson(user: Box[User]): JObject = {
|
|
val views = permittedViews(user)
|
|
("number" -> number) ~
|
|
("account_alias" -> label) ~
|
|
("owner_description" -> "") ~
|
|
("views_available" -> views.map(view => view.toJson)) ~
|
|
View.linksJson(views, accountId, bankId)
|
|
}
|
|
}
|
|
|
|
object BankAccount {
|
|
def apply(bankId: BankId, accountId: AccountId) : Box[BankAccount] = {
|
|
Connector.connector.vend.getBankAccount(bankId, accountId)
|
|
}
|
|
|
|
def apply(bankId: BankId, accountId: AccountId, sessionContext: Option[SessionContext]) : Box[BankAccount] = {
|
|
Connector.connector.vend.getBankAccount(bankId, accountId, sessionContext)
|
|
}
|
|
|
|
def publicAccounts : List[BankAccount] = {
|
|
Views.views.vend.getAllPublicAccounts.flatMap { a =>
|
|
BankAccount(a.bankId, a.accountId)
|
|
}
|
|
}
|
|
|
|
def accounts(user : Box[User]) : List[BankAccount] = {
|
|
Views.views.vend.getAllAccountsUserCanSee(user).flatMap { a =>
|
|
BankAccount(a.bankId, a.accountId)
|
|
}
|
|
}
|
|
|
|
def privateAccounts(user : User) : List[BankAccount] = {
|
|
Views.views.vend.getPrivateBankAccounts(user).flatMap { a =>
|
|
BankAccount(a.bankId, a.accountId)
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
The other bank account or counterparty in a transaction
|
|
as see from the perspective of the original party.
|
|
*/
|
|
|
|
|
|
// Note: See also CounterpartyTrait
|
|
class Counterparty(
|
|
|
|
@deprecated("older version, please first consider the V210, account scheme and address")
|
|
val nationalIdentifier : String, // This is the scheme a consumer would use to instruct a payment e.g. IBAN
|
|
val alreadyFoundMetadata : Option[CounterpartyMetadata],
|
|
val label : String, // Reference given to the counterparty by the original party.
|
|
val kind : String, // Type of bank account.
|
|
|
|
// The following fields started from V210
|
|
val counterPartyId: String,
|
|
val name: String,
|
|
val otherAccountRoutingScheme :String, // This is the scheme a consumer would use to instruct a payment e.g. IBAN
|
|
val otherAccountRoutingAddress : Option[String], // The (IBAN) value e.g. 2349870987820374
|
|
val otherBankRoutingScheme: String, // This is the scheme a consumer would use to specify the bank e.g. BIC
|
|
val otherBankRoutingAddress : Option[String], // The (BIC) value e.g. 67895
|
|
val thisBankId : BankId, // i.e. the Account that sends/receives money to/from this Counterparty
|
|
val thisAccountId: AccountId, // These 2 fields specify the account that uses this Counterparty
|
|
val otherBankId : BankId, // These 3 fields specify the internal locaiton of the account for the
|
|
val otherAccountId: AccountId, //counterparty if it is known. It could be at OBP in which case
|
|
val otherAccountProvider: String, // hasBankId and hasAccountId would refer to an OBP account
|
|
val isBeneficiary: Boolean // True if the originAccount can send money to the Counterparty
|
|
)
|
|
{
|
|
|
|
val metadata : CounterpartyMetadata = {
|
|
// If we already have alreadyFoundMetadata, return it, else get or create it.
|
|
alreadyFoundMetadata match {
|
|
case Some(meta) =>
|
|
meta
|
|
case None =>
|
|
Counterparties.counterparties.vend.getOrCreateMetadata(otherBankId, otherAccountId, this).openOrThrowException("Can not getOrCreateMetadata !")
|
|
}
|
|
}
|
|
}
|
|
|
|
trait TransactionUUID {
|
|
def theTransactionId : TransactionId
|
|
def theBankId : BankId
|
|
def theAccountId : AccountId
|
|
}
|
|
|
|
class Transaction(
|
|
//A universally unique id
|
|
val uuid: String,
|
|
//id is unique for transactions of @thisAccount
|
|
val id : TransactionId,
|
|
val thisAccount : BankAccount,
|
|
val otherAccount : Counterparty,
|
|
//E.g. cash withdrawal, electronic payment, etc.
|
|
val transactionType : String,
|
|
val amount : BigDecimal,
|
|
//ISO 4217, e.g. EUR, GBP, USD, etc.
|
|
val currency : String,
|
|
// Bank provided label
|
|
val description : Option[String],
|
|
// The date the transaction was initiated
|
|
val startDate : Date,
|
|
// The date when the money finished changing hands
|
|
val finishDate : Date,
|
|
//the new balance for the bank account
|
|
val balance : BigDecimal
|
|
) {
|
|
|
|
val bankId = thisAccount.bankId
|
|
val accountId = thisAccount.accountId
|
|
|
|
/**
|
|
* The metadata is set up using dependency injection. If you want to, e.g. override the Comments implementation
|
|
* for a particular scope, use Comments.comments.doWith(NewCommentsImplementation extends Comments{}){
|
|
* //code in here will use NewCommentsImplementation (e.g. val t = new Transaction(...) will result in Comments.comments.vend
|
|
* // return NewCommentsImplementation here below)
|
|
* }
|
|
*
|
|
* If you want to change the current default implementation, you would change the buildOne function in Comments to
|
|
* return a different value
|
|
*
|
|
*/
|
|
val metadata : TransactionMetadata = new TransactionMetadata(
|
|
Narrative.narrative.vend.getNarrative(bankId, accountId, id) _,
|
|
Narrative.narrative.vend.setNarrative(bankId, accountId, id) _,
|
|
Comments.comments.vend.getComments(bankId, accountId, id) _,
|
|
Comments.comments.vend.addComment(bankId, accountId, id) _,
|
|
Comments.comments.vend.deleteComment(bankId, accountId, id) _,
|
|
Tags.tags.vend.getTags(bankId, accountId, id) _,
|
|
Tags.tags.vend.addTag(bankId, accountId, id) _,
|
|
Tags.tags.vend.deleteTag(bankId, accountId, id) _,
|
|
TransactionImages.transactionImages.vend.getImagesForTransaction(bankId, accountId, id) _,
|
|
TransactionImages.transactionImages.vend.addTransactionImage(bankId, accountId, id) _,
|
|
TransactionImages.transactionImages.vend.deleteTransactionImage(bankId, accountId, id) _,
|
|
WhereTags.whereTags.vend.getWhereTagForTransaction(bankId, accountId, id) _,
|
|
WhereTags.whereTags.vend.addWhereTag(bankId, accountId, id) _,
|
|
WhereTags.whereTags.vend.deleteWhereTag(bankId, accountId, id) _
|
|
)
|
|
}
|
|
|
|
case class AmountOfMoney (
|
|
val currency: String,
|
|
val amount: String
|
|
)
|
|
|
|
case class Iban(
|
|
val iban: String
|
|
)
|
|
|
|
case class AccountRouting(
|
|
scheme: String,
|
|
address: String
|
|
)
|
|
|
|
case class CoreAccount(
|
|
id: String,
|
|
label: String,
|
|
bank_id: String,
|
|
account_routing: AccountRouting
|
|
) |