Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/BGv1.3 added periodic_payments #2419

Merged
merged 8 commits into from
Sep 9, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ object APIMethods_PaymentInitiationServicePISApi extends RestHelper {

def checkPaymentServerError(paymentService: String) = {
val ccc = ""
s"${InvalidTransactionRequestType.replaceAll("TRANSACTION_REQUEST_TYPE", "PAYMENT_SERVICE in the URL.")}: '${paymentService}'.It should be `payments` for now, will support (bulk-payments, periodic-payments) soon"
s"${InvalidTransactionRequestType.replaceAll("TRANSACTION_REQUEST_TYPE", "PAYMENT_SERVICE in the URL.")}: '${paymentService}'.It should be `payments` or `periodic-payments` for now, will support `bulk-payments` soon"
}
def checkPaymentProductError(paymentProduct: String) = s"${InvalidTransactionRequestType.replaceAll("TRANSACTION_REQUEST_TYPE", "PAYMENT_PRODUCT in the URL.")}: '${paymentProduct}'.It should be `sepa-credit-transfers`for now, will support (instant-sepa-credit-transfers, target-2-payments, cross-border-credit-transfers) soon."

Expand Down Expand Up @@ -529,37 +529,50 @@ Check the transaction status of a payment initiation.""",
for {
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- passesPsd2Pisp(callContext)

_ <- NewStyle.function.tryons(checkPaymentServerError(paymentService), 400, callContext) {
PaymentServiceTypes.withName(paymentService.replaceAll("-", "_"))
}
_ <- Helper.booleanToFuture(failMsg= checkPaymentServerError(paymentService), cc=callContext) {
PaymentServiceTypes.withName(paymentService.replaceAll("-", "_")).equals(PaymentServiceTypes.payments) ||
PaymentServiceTypes.withName(paymentService.replaceAll("-", "_")).equals(PaymentServiceTypes.periodic_payments)
}

transactionRequestTypes <- NewStyle.function.tryons(checkPaymentProductError(paymentProduct), 400, callContext) {
TransactionRequestTypes.withName(paymentProduct.replaceAll("-", "_").toUpperCase)
}

transDetailsJson <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $SepaCreditTransfersBerlinGroupV13 ", 400, callContext) {
json.extract[SepaCreditTransfersBerlinGroupV13]
sepaCreditTransfersBerlinGroupV13 <- if(PaymentServiceTypes.withName(paymentService.replaceAll("-", "_")).equals(PaymentServiceTypes.payments)){
NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $SepaCreditTransfersBerlinGroupV13 ", 400, callContext) {
json.extract[SepaCreditTransfersBerlinGroupV13]
}
} else{
NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $PeriodicSepaCreditTransfersBerlinGroupV13 ", 400, callContext) {
json.extract[PeriodicSepaCreditTransfersBerlinGroupV13]
}
}
//If it is periodic_payments, we need to make sure, we have more fileds.

transDetailsSerialized <- NewStyle.function.tryons(s"$UnknownError Can not serialize in request Json ", 400, callContext) {
write(transDetailsJson)(Serialization.formats(NoTypeHints))
write(sepaCreditTransfersBerlinGroupV13)(Serialization.formats(NoTypeHints))
}

isValidAmountNumber <- NewStyle.function.tryons(s"$InvalidNumber Current input is ${transDetailsJson.instructedAmount.amount} ", 400, callContext) {
BigDecimal(transDetailsJson.instructedAmount.amount)
isValidAmountNumber <- NewStyle.function.tryons(s"$InvalidNumber Current input is ${sepaCreditTransfersBerlinGroupV13.instructedAmount.amount} ", 400, callContext) {
BigDecimal(sepaCreditTransfersBerlinGroupV13.instructedAmount.amount)
}

_ <- Helper.booleanToFuture(s"${NotPositiveAmount} Current input is: '${isValidAmountNumber}'", cc = callContext) {
isValidAmountNumber > BigDecimal("0")
}

// Prevent default value for transaction request type (at least).
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${transDetailsJson.instructedAmount.currency}'", cc = callContext) {
isValidCurrencyISOCode(transDetailsJson.instructedAmount.currency)
_ <- Helper.booleanToFuture(s"${InvalidISOCurrencyCode} Current input is: '${sepaCreditTransfersBerlinGroupV13.instructedAmount.currency}'", cc = callContext) {
isValidCurrencyISOCode(sepaCreditTransfersBerlinGroupV13.instructedAmount.currency)
}

_ <- NewStyle.function.isEnabledTransactionRequests(callContext)
fromAccountIban = transDetailsJson.debtorAccount.iban
toAccountIban = transDetailsJson.creditorAccount.iban
fromAccountIban = sepaCreditTransfersBerlinGroupV13.debtorAccount.iban
toAccountIban = sepaCreditTransfersBerlinGroupV13.creditorAccount.iban

(fromAccount, callContext) <- NewStyle.function.getBankAccountByIban(fromAccountIban, callContext)
(ibanChecker, callContext) <- NewStyle.function.validateAndCheckIbanNumber(toAccountIban, callContext)
Expand All @@ -578,11 +591,11 @@ Check the transaction status of a payment initiation.""",
NewStyle.function.hasEntitlement(fromAccount.bankId.value, u.userId, ApiRole.canCreateAnyTransactionRequest, callContext, InsufficientAuthorisationToCreateTransactionRequest)

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

amountOfMoneyJSON = transDetailsJson.instructedAmount
amountOfMoneyJSON = sepaCreditTransfersBerlinGroupV13.instructedAmount

(createdTransactionRequest, callContext) <- transactionRequestTypes match {
case TransactionRequestTypes.SEPA_CREDIT_TRANSFERS => {
Expand All @@ -602,7 +615,8 @@ Check the transaction status of a payment initiation.""",
Some(BERLIN_GROUP_PAYMENT_CHALLENGE),
None,
None,
Some(transDetailsJson),
Some(paymentService),
Some(sepaCreditTransfersBerlinGroupV13),
callContext
) //in SANDBOX_TAN, ChargePolicy set default "SHARED"
} yield (createdTransactionRequest, callContext)
Expand Down
3 changes: 3 additions & 0 deletions obp-api/src/main/scala/code/api/util/ExampleValue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2275,6 +2275,9 @@ object ExampleValue {
lazy val descriptionExample = ConnectorField(s"This an optional field. Maximum length is ${ApiCollection.Description.maxLen}. It can be any characters here.","The human readable description here.")
glossaryItems += makeGlossaryItem("description", descriptionExample)

lazy val paymentServiceExample = ConnectorField("payments", s"The berlin group payment services, eg: payments, periodic-payments and bulk-payments. ")
glossaryItems += makeGlossaryItem("paymentService", paymentServiceExample)

lazy val dynamicResourceDocDescriptionExample = ConnectorField("Create one User", "the description for this endpoint")
glossaryItems += makeGlossaryItem("DynamicResourceDoc.description", dynamicResourceDocDescriptionExample)

Expand Down
6 changes: 4 additions & 2 deletions obp-api/src/main/scala/code/api/util/NewStyle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,8 @@ object NewStyle extends MdcLoggable{
challengeType: Option[ChallengeType.Value],
scaMethod: Option[SCA],
reasons: Option[List[TransactionRequestReason]],
berlinGroupPayments: Option[SepaCreditTransfersBerlinGroupV13],
paymentService: Option[String],
berlinGroupPayments: Option[BerlinGroupTransactionRequestCommonBodyJson],
callContext: Option[CallContext]): OBPReturnType[TransactionRequest] =
{
Connector.connector.vend.createTransactionRequestv400(
Expand All @@ -1144,7 +1145,8 @@ object NewStyle extends MdcLoggable{
challengeType = challengeType.map(_.toString),
scaMethod: Option[SCA],
reasons: Option[List[TransactionRequestReason]],
berlinGroupPayments: Option[SepaCreditTransfersBerlinGroupV13],
paymentService: Option[String],
berlinGroupPayments: Option[BerlinGroupTransactionRequestCommonBodyJson],
callContext: Option[CallContext]
) map { i =>
(unboxFullOrFail(i._1, callContext, s"$InvalidConnectorResponseForGetTransactionRequests210", 400), i._2)
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,7 @@ trait APIMethods300 {
"Get Adapter Info for a bank",
s"""Get basic information about the Adapter listening on behalf of this bank.
|
|${authenticationRequiredMessage(false)}
|${authenticationRequiredMessage(true)}
|
""".stripMargin,
EmptyBody,
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ trait APIMethods310 {
"Get Adapter Info",
s"""Get basic information about the Adapter.
|
|${authenticationRequiredMessage(false)}
|${authenticationRequiredMessage(true)}
|
""".stripMargin,
EmptyBody,
Expand Down
8 changes: 8 additions & 0 deletions obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"

_ <- NewStyle.function.createOrUpdateTransactionRequestAttribute(
Expand Down Expand Up @@ -1152,6 +1153,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
} yield (createdTransactionRequest, callContext)
}
Expand Down Expand Up @@ -1181,6 +1183,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
None,
callContext) //in ACCOUNT, ChargePolicy set default "SHARED"
} yield (createdTransactionRequest, callContext)
}
Expand Down Expand Up @@ -1216,6 +1219,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
Expand Down Expand Up @@ -1248,6 +1252,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)

Expand Down Expand Up @@ -1300,6 +1305,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)

Expand Down Expand Up @@ -1335,6 +1341,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
transDetailsSEPAJson.reasons.map(_.map(_.transform)),
None,
None,
callContext)
} yield (createdTransactionRequest, callContext)
}
Expand All @@ -1360,6 +1367,7 @@ trait APIMethods400 extends MdcLoggable {
getScaMethodAtInstance(transactionRequestType.value).toOption,
None,
None,
None,
callContext)
} yield
(createdTransactionRequest, callContext)
Expand Down
4 changes: 3 additions & 1 deletion obp-api/src/main/scala/code/api/v5_0_0/APIMethods500.scala
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,8 @@ trait APIMethods500 {
permissionsFromSource = permission.views.map(view =>APIUtil.getViewPermissions(view.asInstanceOf[ViewDefinition]).toList).flatten.toSet
permissionsFromTarget = targetCreateCustomViewJson.allowed_permissions

//eg: permissionsFromTarget=List(1,2), permissionsFromSource = List(1,3,4) => userMissingPermissions = List(2)
//Here would find the missing permissions and show them in the error messages
userMissingPermissions = permissionsFromTarget.toSet diff permissionsFromSource

failMsg = s"${ErrorMessages.UserDoesNotHavePermission} ${userMissingPermissions.toString}"
Expand Down Expand Up @@ -2359,7 +2361,7 @@ trait APIMethods500 {
"Get Adapter Info",
s"""Get basic information about the Adapter.
|
|${authenticationRequiredMessage(false)}
|${authenticationRequiredMessage(true)}
|
""".stripMargin,
EmptyBody,
Expand Down
45 changes: 18 additions & 27 deletions obp-api/src/main/scala/code/bankconnectors/Connector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,20 @@ trait Connector extends MdcLoggable {
chargeValue <- getChargeValue(chargeLevelAmount,transactionRequestCommonBodyAmount)
charge = TransactionRequestCharge("Total charges for completed transaction", AmountOfMoney(transactionRequestCommonBody.value.currency, chargeValue))
// Always create a new Transaction Request
transactionRequest <- Future{ createTransactionRequestImpl210(TransactionRequestId(generateUUID()), transactionRequestType, fromAccount, toAccount, transactionRequestCommonBody, detailsPlain, status.toString, charge, chargePolicy)} map {
transactionRequest <- Future{
TransactionRequests.transactionRequestProvider.vend.createTransactionRequestImpl210(
TransactionRequestId(generateUUID()),
transactionRequestType,
fromAccount,
toAccount,
transactionRequestCommonBody,
detailsPlain,
status.toString,
charge,
chargePolicy,
None,
)
} map {
unboxFullOrFail(_, callContext, s"$InvalidConnectorResponseForCreateTransactionRequestImpl210")
}

Expand All @@ -1100,7 +1113,7 @@ trait Connector extends MdcLoggable {

//save transaction_id into database
_ <- Future {saveTransactionRequestTransaction(transactionRequest.id, createdTransactionId)}
//update transaction_id field for varibale 'transactionRequest'
//update transaction_id field for variable 'transactionRequest'
transactionRequest <- Future(transactionRequest.copy(transaction_ids = createdTransactionId.value))

} yield {
Expand Down Expand Up @@ -1162,37 +1175,15 @@ trait Connector extends MdcLoggable {
challengeType: Option[String],
scaMethod: Option[SCA],
reasons: Option[List[TransactionRequestReason]],
berlinGroupPayments: Option[SepaCreditTransfersBerlinGroupV13],
paymentService: Option[String],
berlinGroupPayments: Option[BerlinGroupTransactionRequestCommonBodyJson],
callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequest]] = Future{(Failure(setUnimplementedError), callContext)}

//place holder for various connector methods that overwrite methods like these, does the actual data access
//placeholder for various connector methods that overwrite methods like these, does the actual data access
protected def createTransactionRequestImpl(transactionRequestId: TransactionRequestId, transactionRequestType: TransactionRequestType,
fromAccount : BankAccount, counterparty : BankAccount, body: TransactionRequestBody,
status: String, charge: TransactionRequestCharge) : Box[TransactionRequest] = Failure(setUnimplementedError)

/**
*
* @param transactionRequestId
* @param transactionRequestType Support Types: SANDBOX_TAN, FREE_FORM, SEPA and COUNTERPARTY
* @param fromAccount
* @param toAccount
* @param transactionRequestCommonBody Body from http request: should have common fields:
* @param details This is the details / body of the request (contains all fields in the body)
* @param status "INITIATED" "PENDING" "FAILED" "COMPLETED"
* @param charge
* @param chargePolicy SHARED, SENDER, RECEIVER
* @return Always create a new Transaction Request in mapper, and return all the fields
*/
protected def createTransactionRequestImpl210(transactionRequestId: TransactionRequestId,
transactionRequestType: TransactionRequestType,
fromAccount: BankAccount,
toAccount: BankAccount,
transactionRequestCommonBody: TransactionRequestCommonBodyJSON,
details: String,
status: String,
charge: TransactionRequestCharge,
chargePolicy: String): Box[TransactionRequest] = Failure(setUnimplementedError)

def notifyTransactionRequest(fromAccount: BankAccount, toAccount: BankAccount, transactionRequest: TransactionRequest, callContext: Option[CallContext]): OBPReturnType[Box[TransactionRequestStatusValue]] =
Future{(Failure(setUnimplementedError), callContext)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,6 @@ object ConnectorBuilderUtil {
val protectedMethods = List(
"makePaymentImpl",
"createTransactionRequestImpl",
"createTransactionRequestImpl210",
"saveTransactionRequestTransactionImpl",
"saveTransactionRequestChallengeImpl",
"saveTransactionRequestStatusImpl",
Expand Down
Loading
Loading