issue130 - endpoint for create/get branch

This commit is contained in:
sorinmanole 2016-09-13 16:57:32 +02:00
parent 7f2ef47897
commit f830e733f4
9 changed files with 355 additions and 47 deletions

View File

@ -9,10 +9,12 @@ import code.api.v2_0_0.JSONFactory200._
import code.api.v2_0_0.{JSONFactory200, TransactionRequestBodyJSON}
import code.api.v2_1_0.JSONFactory210._
import code.bankconnectors.Connector
import code.branches.Branches.BranchId
import code.fx.fx
import code.model._
import net.liftweb.http.Req
import net.liftweb.json
import net.liftweb.json.Extraction
import net.liftweb.json.JsonAST.JValue
import net.liftweb.util.Props
@ -25,7 +27,7 @@ import net.liftweb.json.JsonDSL._
import code.api.APIFailure
import code.api.util.APIUtil._
import code.sandbox.{OBPDataImport, SandboxDataImport}
import code.sandbox.{SandboxBranchImport, OBPDataImport, SandboxDataImport}
import code.util.Helper
import net.liftweb.common.{Empty, Full, Box}
import net.liftweb.http.JsonResponse
@ -65,7 +67,7 @@ trait APIMethods210 {
"POST",
"/sandbox/data-import",
"Import data into the sandbox.",
s"""Import bulk data into the sandbox (Authenticated access).
"""Import bulk data into the sandbox (Authenticated access).
|The user needs to have CanCreateSandbox entitlement.
|
|An example of an import set of data (json) can be found [here](https://raw.githubusercontent.com/OpenBankProject/OBP-API/develop/src/main/scala/code/api/sandbox/example_data/2016-04-28/example_import.json)
@ -89,7 +91,8 @@ trait APIMethods210 {
allowDataImportProp <- Props.get("allow_sandbox_data_import") ~> APIFailure("Data import is disabled for this API instance.", 403)
allowDataImport <- Helper.booleanToBox(allowDataImportProp == "true") ~> APIFailure("Data import is disabled for this API instance.", 403)
canCreateSandbox <- booleanToBox(hasEntitlement("", u.userId, CanCreateSandbox), s"$CanCreateSandbox entitlement required")
importData <- tryo {json.extract[SandboxDataImport]} ?~ "invalid json"
importData <- tryo {json.extract[
SandboxDataImport]} ?~ "invalid json"
importWorked <- OBPDataImport.importer.vend.importData(importData)
} yield {
successJsonResponse(JsRaw("{}"), 201)
@ -107,7 +110,7 @@ trait APIMethods210 {
"GET",
"/banks/BANK_ID/transaction-request-types",
"Get the Transaction Request Types supported by the bank",
s"""Get the list of the Transaction Request Types supported by the bank.
"""Get the list of the Transaction Request Types supported by the bank.
|
|${authenticationRequiredMessage(!getTransactionRequestTypesIsPublic)}
|""",
@ -144,7 +147,9 @@ trait APIMethods210 {
import net.liftweb.json.JsonAST._
import net.liftweb.json.Extraction._
import net.liftweb.json.Printer._
import net
.liftweb.json.Printer._
val exchangeRates = pretty(render(decompose(fx.exchangeRates)))
resourceDocs += ResourceDoc(
@ -215,9 +220,12 @@ trait APIMethods210 {
u <- user ?~ ErrorMessages.UserNotLoggedIn
// Get Transaction Request Types from Props "transactionRequests_supported_types". Default is empty string
validTransactionRequestTypes <- tryo{Props.get("transactionRequests_supported_types", "")}
validTransactionRequestTypes <- tryo{Props.get(
"transactionRequests_supported_types", "")}
// Use a list instead of a string to avoid partial matches
validTransactionRequestTypesList <- tryo{validTransactionRequestTypes.split(",")}
validTransactionRequestTypesList <-
tryo{validTransactionRequestTypes.split(
",")}
isValidTransactionRequestType <- tryo(assert(transactionRequestType.value != "TRANSACTION_REQUEST_TYPE" && validTransactionRequestTypesList.contains(transactionRequestType.value))) ?~! s"${ErrorMessages.InvalidTransactionRequestType} : Invalid value is: '${transactionRequestType.value}' Valid values are: ${validTransactionRequestTypes}"
transDetailsJson <- transactionRequestType.value match {
@ -239,24 +247,35 @@ trait APIMethods210 {
}
transDetails <- transactionRequestType.value match {
case "SANDBOX_TAN" => tryo{getTransactionRequestDetailsSandBoxTanFromJson(transDetailsJson.asInstanceOf[TransactionRequestDetailsSandBoxTanJSON])}
case "SEPA" => tryo{getTransactionRequestDetailsSEPAFromJson(transDetailsJson.asInstanceOf[TransactionRequestDetailsSEPAJSON])}
case "FREE_FORM" => tryo{getTransactionRequestDetailsFreeFormFromJson(transDetailsJson.asInstanceOf[TransactionRequestDetailsFreeFormJSON])}
case "SANDBOX_TAN" => tryo {getTransactionRequestDetailsSandBoxTanFromJson(transDetailsJson.asInstanceOf[TransactionRequestDetailsSandBoxTanJSON]
)}
case "SEPA" => tryo{
getTransactionRequestDetailsSEPAFromJson(transDetailsJson.asInstanceOf[TransactionRequestDetailsSEPAJSON])
}
case "FREE_FORM" => tryo {
getTransactionRequestDetailsFreeFormFromJson(transDetailsJson.asInstanceOf[TransactionRequestDetailsFreeFormJSON])
}
}
fromBank <- Bank(bankId) ?~! {ErrorMessages.BankNotFound}
fromAccount <- BankAccount(bankId, accountId) ?~! {ErrorMessages.AccountNotFound}
isOwnerOrHasEntitlement <- booleanToBox(u.ownerAccess(fromAccount) == true || hasEntitlement(fromAccount.bankId.value, u.userId, CanCreateAnyTransactionRequest) == true , ErrorMessages.InsufficientAuthorisationToCreateTransactionRequest)
fromBank <- Bank(bankId) ?~! {
ErrorMessages.BankNotFound
}
fromAccount <- BankAccount(bankId, accountId) ?~! {
ErrorMessages.AccountNotFound
}
isOwnerOrHasEntitlement <- booleanToBox(u.ownerAccess(fromAccount) == true || hasEntitlement(fromAccount.bankId.value, u.userId, CanCreateAnyTransactionRequest) == true, ErrorMessages.InsufficientAuthorisationToCreateTransactionRequest)
// Prevent default value for transaction request type (at least).
transferCurrencyEqual <- tryo(assert(transDetailsJson.value.currency == fromAccount.currency)) ?~! {"Transfer body currency and holder account currency must be the same."}
transferCurrencyEqual <- tryo(assert(transDetailsJson.value.currency == fromAccount.currency)) ?~! {
"Transfer body currency and holder account currency must be the same."
}
transDetailsSerialized<- transactionRequestType.value match {
case "FREE_FORM" => tryo{
transDetailsSerialized <- transactionRequestType.value match {
case "FREE_FORM" => tryo {
implicit val formats = Serialization.formats(NoTypeHints)
write(json)
}
case _ => tryo{
case _ => tryo {
implicit val formats = Serialization.formats(NoTypeHints)
write(transDetailsJson)
}
@ -267,7 +286,9 @@ trait APIMethods210 {
for {
toBankId <- Full(BankId(transDetailsJson.asInstanceOf[TransactionRequestDetailsSandBoxTanJSON].to.bank_id))
toAccountId <- Full(AccountId(transDetailsJson.asInstanceOf[TransactionRequestDetailsSandBoxTanJSON].to.account_id))
toAccount <- BankAccount(toBankId, toAccountId) ?~! {ErrorMessages.CounterpartyNotFound}
toAccount <- BankAccount(toBankId, toAccountId) ?~! {
ErrorMessages.CounterpartyNotFound
}
createdTransactionRequest <- Connector.connector.vend.createTransactionRequestv210(u, fromAccount, Full(toAccount), transactionRequestType, transDetails, transDetailsSerialized)
} yield createdTransactionRequest
@ -298,7 +319,7 @@ trait APIMethods210 {
"getTransactionRequests",
"GET",
"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-requests",
"Get Transaction Requests." ,
"Get Transaction Requests.",
"""Returns transaction requests for account specified by ACCOUNT_ID at bank specified by BANK_ID.
|
|The VIEW_ID specified must be 'owner' and the user must have access to this view.
@ -335,9 +356,15 @@ trait APIMethods210 {
if (Props.getBool("transactionRequests_enabled", false)) {
for {
u <- user ?~ ErrorMessages.UserNotLoggedIn
fromBank <- Bank(bankId) ?~! {ErrorMessages.BankNotFound}
fromAccount <- BankAccount(bankId, accountId) ?~! {ErrorMessages.AccountNotFound}
view <- tryo(fromAccount.permittedViews(user).find(_ == viewId)) ?~ {"Current user does not have access to the view " + viewId}
fromBank <- Bank(bankId) ?~! {
ErrorMessages.BankNotFound
}
fromAccount <- BankAccount(bankId, accountId) ?~! {
ErrorMessages.AccountNotFound
}
view <- tryo(fromAccount.permittedViews(user).find(_ == viewId)) ?~ {
"Current user does not have access to the view " + viewId
}
transactionRequests <- Connector.connector.vend.getTransactionRequests210(u, fromAccount)
}
yield {
@ -350,6 +377,83 @@ trait APIMethods210 {
}
}
}
resourceDocs += ResourceDoc(
createBranch,
apiVersion,
"createBranch",
"POST",
"/banks/BANK_ID/branches",
"Create Branch",
s"""Create branch for the bank (Authenticated access).
|${authenticationRequiredMessage(true)}
|""",
emptyObjectJson,
emptyObjectJson,
emptyObjectJson :: Nil,
false,
false,
false,
List(apiTagAccount, apiTagPrivateData, apiTagPublicData))
lazy val createBranch: PartialFunction[Req, Box[User] => Box[JsonResponse]] = {
// Import data into the sandbox
case "banks" :: BankId(bankId) :: "branches" :: Nil JsonPost json -> _ => {
user =>
for {
u <- user ?~ ErrorMessages.UserNotLoggedIn
bank <- Bank(bankId) ?~! {
ErrorMessages.BankNotFound
}
branch <- tryo {
json.extract[SandboxBranchImport]
} ?~ "invalid json"
success <- Connector.connector.vend.createBranch(branch)
} yield {
successJsonResponse(JsRaw("{}"), 201)
}
}
}
resourceDocs += ResourceDoc(
getBranch,
apiVersion,
"getBranch",
"GET",
"/banks/BANK_ID/branches/BRANCH_ID",
"Get Branch",
s"""Get branch by ID (Authenticated access).
|${authenticationRequiredMessage(true)}
|""",
emptyObjectJson,
emptyObjectJson,
emptyObjectJson :: Nil,
false,
false,
false,
List(apiTagAccount, apiTagPrivateData, apiTagPublicData))
lazy val getBranch: PartialFunction[Req, Box[User] => Box[JsonResponse]] = {
// Import data into the sandbox
case "banks" :: BankId(bankId) :: "branches" :: BranchId(branchId) :: Nil JsonGet _ => {
user =>
for {
u <- user ?~ ErrorMessages.UserNotLoggedIn
bank <- Bank(bankId) ?~! {
ErrorMessages.BankNotFound
}
branch <- Connector.connector.vend.getBranch(branchId)
} yield {
val json = JSONFactory210.createBranchJSON(branch)
successJsonResponse(Extraction.decompose(json))
}
}
}
}
}

View File

@ -1,32 +1,32 @@
/**
Open Bank Project - API
Copyright (C) 2011-2015, TESOBE Ltd
* Open Bank Project - API
* Copyright (C) 2011-2015, 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 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.
* 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/>.
* 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 / Music Pictures Ltd
Osloerstrasse 16/17
Berlin 13359, Germany
* Email: contact@tesobe.com
* TESOBE / Music Pictures 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
* 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.api.v2_1_0
@ -36,8 +36,13 @@ import java.util.Date
import code.api.v1_2_1.AmountOfMoneyJSON
import code.api.v1_4_0.JSONFactory1_4_0.{ChallengeJSON, TransactionRequestAccountJSON}
import code.api.v2_0_0.{TransactionRequestWithChargeJSONs, TransactionRequestChargeJSON, TransactionRequestBodyJSON}
import code.branches.Branches.{BranchId, DriveUp, Lobby, Branch}
import code.model.AmountOfMoney
import code.transactionrequests.TransactionRequests._
import code.common.{Meta, License, Location, Address}
case class AddressImpl(line1 : String, line2 : String, line3 : String, city : String, county : String,
state : String, postCode : String, countryCode : String) extends Address
case class TransactionRequestTypeJSON(transaction_request_type: String)
case class TransactionRequestTypesJSON(transaction_request_types: List[TransactionRequestTypeJSON])
@ -79,6 +84,53 @@ case class TransactionRequestWithChargeJSONs210(
transaction_requests_with_charges : List[TransactionRequestWithChargeJSON210]
)
case class BranchJSON (branchId : String,
name : String,
address : AddressJSON,
location : LocationJSON,
lobby : LobbyJSON,
driveUp : DriveUpJSON,
meta : MetaJSON
)
case class LobbyJSON (
hours : String
)
case class DriveUpJSON (
hours : String
)
case class MetaJSON (
license : LicenseJSON
)
case class LicenseJSON (
id : String,
name : String
)
case class AddressJSON (
line1 : String,
line2 : String,
line3 : String,
city : String,
county : String,
state : String,
postCode : String,
countryCode : String
)
case class LocationJSON (
latitude: Double,
longitude: Double
)
object JSONFactory210{
def createTransactionRequestTypeJSON(transactionRequestType : String ) : TransactionRequestTypeJSON = {
new TransactionRequestTypeJSON(
@ -131,6 +183,84 @@ object JSONFactory210{
)
}
def getBranchFromJson(branchJSON: BranchJSON) : Branch = {
val address = new Address {
override def line1 = branchJSON.address.line1
override def line2 = branchJSON.address.line2
override def line3 = branchJSON.address.line3
override def city = branchJSON.address.city
override def county = branchJSON.address.county
override def state = branchJSON.address.state
override def postCode = branchJSON.address.postCode
override def countryCode = branchJSON.address.countryCode
}
val location = new Location {
override def latitude = branchJSON.location.latitude
override def longitude = branchJSON.location.longitude
}
val lobby = new Lobby {
override def hours = branchJSON.lobby.hours
}
val driveUp = new DriveUp {
override def hours = branchJSON.driveUp.hours
}
val license = new License {
override def id = branchJSON.meta.license.id
override def name = branchJSON.meta.license.name
}
val meta = new Meta {
override def license = license
}
new Branch {
override def branchId = BranchId(branchJSON.branchId)
override def name = branchJSON.name
override def address = address
override def location = location
override def lobby = lobby
override def driveUp = driveUp
override def meta = meta
}
}
def createBranchJSON(branch : Branch) : BranchJSON = {
new BranchJSON(
branchId = branch.branchId.value,
name = branch.name,
address = AddressJSON(
line1 = branch.address.line1,
line2 = branch.address.line2,
line3 = branch.address.line3,
city = branch.address.city,
county = branch.address.county,
state = branch.address.state,
postCode = branch.address.postCode,
countryCode = branch.address.countryCode
),
location = LocationJSON(
latitude = branch.location.latitude,
longitude = branch.location.longitude
),
lobby = LobbyJSON(
hours = branch.lobby.hours
),
driveUp = DriveUpJSON(
hours = branch.driveUp.hours
),
meta = MetaJSON(
license = LicenseJSON(
id = branch.meta.license.id,
name = branch.meta.license.name
)
)
)
}
/** Creates v2.1.0 representation of a TransactionType
*
* @param tr An internal TransactionRequest instance

View File

@ -225,6 +225,8 @@ object OBPAPI2_1_0 extends OBPRestHelper with APIMethods130 with APIMethods140 w
if (!disabledEndpoints.contains("getTransactionRequestTypesSupportedByBank")) routes = routes:::List(Implementations2_1_0.getTransactionRequestTypesSupportedByBank)
if (!disabledEndpoints.contains("createTransactionRequest")) routes = routes:::List(Implementations2_1_0.createTransactionRequest)
if (!disabledEndpoints.contains("getTransactionRequests")) routes = routes:::List(Implementations2_1_0.getTransactionRequests)
if (!disabledEndpoints.contains("createBranch")) routes = routes:::List(Implementations2_1_0.createBranch)
if (!disabledEndpoints.contains("getBranch")) routes = routes:::List(Implementations2_1_0.getBranch)
}
// ### VERSION 2.1.0 - END ###

View File

@ -5,9 +5,11 @@ import java.util.Date
import code.api.util.APIUtil._
import code.api.util.ApiRole._
import code.api.util.ErrorMessages
import code.branches.Branches.{Branch, BranchId}
import code.fx.fx
import code.management.ImporterAPI.ImporterTransaction
import code.model.{OtherBankAccount, Transaction, User, _}
import code.sandbox.SandboxBranchImport
import code.transactionrequests.TransactionRequests
import code.transactionrequests.TransactionRequests._
import code.util.Helper._
@ -590,4 +592,8 @@ trait Connector {
def updateAccountLabel(bankId: BankId, accountId: AccountId, label: String): Boolean
def createBranch(branch: SandboxBranchImport): Box[Boolean]
def getBranch(branchId: BranchId): Box[Branch]
}

View File

@ -4,6 +4,7 @@ import java.text.SimpleDateFormat
import java.util.{Date, Locale, UUID}
import code.api.util.ErrorMessages
import code.branches.Branches.{Branch, BranchId}
import code.management.ImporterAPI.ImporterTransaction
import code.metadata.comments.MappedComment
import code.metadata.counterparties.Counterparties
@ -13,7 +14,7 @@ import code.metadata.transactionimages.MappedTransactionImage
import code.metadata.wheretags.MappedWhereTag
import code.model._
import code.model.dataAccess._
import code.sandbox.{CreateViewImpls, Saveable}
import code.sandbox.{SandboxBranchImport, CreateViewImpls, Saveable}
import code.transaction.MappedTransaction
import code.transactionrequests.{MappedTransactionRequest210, MappedTransactionRequest}
import code.transactionrequests.TransactionRequests._
@ -917,6 +918,10 @@ object KafkaMappedConnector extends Connector with CreateViewImpls with Loggable
}
}
override def createBranch(branch: SandboxBranchImport) : Box[Boolean] = ???
override def getBranch(branchId: BranchId): Box[Branch] = ???
case class KafkaBank(r: KafkaInboundBank) extends Bank {
def fullName = r.full_name

View File

@ -3,10 +3,12 @@ package code.bankconnectors
import java.text.SimpleDateFormat
import java.util.{Date, TimeZone, UUID}
import code.branches.Branches.{Branch, BranchId}
import code.management.ImporterAPI.ImporterTransaction
import code.metadata.counterparties.{Counterparties, Metadata, MongoCounterparties}
import code.model._
import code.model.dataAccess._
import code.sandbox.SandboxBranchImport
import code.transactionrequests.TransactionRequests._
import code.util.Helper
import com.mongodb.QueryBuilder
@ -551,4 +553,8 @@ private object LocalConnector extends Connector with Loggable {
false
}
}
override def createBranch(branch: SandboxBranchImport) : Box[Boolean] = ???
override def getBranch(branchId: BranchId): Box[Branch] = ???
}

View File

@ -2,6 +2,8 @@ package code.bankconnectors
import java.util.{Date, UUID}
import code.branches.Branches.{Branch, BranchId}
import code.branches.MappedBranch
import code.fx.fx
import code.management.ImporterAPI.ImporterTransaction
import code.metadata.comments.MappedComment
@ -12,6 +14,8 @@ import code.metadata.transactionimages.MappedTransactionImage
import code.metadata.wheretags.MappedWhereTag
import code.model._
import code.model.dataAccess._
import code.sandbox.LocalMappedConnectorDataImport.BranchType
import code.sandbox.{MappedSaveable, Saveable, SandboxBranchImport}
import code.tesobe.CashTransaction
import code.transaction.MappedTransaction
import code.transactionrequests.{MappedTransactionRequest210, MappedTransactionRequest}
@ -613,4 +617,46 @@ object LocalMappedConnector extends Connector with Loggable {
result.getOrElse(false)
}
override def createBranch(branch: SandboxBranchImport) : Box[Boolean] = {
val lobbyHours = if (branch.lobby.isDefined) {branch.lobby.get.hours.toString} else ""
val driveUpHours = if (branch.driveUp.isDefined) {branch.driveUp.get.hours.toString} else ""
val mappedBranch = MappedBranch.create
.mBranchId(branch.id)
.mBankId(branch.bank_id)
.mName(branch.name)
// Note: address fields are returned in meta.address
// but are stored flat as fields / columns in the table
.mLine1(branch.address.line_1)
.mLine2(branch.address.line_2)
.mLine3(branch.address.line_3)
.mCity(branch.address.city)
.mCounty(branch.address.county)
.mState(branch.address.state)
.mPostCode(branch.address.post_code)
.mCountryCode(branch.address.country_code)
.mlocationLatitude(branch.location.latitude)
.mlocationLongitude(branch.location.longitude)
.mLicenseId(branch.meta.license.id)
.mLicenseName(branch.meta.license.name)
.mLobbyHours(lobbyHours)
.mDriveUpHours(driveUpHours)
val validationErrors = mappedBranch.validate
if(validationErrors.nonEmpty) {
Full(false)
} else {
Full(true)
}
}
//gets a particular bank handled by this connector
override def getBranch(branchId: BranchId): Box[Branch] =
getMappedBranch(branchId)
private def getMappedBranch(branchId: BranchId): Box[MappedBranch] =
MappedBranch.find(By(MappedBranch.mBranchId, branchId.value))
}

View File

@ -13,8 +13,13 @@ import net.liftweb.common.Logger
import net.liftweb.util.SimpleInjector
object Branches extends SimpleInjector {
case class BranchId(val value : String) {
override def toString = value
}
case class BranchId(value : String)
object BranchId {
def unapply(id : String) = Some(BranchId(id))
}
trait Branch {
def branchId : BranchId

View File

@ -5,8 +5,10 @@ import java.util.Date
import code.api.util.APIUtil.OAuth._
import code.api.{DefaultUsers, ServerSetup}
import code.bankconnectors.{Connector, OBPQueryParam}
import code.branches.Branches.{Branch, BranchId}
import code.management.ImporterAPI.ImporterTransaction
import code.model.{PhysicalCard, Consumer => OBPConsumer, Token => OBPToken, _}
import code.sandbox.SandboxBranchImport
import code.transactionrequests.TransactionRequests._
import net.liftweb.common.{Box, Empty, Failure, Loggable}
@ -134,6 +136,8 @@ class PhysicalCardsTest extends ServerSetup with DefaultUsers {
override def updateAccountBalance(bankId: BankId, accountId: AccountId, newBalance: BigDecimal): Boolean = ???
override def setBankAccountLastUpdated(bankNationalIdentifier: String, accountNumber : String, updateDate: Date) : Boolean = ???
override def updateAccountLabel(bankId: BankId, accountId: AccountId, label: String): Boolean = ???
override def createBranch(branch: SandboxBranchImport) : Box[Boolean] = ???
override def getBranch(branchId: BranchId): Box[Branch] = ???
}
override def beforeAll() {