mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 15:06:50 +00:00
Merge branch 'OpenBankProject:develop' into develop
This commit is contained in:
commit
ee9765509a
@ -16,7 +16,7 @@ import code.api.v3_0_0.JSONFactory300.createBranchJsonV300
|
||||
import code.api.v3_0_0.custom.JSONFactoryCustom300
|
||||
import code.api.v3_0_0.{LobbyJsonV330, _}
|
||||
import code.api.v3_1_0.{AccountBalanceV310, AccountsBalancesV310Json, BadLoginStatusJson, ContactDetailsJson, CustomerWithAttributesJsonV310, InviteeJson, ObpApiLoopbackJson, PhysicalCardWithAttributesJsonV310, PutUpdateCustomerEmailJsonV310, _}
|
||||
import code.api.v4_0_0.{AccountMinimalJson400, BankAttributeBankResponseJsonV400, CustomerMinimalJsonV400, FastFirehoseAccountsJsonV400, PostHistoricalTransactionAtBankJson, _}
|
||||
import code.api.v4_0_0.{AccountMinimalJson400, BankAttributeBankResponseJsonV400, CardJsonV400, CustomerMinimalJsonV400, FastFirehoseAccountsJsonV400, PostHistoricalTransactionAtBankJson, _}
|
||||
import code.api.v3_1_0.{AccountBalanceV310, AccountsBalancesV310Json, BadLoginStatusJson, ContactDetailsJson, InviteeJson, ObpApiLoopbackJson, PhysicalCardWithAttributesJsonV310, PutUpdateCustomerEmailJsonV310, _}
|
||||
import code.api.v5_0_0._
|
||||
import code.branches.Branches.{Branch, DriveUpString, LobbyString}
|
||||
@ -4196,6 +4196,22 @@ object SwaggerDefinitionsJSON {
|
||||
refund = RefundJson(transactionIdExample.value, transactionRequestRefundReasonCodeExample.value)
|
||||
)
|
||||
|
||||
val cardJsonV400 = CardJsonV400(
|
||||
card_type = cardTypeExample.value,
|
||||
brand = brandExample.value,
|
||||
cvv = cvvExample.value,
|
||||
card_number = cardNumberExample.value,
|
||||
name_on_card = nameOnCardExample.value,
|
||||
expiry_year = expiryYearExample.value,
|
||||
expiry_month = expiryMonthExample.value,
|
||||
)
|
||||
|
||||
val transactionRequestBodyCardJsonV400 = TransactionRequestBodyCardJsonV400(
|
||||
card = cardJsonV400,
|
||||
to = counterpartyIdJson,
|
||||
value = amountOfMoneyJsonV121,
|
||||
description = "A card payment description. "
|
||||
)
|
||||
val customerAttributesResponseJson = CustomerAttributesResponseJson (
|
||||
customer_attributes = List(customerAttributeResponseJson)
|
||||
)
|
||||
@ -4743,7 +4759,79 @@ object SwaggerDefinitionsJSON {
|
||||
valid_from = Some(new Date()),
|
||||
time_to_live = Some(3600)
|
||||
)
|
||||
|
||||
|
||||
val createPhysicalCardJsonV500 = CreatePhysicalCardJsonV500(
|
||||
card_number = bankCardNumberExample.value,
|
||||
card_type = cardTypeExample.value,
|
||||
name_on_card = nameOnCardExample.value,
|
||||
issue_number = issueNumberExample.value,
|
||||
serial_number = serialNumberExample.value,
|
||||
valid_from_date = DateWithDayExampleObject,
|
||||
expires_date = DateWithDayExampleObject,
|
||||
enabled = true,
|
||||
technology = technologyExample.value,
|
||||
networks = networksExample.value.split("[,;]").toList,
|
||||
allows = List(CardAction.CREDIT.toString.toLowerCase, CardAction.DEBIT.toString.toLowerCase),
|
||||
account_id =accountIdExample.value,
|
||||
replacement = Some(replacementJSON),
|
||||
pin_reset = List(pinResetJSON, pinResetJSON1),
|
||||
collected = Some(DateWithDayExampleObject),
|
||||
posted = Some(DateWithDayExampleObject),
|
||||
customer_id = customerIdExample.value,
|
||||
brand = brandExample.value
|
||||
)
|
||||
|
||||
val physicalCardJsonV500 = PhysicalCardJsonV500(
|
||||
card_id = cardIdExample.value,
|
||||
bank_id = bankIdExample.value,
|
||||
card_number = bankCardNumberExample.value,
|
||||
card_type = cardTypeExample.value,
|
||||
name_on_card = nameOnCardExample.value,
|
||||
issue_number = issueNumberExample.value,
|
||||
serial_number = serialNumberExample.value,
|
||||
valid_from_date = DateWithDayExampleObject,
|
||||
expires_date = DateWithDayExampleObject,
|
||||
enabled = true,
|
||||
cancelled = true,
|
||||
on_hot_list = true,
|
||||
technology = technologyExample.value,
|
||||
networks = networksExample.value.split("[,;]").toList,
|
||||
allows = List(CardAction.CREDIT.toString.toLowerCase, CardAction.DEBIT.toString.toLowerCase),
|
||||
account = accountJSON,
|
||||
replacement = replacementJSON,
|
||||
pin_reset = List(pinResetJSON),
|
||||
collected = DateWithDayExampleObject,
|
||||
posted = DateWithDayExampleObject,
|
||||
customer_id = customerIdExample.value,
|
||||
cvv = cvvExample.value,
|
||||
brand = brandExample.value
|
||||
)
|
||||
|
||||
val physicalCardWithAttributesJsonV500 = PhysicalCardWithAttributesJsonV500(
|
||||
card_id = cardIdExample.value,
|
||||
bank_id = bankIdExample.value,
|
||||
card_number = bankCardNumberExample.value,
|
||||
card_type = cardTypeExample.value,
|
||||
name_on_card = nameOnCardExample.value,
|
||||
issue_number = issueNumberExample.value,
|
||||
serial_number = serialNumberExample.value,
|
||||
valid_from_date = DateWithDayExampleObject,
|
||||
expires_date = DateWithDayExampleObject,
|
||||
enabled = true,
|
||||
cancelled = true,
|
||||
on_hot_list = true,
|
||||
technology = technologyExample.value,
|
||||
networks = networksExample.value.split("[,;]").toList,
|
||||
allows = List(CardAction.CREDIT.toString.toLowerCase, CardAction.DEBIT.toString.toLowerCase),
|
||||
account = accountBasicV310,
|
||||
replacement = replacementJSON,
|
||||
pin_reset = List(pinResetJSON),
|
||||
collected = DateWithDayExampleObject,
|
||||
posted = DateWithDayExampleObject,
|
||||
customer_id = customerIdExample.value,
|
||||
card_attributes = List(cardAttributeCommons),
|
||||
brand = brandExample.value
|
||||
)
|
||||
//The common error or success format.
|
||||
//Just some helper format to use in Json
|
||||
case class NotSupportedYet()
|
||||
|
||||
@ -118,6 +118,8 @@ import scala.xml.{Elem, XML}
|
||||
|
||||
object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
|
||||
val DateWithYear = "yyyy"
|
||||
val DateWithMonth = "yyyy-MM"
|
||||
val DateWithDay = "yyyy-MM-dd"
|
||||
val DateWithDay2 = "yyyyMMdd"
|
||||
val DateWithDay3 = "dd/MM/yyyy"
|
||||
@ -126,11 +128,15 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
|
||||
val DateWithMs = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
||||
val DateWithMsRollback = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" //?? what does this `Rollback` mean ??
|
||||
|
||||
val DateWithYearFormat = new SimpleDateFormat(DateWithYear)
|
||||
val DateWithMonthFormat = new SimpleDateFormat(DateWithMonth)
|
||||
val DateWithDayFormat = new SimpleDateFormat(DateWithDay)
|
||||
val DateWithSecondsFormat = new SimpleDateFormat(DateWithSeconds)
|
||||
val DateWithMsFormat = new SimpleDateFormat(DateWithMs)
|
||||
val DateWithMsRollbackFormat = new SimpleDateFormat(DateWithMsRollback)
|
||||
|
||||
val DateWithYearExampleString: String = "1100"
|
||||
val DateWithMonthExampleString: String = "1100-01"
|
||||
val DateWithDayExampleString: String = "1100-01-01"
|
||||
val DateWithSecondsExampleString: String = "1100-01-01T01:01:01Z"
|
||||
val DateWithMsExampleString: String = "1100-01-01T01:01:01.000Z"
|
||||
|
||||
@ -398,6 +398,8 @@ object ErrorMessages {
|
||||
val ProductFeeNotFoundById = "OBP-30117: Product Fee not found. Please specify a valid value for PRODUCT_FEE_ID."
|
||||
val CreateProductFeeError = "OBP-30118: Could not insert the Product Fee."
|
||||
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 EntitlementIsBankRole = "OBP-30205: This entitlement is a Bank Role. Please set bank_id to a valid bank id."
|
||||
|
||||
@ -372,7 +372,19 @@ object ExampleValue {
|
||||
glossaryItems += makeGlossaryItem("Adapter.card_id", cardIdExample)
|
||||
|
||||
lazy val nameOnCardExample = ConnectorField(owner1Example.value, s"The name on the physical card")
|
||||
glossaryItems += makeGlossaryItem("Adapter.name_on_card", nameOnCardExample)
|
||||
glossaryItems += makeGlossaryItem("Adapter.name_on_card", nameOnCardExample)
|
||||
|
||||
lazy val cvvExample = ConnectorField("123", s"Card Verification Value")
|
||||
glossaryItems += makeGlossaryItem("Adapter.cvv", nameOnCardExample)
|
||||
|
||||
lazy val brandExample = ConnectorField("Visa", s"The brand of the card, eg: Visa, Mastercard")
|
||||
glossaryItems += makeGlossaryItem("Adapter.brand", nameOnCardExample)
|
||||
|
||||
lazy val expiryYearExample = ConnectorField("2023", s"The expiry year of the card")
|
||||
glossaryItems += makeGlossaryItem("Adapter.expiry_year", expiryYearExample)
|
||||
|
||||
lazy val expiryMonthExample = ConnectorField("01", s"The expiry month of the card")
|
||||
glossaryItems += makeGlossaryItem("Adapter.expiry_month", expiryMonthExample)
|
||||
|
||||
lazy val issueNumberExample = ConnectorField("1", s"The issue number of the physical card, eg 1,2,3,4 ....")
|
||||
glossaryItems += makeGlossaryItem("Adapter.issue_number", issueNumberExample)
|
||||
|
||||
@ -2591,6 +2591,8 @@ object NewStyle extends MdcLoggable{
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[PhysicalCard] = {
|
||||
validateBankId(bankId, callContext)
|
||||
@ -2616,6 +2618,8 @@ object NewStyle extends MdcLoggable{
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]
|
||||
) map {
|
||||
i => (unboxFullOrFail(i._1, callContext, s"$CreateCardError"), i._2)
|
||||
@ -2681,6 +2685,12 @@ object NewStyle extends MdcLoggable{
|
||||
i => (unboxFullOrFail(i._1, callContext, CardNotFound), i._2)
|
||||
}
|
||||
|
||||
def getPhysicalCardByCardNumber(bankCardNumber: String, callContext:Option[CallContext]) : OBPReturnType[PhysicalCardTrait] = {
|
||||
Connector.connector.vend.getPhysicalCardByCardNumber(bankCardNumber: String, callContext:Option[CallContext]) map {
|
||||
i => (unboxFullOrFail(i._1, callContext, InvalidCardNumber), i._2)
|
||||
}
|
||||
}
|
||||
|
||||
def getPhysicalCardForBank(bankId: BankId, cardId:String ,callContext:Option[CallContext]) : OBPReturnType[PhysicalCardTrait] =
|
||||
Connector.connector.vend.getPhysicalCardForBank(bankId: BankId, cardId: String, callContext:Option[CallContext]) map {
|
||||
i => (unboxFullOrFail(i._1, callContext, s"$CardNotFound Current CardId($cardId)"), i._2)
|
||||
|
||||
@ -1001,6 +1001,8 @@ trait APIMethods210 {
|
||||
collected= Option(CardCollectionInfo(postJson.collected)),
|
||||
posted= Option(CardPostedInfo(postJson.posted)),
|
||||
customerId = "",// this field is introduced from V310
|
||||
cvv = "",// this field is introduced from V500
|
||||
brand = "",// this field is introduced from V500
|
||||
callContext
|
||||
)
|
||||
|
||||
|
||||
@ -4814,6 +4814,8 @@ trait APIMethods310 {
|
||||
collected = collected,
|
||||
posted = posted,
|
||||
customerId = postJson.customer_id,
|
||||
cvv = "",//added from v500
|
||||
brand = "",//added from v500
|
||||
callContext
|
||||
)
|
||||
} yield {
|
||||
@ -4841,7 +4843,7 @@ trait APIMethods310 {
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagCard, apiTagNewStyle),
|
||||
Some(List(canCreateCardsForBank)))
|
||||
Some(List(canUpdateCardsForBank)))
|
||||
lazy val updatedCardForBank: OBPEndpoint = {
|
||||
case "management" :: "banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonPut json -> _ => {
|
||||
cc =>
|
||||
@ -4957,7 +4959,8 @@ trait APIMethods310 {
|
||||
emptyObjectJson,
|
||||
physicalCardWithAttributesJsonV310,
|
||||
List(UserNotLoggedIn,BankNotFound, UnknownError),
|
||||
List(apiTagCard, apiTagNewStyle))
|
||||
List(apiTagCard, apiTagNewStyle),
|
||||
Some(List(canGetCardsForBank)))
|
||||
lazy val getCardForBank : OBPEndpoint = {
|
||||
case "management" :: "banks" :: BankId(bankId) :: "cards" :: cardId :: Nil JsonGet _ => {
|
||||
cc => {
|
||||
|
||||
@ -914,26 +914,77 @@ trait APIMethods400 {
|
||||
|
||||
def createTransactionRequest(bankId: BankId, accountId: AccountId, viewId: ViewId, transactionRequestType: TransactionRequestType, json: JValue): Future[(TransactionRequestWithChargeJSON400, Option[CallContext])] = {
|
||||
for {
|
||||
(Full(u), fromAccount, callContext) <- SS.userAccount
|
||||
_ <- NewStyle.function.isEnabledTransactionRequests(callContext)
|
||||
_ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext) {
|
||||
isValidID(accountId.value)
|
||||
}
|
||||
_ <- Helper.booleanToFuture(InvalidBankIdFormat, cc=callContext) {
|
||||
isValidID(bankId.value)
|
||||
}
|
||||
(Full(u), callContext) <- SS.user
|
||||
|
||||
account = BankIdAccountId(bankId, accountId)
|
||||
_ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest(viewId, account, u, callContext)
|
||||
transactionRequestTypeValue <- NewStyle.function.tryons(s"$InvalidTransactionRequestType: '${transactionRequestType.value}'. OBP does not support it.", 400, callContext) {
|
||||
TransactionRequestTypes.withName(transactionRequestType.value)
|
||||
}
|
||||
|
||||
(fromAccount, callContext) <- transactionRequestTypeValue match {
|
||||
case CARD =>
|
||||
for{
|
||||
transactionRequestBodyCard <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $CARD json format", 400, callContext) {
|
||||
json.extract[TransactionRequestBodyCardJsonV400]
|
||||
}
|
||||
// 1.1 get Card from card_number
|
||||
(cardFromCbs,callContext) <- NewStyle.function.getPhysicalCardByCardNumber(transactionRequestBodyCard.card.card_number, callContext)
|
||||
|
||||
// 1.2 check card name/expire month. year.
|
||||
calendar = Calendar.getInstance
|
||||
_ = calendar.setTime(cardFromCbs.expires)
|
||||
yearFromCbs = calendar.get(Calendar.YEAR).toString
|
||||
monthFromCbs = calendar.get(Calendar.MONTH).toString
|
||||
nameOnCardFromCbs= cardFromCbs.nameOnCard
|
||||
cvvFromCbs= cardFromCbs.cvv.getOrElse("")
|
||||
brandFromCbs= cardFromCbs.brand.getOrElse("")
|
||||
|
||||
_ <- Helper.booleanToFuture(s"$InvalidJsonValue brand is not matched", cc=callContext) {
|
||||
transactionRequestBodyCard.card.brand.equalsIgnoreCase(brandFromCbs)
|
||||
}
|
||||
|
||||
dateFromJsonBody <- NewStyle.function.tryons(s"$InvalidDateFormat year should be 'yyyy', " +
|
||||
s"eg: 2023, but current expiry_year(${transactionRequestBodyCard.card.expiry_year}), " +
|
||||
s"month should be 'xx', eg: 02, but current expiry_month(${transactionRequestBodyCard.card.expiry_month})", 400, callContext) {
|
||||
DateWithMonthFormat.parse(s"${transactionRequestBodyCard.card.expiry_year}-${transactionRequestBodyCard.card.expiry_month}")
|
||||
}
|
||||
_ <- Helper.booleanToFuture(s"$InvalidJsonValue your credit card is expired.", cc=callContext) {
|
||||
org.apache.commons.lang3.time.DateUtils.addMonths(new Date(), 1).before(dateFromJsonBody)
|
||||
}
|
||||
|
||||
_ <- Helper.booleanToFuture(s"$InvalidJsonValue expiry_year is not matched", cc=callContext) {
|
||||
transactionRequestBodyCard.card.expiry_year.equalsIgnoreCase(yearFromCbs)
|
||||
}
|
||||
_ <- Helper.booleanToFuture(s"$InvalidJsonValue expiry_month is not matched", cc=callContext) {
|
||||
transactionRequestBodyCard.card.expiry_month.toInt.equals(monthFromCbs.toInt+1)
|
||||
}
|
||||
|
||||
_ <- Helper.booleanToFuture(s"$InvalidJsonValue name_on_card is not matched", cc=callContext) {
|
||||
transactionRequestBodyCard.card.name_on_card.equalsIgnoreCase(nameOnCardFromCbs)
|
||||
}
|
||||
_ <- Helper.booleanToFuture(s"$InvalidJsonValue cvv is not matched", cc=callContext) {
|
||||
HashUtil.Sha256Hash(transactionRequestBodyCard.card.cvv).equals(cvvFromCbs)
|
||||
}
|
||||
|
||||
} yield{
|
||||
(cardFromCbs.account, callContext)
|
||||
}
|
||||
|
||||
case _ => NewStyle.function.getBankAccount(bankId,accountId, callContext)
|
||||
}
|
||||
_ <- NewStyle.function.isEnabledTransactionRequests(callContext)
|
||||
_ <- Helper.booleanToFuture(InvalidAccountIdFormat, cc=callContext) {
|
||||
isValidID(fromAccount.accountId.value)
|
||||
}
|
||||
_ <- Helper.booleanToFuture(InvalidBankIdFormat, cc=callContext) {
|
||||
isValidID(fromAccount.bankId.value)
|
||||
}
|
||||
|
||||
_ <- NewStyle.function.checkAuthorisationToCreateTransactionRequest(viewId, BankIdAccountId(fromAccount.bankId, fromAccount.accountId), u, callContext)
|
||||
|
||||
_ <- Helper.booleanToFuture(s"${InvalidTransactionRequestType}: '${transactionRequestType.value}'. Current Sandbox does not support it. ", cc=callContext) {
|
||||
APIUtil.getPropsValue("transactionRequests_supported_types", "").split(",").contains(transactionRequestType.value)
|
||||
}
|
||||
|
||||
transactionRequestTypeValue <- NewStyle.function.tryons(s"$InvalidTransactionRequestType: '${transactionRequestType.value}'. OBP does not support it.", 400, callContext) {
|
||||
TransactionRequestTypes.withName(transactionRequestType.value)
|
||||
}
|
||||
|
||||
// Check the input JSON format, here is just check the common parts of all four types
|
||||
transDetailsJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $TransactionRequestBodyCommonJSON ", 400, callContext) {
|
||||
json.extract[TransactionRequestBodyCommonJSON]
|
||||
@ -1152,6 +1203,38 @@ trait APIMethods400 {
|
||||
None,
|
||||
callContext)
|
||||
} yield (createdTransactionRequest, callContext)
|
||||
}
|
||||
case CARD => {
|
||||
for {
|
||||
//2rd: get toAccount from counterpartyId
|
||||
transactionRequestBodyCard <- NewStyle.function.tryons(s"${InvalidJsonFormat}, it should be $CARD json format", 400, callContext) {
|
||||
json.extract[TransactionRequestBodyCardJsonV400]
|
||||
}
|
||||
toCounterpartyId = transactionRequestBodyCard.to.counterparty_id
|
||||
(toCounterparty, callContext) <- NewStyle.function.getCounterpartyByCounterpartyId(CounterpartyId(toCounterpartyId), callContext)
|
||||
toAccount <- NewStyle.function.getBankAccountFromCounterparty(toCounterparty, true, callContext)
|
||||
// Check we can send money to it.
|
||||
_ <- Helper.booleanToFuture(s"$CounterpartyBeneficiaryPermit", cc=callContext) {
|
||||
toCounterparty.isBeneficiary
|
||||
}
|
||||
chargePolicy = ChargePolicy.RECEIVER.toString
|
||||
transDetailsSerialized <- NewStyle.function.tryons(UnknownError, 400, callContext) {
|
||||
write(transactionRequestBodyCard)(Serialization.formats(NoTypeHints))
|
||||
}
|
||||
(createdTransactionRequest, callContext) <- NewStyle.function.createTransactionRequestv400(u,
|
||||
viewId,
|
||||
fromAccount,
|
||||
toAccount,
|
||||
transactionRequestType,
|
||||
transactionRequestBodyCard,
|
||||
transDetailsSerialized,
|
||||
chargePolicy,
|
||||
Some(OBP_TRANSACTION_REQUEST_CHALLENGE),
|
||||
getScaMethodAtInstance(transactionRequestType.value).toOption,
|
||||
None,
|
||||
None,
|
||||
callContext)
|
||||
} yield (createdTransactionRequest, callContext)
|
||||
|
||||
}
|
||||
case SIMPLE => {
|
||||
@ -1330,6 +1413,53 @@ trait APIMethods400 {
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
createTransactionRequestCard,
|
||||
implementedInApiVersion,
|
||||
nameOf(createTransactionRequestCard),
|
||||
"POST",
|
||||
"/transaction-request-types/CARD/transaction-requests",
|
||||
"Create Transaction Request (CARD)",
|
||||
s"""
|
||||
|
|
||||
|When using CARD, the payee is set in the request body .
|
||||
|
|
||||
|Money goes into the Counterparty in the request body.
|
||||
|
|
||||
|$transactionRequestGeneralText
|
||||
|
|
||||
""".stripMargin,
|
||||
transactionRequestBodyCardJsonV400,
|
||||
transactionRequestWithChargeJSON400,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
InvalidBankIdFormat,
|
||||
InvalidAccountIdFormat,
|
||||
InvalidJsonFormat,
|
||||
$BankNotFound,
|
||||
AccountNotFound,
|
||||
$BankAccountNotFound,
|
||||
InsufficientAuthorisationToCreateTransactionRequest,
|
||||
InvalidTransactionRequestType,
|
||||
InvalidJsonFormat,
|
||||
InvalidNumber,
|
||||
NotPositiveAmount,
|
||||
InvalidTransactionRequestCurrency,
|
||||
TransactionDisabled,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2, apiTagNewStyle)
|
||||
)
|
||||
|
||||
lazy val createTransactionRequestCard: OBPEndpoint = {
|
||||
case "transaction-request-types" :: "CARD" :: "transaction-requests" :: Nil JsonPost json -> _ =>
|
||||
cc =>
|
||||
val transactionRequestType = TransactionRequestType("CARD")
|
||||
createTransactionRequest(BankId(""), AccountId(""), ViewId("owner"), transactionRequestType, json)
|
||||
}
|
||||
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
answerTransactionRequestChallenge,
|
||||
implementedInApiVersion,
|
||||
|
||||
@ -37,7 +37,7 @@ import code.api.v1_2_1.{BankRoutingJsonV121, JSONFactory, UserJSONV121, ViewJSON
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.{LocationJsonV140, MetaJsonV140, TransactionRequestAccountJsonV140, transformToLocationFromV140, transformToMetaFromV140}
|
||||
import code.api.v2_0_0.JSONFactory200.UserJsonV200
|
||||
import code.api.v2_0_0.{CreateEntitlementJSON, EntitlementJSONs, JSONFactory200, TransactionRequestChargeJsonV200}
|
||||
import code.api.v2_1_0.{IbanJson, JSONFactory210, PostCounterpartyBespokeJson, ResourceUserJSON, TransactionRequestBodyCounterpartyJSON}
|
||||
import code.api.v2_1_0.{CounterpartyIdJson, IbanJson, JSONFactory210, PostCounterpartyBespokeJson, ResourceUserJSON, TransactionRequestBodyCounterpartyJSON}
|
||||
import code.api.v2_2_0.CounterpartyMetadataJson
|
||||
import code.api.v3_0_0.JSONFactory300._
|
||||
import code.api.v3_0_0._
|
||||
@ -54,7 +54,6 @@ import code.model.dataAccess.ResourceUser
|
||||
import code.model.{Consumer, ModeratedBankAccount, ModeratedBankAccountCore}
|
||||
import code.ratelimiting.RateLimiting
|
||||
import code.standingorders.StandingOrderTrait
|
||||
|
||||
import code.userlocks.UserLocks
|
||||
import code.users.{UserAgreement, UserAttribute, UserInvitation}
|
||||
import code.views.system.AccountAccess
|
||||
@ -411,6 +410,23 @@ case class TransactionRequestBodySimpleJsonV400(
|
||||
future_date: Option[String] = None
|
||||
) extends TransactionRequestCommonBodyJSON
|
||||
|
||||
case class CardJsonV400(
|
||||
card_type: String,
|
||||
brand: String,
|
||||
cvv: String,
|
||||
card_number: String,
|
||||
name_on_card: String,
|
||||
expiry_year: String,
|
||||
expiry_month: String,
|
||||
)
|
||||
|
||||
case class TransactionRequestBodyCardJsonV400(
|
||||
card: CardJsonV400,
|
||||
to: CounterpartyIdJson,
|
||||
value: AmountOfMoneyJsonV121,
|
||||
description: String,
|
||||
) extends TransactionRequestCommonBodyJSON
|
||||
|
||||
case class TransactionRequestReasonJsonV400(
|
||||
code: String,
|
||||
document_number: Option[String],
|
||||
|
||||
@ -13,6 +13,7 @@ import code.api.v3_0_0.JSONFactory300
|
||||
import code.api.v3_1_0._
|
||||
import code.api.v4_0_0.JSONFactory400.createCustomersMinimalJson
|
||||
import code.api.v4_0_0.{JSONFactory400, PutProductJsonV400}
|
||||
import code.api.v5_0_0.JSONFactory500.createPhysicalCardJson
|
||||
import code.bankconnectors.Connector
|
||||
import code.consent.{ConsentRequests, Consents}
|
||||
import code.entitlement.Entitlement
|
||||
@ -23,7 +24,7 @@ import code.views.Views
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
import com.openbankproject.commons.model.enums.StrongCustomerAuthentication
|
||||
import com.openbankproject.commons.model.{AccountId, AccountRouting, BankId, CreditLimit, CreditRating, CustomerFaceImage, CustomerId, ProductCode, UserAuthContextUpdateStatus}
|
||||
import com.openbankproject.commons.model.{AccountId, AccountRouting, BankId, BankIdAccountId, CardAction, CardAttributeCommons, CardCollectionInfo, CardPostedInfo, CardReplacementInfo, CardReplacementReason, CreditLimit, CreditRating, CustomerFaceImage, CustomerId, PinResetInfo, PinResetReason, ProductCode, TransactionRequestType, UserAuthContextUpdateStatus, View, ViewId}
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import net.liftweb.common.{Empty, Full}
|
||||
import net.liftweb.http.Req
|
||||
@ -32,6 +33,7 @@ import net.liftweb.json
|
||||
import net.liftweb.json.{Extraction, compactRender, prettyRender}
|
||||
import net.liftweb.util.Helpers.tryo
|
||||
import net.liftweb.util.Props
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
|
||||
import scala.collection.immutable.{List, Nil}
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
@ -1290,6 +1292,104 @@ trait APIMethods500 {
|
||||
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
addCardForBank,
|
||||
implementedInApiVersion,
|
||||
nameOf(addCardForBank),
|
||||
"POST",
|
||||
"/management/banks/BANK_ID/cards",
|
||||
"Create Card",
|
||||
s"""Create Card at bank specified by BANK_ID .
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|""",
|
||||
createPhysicalCardJsonV500,
|
||||
physicalCardJsonV500,
|
||||
List(
|
||||
$UserNotLoggedIn,
|
||||
$BankNotFound,
|
||||
UserHasMissingRoles,
|
||||
AllowedValuesAre,
|
||||
UnknownError
|
||||
),
|
||||
List(apiTagCard, apiTagNewStyle),
|
||||
Some(List(canCreateCardsForBank)))
|
||||
lazy val addCardForBank: OBPEndpoint = {
|
||||
case "management" :: "banks" :: BankId(bankId) :: "cards" :: Nil JsonPost json -> _ => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), _,callContext) <- SS.userBank
|
||||
|
||||
failMsg = s"$InvalidJsonFormat The Json body should be the $CreatePhysicalCardJsonV500 "
|
||||
postJson <- NewStyle.function.tryons(failMsg, 400, callContext) {json.extract[CreatePhysicalCardJsonV500]}
|
||||
|
||||
_ <- postJson.allows match {
|
||||
case List() => Future {true}
|
||||
case _ => Helper.booleanToFuture(AllowedValuesAre + CardAction.availableValues.mkString(", "), cc=callContext)(postJson.allows.forall(a => CardAction.availableValues.contains(a)))
|
||||
}
|
||||
|
||||
failMsg = AllowedValuesAre + CardReplacementReason.availableValues.mkString(", ")
|
||||
cardReplacementReason <- NewStyle.function.tryons(failMsg, 400, callContext) {
|
||||
postJson.replacement match {
|
||||
case Some(value) => CardReplacementReason.valueOf(value.reason_requested)
|
||||
case None => CardReplacementReason.valueOf(CardReplacementReason.FIRST.toString)
|
||||
}
|
||||
}
|
||||
|
||||
_<-Helper.booleanToFuture(s"${maximumLimitExceeded.replace("10000", "10")} Current issue_number is ${postJson.issue_number}", cc=callContext)(postJson.issue_number.length<= 10)
|
||||
|
||||
(_, callContext)<- NewStyle.function.getBankAccount(bankId, AccountId(postJson.account_id), callContext)
|
||||
|
||||
(_, callContext)<- NewStyle.function.getCustomerByCustomerId(postJson.customer_id, callContext)
|
||||
|
||||
replacement = postJson.replacement match {
|
||||
case Some(replacement) =>
|
||||
Some(CardReplacementInfo(requestedDate = replacement.requested_date, cardReplacementReason))
|
||||
case None => None
|
||||
}
|
||||
collected = postJson.collected match {
|
||||
case Some(collected) => Some(CardCollectionInfo(collected))
|
||||
case None => None
|
||||
}
|
||||
posted = postJson.posted match {
|
||||
case Some(posted) => Option(CardPostedInfo(posted))
|
||||
case None => None
|
||||
}
|
||||
|
||||
cvv = ThreadLocalRandom.current().nextLong(100, 999)
|
||||
|
||||
(card, callContext) <- NewStyle.function.createPhysicalCard(
|
||||
bankCardNumber=postJson.card_number,
|
||||
nameOnCard=postJson.name_on_card,
|
||||
cardType = postJson.card_type,
|
||||
issueNumber=postJson.issue_number,
|
||||
serialNumber=postJson.serial_number,
|
||||
validFrom=postJson.valid_from_date,
|
||||
expires=postJson.expires_date,
|
||||
enabled=postJson.enabled,
|
||||
cancelled=false,
|
||||
onHotList=false,
|
||||
technology=postJson.technology,
|
||||
networks= postJson.networks,
|
||||
allows= postJson.allows,
|
||||
accountId= postJson.account_id,
|
||||
bankId=bankId.value,
|
||||
replacement = replacement,
|
||||
pinResets= postJson.pin_reset.map(e => PinResetInfo(e.requested_date, PinResetReason.valueOf(e.reason_requested.toUpperCase))),
|
||||
collected = collected,
|
||||
posted = posted,
|
||||
customerId = postJson.customer_id,
|
||||
cvv = cvv.toString,
|
||||
brand = postJson.brand,
|
||||
callContext
|
||||
)
|
||||
} yield {
|
||||
//NOTE: OBP do not store the 3 digits cvv, only the hash, so we copy it here.
|
||||
(createPhysicalCardJson(card, u).copy(cvv=cvv.toString), HttpCode.`201`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -27,15 +27,17 @@
|
||||
package code.api.v5_0_0
|
||||
|
||||
import java.util.Date
|
||||
|
||||
import code.api.util.APIUtil.stringOrNull
|
||||
import code.api.util.APIUtil.{stringOptionOrNull, stringOrNull}
|
||||
import code.api.v1_2_1.BankRoutingJsonV121
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.{CustomerFaceImageJson, MetaJsonV140}
|
||||
import code.api.v1_3_0.JSONFactory1_3_0.{cardActionsToString, createAccountJson, createPinResetJson, createReplacementJson}
|
||||
import code.api.v1_3_0.{PinResetJSON, ReplacementJSON}
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.CustomerFaceImageJson
|
||||
import code.api.v2_1_0.CustomerCreditRatingJSON
|
||||
import code.api.v3_1_0.PostConsentEntitlementJsonV310
|
||||
import code.api.v3_1_0.{AccountBasicV310, PhysicalCardWithAttributesJsonV310, PostConsentEntitlementJsonV310}
|
||||
import code.api.v4_0_0.BankAttributeBankResponseJsonV400
|
||||
import code.bankattribute.BankAttribute
|
||||
import com.openbankproject.commons.model.{AccountRoutingJsonV121, AmountOfMoneyJsonV121, Bank, UserAuthContext, UserAuthContextUpdate}
|
||||
import com.openbankproject.commons.model.{AccountRoutingJsonV121, AmountOfMoneyJsonV121, Bank, CardAttribute, PhysicalCardTrait, User, UserAuthContext, UserAuthContextUpdate, View, ViewBasic}
|
||||
import net.liftweb.json.JsonAST.JValue
|
||||
|
||||
import scala.collection.immutable.List
|
||||
@ -149,6 +151,125 @@ case class PostConsentRequestJsonV500(
|
||||
)
|
||||
|
||||
case class ConsentJsonV500(consent_id: String, jwt: String, status: String, consent_request_id: Option[String])
|
||||
|
||||
case class CreatePhysicalCardJsonV500(
|
||||
card_number: String,
|
||||
card_type: String,
|
||||
name_on_card: String,
|
||||
issue_number: String,
|
||||
serial_number: String,
|
||||
valid_from_date: Date,
|
||||
expires_date: Date,
|
||||
enabled: Boolean,
|
||||
technology: String,
|
||||
networks: List[String],
|
||||
allows: List[String],
|
||||
account_id: String,
|
||||
replacement: Option[ReplacementJSON],
|
||||
pin_reset: List[PinResetJSON],
|
||||
collected: Option[Date],
|
||||
posted: Option[Date],
|
||||
customer_id: String,
|
||||
brand: String
|
||||
)
|
||||
|
||||
case class PhysicalCardJsonV500(
|
||||
card_id: String,
|
||||
bank_id: String,
|
||||
card_number: String,
|
||||
card_type: String,
|
||||
name_on_card: String,
|
||||
issue_number: String,
|
||||
serial_number: String,
|
||||
valid_from_date: Date,
|
||||
expires_date: Date,
|
||||
enabled: Boolean,
|
||||
cancelled: Boolean,
|
||||
on_hot_list: Boolean,
|
||||
technology: String,
|
||||
networks: List[String],
|
||||
allows: List[String],
|
||||
account: code.api.v1_2_1.AccountJSON,
|
||||
replacement: ReplacementJSON,
|
||||
pin_reset: List[PinResetJSON],
|
||||
collected: Date,
|
||||
posted: Date,
|
||||
customer_id: String,
|
||||
cvv: String,
|
||||
brand: String
|
||||
)
|
||||
|
||||
case class UpdatedPhysicalCardJsonV500(
|
||||
card_id: String,
|
||||
bank_id: String,
|
||||
card_number: String,
|
||||
card_type: String,
|
||||
name_on_card: String,
|
||||
issue_number: String,
|
||||
serial_number: String,
|
||||
valid_from_date: Date,
|
||||
expires_date: Date,
|
||||
enabled: Boolean,
|
||||
cancelled: Boolean,
|
||||
on_hot_list: Boolean,
|
||||
technology: String,
|
||||
networks: List[String],
|
||||
allows: List[String],
|
||||
account: code.api.v1_2_1.AccountJSON,
|
||||
replacement: ReplacementJSON,
|
||||
pin_reset: List[PinResetJSON],
|
||||
collected: Date,
|
||||
posted: Date,
|
||||
customer_id: String,
|
||||
brand: String
|
||||
)
|
||||
|
||||
case class PhysicalCardWithAttributesJsonV500(
|
||||
card_id: String,
|
||||
bank_id: String,
|
||||
card_number: String,
|
||||
card_type: String,
|
||||
name_on_card: String,
|
||||
issue_number: String,
|
||||
serial_number: String,
|
||||
valid_from_date: Date,
|
||||
expires_date: Date,
|
||||
enabled: Boolean,
|
||||
cancelled: Boolean,
|
||||
on_hot_list: Boolean,
|
||||
technology: String,
|
||||
networks: List[String],
|
||||
allows: List[String],
|
||||
account: AccountBasicV310,
|
||||
replacement: ReplacementJSON,
|
||||
pin_reset: List[PinResetJSON],
|
||||
collected: Date,
|
||||
posted: Date,
|
||||
customer_id: String,
|
||||
card_attributes: List[CardAttribute],
|
||||
brand: String
|
||||
)
|
||||
|
||||
case class UpdatePhysicalCardJsonV500(
|
||||
card_type: String,
|
||||
name_on_card: String,
|
||||
issue_number: String,
|
||||
serial_number: String,
|
||||
valid_from_date: Date,
|
||||
expires_date: Date,
|
||||
enabled: Boolean,
|
||||
technology: String,
|
||||
networks: List[String],
|
||||
allows: List[String],
|
||||
account_id: String,
|
||||
replacement: ReplacementJSON,
|
||||
pin_reset: List[PinResetJSON],
|
||||
collected: Date,
|
||||
posted: Date,
|
||||
customer_id: String,
|
||||
brand: String
|
||||
)
|
||||
|
||||
object JSONFactory500 {
|
||||
|
||||
def createUserAuthContextJson(userAuthContext: UserAuthContext): UserAuthContextJsonV500 = {
|
||||
@ -200,6 +321,64 @@ object JSONFactory500 {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def createPhysicalCardWithAttributesJson(card: PhysicalCardTrait, cardAttributes: List[CardAttribute],user : User, views: List[View]): PhysicalCardWithAttributesJsonV500 = {
|
||||
PhysicalCardWithAttributesJsonV500(
|
||||
card_id = stringOrNull(card.cardId),
|
||||
bank_id = stringOrNull(card.bankId),
|
||||
card_number = stringOrNull(card.bankCardNumber),
|
||||
card_type = stringOrNull(card.cardType),
|
||||
name_on_card = stringOrNull(card.nameOnCard),
|
||||
issue_number = stringOrNull(card.issueNumber),
|
||||
serial_number = stringOrNull(card.serialNumber),
|
||||
valid_from_date = card.validFrom,
|
||||
expires_date = card.expires,
|
||||
enabled = card.enabled,
|
||||
cancelled = card.cancelled,
|
||||
on_hot_list = card.onHotList,
|
||||
technology = stringOrNull(card.technology),
|
||||
networks = card.networks,
|
||||
allows = card.allows.map(cardActionsToString).toList,
|
||||
account = AccountBasicV310(
|
||||
card.account.accountId.value,
|
||||
card.account.label,
|
||||
views.map(view => ViewBasic(view.viewId.value, view.name, view.description)),
|
||||
card.account.bankId.value),
|
||||
replacement = card.replacement.map(createReplacementJson).getOrElse(null),
|
||||
pin_reset = card.pinResets.map(createPinResetJson),
|
||||
collected = card.collected.map(_.date).getOrElse(null),
|
||||
posted = card.posted.map(_.date).getOrElse(null),
|
||||
customer_id = stringOrNull(card.customerId),
|
||||
card_attributes = cardAttributes,
|
||||
brand = stringOptionOrNull(card.brand),
|
||||
)
|
||||
}
|
||||
def createPhysicalCardJson(card: PhysicalCardTrait, user : User): PhysicalCardJsonV500 = {
|
||||
PhysicalCardJsonV500(
|
||||
card_id = stringOrNull(card.cardId),
|
||||
bank_id = stringOrNull(card.bankId),
|
||||
card_number = stringOrNull(card.bankCardNumber),
|
||||
card_type = stringOrNull(card.cardType),
|
||||
name_on_card = stringOrNull(card.nameOnCard),
|
||||
issue_number = stringOrNull(card.issueNumber),
|
||||
serial_number = stringOrNull(card.serialNumber),
|
||||
valid_from_date = card.validFrom,
|
||||
expires_date = card.expires,
|
||||
enabled = card.enabled,
|
||||
cancelled = card.cancelled,
|
||||
on_hot_list = card.onHotList,
|
||||
technology = stringOrNull(card.technology),
|
||||
networks = card.networks,
|
||||
allows = card.allows.map(cardActionsToString).toList,
|
||||
account = createAccountJson(card.account, user),
|
||||
replacement = card.replacement.map(createReplacementJson).getOrElse(null),
|
||||
pin_reset = card.pinResets.map(createPinResetJson),
|
||||
collected = card.collected.map(_.date).getOrElse(null),
|
||||
posted = card.posted.map(_.date).getOrElse(null),
|
||||
customer_id = stringOrNull(card.customerId),
|
||||
cvv = stringOptionOrNull(card.cvv),
|
||||
brand = stringOptionOrNull(card.brand)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -628,6 +628,9 @@ trait Connector extends MdcLoggable {
|
||||
def getPhysicalCardsForUser(user : User, callContext: Option[CallContext] = None) : OBPReturnType[Box[List[PhysicalCard]]] = Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def getPhysicalCardForBank(bankId: BankId, cardId: String, callContext:Option[CallContext]) : OBPReturnType[Box[PhysicalCardTrait]] = Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def getPhysicalCardByCardNumber(bankCardNumber: String, callContext:Option[CallContext]) : OBPReturnType[Box[PhysicalCardTrait]] = Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def deletePhysicalCardForBank(bankId: BankId, cardId: String, callContext:Option[CallContext]) : OBPReturnType[Box[Boolean]] = Future{(Failure(setUnimplementedError), callContext)}
|
||||
|
||||
def getPhysicalCardsForBankLegacy(bank: Bank, user : User, queryParams: List[OBPQueryParam]) : Box[List[PhysicalCard]] = Failure(setUnimplementedError)
|
||||
@ -654,6 +657,8 @@ trait Connector extends MdcLoggable {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]
|
||||
): Box[PhysicalCard] = Failure(setUnimplementedError)
|
||||
|
||||
@ -678,6 +683,8 @@ trait Connector extends MdcLoggable {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]
|
||||
): OBPReturnType[Box[PhysicalCard]] = Future{(Failure{setUnimplementedError}, callContext)}
|
||||
|
||||
@ -1415,7 +1422,7 @@ trait Connector extends MdcLoggable {
|
||||
}yield{
|
||||
(createdTransactionId,callContext)
|
||||
}
|
||||
case transactionRequestType => Future((throw new Exception(s"${InvalidTransactionRequestType}: '${transactionRequestType}'. Not supported in this version.")), callContext)
|
||||
case _ => Future((throw new Exception(s"${InvalidTransactionRequestType}: '${transactionRequestType}'. Not completed in this version.")), callContext)
|
||||
}
|
||||
|
||||
didSaveTransId <- Future{saveTransactionRequestTransaction(transactionRequestId, transactionId).openOrThrowException(attemptedToOpenAnEmptyBox)}
|
||||
|
||||
@ -1204,7 +1204,9 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
pinResets = l.pinResets,
|
||||
collected = l.collected,
|
||||
posted = l.posted,
|
||||
customerId = l.customerId
|
||||
customerId = l.customerId,
|
||||
cvv = l.cvv,
|
||||
brand = l.brand
|
||||
)
|
||||
(Full(cardList), callContext)
|
||||
}
|
||||
@ -1216,6 +1218,13 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
)
|
||||
}
|
||||
|
||||
override def getPhysicalCardByCardNumber(bankCardNumber: String, callContext:Option[CallContext]) : OBPReturnType[Box[PhysicalCardTrait]] = Future {
|
||||
(
|
||||
code.cards.PhysicalCard.physicalCardProvider.vend.getPhysicalCardByCardNumber(bankCardNumber: String, callContext: Option[CallContext]),
|
||||
callContext
|
||||
)
|
||||
}
|
||||
|
||||
override def getPhysicalCardsForBankLegacy(bank: Bank, user: User, queryParams: List[OBPQueryParam]): Box[List[PhysicalCard]] = {
|
||||
val list = code.cards.PhysicalCard.physicalCardProvider.vend.getPhysicalCardsForBank(bank, user, queryParams)
|
||||
val cardList = for (l <- list) yield
|
||||
@ -1240,7 +1249,9 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
pinResets = l.pinResets,
|
||||
collected = l.collected,
|
||||
posted = l.posted,
|
||||
customerId = l.customerId
|
||||
customerId = l.customerId,
|
||||
cvv = l.cvv,
|
||||
brand = l.brand
|
||||
)
|
||||
Full(cardList)
|
||||
}
|
||||
@ -1276,6 +1287,8 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = Future {
|
||||
(createPhysicalCardLegacy(
|
||||
bankCardNumber: String,
|
||||
@ -1298,6 +1311,8 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]),
|
||||
callContext)
|
||||
}
|
||||
@ -1324,6 +1339,8 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]): Box[PhysicalCard] = {
|
||||
val physicalCardBox: Box[MappedPhysicalCard] = code.cards.PhysicalCard.physicalCardProvider.vend.createPhysicalCard(
|
||||
bankCardNumber: String,
|
||||
@ -1346,6 +1363,8 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext])
|
||||
|
||||
for (l <- physicalCardBox) yield
|
||||
@ -1370,7 +1389,9 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
pinResets = l.pinResets,
|
||||
collected = l.collected,
|
||||
posted = l.posted,
|
||||
customerId = l.customerId
|
||||
customerId = l.customerId,
|
||||
cvv = l.cvv,
|
||||
brand = l.brand,
|
||||
)
|
||||
}
|
||||
|
||||
@ -5088,7 +5109,7 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
} yield {
|
||||
(transactionId, callContext)
|
||||
}
|
||||
case COUNTERPARTY =>
|
||||
case COUNTERPARTY | CARD =>
|
||||
for {
|
||||
bodyToCounterparty <- NewStyle.function.tryons(s"$TransactionRequestDetailsExtractException It can not extract to $TransactionRequestBodyCounterpartyJSON", 400, callContext) {
|
||||
body.to_counterparty.get
|
||||
|
||||
@ -1430,7 +1430,8 @@ object AkkaConnector_vDec2018 extends Connector with AkkaConnectorActorInit {
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value)))
|
||||
customerId=customerIdExample.value
|
||||
)))
|
||||
),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
@ -1496,7 +1497,8 @@ object AkkaConnector_vDec2018 extends Connector with AkkaConnectorActorInit {
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value))
|
||||
customerId=customerIdExample.value
|
||||
))
|
||||
),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
@ -1652,7 +1654,9 @@ object AkkaConnector_vDec2018 extends Connector with AkkaConnectorActorInit {
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value)
|
||||
customerId=customerIdExample.value,
|
||||
cvv = cvvExample.value,
|
||||
brand = brandExample.value)
|
||||
),
|
||||
exampleInboundMessage = (
|
||||
InBoundCreatePhysicalCard(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext,
|
||||
@ -1701,9 +1705,14 @@ object AkkaConnector_vDec2018 extends Connector with AkkaConnectorActorInit {
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
|
||||
override def createPhysicalCard(bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String, serialNumber: String, validFrom: Date, expires: Date, enabled: Boolean, cancelled: Boolean, onHotList: Boolean, technology: String, networks: List[String], allows: List[String], accountId: String, bankId: String, replacement: Option[CardReplacementInfo], pinResets: List[PinResetInfo], collected: Option[CardCollectionInfo], posted: Option[CardPostedInfo], customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = {
|
||||
override def createPhysicalCard(bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String,
|
||||
serialNumber: String, validFrom: Date, expires: Date, enabled: Boolean, cancelled: Boolean, onHotList: Boolean,
|
||||
technology: String, networks: List[String], allows: List[String], accountId: String, bankId: String,
|
||||
replacement: Option[CardReplacementInfo], pinResets: List[PinResetInfo], collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo], customerId: String, cvv: String, brand: String,
|
||||
callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = {
|
||||
import com.openbankproject.commons.dto.{InBoundCreatePhysicalCard => InBound, OutBoundCreatePhysicalCard => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankCardNumber, nameOnCard, cardType, issueNumber, serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId)
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankCardNumber, nameOnCard, cardType, issueNumber, serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId, cvv, brand)
|
||||
val response: Future[Box[InBound]] = (southSideActor ? req).mapTo[InBound].recoverWith(recoverFunction).map(Box !! _)
|
||||
response.map(convertToTuple[PhysicalCard](callContext))
|
||||
}
|
||||
|
||||
@ -1570,7 +1570,8 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value)))
|
||||
customerId=customerIdExample.value
|
||||
)))
|
||||
),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
@ -1750,8 +1751,7 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value)))
|
||||
),
|
||||
customerId=customerIdExample.value)))),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
|
||||
@ -1792,8 +1792,9 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value)
|
||||
),
|
||||
customerId=customerIdExample.value,
|
||||
cvv = cvvExample.value,
|
||||
brand = brandExample.value)),
|
||||
exampleInboundMessage = (
|
||||
InBoundCreatePhysicalCard(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext,
|
||||
status=MessageDocsSwaggerDefinitions.inboundStatus,
|
||||
@ -1836,14 +1837,18 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value))
|
||||
),
|
||||
customerId=customerIdExample.value,
|
||||
cvv = Some(cvvExample.value),
|
||||
brand = Some(brandExample.value)))),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
|
||||
override def createPhysicalCard(bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String, serialNumber: String, validFrom: Date, expires: Date, enabled: Boolean, cancelled: Boolean, onHotList: Boolean, technology: String, networks: List[String], allows: List[String], accountId: String, bankId: String, replacement: Option[CardReplacementInfo], pinResets: List[PinResetInfo], collected: Option[CardCollectionInfo], posted: Option[CardPostedInfo], customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = {
|
||||
import com.openbankproject.commons.dto.{InBoundCreatePhysicalCard => InBound, OutBoundCreatePhysicalCard => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankCardNumber, nameOnCard, cardType, issueNumber, serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId)
|
||||
override def createPhysicalCard(bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String, serialNumber: String, validFrom: Date, expires: Date, enabled: Boolean,
|
||||
cancelled: Boolean, onHotList: Boolean, technology: String, networks: List[String], allows: List[String], accountId: String, bankId: String, replacement: Option[CardReplacementInfo],
|
||||
pinResets: List[PinResetInfo], collected: Option[CardCollectionInfo], posted: Option[CardPostedInfo], customerId: String, cvv: String,
|
||||
brand: String,callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = {
|
||||
import com.openbankproject.commons.dto.{InBoundCreatePhysicalCard => InBound, OutBoundCreatePhysicalCard => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankCardNumber, nameOnCard, cardType, issueNumber, serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId,cvv, brand)
|
||||
val response: Future[Box[InBound]] = sendRequest[InBound](getUrl(callContext, "createPhysicalCard"), HttpMethods.POST, req, callContext)
|
||||
response.map(convertToTuple[PhysicalCard](callContext))
|
||||
}
|
||||
|
||||
@ -1615,7 +1615,8 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value))
|
||||
customerId=customerIdExample.value
|
||||
))
|
||||
),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
@ -1729,7 +1730,8 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value)))
|
||||
customerId=customerIdExample.value
|
||||
)))
|
||||
),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
@ -1771,7 +1773,9 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value)
|
||||
customerId=customerIdExample.value,
|
||||
cvv = cvvExample.value,
|
||||
brand = brandExample.value)
|
||||
),
|
||||
exampleInboundMessage = (
|
||||
InBoundCreatePhysicalCard(inboundAdapterCallContext=MessageDocsSwaggerDefinitions.inboundAdapterCallContext,
|
||||
@ -1815,14 +1819,20 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
|
||||
reasonRequested=com.openbankproject.commons.model.PinResetReason.FORGOT)),
|
||||
collected=Some(CardCollectionInfo(toDate(collectedExample))),
|
||||
posted=Some(CardPostedInfo(toDate(postedExample))),
|
||||
customerId=customerIdExample.value))
|
||||
customerId=customerIdExample.value
|
||||
))
|
||||
),
|
||||
adapterImplementation = Some(AdapterImplementation("- Core", 1))
|
||||
)
|
||||
|
||||
override def createPhysicalCard(bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String, serialNumber: String, validFrom: Date, expires: Date, enabled: Boolean, cancelled: Boolean, onHotList: Boolean, technology: String, networks: List[String], allows: List[String], accountId: String, bankId: String, replacement: Option[CardReplacementInfo], pinResets: List[PinResetInfo], collected: Option[CardCollectionInfo], posted: Option[CardPostedInfo], customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = {
|
||||
import com.openbankproject.commons.dto.{InBoundCreatePhysicalCard => InBound, OutBoundCreatePhysicalCard => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankCardNumber, nameOnCard, cardType, issueNumber, serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId)
|
||||
override def createPhysicalCard(bankCardNumber: String, nameOnCard: String, cardType: String, issueNumber: String, serialNumber: String,
|
||||
validFrom: Date, expires: Date, enabled: Boolean, cancelled: Boolean, onHotList: Boolean, technology: String, networks: List[String],
|
||||
allows: List[String], accountId: String, bankId: String, replacement: Option[CardReplacementInfo], pinResets: List[PinResetInfo],
|
||||
collected: Option[CardCollectionInfo], posted: Option[CardPostedInfo], customerId: String, cvv: String,
|
||||
brand: String, callContext: Option[CallContext]): OBPReturnType[Box[PhysicalCard]] = {
|
||||
import com.openbankproject.commons.dto.{InBoundCreatePhysicalCard => InBound, OutBoundCreatePhysicalCard => OutBound}
|
||||
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull, bankCardNumber, nameOnCard, cardType, issueNumber,
|
||||
serialNumber, validFrom, expires, enabled, cancelled, onHotList, technology, networks, allows, accountId, bankId, replacement, pinResets, collected, posted, customerId, cvv, brand)
|
||||
val response: Future[Box[InBound]] = sendRequest[InBound]("obp_create_physical_card", req, callContext)
|
||||
response.map(convertToTuple[PhysicalCard](callContext))
|
||||
}
|
||||
|
||||
@ -139,6 +139,8 @@ object MappedPhysicalCardProvider extends PhysicalCardProvider {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]
|
||||
): Box[MappedPhysicalCard] = {
|
||||
|
||||
@ -196,6 +198,8 @@ object MappedPhysicalCardProvider extends PhysicalCardProvider {
|
||||
.mPosted(p.date)
|
||||
.mAccount(mappedBankAccountPrimaryKey) // Card <-MappedLongForeignKey-> BankAccount, so need the primary key here.
|
||||
.mCustomerId(customerId)
|
||||
.mBrand(brand)
|
||||
.mCVV(HashUtil.Sha256Hash(cvv))
|
||||
.saveMe()
|
||||
} ?~! ErrorMessages.CreateCardError
|
||||
}
|
||||
@ -231,6 +235,12 @@ object MappedPhysicalCardProvider extends PhysicalCardProvider {
|
||||
}
|
||||
cards
|
||||
}
|
||||
|
||||
override def getPhysicalCardByCardNumber(bankCardNumber: String, callContext:Option[CallContext]) : Box[PhysicalCardTrait] = {
|
||||
MappedPhysicalCard.find(
|
||||
By(MappedPhysicalCard.mBankCardNumber, bankCardNumber),
|
||||
)
|
||||
}
|
||||
|
||||
def getPhysicalCardsForBank(bank: Bank, user: User, queryParams: List[OBPQueryParam]) = {
|
||||
val customerId: Option[Cmp[MappedPhysicalCard, String]] = queryParams.collect { case OBPCustomerId(value) =>
|
||||
@ -312,6 +322,9 @@ class MappedPhysicalCard extends PhysicalCardTrait with LongKeyedMapper[MappedPh
|
||||
//Maybe this will be first uesd for the initialization. and then we can add more `allows` for this card.
|
||||
object mCardType extends MappedString(this, 255)
|
||||
object mCustomerId extends MappedString(this, 255)
|
||||
|
||||
object mBrand extends MappedString(this, 255)
|
||||
object mCVV extends MappedString(this, 255)
|
||||
|
||||
def bankId: String = mBankId.get
|
||||
def bankCardNumber: String = mBankCardNumber.get
|
||||
@ -353,6 +366,8 @@ class MappedPhysicalCard extends PhysicalCardTrait with LongKeyedMapper[MappedPh
|
||||
def cardType: String = mCardType.get
|
||||
def cardId: String = mCardId.get
|
||||
def customerId: String = mCustomerId.get
|
||||
override def cvv: Option[String] = Some(mCVV.get)
|
||||
override def brand: Option[String] = Some(mBrand.get)
|
||||
}
|
||||
|
||||
object MappedPhysicalCard extends MappedPhysicalCard with LongKeyedMetaMapper[MappedPhysicalCard] {
|
||||
|
||||
@ -41,6 +41,8 @@ trait PhysicalCardProvider {
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String,
|
||||
callContext: Option[CallContext]
|
||||
): Box[MappedPhysicalCard]
|
||||
|
||||
@ -76,6 +78,8 @@ trait PhysicalCardProvider {
|
||||
def getPhysicalCardForBank(bankId: BankId, cardId: String, callContext:Option[CallContext]) : Box[PhysicalCardTrait]
|
||||
|
||||
def deletePhysicalCardForBank(bankId: BankId, cardId: String, callContext:Option[CallContext]) : Box[Boolean]
|
||||
|
||||
def getPhysicalCardByCardNumber(bankCardNumber: String, callContext:Option[CallContext]) : Box[PhysicalCardTrait]
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -273,7 +273,8 @@ class MappedTransactionRequest extends LongKeyedMapper[MappedTransactionRequest]
|
||||
else
|
||||
None
|
||||
|
||||
val t_to_counterparty = if (TransactionRequestTypes.withName(transactionType) == TransactionRequestTypes.COUNTERPARTY){
|
||||
val t_to_counterparty = if (TransactionRequestTypes.withName(transactionType) == TransactionRequestTypes.COUNTERPARTY ||
|
||||
TransactionRequestTypes.withName(transactionType) == TransactionRequestTypes.CARD){
|
||||
val counterpartyIdList: List[String] = for {
|
||||
JObject(child) <- parsedDetails
|
||||
JField("counterparty_id", JString(counterpartyId)) <- child
|
||||
|
||||
@ -17,7 +17,7 @@ object TransactionRequests extends SimpleInjector {
|
||||
|
||||
object TransactionRequestTypes extends Enumeration {
|
||||
type TransactionRequestTypes = Value
|
||||
val SANDBOX_TAN, ACCOUNT, ACCOUNT_OTP, COUNTERPARTY, SEPA, FREE_FORM, SIMPLE,
|
||||
val SANDBOX_TAN, ACCOUNT, ACCOUNT_OTP, COUNTERPARTY, SEPA, FREE_FORM, SIMPLE, CARD,
|
||||
TRANSFER_TO_PHONE, TRANSFER_TO_ATM, TRANSFER_TO_ACCOUNT, TRANSFER_TO_REFERENCE_ACCOUNT,
|
||||
//The following are BerlinGroup Standard
|
||||
SEPA_CREDIT_TRANSFERS, INSTANT_SEPA_CREDIT_TRANSFERS, TARGET_2_PAYMENTS, CROSS_BORDER_CREDIT_TRANSFERS, REFUND = Value
|
||||
|
||||
@ -43,7 +43,7 @@ class PhysicalCardsTest extends ServerSetup with DefaultUsers with DefaultConne
|
||||
pinResets = Nil,
|
||||
collected = None,
|
||||
posted = None,
|
||||
customerId = ""
|
||||
customerId = "",
|
||||
)
|
||||
|
||||
val user1CardAtBank1 = createCard("1")
|
||||
|
||||
@ -1,19 +1,22 @@
|
||||
package code.api.v4_0_0
|
||||
|
||||
import java.util.UUID
|
||||
import java.util.{Date, UUID}
|
||||
import code.api.ChargePolicy
|
||||
import code.api.Constant._
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.createPhysicalCardJsonV500
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.APIUtil.extractErrorMessageCode
|
||||
import code.api.util.ApiRole.CanCreateAnyTransactionRequest
|
||||
import code.api.util.ApiRole.{CanCreateAnyTransactionRequest, CanCreateCardsForBank}
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.util.{APIUtil, ErrorMessages}
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.{ChallengeAnswerJSON, TransactionRequestAccountJsonV140}
|
||||
import code.api.v2_0_0.TransactionRequestBodyJsonV200
|
||||
import code.api.v2_1_0._
|
||||
import code.api.v4_0_0.APIMethods400.Implementations4_0_0
|
||||
import code.api.v5_0_0.PhysicalCardJsonV500
|
||||
import code.bankconnectors.Connector
|
||||
import code.entitlement.Entitlement
|
||||
import code.fx.fx
|
||||
import code.model.BankAccountX
|
||||
import code.setup.{APIResponse, DefaultUsers}
|
||||
@ -46,6 +49,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
object ApiEndpoint7 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestFreeForm))
|
||||
object ApiEndpoint8 extends Tag(nameOf(Implementations4_0_0.answerTransactionRequestChallenge))
|
||||
object ApiEndpoint9 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestSimple))
|
||||
object ApiEndpoint10 extends Tag(nameOf(Implementations4_0_0.createTransactionRequestCard))
|
||||
|
||||
def transactionCount(accounts: BankAccount*): Int = {
|
||||
accounts.foldLeft(0)((accumulator, account) => {
|
||||
@ -133,6 +137,33 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
other_account_secondary_routing_address= counterpartyCounterparty.otherAccountSecondaryRoutingAddress
|
||||
), bodyValue, description, sharedChargePolicy)
|
||||
|
||||
val customerId = createAndGetCustomerIdViaEndpoint(bankId.value, user1)
|
||||
val requestWithAuthUser = (v5_0_0_Request / "management" /"banks" / bankId.value / "cards" ).POST <@ (user1)
|
||||
val properCardJson = createPhysicalCardJsonV500.copy(
|
||||
account_id = fromAccount.accountId.value,
|
||||
issue_number = "123",
|
||||
customer_id = customerId,
|
||||
expires_date = org.apache.commons.lang3.time.DateUtils.addMonths(new Date(), 3)
|
||||
)
|
||||
Entitlement.entitlement.vend.addEntitlement(bankId.value, resourceUser1.userId, CanCreateCardsForBank.toString)
|
||||
val responseProper = makePostRequest(requestWithAuthUser, write(properCardJson))
|
||||
val cardJsonV500 = responseProper.body.extract[PhysicalCardJsonV500]
|
||||
|
||||
var transactionRequestBodyCard = TransactionRequestBodyCardJsonV400(
|
||||
card = CardJsonV400(
|
||||
card_type = cardJsonV500.card_type,
|
||||
brand = cardJsonV500.brand,
|
||||
cvv = cardJsonV500.cvv,
|
||||
card_number = cardJsonV500.card_number,
|
||||
name_on_card = cardJsonV500.name_on_card,
|
||||
expiry_year = (cardJsonV500.expires_date.getYear+1900).toString,
|
||||
expiry_month = (cardJsonV500.expires_date.getMonth+1).toString
|
||||
),
|
||||
CounterpartyIdJson(counterpartyCounterparty.counterpartyId),
|
||||
bodyValue,
|
||||
description
|
||||
)
|
||||
|
||||
def setAnswerTransactionRequest(challengeId: String = this.challengeId, transRequestId: String = this.transRequestId, consumerAndToken: Option[(Consumer, Token)] = user1 , challengeAnswer:String = "123") = {
|
||||
this.challengeId = challengeId
|
||||
this.transRequestId = transRequestId
|
||||
@ -154,11 +185,14 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
*/
|
||||
var createTransReqRequest = (v4_0_0_Request / "banks" / testBank.bankId.value / "accounts" / fromAccount.accountId.value /
|
||||
CUSTOM_OWNER_VIEW_ID / "transaction-request-types" / transactionRequestType / "transaction-requests").POST <@ (user1)
|
||||
|
||||
|
||||
var createTransReqRequestCard = (v4_0_0_Request / "transaction-request-types" / "CARD" / "transaction-requests").POST <@ (user1)
|
||||
|
||||
def makeCreateTransReqRequest: APIResponse = makePostRequest(createTransReqRequest, write(transactionRequestBody))
|
||||
def makeCreateTransReqRequestSEPA: APIResponse = makePostRequest(createTransReqRequest, write(transactionRequestBodySEPA))
|
||||
def makeCreateTransReqRequestCounterparty: APIResponse = makePostRequest(createTransReqRequest, write(transactionRequestBodyCounterparty))
|
||||
def makeCreateTransReqRequestSimple: APIResponse = makePostRequest(createTransReqRequest, write(transactionRequestBodySimple))
|
||||
def makeCreateTransReqRequestCard: APIResponse = makePostRequest(createTransReqRequestCard, write(transactionRequestBodyCard))
|
||||
|
||||
def checkAllCreateTransReqResBodyField(createTransactionRequestResponse: APIResponse, withChallenge: Boolean): Unit = {
|
||||
Then("we should get a 201 created code")
|
||||
@ -397,9 +431,9 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
|
||||
Then("we should get a 400 created code")
|
||||
response.code should equal(400)
|
||||
|
||||
|
||||
response.body.extract[ErrorMessage].message should startWith(ErrorMessages.InvalidTransactionRequestType)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,7 +555,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
|
||||
|
||||
scenario("With challenge, No FX, test the allowed_attempts times ", ApiEndpoint1, ApiEndpoint2) {
|
||||
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
|
||||
val helper = defaultSetup()
|
||||
@ -539,7 +573,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
And("We checked all the fields of createTransactionRequestResponse body ")
|
||||
helper.checkAllCreateTransReqResBodyField(createTransactionRequestResponse, true)
|
||||
|
||||
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest(challengeAnswer ="1234")
|
||||
@ -594,7 +628,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest()
|
||||
@ -602,7 +636,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
val ansReqResponse = helper.makeAnswerRequest
|
||||
And("We check the all the fields of getAnsReqResponse body ")
|
||||
helper.checkAllAnsTransReqBodyFields(ansReqResponse, true)
|
||||
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
@ -619,7 +653,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
|
||||
val helper = defaultSetup(FREE_FORM.toString)
|
||||
addEntitlement(helper.bankId.value, resourceUser1.userId, CanCreateAnyTransactionRequest.toString)
|
||||
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequest
|
||||
|
||||
@ -767,7 +801,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest()
|
||||
@ -775,7 +809,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
val ansReqResponse = helper.makeAnswerRequest
|
||||
And("We check the all the fields of getAnsReqResponse body ")
|
||||
helper.checkAllAnsTransReqBodyFields(ansReqResponse, true)
|
||||
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
@ -936,7 +970,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest()
|
||||
@ -944,7 +978,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
val ansReqResponse = helper.makeAnswerRequest
|
||||
And("We check the all the fields of getAnsReqResponse body ")
|
||||
helper.checkAllAnsTransReqBodyFields(ansReqResponse, true)
|
||||
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
@ -1105,7 +1139,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest()
|
||||
@ -1113,7 +1147,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
val ansReqResponse = helper.makeAnswerRequest
|
||||
And("We check the all the fields of getAnsReqResponse body ")
|
||||
helper.checkAllAnsTransReqBodyFields(ansReqResponse, true)
|
||||
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
@ -1152,12 +1186,12 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
user1,
|
||||
PostViewJsonV400(view_id = "owner", is_system = true)
|
||||
)
|
||||
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequestCounterparty
|
||||
val createTransactionRequestJsonResponse = createTransactionRequestResponse.body.extract[TransactionRequestWithChargeJSON400]
|
||||
createTransactionRequestJsonResponse.status should equal(TransactionRequestStatus.INITIATED.toString)
|
||||
|
||||
|
||||
val challengeOfUser1: Option[ChallengeJsonV400] = createTransactionRequestJsonResponse.challenges.find(_.user_id == resourceUser1.userId)
|
||||
val challengeOfUser2: Option[ChallengeJsonV400] = createTransactionRequestJsonResponse.challenges.find(_.user_id == resourceUser2.userId)
|
||||
|
||||
@ -1199,7 +1233,6 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
|
||||
}
|
||||
|
||||
|
||||
feature("we can create transaction requests -- SIMPLE") {
|
||||
|
||||
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
|
||||
@ -1354,7 +1387,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest()
|
||||
@ -1362,7 +1395,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
val ansReqResponse = helper.makeAnswerRequest
|
||||
And("We check the all the fields of getAnsReqResponse body ")
|
||||
helper.checkAllAnsTransReqBodyFields(ansReqResponse, true)
|
||||
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
@ -1401,15 +1434,15 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
user1,
|
||||
PostViewJsonV400(view_id = "owner", is_system = true)
|
||||
)
|
||||
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequestSimple
|
||||
val createTransactionRequestJsonResponse = createTransactionRequestResponse.body.extract[TransactionRequestWithChargeJSON400]
|
||||
createTransactionRequestJsonResponse.status should equal(TransactionRequestStatus.INITIATED.toString)
|
||||
|
||||
|
||||
val challengeOfUser1: Option[ChallengeJsonV400] = createTransactionRequestJsonResponse.challenges.find(_.user_id == resourceUser1.userId)
|
||||
val challengeOfUser2: Option[ChallengeJsonV400] = createTransactionRequestJsonResponse.challenges.find(_.user_id == resourceUser2.userId)
|
||||
|
||||
|
||||
Then("We checked all the fields of createTransactionRequestResponse body ")
|
||||
helper.checkAllCreateTransReqResBodyField(createTransactionRequestResponse, true)
|
||||
|
||||
@ -1433,7 +1466,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
And("we call the endpoint")
|
||||
val ansReqResponseUser1 = helper.makeAnswerRequest
|
||||
ansReqResponseUser1.body.extract[ErrorMessage].message contains extractErrorMessageCode(NextChallengePending) should be (true)
|
||||
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest(
|
||||
@ -1445,7 +1478,272 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
ansReqResponseUser2.body.extract[TransactionRequestWithChargeJSON400].status should equal(TransactionRequestStatus.COMPLETED.toString)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
feature("we can create transaction requests -- CARD") {
|
||||
|
||||
setPropsValues("transactionRequests_supported_types" -> "SEPA,SANDBOX_TAN,FREE_FORM,COUNTERPARTY,ACCOUNT,ACCOUNT_OTP,SIMPLE,CARD")
|
||||
setPropsValues("CARD_OTP_INSTRUCTION_TRANSPORT" -> "DUMMY")
|
||||
|
||||
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
|
||||
ignore("No challenge, No FX ", ApiEndpoint10) {}
|
||||
} else {
|
||||
scenario("No challenge, No FX ", ApiEndpoint10) {
|
||||
setPropsValues("transactionRequests_supported_types" -> "SEPA,SANDBOX_TAN,FREE_FORM,COUNTERPARTY,ACCOUNT,ACCOUNT_OTP,SIMPLE,CARD")
|
||||
setPropsValues("CARD_OTP_INSTRUCTION_TRANSPORT" -> "DUMMY")
|
||||
|
||||
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
|
||||
val helper = defaultSetup(CARD.toString)
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequestCard
|
||||
|
||||
Then("We checked all the fields of createTransact dionRequestResponse body ")
|
||||
helper.checkAllCreateTransReqResBodyField(createTransactionRequestResponse, false)
|
||||
|
||||
When("we need check the 'Get all Transaction Requests. - V400' to double check it in database")
|
||||
val getTransReqResponse = helper.makeGetTransReqRequest
|
||||
|
||||
Then("We checked all the fields of getTransReqResponse body")
|
||||
helper.checkAllGetTransReqResBodyField(getTransReqResponse, false)
|
||||
|
||||
When("we need to check the 'Get Transactions for Account (Full) -V400' to check the transaction info ")
|
||||
val getTransResponse = helper.makeGetTransRequest
|
||||
Then("We checked all the fields of getTransResponse body")
|
||||
helper.checkAllGetTransResBodyField(getTransResponse, false)
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
}
|
||||
|
||||
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
|
||||
ignore("No challenge, With FX ", ApiEndpoint10) {}
|
||||
} else {
|
||||
scenario("No challenge, With FX ", ApiEndpoint10) {
|
||||
|
||||
setPropsValues("transactionRequests_supported_types" -> "SEPA,SANDBOX_TAN,FREE_FORM,COUNTERPARTY,ACCOUNT,ACCOUNT_OTP,SIMPLE,CARD")
|
||||
setPropsValues("CARD_OTP_INSTRUCTION_TRANSPORT" -> "DUMMY")
|
||||
|
||||
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
|
||||
val helper = defaultSetup(CARD.toString)
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val fromCurrency = "AED"
|
||||
val toCurrency = "INR"
|
||||
val amt = "10"
|
||||
helper.setCurrencyAndAmt(fromCurrency, toCurrency, amt)
|
||||
And("We set the special input JSON values for 'V400 Create Transaction Request' endpoint")
|
||||
helper.bodyValue = AmountOfMoneyJsonV121(fromCurrency, amt.toString())
|
||||
helper.transactionRequestBodyCard = helper.transactionRequestBodyCard.copy(value=helper.bodyValue)
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequestCard
|
||||
|
||||
Then("We checked all the fields of createTransactionRequestResponse body ")
|
||||
helper.checkAllCreateTransReqResBodyField(createTransactionRequestResponse, false)
|
||||
|
||||
When("we need check the 'Get all Transaction Requests. - V400' to double check it in database")
|
||||
val getTransReqResponse = helper.makeGetTransReqRequest
|
||||
|
||||
Then("We checked all the fields of getTransReqResponse body")
|
||||
helper.checkAllGetTransReqResBodyField(getTransReqResponse, false)
|
||||
|
||||
When("we need to check the 'Get Transactions for Account (Full) -V400' to check the transaction info ")
|
||||
val getTransResponse = helper.makeGetTransRequest
|
||||
Then("We checked all the fields of getTransResponse body")
|
||||
helper.checkAllGetTransResBodyField(getTransResponse, false)
|
||||
|
||||
When("We checked all the data in database, we need check the account amout info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
|
||||
ignore("With challenge, No FX ", ApiEndpoint10) {}
|
||||
} else {
|
||||
scenario("With challenge, No FX ", ApiEndpoint10) {
|
||||
setPropsValues("transactionRequests_supported_types" -> "SEPA,SANDBOX_TAN,FREE_FORM,COUNTERPARTY,ACCOUNT,ACCOUNT_OTP,SIMPLE,CARD")
|
||||
setPropsValues("CARD_OTP_INSTRUCTION_TRANSPORT" -> "DUMMY")
|
||||
|
||||
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
|
||||
val helper = defaultSetup(CARD.toString)
|
||||
And("We set the special conditions for different currencies")
|
||||
val fromCurrency = "AED"
|
||||
val toCurrency = "AED"
|
||||
val amt = "50000.00"
|
||||
helper.setCurrencyAndAmt(fromCurrency, toCurrency, amt)
|
||||
And("We set the special input JSON values for 'V400 Create Transaction Request' endpoint")
|
||||
helper.bodyValue = AmountOfMoneyJsonV121(fromCurrency, amt.toString())
|
||||
helper.transactionRequestBodyCard = helper.transactionRequestBodyCard.copy(value=helper.bodyValue)
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequestCard
|
||||
And("We checked all the fields of createTransactionRequestResponse body ")
|
||||
helper.checkAllCreateTransReqResBodyField(createTransactionRequestResponse, true)
|
||||
|
||||
Then("we need check the 'Get all Transaction Requests. - V400' to double check it in database")
|
||||
val getTransReqResponse = helper.makeGetTransReqRequest
|
||||
And("We checked all the fields of getTransReqResponse body")
|
||||
helper.checkAllGetTransReqResBodyField(getTransReqResponse, true)
|
||||
|
||||
Then("we need to check the 'Get Transactions for Account (Full) -V400' to check the transaction info ")
|
||||
val getTransResponse = helper.makeGetTransRequest
|
||||
And("We checked all the fields of getTransResponse body")
|
||||
helper.checkAllGetTransResBodyField(getTransResponse, true)
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest()
|
||||
And("we call the endpoint")
|
||||
val ansReqResponse = helper.makeAnswerRequest
|
||||
And("We check the all the fields of getAnsReqResponse body ")
|
||||
helper.checkAllAnsTransReqBodyFields(ansReqResponse, true)
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
}
|
||||
|
||||
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
|
||||
ignore("With challenge, With FX", ApiEndpoint10) {}
|
||||
} else {
|
||||
scenario("With challenge, With FX", ApiEndpoint10) {
|
||||
setPropsValues("transactionRequests_supported_types" -> "SEPA,SANDBOX_TAN,FREE_FORM,COUNTERPARTY,ACCOUNT,ACCOUNT_OTP,SIMPLE,CARD")
|
||||
setPropsValues("CARD_OTP_INSTRUCTION_TRANSPORT" -> "DUMMY")
|
||||
|
||||
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
|
||||
val helper = defaultSetup(CARD.toString)
|
||||
|
||||
And("We set the special conditions for different currencies")
|
||||
val fromCurrency = "AED"
|
||||
val toCurrency = "INR"
|
||||
val amt = "50000.00"
|
||||
helper.setCurrencyAndAmt(fromCurrency, toCurrency, amt)
|
||||
|
||||
And("We set the special input JSON values for 'V400 Create Transaction Request' endpoint")
|
||||
helper.bodyValue = AmountOfMoneyJsonV121(fromCurrency, amt.toString())
|
||||
helper.transactionRequestBodyCard = helper.transactionRequestBodyCard.copy(value=helper.bodyValue)
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequestCard
|
||||
|
||||
Then("We checked all the fields of createTransactionRequestResponse body ")
|
||||
helper.checkAllCreateTransReqResBodyField(createTransactionRequestResponse, true)
|
||||
|
||||
When("we need check the 'Get all Transaction Requests. - V400' to double check it in database")
|
||||
val getTransReqResponse = helper.makeGetTransReqRequest
|
||||
|
||||
Then("We checked all the fields of getTransReqResponse body")
|
||||
helper.checkAllGetTransReqResBodyField(getTransReqResponse, true)
|
||||
|
||||
When("we need to check the 'Get Transactions for Account (Full) -V400' to check the transaction info ")
|
||||
val getTransResponse = helper.makeGetTransRequest
|
||||
Then("We checked all the fields of getTransResponse body")
|
||||
helper.checkAllGetTransResBodyField(getTransResponse, true)
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest()
|
||||
And("we call the endpoint")
|
||||
val ansReqResponse = helper.makeAnswerRequest
|
||||
And("We check the all the fields of getAnsReqResponse body ")
|
||||
helper.checkAllAnsTransReqBodyFields(ansReqResponse, true)
|
||||
|
||||
Then("we need check the account amount info")
|
||||
helper.checkBankAccountBalance(true)
|
||||
}
|
||||
}
|
||||
|
||||
if (APIUtil.getPropsAsBoolValue("transactionRequests_enabled", false) == false) {
|
||||
ignore("With N challenges, With FX", ApiEndpoint10) {}
|
||||
} else {
|
||||
scenario("With N challenges, With FX", ApiEndpoint10) {
|
||||
setPropsValues("transactionRequests_supported_types" -> "SEPA,SANDBOX_TAN,FREE_FORM,COUNTERPARTY,ACCOUNT,ACCOUNT_OTP,SIMPLE,CARD")
|
||||
setPropsValues("CARD_OTP_INSTRUCTION_TRANSPORT" -> "DUMMY")
|
||||
|
||||
When("we prepare all the conditions for a normal success -- V400 Create Transaction Request")
|
||||
val helper = defaultSetup(CARD.toString)
|
||||
|
||||
And("We set the special conditions for different currencies")
|
||||
val fromCurrency = "AED"
|
||||
val toCurrency = "INR"
|
||||
val amt = "50000.00"
|
||||
helper.setCurrencyAndAmt(fromCurrency, toCurrency, amt)
|
||||
|
||||
And("We set the special input JSON values for 'V400 Create Transaction Request' endpoint")
|
||||
helper.bodyValue = AmountOfMoneyJsonV121(fromCurrency, amt.toString())
|
||||
helper.transactionRequestBodyCard = helper.transactionRequestBodyCard.copy(value=helper.bodyValue)
|
||||
|
||||
createAccountAttributeViaEndpoint(
|
||||
helper.bankId.value,
|
||||
helper.accountId1.value,
|
||||
"REQUIRED_CHALLENGE_ANSWERS",
|
||||
"2",
|
||||
"INTEGER",
|
||||
Some("LKJL98769F")
|
||||
)
|
||||
|
||||
val grantedView = grantUserAccessToViewViaEndpoint(
|
||||
helper.bankId.value,
|
||||
helper.accountId1.value,
|
||||
resourceUser2.userId,
|
||||
user1,
|
||||
PostViewJsonV400(view_id = "owner", is_system = true)
|
||||
)
|
||||
|
||||
Then("we call the 'V400 Create Transaction Request' endpoint")
|
||||
val createTransactionRequestResponse = helper.makeCreateTransReqRequestCard
|
||||
val createTransactionRequestJsonResponse = createTransactionRequestResponse.body.extract[TransactionRequestWithChargeJSON400]
|
||||
createTransactionRequestJsonResponse.status should equal(TransactionRequestStatus.INITIATED.toString)
|
||||
|
||||
val challengeOfUser1: Option[ChallengeJsonV400] = createTransactionRequestJsonResponse.challenges.find(_.user_id == resourceUser1.userId)
|
||||
val challengeOfUser2: Option[ChallengeJsonV400] = createTransactionRequestJsonResponse.challenges.find(_.user_id == resourceUser2.userId)
|
||||
|
||||
Then("We checked all the fields of createTransactionRequestResponse body ")
|
||||
helper.checkAllCreateTransReqResBodyField(createTransactionRequestResponse, true)
|
||||
|
||||
When("we need check the 'Get all Transaction Requests. - V400' to double check it in database")
|
||||
val getTransReqResponse = helper.makeGetTransReqRequest
|
||||
|
||||
Then("We checked all the fields of getTransReqResponse body")
|
||||
helper.checkAllGetTransReqResBodyField(getTransReqResponse, true)
|
||||
|
||||
When("we need to check the 'Get Transactions for Account (Full) -V400' to check the transaction info ")
|
||||
val getTransResponse = helper.makeGetTransRequest
|
||||
Then("We checked all the fields of getTransResponse body")
|
||||
helper.checkAllGetTransResBodyField(getTransResponse, true)
|
||||
|
||||
When("We checked all the data in database, we need check the account amount info")
|
||||
helper.checkBankAccountBalance(false)
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest(challengeId = challengeOfUser1.map(_.id).getOrElse(""))
|
||||
And("we call the endpoint")
|
||||
val ansReqResponseUser1 = helper.makeAnswerRequest
|
||||
ansReqResponseUser1.body.extract[ErrorMessage].message contains extractErrorMessageCode(NextChallengePending) should be (true)
|
||||
|
||||
Then("We call 'Answer Transaction Request Challenge - V400' to finish the request")
|
||||
And("we prepare the parameters for it")
|
||||
helper.setAnswerTransactionRequest(
|
||||
challengeId = challengeOfUser2.map(_.id).getOrElse(""),
|
||||
consumerAndToken = user2
|
||||
)
|
||||
And("we call the endpoint")
|
||||
val ansReqResponseUser2 = helper.makeAnswerRequest
|
||||
ansReqResponseUser2.body.extract[TransactionRequestWithChargeJSON400].status should equal(TransactionRequestStatus.COMPLETED.toString)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint3 version $VersionOfApi - Unauthorized access") {
|
||||
@ -1453,11 +1751,11 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
lazy val bankId = testBankId1.value
|
||||
lazy val accountId = testAccountId1.value
|
||||
lazy val view = "owner"
|
||||
|
||||
|
||||
scenario("We will call the endpoint WITHOUT user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
|
||||
val transactionRequestId = randomTransactionRequestViaEndpoint(bankId, accountId, view, user1).id
|
||||
|
||||
|
||||
When("We make a request v4.0.0")
|
||||
val request400 = (v4_0_0_Request / "banks" / bankId / "accounts"/ accountId / view / "transaction-requests" / transactionRequestId).GET
|
||||
val response400 = makeGetRequest(request400)
|
||||
@ -1467,9 +1765,9 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
}
|
||||
|
||||
scenario("We will call the endpoint WITH user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
|
||||
|
||||
val transactionRequestId = randomTransactionRequestViaEndpoint(bankId, accountId, view, user1).id
|
||||
|
||||
|
||||
When("We make a request v4.0.0")
|
||||
val request400 = (v4_0_0_Request / "banks" / bankId / "accounts"/ accountId / view / "transaction-requests" / transactionRequestId).GET <@ (user1)
|
||||
val response400 = makeGetRequest(request400)
|
||||
@ -1477,7 +1775,7 @@ class TransactionRequestsTest extends V400ServerSetup with DefaultUsers {
|
||||
response400.code should equal(200)
|
||||
response400.body.extract[TransactionRequestWithChargeJSON210].id should equal(transactionRequestId)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ import scala.util.Random.nextInt
|
||||
trait V400ServerSetup extends ServerSetupWithTestData with DefaultUsers {
|
||||
|
||||
def v4_0_0_Request: Req = baseRequest / "obp" / "v4.0.0"
|
||||
def v5_0_0_Request: Req = baseRequest / "obp" / "v5.0.0"
|
||||
def dynamicEndpoint_Request: Req = baseRequest / "obp" / ApiShortVersions.`dynamic-endpoint`.toString
|
||||
def dynamicEntity_Request: Req = baseRequest / "obp" / ApiShortVersions.`dynamic-entity`.toString
|
||||
|
||||
|
||||
158
obp-api/src/test/scala/code/api/v5_0_0/CardTest.scala
Normal file
158
obp-api/src/test/scala/code/api/v5_0_0/CardTest.scala
Normal file
@ -0,0 +1,158 @@
|
||||
package code.api.v5_0_0
|
||||
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{createPhysicalCardJsonV500}
|
||||
import code.api.util.ApiRole
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiRole.CanCreateCustomer
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.v1_3_0.ReplacementJSON
|
||||
import code.api.v3_1_0.CustomerJsonV310
|
||||
import code.api.v5_0_0.APIMethods500.Implementations5_0_0
|
||||
import code.entitlement.Entitlement
|
||||
import code.setup.DefaultUsers
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.{CardAction, CardReplacementReason}
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import net.liftweb.json.Serialization.write
|
||||
import org.scalatest.Tag
|
||||
|
||||
import java.util.Date
|
||||
|
||||
class CardTest extends V500ServerSetupAsync with DefaultUsers {
|
||||
|
||||
object VersionOfApi extends Tag(ApiVersion.v5_0_0.toString)
|
||||
object ApiEndpointAddCardForBank extends Tag(nameOf(Implementations5_0_0.addCardForBank))
|
||||
|
||||
|
||||
|
||||
feature("test Card APIs") {
|
||||
scenario("We will create Card with many error cases",
|
||||
ApiEndpointAddCardForBank,
|
||||
VersionOfApi
|
||||
) {
|
||||
Given("The test bank and test account")
|
||||
val testBank = testBankId1
|
||||
val testAccount = testAccountId1
|
||||
val dummyCard = createPhysicalCardJsonV500
|
||||
|
||||
And("We need to prepare the Customer Info")
|
||||
|
||||
Then("We prepare the Customer data")
|
||||
val request310 = (v5_0_0_Request / "banks" / testBankId1.value / "customers").POST <@(user1)
|
||||
val postCustomerJson = SwaggerDefinitionsJSON.postCustomerJsonV310
|
||||
Entitlement.entitlement.vend.addEntitlement(testBank.value, resourceUser1.userId, CanCreateCustomer.toString)
|
||||
val responseCustomer310 = makePostRequest(request310, write(postCustomerJson))
|
||||
val customerId = responseCustomer310.body.extract[CustomerJsonV310].customer_id
|
||||
|
||||
val properCardJson = dummyCard.copy(account_id = testAccount.value, issue_number = "123", customer_id = customerId)
|
||||
|
||||
val requestAnonymous = (v5_0_0_Request / "management"/"banks" / testBank.value / "cards" ).POST
|
||||
val requestWithAuthUser = (v5_0_0_Request / "management" /"banks" / testBank.value / "cards" ).POST <@ (user1)
|
||||
|
||||
Then(s"We test with anonymous user.")
|
||||
val responseAnonymous = makePostRequest(requestAnonymous, write(properCardJson))
|
||||
And(s"We should get 401 and get the authentication error")
|
||||
responseAnonymous.code should equal(401)
|
||||
responseAnonymous.body.toString contains(s"$UserNotLoggedIn") should be (true)
|
||||
|
||||
Then(s"We call the authentication user, but without proper role: ${ApiRole.canCreateCardsForBank}")
|
||||
val responseUserButNoRole = makePostRequest(requestWithAuthUser, write(properCardJson))
|
||||
And(s"We should get 403 and the error message missing can ${ApiRole.canCreateCardsForBank} role")
|
||||
responseUserButNoRole.code should equal(403)
|
||||
responseUserButNoRole.body.toString contains(s"${ApiRole.canCreateCardsForBank}") should be (true)
|
||||
|
||||
Then(s"We grant the user ${ApiRole.canCreateCardsForBank} role, but with the wrong AccountId")
|
||||
Entitlement.entitlement.vend.addEntitlement(testBankId1.value, resourceUser1.userId, ApiRole.canCreateCardsForBank.toString)
|
||||
val wrongAccountCardJson = dummyCard
|
||||
val responseHasRoleWrongAccountId = makePostRequest(requestWithAuthUser, write(wrongAccountCardJson))
|
||||
And(s"We should get 404 and get the error message: $BankAccountNotFound.")
|
||||
responseHasRoleWrongAccountId.code should equal(404)
|
||||
responseHasRoleWrongAccountId.body.toString contains(s"$BankAccountNotFound")
|
||||
|
||||
Then(s"We call the authentication user, but totally wrong Json format.")
|
||||
val wrongPostJsonFormat = testBankId1
|
||||
val responseWrongJsonFormat = makePostRequest(requestWithAuthUser, write(wrongPostJsonFormat))
|
||||
And(s"We should get 400 and get the error message: $InvalidJsonFormat.")
|
||||
responseWrongJsonFormat.code should equal(400)
|
||||
responseWrongJsonFormat.body.toString contains(s"$InvalidJsonFormat")
|
||||
|
||||
Then(s"We call the authentication user, but wrong card.allows value")
|
||||
val withWrongVlaueForAllows = properCardJson.copy(allows = List("123"))
|
||||
val responseWithWrongVlaueForAllows = makePostRequest(requestWithAuthUser, write(withWrongVlaueForAllows))
|
||||
And(s"We should get 400 and get the error message")
|
||||
responseWithWrongVlaueForAllows.code should equal(400)
|
||||
responseWithWrongVlaueForAllows.body.toString contains(AllowedValuesAre++ CardAction.availableValues.mkString(", "))
|
||||
|
||||
Then(s"We call the authentication user, but wrong card.replacement value")
|
||||
val wrongCardReplacementReasonJson = dummyCard.copy(replacement = Some(ReplacementJSON(new Date(),"Wrong"))) // The replacement must be Enum of `CardReplacementReason`
|
||||
val responseWrongCardReplacementReasonJson = makePostRequest(requestWithAuthUser, write(wrongCardReplacementReasonJson))
|
||||
And(s"We should get 400 and get the error message")
|
||||
responseWrongCardReplacementReasonJson.code should equal(400)
|
||||
responseWrongCardReplacementReasonJson.body.toString contains(AllowedValuesAre + CardReplacementReason.availableValues.mkString(", "))
|
||||
|
||||
Then(s"We call the authentication user, but too long issue number.")
|
||||
val properCardJsonTooLongIssueNumber = dummyCard.copy(account_id = testAccount.value, issue_number = "01234567891")
|
||||
val responseUserWrongIssueNumber = makePostRequest(requestWithAuthUser, write(properCardJsonTooLongIssueNumber))
|
||||
And(s"We should get 400 and the error message missing can ${ApiRole.canCreateCardsForBank} role")
|
||||
responseUserWrongIssueNumber.code should equal(400)
|
||||
responseUserWrongIssueNumber.body.toString contains(s"${maximumLimitExceeded.replace("10000", "10")}") should be (true)
|
||||
|
||||
Then(s"We grant the user ${ApiRole.canCreateCardsForBank} role, but wrong customerId")
|
||||
val wrongCustomerCardJson = properCardJson.copy(customer_id = "wrongId")
|
||||
val responsewrongCustomerCardJson = makePostRequest(requestWithAuthUser, write(wrongCustomerCardJson))
|
||||
And(s"We should get 400 and get the error message: $CustomerNotFoundByCustomerId.")
|
||||
responsewrongCustomerCardJson.code should equal(404)
|
||||
responsewrongCustomerCardJson.body.toString contains(s"$CustomerNotFoundByCustomerId") should be (true)
|
||||
|
||||
Then(s"We test the success case, prepare all stuff.")
|
||||
val responseProper = makePostRequest(requestWithAuthUser, write(properCardJson))
|
||||
And("We should get 400 and get the error message: Not Found the BankAccount.")
|
||||
responseProper.code should equal(201)
|
||||
val cardJsonV500 = responseProper.body.extract[PhysicalCardJsonV500]
|
||||
cardJsonV500.card_number should be (properCardJson.card_number)
|
||||
cardJsonV500.card_type should be (properCardJson.card_type)
|
||||
cardJsonV500.name_on_card should be (properCardJson.name_on_card)
|
||||
cardJsonV500.issue_number should be (properCardJson.issue_number)
|
||||
cardJsonV500.serial_number should be (properCardJson.serial_number )
|
||||
cardJsonV500.valid_from_date should be (properCardJson.valid_from_date )
|
||||
cardJsonV500.expires_date should be (properCardJson.expires_date )
|
||||
cardJsonV500.enabled should be (properCardJson.enabled )
|
||||
cardJsonV500.cancelled should be (false)
|
||||
cardJsonV500.on_hot_list should be (false)
|
||||
cardJsonV500.technology should be (properCardJson.technology )
|
||||
cardJsonV500.networks should be (properCardJson.networks )
|
||||
cardJsonV500.allows should be (properCardJson.allows )
|
||||
cardJsonV500.account.id should be (properCardJson.account_id )
|
||||
cardJsonV500.replacement should be {
|
||||
properCardJson.replacement match {
|
||||
case Some(x) => x
|
||||
case None => null
|
||||
}
|
||||
}
|
||||
cardJsonV500.pin_reset.toString() should be(properCardJson.pin_reset.toString())
|
||||
cardJsonV500.collected should be {
|
||||
properCardJson.collected match {
|
||||
case Some(x) => x
|
||||
case None => null
|
||||
}
|
||||
}
|
||||
cardJsonV500.posted should be {
|
||||
properCardJson.posted match {
|
||||
case Some(x) => x
|
||||
case None => null
|
||||
}
|
||||
}
|
||||
|
||||
cardJsonV500.cvv.length equals (3) should be(true)
|
||||
cardJsonV500.brand equals ("Visa") should be(true)
|
||||
|
||||
Then(s"We create the card with same bankId, cardNumber and issueNumber")
|
||||
val responseDeplicated = makePostRequest(requestWithAuthUser, write(properCardJson))
|
||||
And("We should get 400 and get the error message: the card already existing .")
|
||||
responseDeplicated.code should equal(400)
|
||||
responseDeplicated.body.toString contains(s"$CardAlreadyExists") should be (true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@ -51,6 +51,8 @@ trait ServerSetup extends FeatureSpec with SendServerRequests
|
||||
setPropsValues("dauth.host" -> "127.0.0.1")
|
||||
setPropsValues("jwt.token_secret"->"your-at-least-256-bit-secret-token")
|
||||
setPropsValues("jwt.public_key_rsa" -> "src/test/resources/cert/public_dauth.pem")
|
||||
setPropsValues("transactionRequests_supported_types" -> "SEPA,SANDBOX_TAN,FREE_FORM,COUNTERPARTY,ACCOUNT,ACCOUNT_OTP,SIMPLE,CARD")
|
||||
setPropsValues("CARD_OTP_INSTRUCTION_TRANSPORT" -> "DUMMY")
|
||||
|
||||
val server = TestServer
|
||||
def baseRequest = host(server.host, server.port)
|
||||
|
||||
@ -691,7 +691,8 @@ case class OutBoundUpdatePhysicalCard(outboundAdapterCallContext: OutboundAdapte
|
||||
pinResets: List[PinResetInfo],
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String) extends TopicTrait
|
||||
customerId: String
|
||||
) extends TopicTrait
|
||||
case class InBoundUpdatePhysicalCard(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: PhysicalCard) extends InBoundTrait[PhysicalCard]
|
||||
|
||||
case class OutBoundDeletePhysicalCardForBank(outboundAdapterCallContext: OutboundAdapterCallContext,
|
||||
@ -734,7 +735,9 @@ case class OutBoundCreatePhysicalCard(outboundAdapterCallContext: OutboundAdapte
|
||||
pinResets: List[PinResetInfo],
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String
|
||||
customerId: String,
|
||||
cvv: String,
|
||||
brand: String
|
||||
) extends TopicTrait
|
||||
case class InBoundCreatePhysicalCard(inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: PhysicalCard) extends InBoundTrait[PhysicalCard]
|
||||
|
||||
@ -947,7 +950,9 @@ case class OutBoundCreatePhysicalCardLegacy (outboundAdapterCallContext: Outboun
|
||||
pinResets: List[PinResetInfo],
|
||||
collected: Option[CardCollectionInfo],
|
||||
posted: Option[CardPostedInfo],
|
||||
customerId: String) extends TopicTrait
|
||||
customerId: String,
|
||||
cvv: String = "",
|
||||
brand: String = "") extends TopicTrait
|
||||
case class InBoundCreatePhysicalCardLegacy (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: PhysicalCard) extends InBoundTrait[PhysicalCard]
|
||||
|
||||
|
||||
|
||||
@ -61,6 +61,8 @@ trait PhysicalCardTrait {
|
||||
def collected: Option[CardCollectionInfo]
|
||||
def posted: Option[CardPostedInfo]
|
||||
def customerId: String
|
||||
def cvv: Option[String] = None //added from V500
|
||||
def brand: Option[String] = None //added from V500
|
||||
}
|
||||
|
||||
case class PhysicalCard (
|
||||
@ -84,7 +86,9 @@ case class PhysicalCard (
|
||||
val pinResets : List[PinResetInfo],
|
||||
val collected : Option[CardCollectionInfo],
|
||||
val posted : Option[CardPostedInfo],
|
||||
val customerId: String
|
||||
val customerId: String,
|
||||
override val cvv: Option[String] = None,
|
||||
override val brand: Option[String] = None
|
||||
) extends PhysicalCardTrait
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user