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

feat: open banking PIS integration #541

Merged
merged 10 commits into from
Aug 7, 2024
23 changes: 7 additions & 16 deletions src/Payments/PaymentMethodsRecord.res
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,13 @@ let paymentMethodsFields = [
fields: [InfoElement],
miniIcon: Some(icon("bank", ~size=19)),
},
{
paymentMethodName: "open_banking_pis",
icon: Some(icon("bank", ~size=19)),
displayName: "Open Banking",
fields: [InfoElement],
miniIcon: Some(icon("bank", ~size=19)),
},
{
paymentMethodName: "evoucher",
icon: Some(icon("cashtocode", ~size=50)),
Expand Down Expand Up @@ -739,9 +746,6 @@ let getPaymentDetails = (arr: array<string>) => {
finalArr
}

type paymentMethod =
Cards | Wallets | PayLater | BankRedirect | BankTransfer | BankDebit | Crypto | Voucher | NONE

type cardType = Credit | Debit

type paymentExperience = {
Expand Down Expand Up @@ -825,19 +829,6 @@ let defaultList = {
merchant_name: "",
collect_billing_details_from_wallets: true,
}
let getMethod = str => {
switch str {
| "card" => Cards
| "wallet" => Wallets
| "pay_later" => PayLater
| "bank_redirect" => BankRedirect
| "bank_transfer" => BankTransfer
| "bank_debit" => BankDebit
| "crypto" => Crypto
| "voucher" => Voucher
| _ => NONE
}
}

let getPaymentExperienceType = str => {
switch str {
Expand Down
75 changes: 64 additions & 11 deletions src/Payments/PlaidSDKIframe.res
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ let make = () => {
let (isReady, setIsReady) = React.useState(_ => false)
let (pmAuthConnectorsArr, setPmAuthConnectorsArr) = React.useState(_ => [])
let (publishableKey, setPublishableKey) = React.useState(_ => "")
let (paymentId, setPaymentId) = React.useState(_ => "")
let (clientSecret, setClientSecret) = React.useState(_ => "")
let (isForceSync, setIsForceSync) = React.useState(_ => false)
let logger = React.useMemo(() => {
OrcaLogger.make(~source=Elements(Payment), ~clientSecret=paymentId, ~merchantId=publishableKey)
}, (publishableKey, paymentId))
OrcaLogger.make(~source=Elements(Payment), ~clientSecret, ~merchantId=publishableKey)
}, (publishableKey, clientSecret))

React.useEffect0(() => {
let handle = (ev: Window.event) => {
Expand All @@ -24,8 +25,9 @@ let make = () => {

setLinkToken(_ => linkToken)
setPmAuthConnectorsArr(_ => pmAuthConnectorArray)
setPublishableKey(_ => metaData->getString("payment_id", ""))
setPaymentId(_ => metaData->getString("publishableKey", ""))
setPublishableKey(_ => metaData->getString("publishableKey", ""))
setClientSecret(_ => metaData->getString("clientSecret", ""))
setIsForceSync(_ => metaData->getBool("isForceSync", false))
}
}
Window.addEventListener("message", handle)
Expand All @@ -47,6 +49,50 @@ let make = () => {
None
}, [pmAuthConnectorsArr])

let callbackOnSuccessOfPlaidPaymentsFlow = () => {
open Promise
let headers = [("Content-Type", "application/json"), ("api-key", publishableKey)]

PaymentHelpers.retrievePaymentIntent(
clientSecret,
headers,
~optLogger=Some(logger),
~switchToCustomPod=false,
~isForceSync=true,
)
->then(json => {
let dict = json->getDictFromJson
let status = dict->getString("status", "")
let return_url = dict->getString("return_url", "")

if (
status === "succeeded" || status === "requires_customer_action" || status === "processing"
) {
postSubmitResponse(~jsonData=json, ~url=return_url)
} else if status === "failed" {
postFailedSubmitResponse(
~errortype="confirm_payment_failed",
~message="Payment failed. Try again!",
)
} else {
postFailedSubmitResponse(
~errortype="sync_payment_failed",
~message="Payment is processing. Try again later!",
)
}
handlePostMessage([("fullscreen", false->JSON.Encode.bool)])
resolve(json)
})
->then(_ => {
resolve(Nullable.null)
})
->catch(e => {
logInfo(Console.log2("Retrieve Failed", e))
resolve(Nullable.null)
})
->ignore
}

React.useEffect(() => {
if isReady && linkToken->String.length > 0 {
let handler = Plaid.create({
Expand All @@ -59,14 +105,21 @@ let make = () => {
("isPlaid", true->JSON.Encode.bool),
("publicToken", publicToken->JSON.Encode.string),
])
if isForceSync {
callbackOnSuccessOfPlaidPaymentsFlow()
}
},
onExit: _ => {
handlePostMessage([
("fullscreen", false->JSON.Encode.bool),
("isPlaid", true->JSON.Encode.bool),
("isExited", true->JSON.Encode.bool),
("publicToken", ""->JSON.Encode.string),
])
if isForceSync {
callbackOnSuccessOfPlaidPaymentsFlow()
} else {
handlePostMessage([
("fullscreen", false->JSON.Encode.bool),
("isPlaid", true->JSON.Encode.bool),
("isExited", true->JSON.Encode.bool),
("publicToken", ""->JSON.Encode.string),
])
}
},
})

Expand Down
2 changes: 1 addition & 1 deletion src/Payments/QRCodeDisplay.res
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ let make = () => {
~switchToCustomPod,
)
->then(json => {
let dict = json->JSON.Decode.object->Option.getOr(Dict.make())
let dict = json->getDictFromJson
let status = dict->getString("status", "")

if (
Expand Down
2 changes: 1 addition & 1 deletion src/ThreeDSAuth.res
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ let make = () => {
~headers,
)
->then(json => {
let dict = json->JSON.Decode.object->Option.getOr(Dict.make())
let dict = json->getDictFromJson
if dict->Dict.get("error")->Option.isSome {
let errorObj = PaymentError.itemToObjMapper(dict)
handlePostMessage([("fullscreen", false->JSON.Encode.bool)])
Expand Down
28 changes: 25 additions & 3 deletions src/Utilities/PaymentHelpers.res
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ let rec pollRetrievePaymentIntent = (
open Promise
retrievePaymentIntent(clientSecret, headers, ~optLogger, ~switchToCustomPod, ~isForceSync)
->then(json => {
let dict = json->JSON.Decode.object->Option.getOr(Dict.make())
let dict = json->getDictFromJson
let status = dict->getString("status", "")

if status === "succeeded" || status === "failed" {
Expand Down Expand Up @@ -261,7 +261,7 @@ let rec pollStatus = (
open Promise
retrieveStatus(~headers, ~switchToCustomPod, pollId, logger)
->then(json => {
let dict = json->JSON.Decode.object->Option.getOr(Dict.make())
let dict = json->getDictFromJson
let status = dict->getString("status", "")
Promise.make((resolve, _) => {
if status === "completed" {
Expand Down Expand Up @@ -693,12 +693,33 @@ let rec intentCall = (
| None => Dict.make()
}
let walletName = session_token->getString("wallet_name", "")

let message = switch walletName {
| "apple_pay" => [
("applePayButtonClicked", true->JSON.Encode.bool),
("applePayPresent", session_token->anyTypeToJson),
]
| "google_pay" => [("googlePayThirdPartyFlow", session_token->anyTypeToJson)]
| "open_banking" => {
let metaData = [
(
"linkToken",
session_token
->getString("open_banking_session_token", "")
->JSON.Encode.string,
),
("pmAuthConnectorArray", ["plaid"]->Identity.anyTypeToJson),
("publishableKey", confirmParam.publishableKey->JSON.Encode.string),
("clientSecret", clientSecret->JSON.Encode.string),
("isForceSync", true->JSON.Encode.bool),
]->getJsonFromArrayOfJson
[
("fullscreen", true->JSON.Encode.bool),
("param", "plaidSDK"->JSON.Encode.string),
("iframeId", iframeId->JSON.Encode.string),
("metadata", metaData),
]
}
| _ => []
}

Expand Down Expand Up @@ -1687,8 +1708,9 @@ let callAuthLink = (
[
("linkToken", data->getDictFromJson->getString("link_token", "")->JSON.Encode.string),
("pmAuthConnectorArray", pmAuthConnectorsArr->Identity.anyTypeToJson),
("payment_id", clientSecret->Option.getOr("")->getPaymentId->JSON.Encode.string),
("publishableKey", publishableKey->JSON.Encode.string),
("clientSecret", clientSecret->Option.getOr("")->JSON.Encode.string),
("isForceSync", false->JSON.Encode.bool),
]->getJsonFromArrayOfJson

handlePostMessage([
Expand Down
2 changes: 1 addition & 1 deletion src/orca-loader/Elements.res
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ let make = (
)
->then(json => {
if redirect.contents === "always" {
let dict = json->JSON.Decode.object->Option.getOr(Dict.make())
let dict = json->getDictFromJson
let status = dict->getString("status", "")
let returnUrl = dict->getString("return_url", "")
Window.Location.replace(
Expand Down
Loading