Skip to content

Commit

Permalink
Merge pull request #2404 from hongwei1/feature/CounterpartyLimit
Browse files Browse the repository at this point in the history
Feature/counterparty limit
  • Loading branch information
simonredfern committed Jun 25, 2024
2 parents a17ce7e + dde9558 commit 630f0aa
Show file tree
Hide file tree
Showing 16 changed files with 824 additions and 10 deletions.
4 changes: 3 additions & 1 deletion obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import code.connectormethod.ConnectorMethod
import code.consent.{ConsentRequest, MappedConsent}
import code.consumer.Consumers
import code.context.{MappedConsentAuthContext, MappedUserAuthContext, MappedUserAuthContextUpdate}
import code.counterpartylimit.CounterpartyLimit
import code.crm.MappedCrmEvent
import code.customer.internalMapping.MappedCustomerIdMapping
import code.customer.{MappedCustomer, MappedCustomerMessage}
Expand Down Expand Up @@ -1087,7 +1088,8 @@ object ToSchemify {
EndpointTag,
ProductFee,
ViewPermission,
UserInitAction
UserInitAction,
CounterpartyLimit
)

// start grpc server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5396,6 +5396,27 @@ object SwaggerDefinitionsJSON {
phone = phoneExample.value,
)

val postCounterpartyLimitV510 = PostCounterpartyLimitV510(
max_single_amount = maxSingleAmountExample.value.toInt,
max_monthly_amount = maxMonthlyAmountExample.value.toInt,
max_number_of_monthly_transactions = maxNumberOfMonthlyTransactionsExample.value.toInt,
max_yearly_amount = maxYearlyAmountExample.value.toInt,
max_number_of_yearly_transactions = maxNumberOfYearlyTransactionsExample.value.toInt
)

val counterpartyLimitV510 = CounterpartyLimitV510(
counterparty_limit_id = counterpartyLimitIdExample.value,
bank_id = bankIdExample.value,
account_id = accountIdExample.value,
view_id = viewIdExample.value,
counterparty_id = counterpartyIdExample.value,
max_single_amount = maxSingleAmountExample.value.toInt,
max_monthly_amount = maxMonthlyAmountExample.value.toInt,
max_number_of_monthly_transactions = maxNumberOfMonthlyTransactionsExample.value.toInt,
max_yearly_amount = maxYearlyAmountExample.value.toInt,
max_number_of_yearly_transactions = maxNumberOfYearlyTransactionsExample.value.toInt
)

val atmsJsonV510 = AtmsJsonV510(
atms = List(atmJsonV510)
)
Expand Down
23 changes: 22 additions & 1 deletion obp-api/src/main/scala/code/api/util/APIUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,8 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
private val isNeedCheckView = errorResponseBodies.contains($UserNoPermissionAccessView) &&
requestUrlPartPath.contains("BANK_ID") && requestUrlPartPath.contains("ACCOUNT_ID") && requestUrlPartPath.contains("VIEW_ID")

private val isNeedCheckCounterparty = errorResponseBodies.contains($CounterpartyNotFoundByCounterpartyId) && requestUrlPartPath.contains("COUNTERPARTY_ID")

private val reversedRequestUrl = requestUrlPartPath.reverse
def getPathParams(url: List[String]): Map[String, String] =
reversedRequestUrl.zip(url.reverse) collect {
Expand Down Expand Up @@ -1775,6 +1777,14 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
Future.successful(null.asInstanceOf[View])
}
}

def checkCounterparty(counterpartyId: Option[CounterpartyId], callContext: Option[CallContext]): OBPReturnType[CounterpartyTrait] = {
if(isNeedCheckCounterparty && counterpartyId.isDefined) {
checkCounterpartyFun(counterpartyId.get)(callContext)
} else {
Future.successful(null.asInstanceOf[CounterpartyTrait] -> callContext)
}
}
// reset connectorMethods
{
val checkerFunctions = mutable.ListBuffer[PartialFunction[_, _]]()
Expand All @@ -1795,6 +1805,9 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
if (isNeedCheckView) {
checkerFunctions += checkViewFun
}
if (isNeedCheckCounterparty) {
checkerFunctions += checkCounterpartyFun
}
val addedMethods: List[String] = checkerFunctions.toList.flatMap(getDependentConnectorMethods(_))
.map(value =>("obp." +value).intern())

Expand Down Expand Up @@ -1841,6 +1854,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
val bankId = pathParams.get("BANK_ID").map(BankId(_))
val accountId = pathParams.get("ACCOUNT_ID").map(AccountId(_))
val viewId = pathParams.get("VIEW_ID").map(ViewId(_))
val counterpartyId = pathParams.get("COUNTERPARTY_ID").map(CounterpartyId(_))

val request: Box[Req] = S.request
val session: Box[LiftSession] = S.session
Expand All @@ -1851,7 +1865,8 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
* 2. check bankId
* 3. roles check
* 4. check accountId
* 5. view
* 5. view access
* 6. check counterpartyId
*
* A Bank MUST be checked before Roles.
* In opposite case we get next paradox:
Expand All @@ -1878,6 +1893,9 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{

// check user access permission of this viewId corresponding view
view <- checkView(viewId, bankId, accountId, boxUser, callContext)

counterparty <- checkCounterparty(counterpartyId, callContext)

} yield {
val newCallContext = if(boxUser.isDefined) callContext.map(_.copy(user=boxUser)) else callContext

Expand Down Expand Up @@ -4232,6 +4250,9 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
private val checkViewFun: PartialFunction[ViewId, (BankIdAccountId, Option[User], Option[CallContext]) => Future[View]] = {
case x => NewStyle.function.checkViewAccessAndReturnView(x, _, _, _)
}
private val checkCounterpartyFun: PartialFunction[CounterpartyId, Option[CallContext] => OBPReturnType[CounterpartyTrait]] = {
case x => NewStyle.function.getCounterpartyByCounterpartyId(x, _)
}

// cache for method -> called obp methods:
// (className, methodName, signature) -> List[(className, methodName, signature)]
Expand Down
1 change: 1 addition & 0 deletions obp-api/src/main/scala/code/api/util/ApiTag.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ object ApiTag {
val apiTagWebUiProps = ResourceDocTag("WebUi-Props")
val apiTagEndpointMapping = ResourceDocTag("Endpoint-Mapping")
val apiTagRateLimits = ResourceDocTag("Rate-Limits")
val apiTagCounterpartyLimits = ResourceDocTag("Counterparty-Limits")

val apiTagApiCollection = ResourceDocTag("Api-Collection")

Expand Down
10 changes: 10 additions & 0 deletions obp-api/src/main/scala/code/api/util/ErrorMessages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ object ErrorMessages {
val SystemViewCannotBePublicError = "OBP-30258: System view cannot be public"
val CreateCustomViewError = "OBP-30259: Could not create the custom view"
val UpdateCustomViewError = "OBP-30260: Could not update the custom view"
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 DeleteCounterpartyLimitError = "OBP-30265: Could not delete the counterparty limit."

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. "
Expand Down Expand Up @@ -848,6 +853,11 @@ object ErrorMessages {
* validate method: NewStyle.function.checkViewAccessAndReturnView
*/
def $UserNoPermissionAccessView = UserNoPermissionAccessView

/**
* validate method: NewStyle.function.getCounterpartyByCounterpartyId
*/
def $CounterpartyNotFoundByCounterpartyId = CounterpartyNotFoundByCounterpartyId


def getDuplicatedMessageNumbers = {
Expand Down
18 changes: 18 additions & 0 deletions obp-api/src/main/scala/code/api/util/ExampleValue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2147,6 +2147,24 @@ object ExampleValue {
lazy val transactionRequestTypesExample = ConnectorField(NoExampleProvided,NoDescriptionProvided)
glossaryItems += makeGlossaryItem("transaction_request_types", transactionRequestTypesExample)

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)
glossaryItems += makeGlossaryItem("max_single_amount", maxSingleAmountExample)

lazy val maxMonthlyAmountExample = ConnectorField("10000",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)
glossaryItems += makeGlossaryItem("max_yearly_amount", maxYearlyAmountExample)

lazy val maxNumberOfYearlyTransactionsExample = ConnectorField("100",NoDescriptionProvided)
glossaryItems += makeGlossaryItem("max_number_of_yearly_transactions", maxNumberOfYearlyTransactionsExample)

lazy val canAddImageUrlExample = ConnectorField(booleanTrue,NoDescriptionProvided)
glossaryItems += makeGlossaryItem("can_add_image_url", canAddImageUrlExample)

Expand Down
65 changes: 63 additions & 2 deletions obp-api/src/main/scala/code/api/util/NewStyle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package code.api.util

import java.util.Date
import java.util.UUID.randomUUID

import akka.http.scaladsl.model.HttpMethod
import code.DynamicEndpoint.{DynamicEndpointProvider, DynamicEndpointT}
import code.api.{APIFailureNewStyle, Constant, JsonResponseException}
Expand Down Expand Up @@ -54,8 +53,8 @@ import net.liftweb.json.JsonDSL._
import net.liftweb.json.{JField, JInt, JNothing, JNull, JObject, JString, JValue, _}
import net.liftweb.util.Helpers.tryo
import org.apache.commons.lang3.StringUtils
import java.security.AccessControlException

import java.security.AccessControlException
import scala.collection.immutable.{List, Nil}
import scala.concurrent.Future
import scala.math.BigDecimal
Expand All @@ -71,6 +70,7 @@ import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo}
import code.atmattribute.AtmAttribute
import code.bankattribute.BankAttribute
import code.connectormethod.{ConnectorMethodProvider, JsonConnectorMethod}
import code.counterpartylimit.{CounterpartyLimit, CounterpartyLimitTrait}
import code.crm.CrmEvent
import code.crm.CrmEvent.CrmEvent
import code.customeraccountlinks.CustomerAccountLinkTrait
Expand Down Expand Up @@ -4056,6 +4056,67 @@ object NewStyle extends MdcLoggable{
(unboxFullOrFail(i, callContext, s"$DeleteCustomViewError"), callContext)
}

def createOrUpdateCounterpartyLimit(
bankId: String,
accountId: String,
viewId: String,
counterpartyId: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int,
callContext: Option[CallContext]
): OBPReturnType[CounterpartyLimitTrait] =
Connector.connector.vend.createOrUpdateCounterpartyLimit(
bankId: String,
accountId: String,
viewId: String,
counterpartyId: String,
maxSingleAmount: Int,
maxMonthlyAmount: Int,
maxNumberOfMonthlyTransactions: Int,
maxYearlyAmount: Int,
maxNumberOfYearlyTransactions: Int,
callContext: Option[CallContext]
) map {
i => (unboxFullOrFail(i._1, callContext, CreateCounterpartyLimitError), i._2)
}

def getCounterpartyLimit(
bankId: String,
accountId: String,
viewId: String,
counterpartyId: String,
callContext: Option[CallContext]
): OBPReturnType[CounterpartyLimitTrait] =
Connector.connector.vend.getCounterpartyLimit(
bankId: String,
accountId: String,
viewId: String,
counterpartyId: String,
callContext: Option[CallContext]
) map {
i => (unboxFullOrFail(i._1, callContext, s"$GetCounterpartyLimitError Current BANK_ID($bankId), " +
s"ACCOUNT_ID($accountId), VIEW_ID($viewId),COUNTERPARTY_ID($counterpartyId)"), i._2)
}

def deleteCounterpartyLimit(
bankId: String,
accountId: String,
viewId: String,
counterpartyId: String,
callContext: Option[CallContext]
): OBPReturnType[Boolean] =
Connector.connector.vend.deleteCounterpartyLimit(
bankId: String,
accountId: String,
viewId: String,
counterpartyId: String,
callContext: Option[CallContext]
) map {
i => (unboxFullOrFail(i._1, callContext, s"$DeleteCounterpartyLimitError"), i._2)
}
}

}
3 changes: 2 additions & 1 deletion obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,8 @@ trait APIMethods121 {
),
List(apiTagAccount, apiTagView, apiTagOldStyle)
)


//TODO. remove and replace it with V510.
lazy val updateViewForBankAccount: OBPEndpoint = {
//updates a view on a bank account
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId
Expand Down
1 change: 1 addition & 0 deletions obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ trait APIMethods300 {
),
List(apiTagView, apiTagAccount))

//TODO. remove and replace it with V510.
lazy val createViewForBankAccount : OBPEndpoint = {
//creates a view on an bank account
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: Nil JsonPost json -> _ => {
Expand Down
Loading

0 comments on commit 630f0aa

Please sign in to comment.