Merge pull request #2460 from hongwei1/develop

feature/added counterpartyLimit to payment counterparty type
This commit is contained in:
Simon Redfern 2024-12-06 13:07:17 +01:00 committed by GitHub
commit 8be900f5a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 556 additions and 127 deletions

View File

@ -5458,11 +5458,13 @@ object SwaggerDefinitionsJSON {
val postCounterpartyLimitV510 = PostCounterpartyLimitV510(
currency = currencyExample.value,
max_single_amount = maxSingleAmountExample.value.toInt,
max_monthly_amount = maxMonthlyAmountExample.value.toInt,
max_single_amount = maxSingleAmountExample.value,
max_monthly_amount = maxMonthlyAmountExample.value,
max_number_of_monthly_transactions = maxNumberOfMonthlyTransactionsExample.value.toInt,
max_yearly_amount = maxYearlyAmountExample.value.toInt,
max_number_of_yearly_transactions = maxNumberOfYearlyTransactionsExample.value.toInt
max_yearly_amount = maxYearlyAmountExample.value,
max_number_of_yearly_transactions = maxNumberOfYearlyTransactionsExample.value.toInt,
max_total_amount = maxTotalAmountExample.value,
max_number_of_transactions = maxNumberOfTransactionsExample.value.toInt
)
val counterpartyLimitV510 = CounterpartyLimitV510(
@ -5472,11 +5474,13 @@ object SwaggerDefinitionsJSON {
view_id = viewIdExample.value,
counterparty_id = counterpartyIdExample.value,
currency = currencyExample.value,
max_single_amount = maxSingleAmountExample.value.toInt,
max_monthly_amount = maxMonthlyAmountExample.value.toInt,
max_single_amount = maxSingleAmountExample.value,
max_monthly_amount = maxMonthlyAmountExample.value,
max_number_of_monthly_transactions = maxNumberOfMonthlyTransactionsExample.value.toInt,
max_yearly_amount = maxYearlyAmountExample.value.toInt,
max_number_of_yearly_transactions = maxNumberOfYearlyTransactionsExample.value.toInt
max_yearly_amount = maxYearlyAmountExample.value,
max_number_of_yearly_transactions = maxNumberOfYearlyTransactionsExample.value.toInt,
max_total_amount = maxTotalAmountExample.value,
max_number_of_transactions = maxNumberOfTransactionsExample.value.toInt
)
val atmsJsonV510 = AtmsJsonV510(

View File

@ -506,10 +506,11 @@ object ErrorMessages {
val CreateCounterpartyLimitError = "OBP-30261: Could not create the counterparty limit."
val UpdateCounterpartyLimitError = "OBP-30262: Could not update the counterparty limit."
val GetCounterpartyLimitError = "OBP-30263: Counterparty limit not found. Please specify a valid value for BANK_ID, ACCOUNT_ID, VIEW_ID or COUNTERPARTY_ID."
val CounterpartyLimitAlreadyExists = "OBP-30264: Counterparty limit already exists. Please specify a different value for BANK_ID, ACCOUNT_ID, VIEW_ID or COUNTERPARTY_ID."
val CounterpartyLimitAlreadyExists = "OBP-30264: Counterparty limit already exists. Please specify a different value for BANK_ID, ACCOUNT_ID, VIEW_ID or COUNTERPARTY_ID."
val DeleteCounterpartyLimitError = "OBP-30265: Could not delete the counterparty limit."
val CustomViewAlreadyExistsError = "OBP-30266: The custom view is already exists."
val UserDoesNotHavePermission = "OBP-30267: The user does not have the permission:"
val CounterpartyLimitValidationError = "OBP-30268: Counterparty Limit Validation Error."
val TaxResidenceNotFound = "OBP-30300: Tax Residence not found by TAX_RESIDENCE_ID. "
val CustomerAddressNotFound = "OBP-30310: Customer's Address not found by CUSTOMER_ADDRESS_ID. "

View File

@ -2210,20 +2210,26 @@ object ExampleValue {
lazy val counterpartyLimitIdExample = ConnectorField("abc9a7e4-6d02-40e3-a129-0b2bf89de9b1","A string that MUST uniquely identify the Counterparty Limit on this OBP instance.")
glossaryItems += makeGlossaryItem("counterparty_limit_id", counterpartyLimitIdExample)
lazy val maxSingleAmountExample = ConnectorField("1000",NoDescriptionProvided)
lazy val maxSingleAmountExample = ConnectorField("1000.11",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_single_amount", maxSingleAmountExample)
lazy val maxMonthlyAmountExample = ConnectorField("10000",NoDescriptionProvided)
lazy val maxMonthlyAmountExample = ConnectorField("10000.11",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_monthly_amount", maxMonthlyAmountExample)
lazy val maxNumberOfMonthlyTransactionsExample = ConnectorField("10",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_number_of_monthly_transactions", maxNumberOfMonthlyTransactionsExample)
lazy val maxYearlyAmountExample = ConnectorField("12000",NoDescriptionProvided)
lazy val maxYearlyAmountExample = ConnectorField("12000.11",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_yearly_amount", maxYearlyAmountExample)
lazy val maxNumberOfYearlyTransactionsExample = ConnectorField("100",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_number_of_yearly_transactions", maxNumberOfYearlyTransactionsExample)
lazy val maxNumberOfTransactionsExample = ConnectorField("100",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_number_of_transactions", maxNumberOfTransactionsExample)
lazy val maxTotalAmountExample = ConnectorField("10000.12",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_total_amount", maxTotalAmountExample)
lazy val canAddImageUrlExample = ConnectorField(booleanFalse,NoDescriptionProvided)
glossaryItems += makeGlossaryItem("can_add_image_url", canAddImageUrlExample)

View File

@ -4232,11 +4232,13 @@ object NewStyle extends MdcLoggable{
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int,
callContext: Option[CallContext]
): OBPReturnType[CounterpartyLimitTrait] =
Connector.connector.vend.createOrUpdateCounterpartyLimit(
@ -4245,11 +4247,13 @@ object NewStyle extends MdcLoggable{
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int,
callContext: Option[CallContext]
) map {
i => (unboxFullOrFail(i._1, callContext, CreateCounterpartyLimitError), i._2)
@ -4272,6 +4276,46 @@ object NewStyle extends MdcLoggable{
i => (unboxFullOrFail(i._1, callContext, s"$GetCounterpartyLimitError Current BANK_ID($bankId), " +
s"ACCOUNT_ID($accountId), VIEW_ID($viewId),COUNTERPARTY_ID($counterpartyId)"), i._2)
}
def getCountOfTransactionsFromAccountToCounterparty(
fromBankId: BankId,
fromAccountId: AccountId,
counterpartyId: CounterpartyId,
fromDate: Date,
toDate: Date,
callContext: Option[CallContext]
): OBPReturnType[Int] =
Connector.connector.vend.getCountOfTransactionsFromAccountToCounterparty(
fromBankId: BankId,
fromAccountId: AccountId,
counterpartyId: CounterpartyId,
fromDate: Date,
toDate: Date,
callContext: Option[CallContext]
) map {
i =>
(unboxFullOrFail(i._1, callContext, s"$InvalidConnectorResponse ${nameOf(getCountOfTransactionsFromAccountToCounterparty _)}"), i._2)
}
def getSumOfTransactionsFromAccountToCounterparty(
fromBankId: BankId,
fromAccountId: AccountId,
counterpartyId: CounterpartyId,
fromDate: Date,
toDate:Date,
callContext: Option[CallContext]
):OBPReturnType[AmountOfMoney] =
Connector.connector.vend.getSumOfTransactionsFromAccountToCounterparty(
fromBankId: BankId,
fromAccountId: AccountId,
counterpartyId: CounterpartyId,
fromDate: Date,
toDate:Date,
callContext: Option[CallContext]
) map {
i =>
(unboxFullOrFail(i._1, callContext, s"$InvalidConnectorResponse ${nameOf(getCountOfTransactionsFromAccountToCounterparty _)}"), i._2)
}
def deleteCounterpartyLimit(
bankId: String,

View File

@ -102,6 +102,7 @@ object Migration extends MdcLoggable {
dropMappedBadLoginAttemptIndex()
alterMetricColumnUrlLength()
populateViewDefinitionCanAddTransactionRequestToBeneficiary()
alterCounterpartyLimitFieldType()
}
private def dummyScript(): Boolean = {
@ -478,6 +479,13 @@ object Migration extends MdcLoggable {
MigrationOfMappedBadLoginAttemptDropIndex.dropUniqueIndex(name)
}
}
private def alterCounterpartyLimitFieldType(): Boolean = {
val name = nameOf(alterCounterpartyLimitFieldType)
runOnce(name) {
MigrationOfCounterpartyLimitFieldType.alterCounterpartyLimitFieldType(name)
}
}
}
/**

View File

@ -0,0 +1,73 @@
package code.api.util.migration
import code.api.util.APIUtil
import code.api.util.migration.Migration.{DbFunction, saveLog}
import code.counterpartylimit.CounterpartyLimit
import net.liftweb.common.Full
import net.liftweb.mapper.Schemifier
import java.time.format.DateTimeFormatter
import java.time.{ZoneId, ZonedDateTime}
object MigrationOfCounterpartyLimitFieldType {
val oneDayAgo = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(1)
val oneYearInFuture = ZonedDateTime.now(ZoneId.of("UTC")).plusYears(1)
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'")
def alterCounterpartyLimitFieldType(name: String): Boolean = {
DbFunction.tableExists(CounterpartyLimit)
match {
case true =>
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
var isSuccessful = false
val executedSql =
DbFunction.maybeWrite(true, Schemifier.infoF _) {
APIUtil.getPropsValue("db.driver") match {
case Full(dbDriver) if dbDriver.contains("com.microsoft.sqlserver.jdbc.SQLServerDriver") =>
() =>
"""
|ALTER TABLE counterpartylimit
|ALTER COLUMN maxsingleamount numeric(16, 10);
|
|ALTER TABLE counterpartylimit
|ALTER COLUMN maxmonthlyamount numeric(16, 10);
|
|ALTER TABLE counterpartylimit
|ALTER COLUMN maxyearlyamount numeric(16, 10);
|""".stripMargin
case _ =>
() =>
"""
|alter table counterpartylimit
| alter column maxsingleamount type numeric(16, 10) using maxsingleamount::numeric(16, 10);
|alter table counterpartylimit
| alter column maxmonthlyamount type numeric(16, 10) using maxmonthlyamount::numeric(16, 10);
|alter table counterpartylimit
| alter column maxyearlyamount type numeric(16, 10) using maxyearlyamount::numeric(16, 10);
|""".stripMargin
}
}
val endDate = System.currentTimeMillis()
val comment: String =
s"""Executed SQL:
|$executedSql
|""".stripMargin
isSuccessful = true
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
case false =>
val startDate = System.currentTimeMillis()
val commitId: String = APIUtil.gitCommit
val isSuccessful = false
val endDate = System.currentTimeMillis()
val comment: String = s"""${CounterpartyLimit._dbTableNameLC} table does not exist""".stripMargin
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful
}
}
}

View File

@ -465,7 +465,7 @@ trait APIMethods210 {
}
// Prevent default value for transaction request type (at least).
_ <- Helper.booleanToFuture(s"From Account Currency is ${fromAccount.currency}, but Requested Transaction Currency is: ${transDetailsJson.value.currency}", cc=callContext) {
_ <- Helper.booleanToFuture(s"$InvalidTransactionRequestCurrency From Account Currency is ${fromAccount.currency}, but Requested Transaction Currency is: ${transDetailsJson.value.currency}", cc=callContext) {
transDetailsJson.value.currency == fromAccount.currency
}

View File

@ -40,6 +40,7 @@ import code.api.v2_1_0._
import code.api.v3_0_0.{CreateScopeJson, JSONFactory300}
import code.api.v3_1_0._
import code.api.v4_0_0.JSONFactory400._
import code.fx.{MappedFXRate, fx}
import code.api.dynamic.endpoint.helper._
import code.api.dynamic.endpoint.helper.practise.PractiseEndpoint
import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo}
@ -58,6 +59,7 @@ import code.dynamicMessageDoc.JsonDynamicMessageDoc
import code.dynamicResourceDoc.JsonDynamicResourceDoc
import code.endpointMapping.EndpointMappingCommons
import code.entitlement.Entitlement
import code.fx.fx
import code.loginattempts.LoginAttempt
import code.metadata.counterparties.{Counterparties, MappedCounterparty}
import code.metadata.tags.Tags
@ -103,6 +105,8 @@ import net.liftweb.util.Mailer.{From, PlainMailBodyType, Subject, To, XHTMLMailB
import net.liftweb.util.{Helpers, Mailer, StringHelpers}
import org.apache.commons.lang3.StringUtils
import java.time.{LocalDate, ZoneId, ZonedDateTime}
import java.util.Date
import scala.collection.immutable.{List, Nil}
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
@ -1102,7 +1106,7 @@ trait APIMethods400 extends MdcLoggable {
}
account = BankIdAccountId(fromAccount.bankId, fromAccount.accountId)
_ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest(viewId, account, u, callContext)
// _ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest(viewId, account, u, callContext)
// Check transReqId is valid
(existingTransactionRequest, callContext) <- NewStyle.function.getTransactionRequestImpl(transReqId, callContext)
@ -12241,11 +12245,6 @@ object APIMethods400 extends RestHelper with APIMethods400 {
isValidCurrencyISOCode(transDetailsJson.value.currency)
}
// Prevent default value for transaction request type (at least).
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.value.currency}'", cc=callContext) {
isValidCurrencyISOCode(transDetailsJson.value.currency)
}
(createdTransactionRequest, callContext) <- transactionRequestTypeValue match {
case REFUND => {
for {
@ -12413,6 +12412,146 @@ object APIMethods400 extends RestHelper with APIMethods400 {
}
toCounterpartyId = transactionRequestBodyCounterparty.to.counterparty_id
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(toCounterpartyId), callContext)
(counterpartyLimitBox, callContext) <- Connector.connector.vend.getCounterpartyLimit(
bankId.value,
accountId.value,
viewId.value,
toCounterpartyId,
callContext
)
_<- if(counterpartyLimitBox.isDefined){
for{
counterpartyLimit <- Future.successful(counterpartyLimitBox.head)
maxSingleAmount = counterpartyLimit.maxSingleAmount
maxMonthlyAmount = counterpartyLimit.maxMonthlyAmount
maxNumberOfMonthlyTransactions = counterpartyLimit.maxNumberOfMonthlyTransactions
maxYearlyAmount = counterpartyLimit.maxYearlyAmount
maxNumberOfYearlyTransactions = counterpartyLimit.maxNumberOfYearlyTransactions
maxTotalAmount = counterpartyLimit.maxTotalAmount
maxNumberOfTransactions = counterpartyLimit.maxNumberOfTransactions
// Get the first day of the current month
firstDayOfMonth: LocalDate = LocalDate.now().withDayOfMonth(1)
// Get the last day of the current month
lastDayOfMonth: LocalDate = LocalDate.now().withDayOfMonth(
LocalDate.now().lengthOfMonth()
)
// Get the first day of the current year
firstDayOfYear: LocalDate = LocalDate.now().withDayOfYear(1)
// Get the last day of the current year
lastDayOfYear: LocalDate = LocalDate.now().withDayOfYear(
LocalDate.now().lengthOfYear()
)
// Convert LocalDate to Date
zoneId: ZoneId = ZoneId.systemDefault()
firstCurrentMonthDate: Date = Date.from(firstDayOfMonth.atStartOfDay(zoneId).toInstant)
lastCurrentMonthDate: Date = Date.from(lastDayOfMonth.atStartOfDay(zoneId).toInstant)
firstCurrentYearDate: Date = Date.from(firstDayOfYear.atStartOfDay(zoneId).toInstant)
lastCurrentYearDate: Date = Date.from(lastDayOfYear.atStartOfDay(zoneId).toInstant)
defaultFromDate: Date = theEpochTime
defaultToDate: Date = APIUtil.ToDateInFuture
(sumOfTransactionsFromAccountToCounterpartyMonthly, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty(
fromAccount.bankId: BankId,
fromAccount.accountId: AccountId,
CounterpartyId(toCounterpartyId): CounterpartyId,
firstCurrentMonthDate: Date,
lastCurrentMonthDate: Date,
callContext: Option[CallContext]
)
(countOfTransactionsFromAccountToCounterpartyMonthly, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty(
fromAccount.bankId: BankId,
fromAccount.accountId: AccountId,
CounterpartyId(toCounterpartyId): CounterpartyId,
firstCurrentMonthDate: Date,
lastCurrentMonthDate: Date,
callContext: Option[CallContext]
)
(sumOfTransactionsFromAccountToCounterpartyYearly, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty(
fromAccount.bankId: BankId,
fromAccount.accountId: AccountId,
CounterpartyId(toCounterpartyId): CounterpartyId,
firstCurrentYearDate: Date,
lastCurrentYearDate: Date,
callContext: Option[CallContext]
)
(countOfTransactionsFromAccountToCounterpartyYearly, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty(
fromAccount.bankId: BankId,
fromAccount.accountId: AccountId,
CounterpartyId(toCounterpartyId): CounterpartyId,
firstCurrentYearDate: Date,
lastCurrentYearDate: Date,
callContext: Option[CallContext]
)
(sumOfAllTransactionsFromAccountToCounterparty, callContext) <- NewStyle.function.getSumOfTransactionsFromAccountToCounterparty(
fromAccount.bankId: BankId,
fromAccount.accountId: AccountId,
CounterpartyId(toCounterpartyId): CounterpartyId,
defaultFromDate: Date,
defaultToDate: Date,
callContext: Option[CallContext]
)
(countOfAllTransactionsFromAccountToCounterparty, callContext) <- NewStyle.function.getCountOfTransactionsFromAccountToCounterparty(
fromAccount.bankId: BankId,
fromAccount.accountId: AccountId,
CounterpartyId(toCounterpartyId): CounterpartyId,
defaultFromDate: Date,
defaultToDate: Date,
callContext: Option[CallContext]
)
currentTransactionAmountWithFxApplied <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $COUNTERPARTY json format", 400, callContext) {
val fromAccountCurrency = fromAccount.currency //eg: if from account currency is EUR
val transferCurrency = transactionRequestBodyCounterparty.value.currency //eg: if the payment json body currency is GBP.
val transferAmount = BigDecimal(transactionRequestBodyCounterparty.value.amount) //eg: if the payment json body amount is 1.
val debitRate = fx.exchangeRate(transferCurrency, fromAccountCurrency, Some(fromAccount.bankId.value), callContext) //eg: the rate here is 1.16278.
fx.convert(transferAmount, debitRate) // 1.16278 Euro
}
_ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_single_amount is $maxSingleAmount ${fromAccount.currency}, " +
s"but current transaction body amount is ${transactionRequestBodyCounterparty.value.amount} ${transactionRequestBodyCounterparty.value.currency}, " +
s"which is $currentTransactionAmountWithFxApplied ${fromAccount.currency}. ", cc = callContext) {
maxSingleAmount >= currentTransactionAmountWithFxApplied
}
_ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_monthly_amount is $maxSingleAmount, but current monthly amount is ${sumOfTransactionsFromAccountToCounterpartyMonthly.amount}", cc = callContext) {
maxMonthlyAmount >= BigDecimal(sumOfTransactionsFromAccountToCounterpartyMonthly.amount)
}
_ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_monthly_transactions is $maxSingleAmount, but current count of monthly transactions is ${countOfTransactionsFromAccountToCounterpartyMonthly}", cc = callContext) {
maxNumberOfMonthlyTransactions >= countOfTransactionsFromAccountToCounterpartyMonthly
}
_ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_yearly_amount is $maxYearlyAmount, but current yearly amount is ${sumOfTransactionsFromAccountToCounterpartyYearly.amount}", cc = callContext) {
maxYearlyAmount >= BigDecimal(sumOfTransactionsFromAccountToCounterpartyYearly.amount)
}
result <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_yearly_transactions is $maxNumberOfYearlyTransactions, but current count of yearly transaction is ${countOfTransactionsFromAccountToCounterpartyYearly}", cc = callContext) {
maxNumberOfYearlyTransactions >= countOfTransactionsFromAccountToCounterpartyYearly
}
_ <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_total_amount is $maxTotalAmount, but current amount is ${sumOfAllTransactionsFromAccountToCounterparty.amount}", cc = callContext) {
maxTotalAmount >= BigDecimal(sumOfAllTransactionsFromAccountToCounterparty.amount)
}
result <- Helper.booleanToFuture(s"$CounterpartyLimitValidationError max_number_of_transactions is $maxNumberOfTransactions, but current count of all transactions is ${countOfAllTransactionsFromAccountToCounterparty}", cc = callContext) {
maxNumberOfTransactions >= countOfAllTransactionsFromAccountToCounterparty
}
}yield{
result
}
}
else {
Future.successful(true)
}
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
// Check we can send money to it.
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {

View File

@ -950,8 +950,8 @@ trait APIMethods500 {
// TODO Add routing scheme as well. In case IBAN is provided this will not work.
val fromBankIdAccountId = BankIdAccountId(BankId(postConsentRequestJsonV510.from_account.bank_routing.address), AccountId(postConsentRequestJsonV510.from_account.account_routing.address))
val vrpViewId = s"_VRP-${UUID.randomUUID.toString}".dropRight(5)// to make sure the length of the viewId is 36.
val targetPermissions = List(//may need getTransactionRequest .. so far only this payments.
val vrpViewId = s"_vrp-${UUID.randomUUID.toString}".dropRight(5)// to make sure the length of the viewId is 36.
val targetPermissions = List(//may need getTransactionRequest . so far only these payments.
"can_add_transaction_request_to_beneficiary",
"can_get_counterparty"
)
@ -967,7 +967,7 @@ trait APIMethods500 {
)
for {
//1st: create the Custom View for the from account.
//1st: create the Custom View for the fromAccount.
(fromAccount, callContext) <- NewStyle.function.checkBankAccountExists(fromBankIdAccountId.bankId, fromBankIdAccountId.accountId, callContext)
//we do not need sourceViewId so far, we need to get all the view access for the login user, and
@ -988,7 +988,7 @@ trait APIMethods500 {
_ <-NewStyle.function.grantAccessToCustomView(vrpView, user, callContext)
//2st: Create a new counterparty on that view (_VRP-9d429899-24f5-42c8-8565-943ffa6a7945)
//2rd: Create a new counterparty on that view (_VRP-9d429899-24f5-42c8-8565-943ffa6a7945)
postJson = PostCounterpartyJson400(
name = postConsentRequestJsonV510.to_account.counterparty_name,
description = postConsentRequestJsonV510.to_account.counterparty_name,
@ -1041,15 +1041,17 @@ trait APIMethods500 {
callContext
)
postCounterpartyLimitV510 = PostCounterpartyLimitV510(
currency = postConsentRequestJsonV510.to_account.limit.currency,
max_single_amount = postConsentRequestJsonV510.to_account.limit.max_single_amount,
max_monthly_amount = postConsentRequestJsonV510.to_account.limit.max_monthly_amount,
max_number_of_monthly_transactions = postConsentRequestJsonV510.to_account.limit.max_number_of_monthly_transactions,
max_yearly_amount = postConsentRequestJsonV510.to_account.limit.max_yearly_amount,
max_number_of_yearly_transactions = postConsentRequestJsonV510.to_account.limit.max_number_of_yearly_transactions
max_number_of_yearly_transactions = postConsentRequestJsonV510.to_account.limit.max_number_of_yearly_transactions,
max_total_amount = postConsentRequestJsonV510.to_account.limit.max_total_amount,
max_number_of_transactions = postConsentRequestJsonV510.to_account.limit.max_number_of_transactions
)
//3rd: create the counterparty limit
(counterpartyLimitBox, callContext) <- Connector.connector.vend.getCounterpartyLimit(
fromBankIdAccountId.bankId.value,
@ -1058,7 +1060,8 @@ trait APIMethods500 {
counterparty.counterpartyId,
cc.callContext
)
failMsg = s"$CounterpartyLimitAlreadyExists Current BANK_ID(${fromBankIdAccountId.bankId.value}), ACCOUNT_ID(${fromBankIdAccountId.accountId.value}), VIEW_ID($vrpViewId),COUNTERPARTY_ID(${counterparty.counterpartyId})"
failMsg = s"$CounterpartyLimitAlreadyExists Current BANK_ID(${fromBankIdAccountId.bankId.value}), " +
s"ACCOUNT_ID(${fromBankIdAccountId.accountId.value}), VIEW_ID($vrpViewId),COUNTERPARTY_ID(${counterparty.counterpartyId})"
_ <- Helper.booleanToFuture(failMsg, cc = callContext) {
counterpartyLimitBox.isEmpty
}
@ -1068,11 +1071,13 @@ trait APIMethods500 {
viewId = counterparty.thisViewId,
counterpartyId = counterparty.counterpartyId,
postCounterpartyLimitV510.currency,
postCounterpartyLimitV510.max_single_amount,
postCounterpartyLimitV510.max_monthly_amount,
BigDecimal(postCounterpartyLimitV510.max_single_amount),
BigDecimal(postCounterpartyLimitV510.max_monthly_amount),
postCounterpartyLimitV510.max_number_of_monthly_transactions,
postCounterpartyLimitV510.max_yearly_amount,
BigDecimal(postCounterpartyLimitV510.max_yearly_amount),
postCounterpartyLimitV510.max_number_of_yearly_transactions,
BigDecimal(postCounterpartyLimitV510.max_total_amount),
postCounterpartyLimitV510.max_number_of_transactions,
cc.callContext
)

View File

@ -2989,9 +2989,12 @@ trait APIMethods510 {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits" :: Nil JsonPost json -> _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
postCounterpartyLimitV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV510]}", 400, cc.callContext) {
postCounterpartyLimitV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[PostCounterpartyLimitV510]}", 400, cc.callContext) {
json.extract[PostCounterpartyLimitV510]
}
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${postCounterpartyLimitV510.currency}'", cc=cc.callContext) {
isValidCurrencyISOCode(postCounterpartyLimitV510.currency)
}
(counterpartyLimitBox, callContext) <- Connector.connector.vend.getCounterpartyLimit(
bankId.value,
accountId.value,
@ -3009,15 +3012,16 @@ trait APIMethods510 {
viewId.value,
counterpartyId.value,
postCounterpartyLimitV510.currency,
postCounterpartyLimitV510.max_single_amount,
postCounterpartyLimitV510.max_monthly_amount,
BigDecimal(postCounterpartyLimitV510.max_single_amount),
BigDecimal(postCounterpartyLimitV510.max_monthly_amount),
postCounterpartyLimitV510.max_number_of_monthly_transactions,
postCounterpartyLimitV510.max_yearly_amount,
BigDecimal(postCounterpartyLimitV510.max_yearly_amount),
postCounterpartyLimitV510.max_number_of_yearly_transactions,
BigDecimal(postCounterpartyLimitV510.max_total_amount),
postCounterpartyLimitV510.max_number_of_transactions,
cc.callContext
)
} yield {
(counterpartyLimit.toJValue, HttpCode.`201`(callContext))
}
}
@ -3048,24 +3052,29 @@ trait APIMethods510 {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) ::"counterparties" :: CounterpartyId(counterpartyId) ::"limits" :: Nil JsonPut json -> _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
postCounterpartyLimitV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[AtmJsonV510]}", 400, cc.callContext) {
postCounterpartyLimitV510 <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the ${classOf[PostCounterpartyLimitV510]}", 400, cc.callContext) {
json.extract[PostCounterpartyLimitV510]
}
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${postCounterpartyLimitV510.currency}'", cc=cc.callContext) {
isValidCurrencyISOCode(postCounterpartyLimitV510.currency)
}
(counterpartyLimit,callContext) <- NewStyle.function.createOrUpdateCounterpartyLimit(
bankId.value,
accountId.value,
viewId.value,
counterpartyId.value,
postCounterpartyLimitV510.currency,
postCounterpartyLimitV510.max_single_amount,
postCounterpartyLimitV510.max_monthly_amount,
BigDecimal(postCounterpartyLimitV510.max_single_amount),
BigDecimal(postCounterpartyLimitV510.max_monthly_amount),
postCounterpartyLimitV510.max_number_of_monthly_transactions,
postCounterpartyLimitV510.max_yearly_amount,
BigDecimal(postCounterpartyLimitV510.max_yearly_amount),
postCounterpartyLimitV510.max_number_of_yearly_transactions,
BigDecimal(postCounterpartyLimitV510.max_total_amount),
postCounterpartyLimitV510.max_number_of_transactions,
cc.callContext
)
} yield {
(counterpartyLimit.toJValue, HttpCode.`200`(cc.callContext))
(counterpartyLimit.toJValue, HttpCode.`200`(callContext))
}
}
}

View File

@ -191,11 +191,13 @@ case class PostAtmJsonV510 (
case class PostCounterpartyLimitV510(
currency: String,
max_single_amount: Int,
max_monthly_amount: Int,
max_single_amount: String,
max_monthly_amount: String,
max_number_of_monthly_transactions: Int,
max_yearly_amount: Int,
max_number_of_yearly_transactions: Int
max_yearly_amount: String,
max_number_of_yearly_transactions: Int,
max_total_amount: String,
max_number_of_transactions: Int
)
case class CounterpartyLimitV510(
@ -205,11 +207,13 @@ case class CounterpartyLimitV510(
view_id: String,
counterparty_id: String,
currency: String,
max_single_amount: Int,
max_monthly_amount: Int,
max_single_amount: String,
max_monthly_amount: String,
max_number_of_monthly_transactions: Int,
max_yearly_amount: Int,
max_number_of_yearly_transactions: Int
max_yearly_amount: String,
max_number_of_yearly_transactions: Int,
max_total_amount: String,
max_number_of_transactions: Int
)
case class AtmJsonV510 (
@ -789,7 +793,7 @@ object JSONFactory510 extends CustomJsonFormats {
consents.map { c =>
val jwtPayload: Box[ConsentJWT] = JwtUtil.getSignedPayloadAsJson(c.jsonWebToken).map(parse(_).extract[ConsentJWT])
AllConsentJsonV510(
consent_reference_id = c.id.get.toString,
consent_reference_id = c.consentReferenceId,
consumer_id = c.consumerId,
created_by_user_id = c.userId,
status = c.status,

View File

@ -582,6 +582,10 @@ trait Connector extends MdcLoggable {
def getTransactionsCore(bankId: BankId, accountId: AccountId, queryParams: List[OBPQueryParam] = Nil, callContext: Option[CallContext]): OBPReturnType[Box[List[TransactionCore]]] = Future{(Failure(setUnimplementedError(nameOf(getTransactionsCore _))), callContext)}
def getCountOfTransactionsFromAccountToCounterparty(fromBankId: BankId, fromAccountId: AccountId, counterpartyId: CounterpartyId, fromDate: Date, toDate:Date, callContext: Option[CallContext]) :OBPReturnType[Box[Int]] = Future{(Failure(setUnimplementedError(nameOf(getCountOfTransactionsFromAccountToCounterparty _))), callContext: Option[CallContext])}
def getSumOfTransactionsFromAccountToCounterparty(fromBankId: BankId, fromAccountId: AccountId, counterpartyId: CounterpartyId, fromDate: Date, toDate:Date, callContext: Option[CallContext]):OBPReturnType[Box[AmountOfMoney]] = Future{(Failure(setUnimplementedError(nameOf(getSumOfTransactionsFromAccountToCounterparty _))), callContext: Option[CallContext])}
def getTransactionLegacy(bankId: BankId, accountId : AccountId, transactionId : TransactionId, callContext: Option[CallContext] = None): Box[(Transaction, Option[CallContext])] = Failure(setUnimplementedError(nameOf(getTransactionLegacy _)))
def getTransaction(bankId: BankId, accountId : AccountId, transactionId : TransactionId, callContext: Option[CallContext] = None): OBPReturnType[Box[Transaction]] = Future{(Failure(setUnimplementedError(nameOf(getTransaction _))), callContext)}
@ -979,7 +983,10 @@ trait Connector extends MdcLoggable {
def getCurrentCurrencies(bankId: BankId, callContext: Option[CallContext]): OBPReturnType[Box[List[String]]] = Future{Failure(setUnimplementedError(nameOf(getCurrentCurrencies _)))}
def getCurrentFxRate(bankId: BankId, fromCurrencyCode: String, toCurrencyCode: String, callContext: Option[CallContext]): Box[FXRate] = Failure(setUnimplementedError(nameOf(getCurrentFxRate _)))
/**
* There is no mapped implimetaion . it is only use for CBS mode at the moment.
*/
def createTransactionAfterChallengev300(
initiator: User,
fromAccount: BankAccount,
@ -1829,11 +1836,14 @@ trait Connector extends MdcLoggable {
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int, callContext: Option[CallContext]
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int,
callContext: Option[CallContext]
): OBPReturnType[Box[CounterpartyLimitTrait]] = Future{(Failure(setUnimplementedError(nameOf(createOrUpdateCounterpartyLimit _))), callContext)}
def getCounterpartyLimit(

View File

@ -774,6 +774,41 @@ object LocalMappedConnector extends Connector with MdcLoggable {
}
}
override def getCountOfTransactionsFromAccountToCounterparty(fromBankId: BankId, fromAccountId: AccountId, counterpartyId: CounterpartyId, fromDate: Date, toDate:Date, callContext: Option[CallContext]) :OBPReturnType[Box[Int]] = {
val queryParams = List(OBPFromDate(fromDate),OBPToDate(toDate), OBPOrdering(None,OBPAscending))
for{
(transactionRequestsBox,callContext) <- LocalMappedConnectorInternal.getTransactionRequestsInternal(fromBankId: BankId, fromAccountId: AccountId, counterpartyId: CounterpartyId, queryParams, callContext: Option[CallContext])
}yield{
(transactionRequestsBox.map(_.length), callContext)
}
}
override def getSumOfTransactionsFromAccountToCounterparty(fromBankId: BankId, fromAccountId: AccountId, counterpartyId: CounterpartyId, fromDate: Date, toDate:Date, callContext: Option[CallContext]):OBPReturnType[Box[AmountOfMoney]] = {
val queryParams = List(OBPFromDate(fromDate),OBPToDate(toDate), OBPOrdering(None,OBPAscending))
for{
(fromBankAccount, callContext) <- NewStyle.function.getBankAccount(fromBankId, fromAccountId, callContext)
(transactionRequestsBox,callContext) <- LocalMappedConnectorInternal.getTransactionRequestsInternal(fromBankId: BankId, fromAccountId: AccountId, counterpartyId: CounterpartyId, queryParams, callContext: Option[CallContext])
// Check the input JSON format, here is just check the common parts of all four types
(amountSum,currency) <- NewStyle.function.tryons(s"$UnknownError can not get the sum of transactions", 400, callContext) {
val transactionRequests = transactionRequestsBox.getOrElse(Nil)
val fromAccountCurrency = fromBankAccount.currency // eg: the fromAccount currency is EUR, and the 1 GBP = 1.16278 Euro.
val allAmounts = for{
transactionRequest <- transactionRequests
transferCurrency = transactionRequest.mBody_Value_Currency.get //eg: if the payment json body currency is GBP.
transferAmount= BigDecimal(transactionRequest.mBody_Value_Amount.get) //eg: if the payment json body amount is 1.
debitRate = fx.exchangeRate(transferCurrency, fromAccountCurrency, Some(fromBankId.value), callContext) //eg: the rate here is 1.16278.
transactionAmount = fx.convert(transferAmount, debitRate) // 1.16278 Euro
}yield{
transactionAmount // 1.16278 Euro
}
(allAmounts.sum, fromAccountCurrency) // Here we just sum all the transfer amounts.
}
} yield {
(Full(AmountOfMoney(currency, amountSum.toString())), callContext)
}
}
/**
*
* refreshes transactions via hbci if the transaction info is sourced from hbci
@ -4351,7 +4386,9 @@ object LocalMappedConnector extends Connector with MdcLoggable {
charge,
chargePolicy,
None,
None)
None,
callContext
)
} map {
unboxFullOrFail(_, callContext, s"$InvalidConnectorResponseForCreateTransactionRequestImpl210")
}
@ -4505,7 +4542,8 @@ object LocalMappedConnector extends Connector with MdcLoggable {
charge,
chargePolicy,
None,
None
None,
callContext
)
saveTransactionRequestReasons(reasons, transactionRequest)
transactionRequest
@ -5134,22 +5172,28 @@ object LocalMappedConnector extends Connector with MdcLoggable {
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int, callContext: Option[CallContext]) =
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int,
callContext: Option[CallContext]) =
CounterpartyLimitProvider.counterpartyLimit.vend.createOrUpdateCounterpartyLimit(
bankId: String,
accountId: String,
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int) map {
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int
) map {
(_, callContext)
}

View File

@ -22,7 +22,7 @@ import com.openbankproject.commons.model.enums.{AccountRoutingScheme, PaymentSer
import net.liftweb.common._
import net.liftweb.json.Serialization.write
import net.liftweb.json.{NoTypeHints, Serialization}
import net.liftweb.mapper.By
import net.liftweb.mapper.{Ascending, By, By_<=, By_>=, Descending, OrderBy, QueryParam}
import net.liftweb.util.Helpers.{now, tryo}
import java.util.Date
@ -92,7 +92,7 @@ object LocalMappedConnectorInternal extends MdcLoggable {
}
// Prevent default value for transaction request type (at least).
_ <- Helper.booleanToFuture(s"From Account Currency is ${fromAccount.currency}, but Requested instructedAmount.currency is: ${transactionRequestBody.instructedAmount.currency}", cc = callContext) {
_ <- Helper.booleanToFuture(s"$InvalidTransactionRequestCurrency From Account Currency is ${fromAccount.currency}, but Requested instructedAmount.currency is: ${transactionRequestBody.instructedAmount.currency}", cc = callContext) {
transactionRequestBody.instructedAmount.currency == fromAccount.currency
}
@ -157,7 +157,8 @@ object LocalMappedConnectorInternal extends MdcLoggable {
charge,
"", // chargePolicy is not used in BG so far.
Some(paymentServiceType.toString),
Some(transactionRequestBody)
Some(transactionRequestBody),
callContext
)
transactionRequest
} map {
@ -631,6 +632,32 @@ object LocalMappedConnectorInternal extends MdcLoggable {
}
}
def getTransactionRequestStatuses() : Box[TransactionRequestStatus] = Failure(NotImplemented + nameOf(getTransactionRequestStatuses _) )
def getTransactionRequestsInternal(fromBankId: BankId, fromAccountId: AccountId, counterpartyId: CounterpartyId, queryParams: List[OBPQueryParam], callContext: Option[CallContext]): OBPReturnType[Box[List[MappedTransactionRequest]]] = {
val fromDate = queryParams.collect { case OBPFromDate(date) => By_>=(MappedTransactionRequest.updatedAt, date) }.headOption
val toDate = queryParams.collect { case OBPToDate(date) => By_<=(MappedTransactionRequest.updatedAt, date) }.headOption
val ordering = queryParams.collect {
//we don't care about the intended sort field and only sort on finish date for now
case OBPOrdering(_, direction) =>
direction match {
case OBPAscending => OrderBy(MappedTransactionRequest.updatedAt, Ascending)
case OBPDescending => OrderBy(MappedTransactionRequest.updatedAt, Descending)
}
}
val optionalParams: Seq[QueryParam[MappedTransactionRequest]] = Seq(fromDate.toSeq, toDate.toSeq, ordering.toSeq).flatten
val mapperParams = Seq(
By(MappedTransactionRequest.mFrom_BankId, fromBankId.value),
By(MappedTransactionRequest.mFrom_AccountId, fromAccountId.value),
By(MappedTransactionRequest.mCounterpartyId, counterpartyId.value),
By(MappedTransactionRequest.mStatus, TransactionRequestStatus.COMPLETED.toString)
) ++ optionalParams
Future {
(Full(MappedTransactionRequest.findAll(mapperParams: _*)), callContext)
}
}
def getTransactionRequestStatuses() : Box[TransactionRequestStatus] = Failure(NotImplemented + nameOf(getTransactionRequestStatuses _))
}

View File

@ -31,10 +31,13 @@ trait CounterpartyLimitProviderTrait {
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int): Future[Box[CounterpartyLimitTrait]]
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int
): Future[Box[CounterpartyLimitTrait]]
}

View File

@ -7,11 +7,14 @@ import net.liftweb.util.Helpers.tryo
import com.openbankproject.commons.ExecutionContext.Implicits.global
import net.liftweb.json
import net.liftweb.json.Formats
import net.liftweb.json.JsonAST.{JValue,JString}
import net.liftweb.json.JsonAST.{JString, JValue}
import net.liftweb.json.JsonDSL._
import scala.concurrent.Future
import com.openbankproject.commons.model.CounterpartyLimitTrait
import java.math.MathContext
object MappedCounterpartyLimitProvider extends CounterpartyLimitProviderTrait {
def getCounterpartyLimit(
@ -48,11 +51,13 @@ object MappedCounterpartyLimitProvider extends CounterpartyLimitProviderTrait {
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int)= Future {
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int)= Future {
def createCounterpartyLimit(counterpartyLimit: CounterpartyLimit)= {
tryo {
@ -66,6 +71,8 @@ object MappedCounterpartyLimitProvider extends CounterpartyLimitProviderTrait {
counterpartyLimit.MaxNumberOfMonthlyTransactions(maxNumberOfMonthlyTransactions)
counterpartyLimit.MaxYearlyAmount(maxYearlyAmount)
counterpartyLimit.MaxNumberOfYearlyTransactions(maxNumberOfYearlyTransactions)
counterpartyLimit.MaxTotalAmount(maxTotalAmount)
counterpartyLimit.MaxNumberOfTransactions(maxNumberOfTransactions)
counterpartyLimit.saveMe()
}
}
@ -105,22 +112,34 @@ class CounterpartyLimit extends CounterpartyLimitTrait with LongKeyedMapper[Coun
object Currency extends MappedString(this, 255)
object MaxSingleAmount extends MappedInt(this) {
override def defaultValue = -1
object MaxSingleAmount extends MappedDecimal(this, MathContext.DECIMAL64, 10){
override def defaultValue = BigDecimal(0) // Default value for Amount
}
object MaxMonthlyAmount extends MappedInt(this) {
override def defaultValue = -1
object MaxMonthlyAmount extends MappedDecimal(this, MathContext.DECIMAL64, 10){
override def defaultValue = BigDecimal(0) // Default value for Amount
}
object MaxNumberOfMonthlyTransactions extends MappedInt(this) {
override def defaultValue = -1
}
object MaxYearlyAmount extends MappedInt(this) {
override def defaultValue = -1
object MaxYearlyAmount extends MappedDecimal(this, MathContext.DECIMAL64, 10){
override def defaultValue = BigDecimal(0) // Default value for Amount
}
object MaxNumberOfYearlyTransactions extends MappedInt(this) {
override def defaultValue = -1
}
object MaxTotalAmount extends MappedDecimal(this, MathContext.DECIMAL64, 10){
override def defaultValue = BigDecimal(0) // Default value for Amount
}
object MaxNumberOfTransactions extends MappedInt(this) {
override def defaultValue = -1
}
def counterpartyLimitId: String = CounterpartyLimitId.get
def bankId: String = BankId.get
@ -129,13 +148,15 @@ class CounterpartyLimit extends CounterpartyLimitTrait with LongKeyedMapper[Coun
def counterpartyId: String = CounterpartyId.get
def currency: String = Currency.get
def maxSingleAmount: Int = MaxSingleAmount.get
def maxMonthlyAmount: Int = MaxMonthlyAmount.get
def maxSingleAmount: BigDecimal = MaxSingleAmount.get
def maxMonthlyAmount: BigDecimal = MaxMonthlyAmount.get
def maxNumberOfMonthlyTransactions: Int = MaxNumberOfMonthlyTransactions.get
def maxYearlyAmount: Int = MaxYearlyAmount.get
def maxYearlyAmount: BigDecimal = MaxYearlyAmount.get
def maxNumberOfYearlyTransactions: Int = MaxNumberOfYearlyTransactions.get
def maxTotalAmount: BigDecimal = MaxTotalAmount.get
def maxNumberOfTransactions: Int = MaxNumberOfTransactions.get
override def toJValue(implicit format: Formats): JValue ={
override def toJValue(implicit format: Formats): JValue = {
("counterparty_limit_id", counterpartyLimitId) ~
("bank_id", bankId) ~
("account_id",accountId) ~
@ -146,7 +167,9 @@ class CounterpartyLimit extends CounterpartyLimitTrait with LongKeyedMapper[Coun
("max_monthly_amount", maxMonthlyAmount) ~
("max_number_of_monthly_transactions", maxNumberOfMonthlyTransactions) ~
("max_yearly_amount", maxYearlyAmount) ~
("max_number_of_yearly_transactions", maxNumberOfYearlyTransactions)
("max_number_of_yearly_transactions", maxNumberOfYearlyTransactions) ~
("max_total_amount", maxTotalAmount) ~
("max_number_of_transactions", maxNumberOfTransactions)
}
}

View File

@ -1,15 +1,17 @@
package code.transactionrequests
import code.api.util.APIUtil.DateWithMsFormat
import code.api.util.CustomJsonFormats
import code.api.util.APIUtil.{DateWithMsFormat}
import code.api.util.{APIUtil, CallContext, CustomJsonFormats}
import code.api.util.ErrorMessages._
import code.api.v4_0_0.TransactionRequestBodyAgentJsonV400
import code.api.v2_1_0.TransactionRequestBodyCounterpartyJSON
import code.bankconnectors.LocalMappedConnectorInternal
import code.consent.Consents
import code.model._
import code.util.{AccountIdString, UUIDString}
import com.openbankproject.commons.model._
import com.openbankproject.commons.model.enums.{AccountRoutingScheme, TransactionRequestStatus}
import com.openbankproject.commons.model.enums.TransactionRequestTypes
import com.openbankproject.commons.model.enums.TransactionRequestTypes.{COUNTERPARTY, SEPA}
import net.liftweb.common.{Box, Failure, Full, Logger}
import net.liftweb.json
import net.liftweb.json.JsonAST.{JField, JObject, JString}
@ -90,14 +92,20 @@ object MappedTransactionRequestProvider extends TransactionRequestProvider {
charge: TransactionRequestCharge,
chargePolicy: String,
paymentService: Option[String],
berlinGroupPayments: Option[BerlinGroupTransactionRequestCommonBodyJson]): Box[TransactionRequest] = {
berlinGroupPayments: Option[BerlinGroupTransactionRequestCommonBodyJson],
callContext: Option[CallContext]): Box[TransactionRequest] = {
val toAccountRouting = transactionRequestType.value match {
case "SEPA" =>
val toAccountRouting = TransactionRequestTypes.withName(transactionRequestType.value) match {
case SEPA =>
toAccount.accountRoutings.find(_.scheme == AccountRoutingScheme.IBAN.toString)
.orElse(toAccount.accountRoutings.headOption)
case _ => toAccount.accountRoutings.headOption
}
val counterpartyIdOption = TransactionRequestTypes.withName(transactionRequestType.value) match {
case COUNTERPARTY => Some(transactionRequestCommonBody.asInstanceOf[TransactionRequestBodyCounterpartyJSON].to.counterparty_id)
case _ => None
}
val (paymentStartDate, paymentEndDate, executionRule, frequency, dayOfExecution) = if(paymentService == Some("periodic-payments")){
val paymentFields = berlinGroupPayments.asInstanceOf[Option[PeriodicSepaCreditTransfersBerlinGroupV13]]
@ -114,6 +122,9 @@ object MappedTransactionRequestProvider extends TransactionRequestProvider {
(null, null, null, null, null)
}
val consentIdOption = callContext.map(_.requestHeaders).map(APIUtil.getConsentIdRequestHeaderValue).flatten
val consentOption = consentIdOption.map(consentId =>Consents.consentProvider.vend.getConsentByConsentId(consentId).toOption).flatten
val consentReferenceIdOption = consentOption.map(_.consentReferenceId)
// Note: We don't save transaction_ids, status and challenge here.
val mappedTransactionRequest = MappedTransactionRequest.create
@ -150,7 +161,7 @@ object MappedTransactionRequestProvider extends TransactionRequestProvider {
//.mThisBankId(toAccount.bankId.value)
//.mThisAccountId(toAccount.accountId.value)
//.mThisViewId(toAccount.v)
//.mCounterpartyId(toAccount.branchId)
.mCounterpartyId(counterpartyIdOption.getOrElse(null))
//.mIsBeneficiary(toAccount.isBeneficiary)
//Body from http request: SANDBOX_TAN, FREE_FORM, SEPA and COUNTERPARTY should have the same following fields:
@ -166,6 +177,7 @@ object MappedTransactionRequestProvider extends TransactionRequestProvider {
.mPaymentExecutionRule(executionRule)
.mPaymentFrequency(frequency)
.mPaymentDayOfExecution(dayOfExecution)
.mConsentReferenceId(consentReferenceIdOption.getOrElse(null))
.saveMe
Full(mappedTransactionRequest).flatMap(_.toTransactionRequest)
@ -272,6 +284,8 @@ class MappedTransactionRequest extends LongKeyedMapper[MappedTransactionRequest]
object mPaymentFrequency extends MappedString(this, 64) //BGv1.3 Open API Document example value: "frequency":"Monthly",
object mPaymentDayOfExecution extends MappedString(this, 64)//BGv1.3 Open API Document example value: "dayOfExecution":"01"
object mConsentReferenceId extends MappedString(this, 64)
def updateStatus(newStatus: String) = {
mStatus.set(newStatus)
}

View File

@ -1,7 +1,7 @@
package code.transactionrequests
import code.api.util.APIUtil
import code.api.util.{APIUtil, CallContext}
import com.openbankproject.commons.model.{TransactionRequest, TransactionRequestChallenge, TransactionRequestCharge, _}
import net.liftweb.common.{Box, Logger}
import net.liftweb.util.SimpleInjector
@ -76,7 +76,8 @@ trait TransactionRequestProvider {
charge: TransactionRequestCharge,
chargePolicy: String,
paymentService: Option[String],
berlinGroupPayments: Option[BerlinGroupTransactionRequestCommonBodyJson]): Box[TransactionRequest]
berlinGroupPayments: Option[BerlinGroupTransactionRequestCommonBodyJson],
callContext: Option[CallContext]): Box[TransactionRequest]
def saveTransactionRequestTransactionImpl(transactionRequestId: TransactionRequestId, transactionId: TransactionId): Box[Boolean]
def saveTransactionRequestChallengeImpl(transactionRequestId: TransactionRequestId, challenge: TransactionRequestChallenge): Box[Boolean]

View File

@ -31,11 +31,13 @@ class CounterpartyLimitTest extends V510ServerSetup {
val postCounterpartyLimitV510 = code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.postCounterpartyLimitV510
val putCounterpartyLimitV510 = PostCounterpartyLimitV510(
currency = "EUR",
max_single_amount = 1,
max_monthly_amount = 2,
max_single_amount = "1.1",
max_monthly_amount = "2.1",
max_number_of_monthly_transactions = 3,
max_yearly_amount = 4,
max_number_of_yearly_transactions = 5
max_yearly_amount = "4.1",
max_number_of_yearly_transactions = 5,
max_total_amount="6.1",
max_number_of_transactions=7,
)
@ -116,6 +118,8 @@ class CounterpartyLimitTest extends V510ServerSetup {
response510.body.extract[CounterpartyLimitV510].max_number_of_yearly_transactions should equal(putCounterpartyLimitV510.max_number_of_yearly_transactions)
response510.body.extract[CounterpartyLimitV510].max_single_amount should equal(putCounterpartyLimitV510.max_single_amount)
response510.body.extract[CounterpartyLimitV510].max_yearly_amount should equal(putCounterpartyLimitV510.max_yearly_amount)
response510.body.extract[CounterpartyLimitV510].max_total_amount should equal(putCounterpartyLimitV510.max_total_amount)
response510.body.extract[CounterpartyLimitV510].max_number_of_transactions should equal(putCounterpartyLimitV510.max_number_of_transactions)
}
{
@ -128,6 +132,8 @@ class CounterpartyLimitTest extends V510ServerSetup {
response510.body.extract[CounterpartyLimitV510].max_number_of_yearly_transactions should equal(putCounterpartyLimitV510.max_number_of_yearly_transactions)
response510.body.extract[CounterpartyLimitV510].max_single_amount should equal(putCounterpartyLimitV510.max_single_amount)
response510.body.extract[CounterpartyLimitV510].max_yearly_amount should equal(putCounterpartyLimitV510.max_yearly_amount)
response510.body.extract[CounterpartyLimitV510].max_total_amount should equal(putCounterpartyLimitV510.max_total_amount)
response510.body.extract[CounterpartyLimitV510].max_number_of_transactions should equal(putCounterpartyLimitV510.max_number_of_transactions)
}
{

View File

@ -33,22 +33,11 @@ import com.openbankproject.commons.model.enums._
import com.openbankproject.commons.util.{ReflectUtils, optional}
import net.liftweb.json.JsonAST.{JObject, JValue}
import net.liftweb.json.{Formats, JInt, JString}
import net.liftweb.json.JsonDSL._
import java.lang
import scala.collection.immutable.List
import scala.reflect.runtime.universe._
//import code.customeraddress.CustomerAddress
//import code.bankconnectors.InboundAccountCommon
//import code.branches.Branches.BranchT
//import code.context.UserAuthContext
//import code.meetings.Meeting
//import code.taxresidence.TaxResidence
//import code.productcollectionitem.ProductCollectionItem
//import code.productcollection.ProductCollection
//import code.atms.Atms.AtmT
//import code.productattribute.ProductAttribute.ProductAttribute
//import code.accountattribute.AccountAttribute.AccountAttribute
//import code.accountapplication.AccountApplication
abstract class Converter[T, D <% T: TypeTag]{
//this method declared as common method to avoid conflict with Predf#$confirms
@ -621,13 +610,29 @@ case class CounterpartyLimitTraitCommons(
viewId: String,
counterpartyId: String,
currency: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxSingleAmount: BigDecimal,
maxMonthlyAmount: BigDecimal,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int
maxYearlyAmount: BigDecimal,
maxNumberOfYearlyTransactions: Int,
maxTotalAmount: BigDecimal,
maxNumberOfTransactions: Int,
) extends CounterpartyLimitTrait {
override def toJValue(implicit format: Formats): JValue = ???
override def toJValue(implicit format: Formats): JValue = {
("counterparty_limit_id", counterpartyLimitId) ~
("bank_id", bankId) ~
("account_id",accountId) ~
("view_id",viewId) ~
("counterparty_id",counterpartyId) ~
("currency",currency) ~
("max_single_amount", maxSingleAmount) ~
("max_monthly_amount", maxMonthlyAmount) ~
("max_number_of_monthly_transactions", maxNumberOfMonthlyTransactions) ~
("max_yearly_amount", maxYearlyAmount) ~
("max_number_of_yearly_transactions", maxNumberOfYearlyTransactions) ~
("max_total_amount", maxTotalAmount) ~
("max_number_of_transactions", maxNumberOfTransactions)
}
}
object CounterpartyLimitTraitCommons extends Converter[CounterpartyLimitTrait, CounterpartyLimitTraitCommons]

View File

@ -663,11 +663,13 @@ trait CounterpartyLimitTrait extends JsonAble{
def counterpartyId: String
def currency: String
def maxSingleAmount: Int
def maxMonthlyAmount: Int
def maxSingleAmount: BigDecimal
def maxMonthlyAmount: BigDecimal
def maxNumberOfMonthlyTransactions: Int
def maxYearlyAmount: Int
def maxYearlyAmount: BigDecimal
def maxNumberOfYearlyTransactions: Int
def maxTotalAmount: BigDecimal
def maxNumberOfTransactions: Int
}
trait EndpointTagT {

View File

@ -147,6 +147,7 @@ object BigDecimalSerializer extends Serializer[BigDecimal] {
override def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), BigDecimal] = {
case (TypeInfo(IntervalClass, _), json) => json match {
case JString(s) => BigDecimal(s)
// case JDouble(s) => BigDecimal(s)
case x => throw new MappingException("Can't convert " + x + " to BigDecimal")
}
}