feature/Added Agent Trait

This commit is contained in:
hongwei 2024-11-19 15:07:42 +01:00
parent a871f79794
commit 377f3dd618
10 changed files with 304 additions and 71 deletions

View File

@ -453,6 +453,8 @@ object ErrorMessages {
val InvalidCardNumber = "OBP-30200: Card not found. Please specify a valid value for CARD_NUMBER. "
val AgentNotFound = "OBP-30201: Agent not found. Please specify a valid value for AGENT_ID. "
val CreateAgentError = "OBP-30202: Could not create Agent."
val UpdateAgentError = "OBP-30203: Could not update Agent."
val CustomerAccountLinkNotFound = "OBP-30204: Customer Account Link not found"
@ -525,6 +527,8 @@ object ErrorMessages {
val GetChargeValueError = "OBP-30323: Could not get the Charge Value."
val GetTransactionRequestTypeChargesError = "OBP-30324: Could not get Transaction Request Type Charges."
val AgentAccountLinkNotFound = "OBP-30325: Agent Account Link not found."
val AgentsNotFound = "OBP-30326: Agents not found."
val CreateAgentAccountLinkError = "OBP-30327: Could not create the agent account link."
// Branch related messages
val BranchesNotFoundLicense = "OBP-32001: No branches available. License may not be set."

View File

@ -749,11 +749,6 @@ object NewStyle extends MdcLoggable{
}
}
def getAgentByAgentId(agentId : String, callContext: Option[CallContext]): OBPReturnType[Customer] = {
Connector.connector.vend.getCustomerByCustomerId(agentId, callContext) map {
unboxFullOrFail(_, callContext, s"$AgentNotFound. Current AGENT_ID($agentId)", 404)
}
}
def checkCustomerNumberAvailable(bankId: BankId, customerNumber: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = {
Connector.connector.vend.checkCustomerNumberAvailable(bankId: BankId, customerNumber: String, callContext: Option[CallContext]) map {
i => (unboxFullOrFail(i._1, callContext, s"$InvalidConnectorResponse", 400), i._2)
@ -2839,19 +2834,49 @@ object NewStyle extends MdcLoggable{
i => (unboxFullOrFail(i._1, callContext, UpdateCustomerError), i._2)
}
def createAgent(
bankId: String,
legalName : String,
mobileNumber : String,
number : String,
callContext: Option[CallContext]
): OBPReturnType[Agent] =
Connector.connector.vend.createAgent(
bankId: String,
legalName : String,
mobileNumber : String,
number : String,
callContext: Option[CallContext]
) map {
i => (unboxFullOrFail(i._1, callContext, CreateAgentError), i._2)
}
def getAgents(bankId : String, queryParams: List[OBPQueryParam], callContext: Option[CallContext]): OBPReturnType[List[Agent]] = {
Connector.connector.vend.getAgents(bankId : String, queryParams: List[OBPQueryParam], callContext: Option[CallContext]) map {
i => (unboxFullOrFail(i._1, callContext, s"$AgentsNotFound."), i._2)
}
}
def getAgentByAgentId(agentId : String, callContext: Option[CallContext]): OBPReturnType[Agent] = {
Connector.connector.vend.getAgentByAgentId(agentId : String, callContext: Option[CallContext]) map {
i => (unboxFullOrFail(i._1, callContext, s"$AgentNotFound. Current AGENT_ID($agentId)"), i._2)
}
}
def updateAgentStatus(
agentId: String,
is_pending_agent: Boolean,
is_confirmed_agent: Boolean,
callContext: Option[CallContext]): OBPReturnType[Customer] =
callContext: Option[CallContext]): OBPReturnType[Agent] =
Connector.connector.vend.updateAgentStatus(
agentId: String,
is_pending_agent: Boolean,
is_confirmed_agent: Boolean,
callContext: Option[CallContext]
) map {
i => (unboxFullOrFail(i._1, callContext, UpdateCustomerError), i._2)
i => (unboxFullOrFail(i._1, callContext, UpdateAgentError), i._2)
}
def updateCustomerCreditData(customerId: String,
creditRating: Option[String],
creditSource: Option[String],
@ -4103,6 +4128,11 @@ object NewStyle extends MdcLoggable{
i => (unboxFullOrFail(i._1, callContext, CreateCustomerAccountLinkError), i._2)
}
def createAgentAccountLink(agentId: String, bankId: String, accountId: String, relationshipType: String, callContext: Option[CallContext]): OBPReturnType[CustomerAccountLinkTrait] =
Connector.connector.vend.createCustomerAccountLink(agentId: String, bankId, accountId: String, relationshipType: String, callContext: Option[CallContext]) map {
i => (unboxFullOrFail(i._1, callContext, CreateAgentAccountLinkError), i._2)
}
def getCustomerAccountLinksByCustomerId(customerId: String, callContext: Option[CallContext]): OBPReturnType[List[CustomerAccountLinkTrait]] =
Connector.connector.vend.getCustomerAccountLinksByCustomerId(customerId: String, callContext: Option[CallContext]) map {
i => (unboxFullOrFail(i._1, callContext, GetCustomerAccountLinksError), i._2)

View File

@ -353,11 +353,6 @@ trait APIMethods510 {
"/banks/BANK_ID/agents",
"Create Agent",
s"""
|The Customer resource stores the customer number (which is set by the backend), legal name, email, phone number, their date of birth, relationship status, education attained, a url for a profile image, KYC status etc.
|Dates need to be in the format 2013-01-21T23:08:00Z
|
|Note: If you need to set a specific customer number, use the Update Customer Number endpoint after this call.
|
|${authenticationRequiredMessage(true)}
|""",
postAgentJsonV510,
@ -383,26 +378,11 @@ trait APIMethods510 {
json.extract[PostAgentJsonV510]
}
(_, callContext) <- NewStyle.function.checkCustomerNumberAvailable(bankId, postedData.agent_number, cc.callContext)
(customer, callContext) <- NewStyle.function.createCustomerC2(
bankId,
postedData.legal_name,
postedData.agent_number,
postedData.mobile_phone_number,
"",
CustomerFaceImage(null, ""),
null,
"",
0,
Nil,
"",
"",
false,
null,
None,
None,
"",
"",
"",
(agent, callContext) <- NewStyle.function.createAgent(
bankId = bankId.value,
legalName = postedData.legal_name,
mobileNumber = postedData.mobile_phone_number,
number = postedData.agent_number,
callContext,
)
(bankAccount, callContext) <- NewStyle.function.createBankAccount(
@ -417,9 +397,9 @@ trait APIMethods510 {
Nil,
callContext
)
(_, callContext) <- NewStyle.function.createCustomerAccountLink(customer.customerId, bankAccount.bankId.value, bankAccount.accountId.value, "Owner", callContext)
(_, callContext) <- NewStyle.function.createCustomerAccountLink(agent.agentId, bankAccount.bankId.value, bankAccount.accountId.value, "Owner", callContext)
} yield {
(JSONFactory510.createAgentJson(customer, bankAccount), HttpCode.`201`(callContext))
(JSONFactory510.createAgentJson(agent, bankAccount), HttpCode.`201`(callContext))
}
}
}
@ -463,11 +443,10 @@ trait APIMethods510 {
customerAccountLinks.head
}
(bankAccount, callContext) <- NewStyle.function.getBankAccount(BankId(customerAccountLink.bankId), AccountId(customerAccountLink.accountId), callContext)
(customer, callContext) <- NewStyle.function.updateCustomerScaData(
(agent, callContext) <- NewStyle.function.updateAgentStatus(
agentId,
Some(postedData.is_pending_agent.toString),
None,
None,
postedData.is_pending_agent,
postedData.is_confirmed_agent,
callContext)
} yield {
(JSONFactory510.createAgentJson(agent, bankAccount), HttpCode.`201`(callContext))
@ -997,9 +976,9 @@ trait APIMethods510 {
cc => implicit val ec = EndpointContext(Some(cc))
for {
(requestParams, callContext) <- extractQueryParams(cc.url, List("limit","offset","sort_direction"), cc.callContext)
customers <- NewStyle.function.getCustomers(bankId, callContext, requestParams)
(agents, callContext) <- NewStyle.function.getAgents(bankId.value, requestParams, callContext)
} yield {
(JSONFactory510.createAgentMinimalsJson(customers), HttpCode.`200`(callContext))
(JSONFactory510.createAgentMinimalsJson(agents), HttpCode.`200`(callContext))
}
}
}

View File

@ -27,33 +27,30 @@
package code.api.v5_1_0
import code.api.Constant
import code.api.util.{APIUtil, ConsentJWT, CustomJsonFormats, JwtUtil, Role}
import code.api.util.APIUtil.{DateWithDay, DateWithSeconds, gitCommit, stringOrNull}
import code.api.util._
import code.api.v1_2_1.BankRoutingJsonV121
import code.api.v1_4_0.JSONFactory1_4_0.{LocationJsonV140, MetaJsonV140, transformToLocationFromV140, transformToMetaFromV140}
import code.api.v2_1_0.ResourceUserJSON
import code.api.v3_0_0.JSONFactory300.{createLocationJson, createMetaJson, transformToAddressFromV300}
import code.api.v3_0_0.{AccountIdJson, AccountsIdsJsonV300, AddressJsonV300, OpeningTimesV300, ViewJsonV300}
import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400, PostViewJsonV400}
import code.api.v3_0_0.{AddressJsonV300, OpeningTimesV300}
import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400}
import code.api.v5_0_0.PostConsentRequestJsonV500
import code.atmattribute.AtmAttribute
import code.atms.Atms.Atm
import code.users.{UserAttribute, Users}
import code.views.system.{AccountAccess, ViewDefinition}
import com.openbankproject.commons.model.{AccountRoutingJsonV121, Address, AmountOfMoneyJsonV121, AtmId, AtmT, BankAccount, BankId, BankIdAccountId, BranchRoutingJsonV141, CreateViewJson, Customer, Location, Meta, RegulatedEntityTrait, TransactionRequestCommonBodyJSON, UpdateViewJSON, View}
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
import java.util.Date
import code.consent.MappedConsent
import code.metrics.APIMetric
import code.model.Consumer
import com.openbankproject.commons.model.enums.ConsentType
import code.users.{UserAttribute, Users}
import code.views.system.{AccountAccess, ViewDefinition}
import com.openbankproject.commons.model._
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.common.{Box, Full}
import net.liftweb.json
import net.liftweb.json.{JString, JValue, parse, parseOpt}
import java.text.SimpleDateFormat
import scala.collection.immutable.List
import java.util.Date
import scala.util.Try
@ -945,22 +942,22 @@ object JSONFactory510 extends CustomJsonFormats {
ConsumersJsonV510(consumers.map(createConsumerJSON(_,None)))
}
def createAgentJson(customer: Customer, bankAccount: BankAccount): AgentJsonV510 = {
def createAgentJson(agent: Agent, bankAccount: BankAccount): AgentJsonV510 = {
AgentJsonV510(
agent_id = customer.customerId,
legal_name = customer.legalName,
mobile_phone_number = customer.mobileNumber,
agent_number = customer.number,
agent_id = agent.agentId,
legal_name = agent.legalName,
mobile_phone_number = agent.mobileNumber,
agent_number = agent.number,
currency = bankAccount.currency
)
}
def createAgentMinimalsJson(customers: List[Customer]): AgentMinimalsJsonV510 = {
def createAgentMinimalsJson(agents: List[Agent]): AgentMinimalsJsonV510 = {
AgentMinimalsJsonV510(
customers
.filter(_.isConfirmedAgent == Some(true))
.map(customer => AgentMinimalJsonV510(
agent_id = customer.customerId,
legal_name = customer.legalName
agents
.filter(_.isConfirmedAgent == true)
.map(agent => AgentMinimalJsonV510(
agent_id = agent.agentId,
legal_name = agent.legalName
)))
}

View File

@ -1113,12 +1113,33 @@ trait Connector extends MdcLoggable {
callContext: Option[CallContext]): OBPReturnType[Box[Customer]] =
Future{(Failure(setUnimplementedError(nameOf(updateCustomerScaData _))), callContext)}
def getAgentByAgentId(
agentId : String,
callContext: Option[CallContext]
): OBPReturnType[Box[Agent]] = Future{(Failure(setUnimplementedError(nameOf(getAgentByAgentId _))), callContext)}
def getAgents(
bankId : String,
queryParams: List[OBPQueryParam],
callContext: Option[CallContext]
): OBPReturnType[Box[List[Agent]]] = Future{(Failure(setUnimplementedError(nameOf(getAgents _))), callContext)}
def updateAgentStatus(
agentId: String,
is_pending_agent: Boolean,
is_confirmed_agent: Boolean,
callContext: Option[CallContext]
): OBPReturnType[Box[Customer]] = Future{(Failure(setUnimplementedError(nameOf(updateCustomerScaData _))), callContext)}
): OBPReturnType[Box[Agent]] = Future{(Failure(setUnimplementedError(nameOf(updateAgentStatus _))), callContext)}
def createAgent(
bankId: String,
legalName : String,
mobileNumber : String,
number : String,
callContext: Option[CallContext]
): OBPReturnType[Box[Agent]] = Future{(Failure(setUnimplementedError(nameOf(createAgent _))), callContext)}
def updateCustomerCreditData(customerId: String,
creditRating: Option[String],

View File

@ -32,7 +32,7 @@ object MappedCustomerProvider extends CustomerProvider with MdcLoggable {
Full(MappedCustomer.findAll(mapperParams:_*))
}
private def getOptionalParams(queryParams: List[OBPQueryParam]) = {
def getOptionalParams(queryParams: List[OBPQueryParam]) = {
val limit = queryParams.collect { case OBPLimit(value) => MaxRows[MappedCustomer](value) }.headOption
val offset = queryParams.collect { case OBPOffset(value) => StartAt[MappedCustomer](value) }.headOption
val fromDate = queryParams.collect { case OBPFromDate(date) => By_>=(MappedCustomer.updatedAt, date) }.headOption
@ -333,7 +333,7 @@ object MappedCustomerProvider extends CustomerProvider with MdcLoggable {
}
class MappedCustomer extends Customer with LongKeyedMapper[MappedCustomer] with IdPK with CreatedUpdated {
class MappedCustomer extends Customer with Agent with LongKeyedMapper[MappedCustomer] with IdPK with CreatedUpdated {
def getSingleton = MappedCustomer
@ -402,9 +402,12 @@ class MappedCustomer extends Customer with LongKeyedMapper[MappedCustomer] with
override def title: String = mTitle.get
override def branchId: String = mBranchId.get
override def nameSuffix: String = mNameSuffix.get
override def isConfirmedAgent = Some(mIsConfirmedAgent.get)
override def isPendingAgent = Some(mIsPendingAgent.get)
override def isConfirmedAgent: Boolean = mIsConfirmedAgent.get //This is for Agent
override def isPendingAgent: Boolean = mIsPendingAgent.get //This is for Agent
override def agentId: String = mCustomerId.get //this is for Agent
}
object MappedCustomer extends MappedCustomer with LongKeyedMetaMapper[MappedCustomer] {

View File

@ -0,0 +1,55 @@
package code.customer.agent
import code.api.util.{CallContext, OBPQueryParam}
import com.openbankproject.commons.model._
import net.liftweb.common.Box
import net.liftweb.util.SimpleInjector
import scala.concurrent.Future
object AgentX extends SimpleInjector {
val agentProvider = new Inject(buildOne _) {}
def buildOne: AgentProvider = MappedAgentProvider
}
trait AgentProvider {
def getAgentsAtAllBanks(queryParams: List[OBPQueryParam]): Future[Box[List[Agent]]]
def getAgentsFuture(bankId: BankId, queryParams: List[OBPQueryParam]): Future[Box[List[Agent]]]
def getAgentsByAgentPhoneNumber(bankId: BankId, phoneNumber: String): Future[Box[List[Agent]]]
def getAgentsByAgentLegalName(bankId: BankId, legalName: String): Future[Box[List[Agent]]]
def getAgentByAgentId(agentId: String): Box[Agent]
def getAgentByAgentIdFuture(agentId: String): Future[Box[Agent]]
def getBankIdByAgentId(agentId: String): Box[String]
def getAgentByAgentNumber(agentNumber: String, bankId: BankId): Box[Agent]
def getAgentByAgentNumberFuture(agentNumber: String, bankId: BankId): Future[Box[Agent]]
def checkAgentNumberAvailable(bankId: BankId, agentNumber: String): Boolean
def createAgent(
bankId: String,
legalName : String,
mobileNumber : String,
number : String,
callContext: Option[CallContext]
): Future[Box[Agent]]
def updateAgentStatus(
agentId: String,
isPendingAgent: Boolean,
isConfirmedAgent: Boolean,
callContext: Option[CallContext]
): Future[Box[Agent]]
}

View File

@ -0,0 +1,127 @@
package code.customer.agent
import code.api.util._
import code.customer.{MappedCustomer, MappedCustomerProvider}
import code.util.Helper.MdcLoggable
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.model._
import net.liftweb.common.{Box, Full}
import net.liftweb.mapper._
import net.liftweb.util.Helpers.tryo
import scala.concurrent.Future
object MappedAgentProvider extends AgentProvider with MdcLoggable {
override def getAgentsAtAllBanks(queryParams: List[OBPQueryParam]): Future[Box[List[Agent]]] = Future {
val mapperParams = MappedCustomerProvider.getOptionalParams(queryParams)
Full(MappedCustomer.findAll(mapperParams: _*))
}
override def getAgentsFuture(bankId: BankId, queryParams: List[OBPQueryParam]): Future[Box[List[Agent]]] = Future {
val mapperParams = Seq(By(MappedCustomer.mBank, bankId.value)) ++ MappedCustomerProvider.getOptionalParams(queryParams)
Full(MappedCustomer.findAll(mapperParams: _*))
}
override def getAgentsByAgentPhoneNumber(bankId: BankId, phoneNumber: String): Future[Box[List[Agent]]] = Future {
val result = MappedCustomer.findAll(
By(MappedCustomer.mBank, bankId.value),
Like(MappedCustomer.mMobileNumber, phoneNumber)
)
Full(result)
}
override def getAgentsByAgentLegalName(bankId: BankId, legalName: String): Future[Box[List[Agent]]] = Future {
val result = MappedCustomer.findAll(
By(MappedCustomer.mBank, bankId.value),
Like(MappedCustomer.mLegalName, legalName)
)
Full(result)
}
override def checkAgentNumberAvailable(bankId: BankId, customerNumber: String): Boolean = {
val customers = MappedCustomer.findAll(
By(MappedCustomer.mBank, bankId.value),
By(MappedCustomer.mNumber, customerNumber)
)
val available: Boolean = customers.size match {
case 0 => true
case _ => false
}
available
}
override def getAgentByAgentId(customerId: String): Box[Agent] = {
MappedCustomer.find(
By(MappedCustomer.mCustomerId, customerId)
)
}
override def getBankIdByAgentId(customerId: String): Box[String] = {
val customer: Box[MappedCustomer] = MappedCustomer.find(
By(MappedCustomer.mCustomerId, customerId)
)
for (c <- customer) yield {
c.mBank.get
}
}
override def getAgentByAgentNumber(customerNumber: String, bankId: BankId): Box[Agent] = {
MappedCustomer.find(
By(MappedCustomer.mNumber, customerNumber),
By(MappedCustomer.mBank, bankId.value)
)
}
override def getAgentByAgentNumberFuture(customerNumber: String, bankId: BankId): Future[Box[Agent]] = {
Future(getAgentByAgentNumber(customerNumber, bankId))
}
override def createAgent(
bankId: String,
legalName: String,
mobileNumber: String,
number: String,
callContext: Option[CallContext]
): Future[Box[Agent]] = Future {
tryo {
MappedCustomer
.create
.mBank(bankId)
.mLegalName(legalName)
.mMobileNumber(mobileNumber)
.mNumber(number)
.mIsPendingAgent(true) //default value
.mIsConfirmedAgent(false) // default value
.saveMe()
}
}
override def updateAgentStatus(
agentId: String,
isPendingAgent: Boolean,
isConfirmedAgent: Boolean,
callContext: Option[CallContext]
): Future[Box[Agent]] = Future {
MappedCustomer.find(
By(MappedCustomer.mCustomerId, agentId)
) map {
c =>
c.mIsPendingAgent(isPendingAgent)
c.mIsConfirmedAgent(isConfirmedAgent)
c.saveMe()
}
}
override def getAgentByAgentIdFuture(agentId: String): Future[Box[Agent]] = Future {
getAgentByAgentId(agentId: String)
}
}

View File

@ -170,6 +170,16 @@ case class CustomerCommons(
object CustomerCommons extends Converter[Customer, CustomerCommons]
case class AgentCommons(
agentId: String,
bankId: String,
number: String,
legalName: String,
mobileNumber: String,
isConfirmedAgent: Boolean,
isPendingAgent: Boolean,
) extends Agent
object AgentCommons extends Converter[Agent, AgentCommons]
case class CustomerAddressCommons(
customerId :String,

View File

@ -53,9 +53,16 @@ trait Customer {
def title: String
def branchId: String
def nameSuffix: String
def isConfirmedAgent: Option[Boolean] = None //this is for agent
def isPendingAgent: Option[Boolean]= None // this is for agent
}
trait Agent {
def agentId : String
def bankId : String
def number : String
def legalName : String
def mobileNumber : String
def isConfirmedAgent: Boolean
def isPendingAgent: Boolean
}
trait CustomerFaceImageTrait {