feature/OBPv510 added new endpoints:createAgent,getAgent and createTransactionRequestAgent

This commit is contained in:
hongwei 2024-11-14 12:12:40 +01:00
parent 65bd7bd2de
commit 6d0e316dc6
10 changed files with 808 additions and 513 deletions

View File

@ -5515,6 +5515,32 @@ object SwaggerDefinitionsJSON {
val consumersJsonV510 = ConsumersJsonV510(
List(consumerJsonV510)
)
val agentIdJson = AgentIdJson("")
val transactionRequestBodyAgentJsonV510 = TransactionRequestBodyAgentJsonV510(
to = agentIdJson,
value = amountOfMoneyJsonV121,
description = descriptionExample.value,
charge_policy = chargePolicyExample.value,
future_date = Some(futureDateExample.value)
)
val postAgentJsonV510 = PostAgentJsonV510(
legal_name = legalNameExample.value,
mobile_phone_number = mobilePhoneNumberExample.value,
agent_number = agentNumberExample.value,
currency = currencyExample.value
)
val agentJsonV510 = AgentJsonV510(
agent_id = agentIdExample.value,
legal_name = legalNameExample.value,
mobile_phone_number = mobilePhoneNumberExample.value,
agent_number = agentNumberExample.value,
currency = currencyExample.value
)
//The common error or success format.
//Just some helper format to use in Json
case class NotSupportedYet()

View File

@ -104,6 +104,12 @@ object ApiRole extends MdcLoggable{
case class CanCreateCustomer(requiresBankId: Boolean = true) extends ApiRole
lazy val canCreateCustomer = CanCreateCustomer()
case class CanCreateAgent(requiresBankId: Boolean = true) extends ApiRole
lazy val canCreateAgent = CanCreateAgent()
case class CanGetAgent(requiresBankId: Boolean = true) extends ApiRole
lazy val canGetAgent = CanGetAgent()
case class CanUpdateCustomerEmail(requiresBankId: Boolean = true) extends ApiRole
lazy val canUpdateCustomerEmail = CanUpdateCustomerEmail()
@ -134,6 +140,9 @@ object ApiRole extends MdcLoggable{
case class CanCreateCustomerAtAnyBank(requiresBankId: Boolean = false) extends ApiRole
lazy val canCreateCustomerAtAnyBank = CanCreateCustomerAtAnyBank()
case class CanCreateAgentAtAnyBank(requiresBankId: Boolean = false) extends ApiRole
lazy val canCreateAgentAtAnyBank = CanCreateAgentAtAnyBank()
case class CanGetCorrelatedUsersInfo(requiresBankId: Boolean = true) extends ApiRole
lazy val canGetCorrelatedUsersInfo = CanGetCorrelatedUsersInfo()

View File

@ -452,6 +452,7 @@ object ErrorMessages {
val UpdateProductFeeError = "OBP-30119: Could not update the Product Fee."
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 CustomerAccountLinkNotFound = "OBP-30204: Customer Account Link not found"
@ -523,6 +524,7 @@ 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."
// Branch related messages
val BranchesNotFoundLicense = "OBP-32001: No branches available. License may not be set."

View File

@ -65,6 +65,9 @@ object ExampleValue {
lazy val customerIdExample = ConnectorField("7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", s"A non human friendly string that identifies the customer and is used in URLs. This SHOULD NOT be the customer number. The combination of customerId and bankId MUST be unique on an OBP instance. customerId SHOULD be unique on an OBP instance. Ideally customerId is a UUID. A mapping between customer number and customer id is kept in OBP.")
glossaryItems += makeGlossaryItem("Customer.customerId", customerIdExample)
lazy val agentIdExample = ConnectorField("7uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", s"A non human friendly string that identifies the agent and is used in URLs. This SHOULD NOT be the agent number. The combination of agentId and bankId MUST be unique on an OBP instance. AgentId SHOULD be unique on an OBP instance. Ideally agentId is a UUID. A mapping between agent number and agent id is kept in OBP.")
glossaryItems += makeGlossaryItem("Agent.agent_id", agentIdExample)
lazy val customerAccountLinkIdExample = ConnectorField("xyz8a7e4-6d02-40e3-a129-0b2bf89de8uh", s"A non human friendly string that identifies the Customer Account Link and is used in URLs. ")
glossaryItems += makeGlossaryItem("Customer.customerAccountLinkId", customerAccountLinkIdExample)
@ -114,6 +117,9 @@ object ExampleValue {
lazy val customerNumberExample = ConnectorField("5987953", s"The human friendly customer identifier that MUST uniquely identify the Customer at the Bank ID. Customer Number is NOT used in URLs.")
glossaryItems += makeGlossaryItem("Customer.customerNumber", customerNumberExample)
lazy val agentNumberExample = ConnectorField("5987953", s"The human friendly agent identifier that MUST uniquely identify the Agent at the Bank ID. Agent Number is NOT used in URLs.")
glossaryItems += makeGlossaryItem("Agent.agent_number", agentNumberExample)
lazy val licenseIdExample = ConnectorField("ODbL-1.0", s"")
glossaryItems += makeGlossaryItem("License.id", licenseIdExample)

View File

@ -748,6 +748,12 @@ object NewStyle extends MdcLoggable{
unboxFullOrFail(_, callContext, s"$CustomerNotFoundByCustomerId. Current CustomerId($customerId)", 404)
}
}
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)

File diff suppressed because it is too large Load Diff

View File

@ -1290,7 +1290,7 @@ trait APIMethods500 {
case "banks" :: BankId(bankId) :: "customers" :: Nil JsonPost json -> _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV310 ", 400, cc.callContext) {
postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostCustomerJsonV500 ", 400, cc.callContext) {
json.extract[PostCustomerJsonV500]
}
_ <- Helper.booleanToFuture(failMsg = InvalidJsonContent + s" The field dependants(${postedData.dependants.getOrElse(0)}) not equal the length(${postedData.dob_of_dependants.getOrElse(Nil).length }) of dob_of_dependants array", 400, cc.callContext) {

View File

@ -18,15 +18,13 @@ import code.api.util.newstyle.RegulatedEntityNewStyle.{createRegulatedEntityNewS
import code.api.v2_1_0.ConsumerRedirectUrlJSON
import code.api.v3_0_0.JSONFactory300
import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
import code.api.v3_1_0.ConsentJsonV310
import code.api.v3_1_0.{ConsentJsonV310, JSONFactory310}
import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson
import code.api.v4_0_0.APIMethods400.{createTransactionRequest, transactionRequestGeneralText}
import code.api.v4_0_0.JSONFactory400.{createAccountBalancesJson, createBalancesJson, createNewCoreBankAccountJson}
import code.api.v4_0_0.{JSONFactory400, PostAccountAccessJsonV400, PostApiCollectionJson400, RevokedJsonV400}
import code.api.v5_0_0.{JSONFactory500, PostConsentRequestJsonV500}
import code.api.v5_1_0.JSONFactory510.{createConsentsInfoJsonV510, createConsentsJsonV510, createRegulatedEntitiesJson, createRegulatedEntityJson}
import code.api.v5_1_0.JSONFactory510.{createConsentsInfoJsonV510, createRegulatedEntitiesJson, createRegulatedEntityJson}
import code.api.v5_0_0.JSONFactory500
import code.api.v5_1_0.JSONFactory510.{createRegulatedEntitiesJson, createRegulatedEntityJson}
import code.api.v5_1_0.JSONFactory510.{createConsentsInfoJsonV510, createConsentsJsonV510, createRegulatedEntitiesJson, createRegulatedEntityJson}
import code.atmattribute.AtmAttribute
import code.bankconnectors.Connector
import code.consent.{ConsentRequests, Consents}
@ -345,6 +343,178 @@ trait APIMethods510 {
}
}
}
staticResourceDocs += ResourceDoc(
createAgent,
implementedInApiVersion,
nameOf(createAgent),
"POST",
"/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,
agentJsonV510,
List(
$UserNotLoggedIn,
$BankNotFound,
InvalidJsonFormat,
CustomerNumberAlreadyExists,
UserNotFoundById,
CustomerAlreadyExistsForUser,
CreateConsumerError,
UnknownError
),
List(apiTagCustomer, apiTagPerson)
)
lazy val createAgent : OBPEndpoint = {
case "banks" :: BankId(bankId) :: "agents" :: Nil JsonPost json -> _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PostAgentJsonV510 ", 400, cc.callContext) {
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,
"",
"",
"",
callContext,
)
(bankAccount, callContext) <- NewStyle.function.createBankAccount(
bankId,
AccountId(APIUtil.generateUUID()),
"AGENT",
"AGENT",
postedData.currency,
0,
postedData.legal_name,
null,
Nil,
callContext
)
(_, callContext) <- NewStyle.function.createCustomerAccountLink(customer.customerId, bankAccount.bankId.value, bankAccount.accountId.value, "Owner", callContext)
} yield {
(JSONFactory510.createAgentJson(customer, bankAccount), HttpCode.`201`(callContext))
}
}
}
staticResourceDocs += ResourceDoc(
getAgent,
implementedInApiVersion,
nameOf(getAgent),
"GET",
"/banks/BANK_ID/agents/AGENT_ID",
"Get Agent",
s"""Get Agent.
|
|${authenticationRequiredMessage(true)}
|""".stripMargin,
EmptyBody,
agentJsonV510,
List(
$UserNotLoggedIn,
$BankNotFound,
UnknownError
),
List(apiTagAccount)
)
lazy val getAgent: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "agents" :: agentId :: Nil JsonGet _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
(Full(u), callContext) <- SS.user
(agent, callContext) <- NewStyle.function.getAgentByAgentId(agentId, callContext)
(customerAccountLinks, callContext) <- NewStyle.function.getCustomerAccountLinksByCustomerId(agentId, callContext)
customerAccountLink <- NewStyle.function.tryons(AgentAccountLinkNotFound, 400, cc.callContext) {
customerAccountLinks.head
}
(bankAccount, callContext) <- NewStyle.function.getBankAccount(BankId(customerAccountLink.bankId), AccountId(customerAccountLink.accountId), callContext)
} yield {
(JSONFactory510.createAgentJson(agent, bankAccount), HttpCode.`200`(callContext))
}
}
}
staticResourceDocs += ResourceDoc(
createTransactionRequestAgent,
implementedInApiVersion,
nameOf(createTransactionRequestAgent),
"POST",
"/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/AGENT/transaction-requests",
"Create Transaction Request (AGENT)",
s"""
|
|Either the `from` or the `to` field must be filled. Those fields refers to the information about the party that will be refunded.
|
|In case the `from` object is used, it means that the refund comes from the part that sent you a transaction.
|In the `from` object, you have two choices :
|- Use `bank_id` and `account_id` fields if the other account is registered on the OBP-API
|- Use the `counterparty_id` field in case the counterparty account is out of the OBP-API
|
|In case the `to` object is used, it means you send a request to a counterparty to ask for a refund on a previous transaction you sent.
|(This case is not managed by the OBP-API and require an external adapter)
|
|
|$transactionRequestGeneralText
|
""".stripMargin,
transactionRequestBodyAgentJsonV510,
transactionRequestWithChargeJSON400,
List(
$UserNotLoggedIn,
InvalidBankIdFormat,
InvalidAccountIdFormat,
InvalidJsonFormat,
$BankNotFound,
AccountNotFound,
$BankAccountNotFound,
InsufficientAuthorisationToCreateTransactionRequest,
InvalidTransactionRequestType,
InvalidJsonFormat,
InvalidNumber,
NotPositiveAmount,
InvalidTransactionRequestCurrency,
TransactionDisabled,
UnknownError
),
List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
)
lazy val createTransactionRequestAgent: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
"AGENT-CASH-WITHDRAWAL" :: "transaction-requests" :: Nil JsonPost json -> _ =>
cc =>
implicit val ec = EndpointContext(Some(cc))
val transactionRequestType = TransactionRequestType("ACCOUNT")
createTransactionRequest(bankId, accountId, viewId, transactionRequestType, json)
}
staticResourceDocs += ResourceDoc(
createNonPersonalUserAttribute,
implementedInApiVersion,

View File

@ -40,7 +40,7 @@ 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, AtmId, AtmT, BankId, BankIdAccountId, BranchRoutingJsonV141, CreateViewJson, Customer, Location, Meta, RegulatedEntityTrait, UpdateViewJSON, View}
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
@ -317,6 +317,38 @@ case class UserAttributesResponseJsonV510(
)
case class CustomerIdJson(id: String)
case class AgentJson(
id: String,
name:String
)
case class AgentIdJson(
agent_id: String
)
case class TransactionRequestBodyAgentJsonV510(
to: AgentIdJson,
value: AmountOfMoneyJsonV121,
description: String,
charge_policy: String,
future_date: Option[String] = None
) extends TransactionRequestCommonBodyJSON
case class PostAgentJsonV510(
legal_name: String,
mobile_phone_number: String,
agent_number: String,
currency: String
)
case class AgentJsonV510(
agent_id: String,
legal_name: String,
mobile_phone_number: String,
agent_number: String,
currency: String
)
case class CustomersIdsJsonV510(customers: List[CustomerIdJson])
case class PostCustomerLegalNameJsonV510(legal_name: String)
@ -912,6 +944,15 @@ object JSONFactory510 extends CustomJsonFormats {
ConsumersJsonV510(consumers.map(createConsumerJSON(_,None)))
}
def createAgentJson(customer: Customer, bankAccount: BankAccount): AgentJsonV510 = {
AgentJsonV510(
agent_id = customer.customerId,
legal_name = customer.legalName,
mobile_phone_number = customer.mobileNumber,
agent_number = customer.number,
currency = bankAccount.currency
)
}
}

View File

@ -105,6 +105,7 @@ object TransactionRequestTypes extends OBPEnumeration[TransactionRequestTypes]{
object TARGET_2_PAYMENTS extends Value
object CROSS_BORDER_CREDIT_TRANSFERS extends Value
object REFUND extends Value
object AGENT_CASH_WITHDRAWAL extends Value
}
sealed trait StrongCustomerAuthentication extends EnumValue