From 0eaac2ac98481af547703dc56fdfff666df2f5a4 Mon Sep 17 00:00:00 2001 From: Arush Date: Thu, 7 Mar 2024 13:27:47 +0530 Subject: [PATCH 1/2] feat: added Payment Session Headless feat #207 --- src/Utilities/PaymentHelpers.res | 691 ++++++++++++----------- src/Window.res | 3 + src/orca-loader/Hyper.res | 29 + src/orca-loader/HyperLoader.res | 1 + src/orca-loader/LoaderPaymentElement.res | 5 +- src/orca-loader/PaymentSession.res | 156 +++++ src/orca-loader/Types.res | 20 + src/orca-log-catcher/OrcaLogger.res | 2 + 8 files changed, 577 insertions(+), 330 deletions(-) create mode 100644 src/orca-loader/PaymentSession.res diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index b99cc78fc..917ddb84d 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -115,6 +115,8 @@ let rec intentCall = ( ~switchToCustomPod, ~sdkHandleOneClickConfirmPayment, ~counter, + ~isPaymentSession=false, + (), ) => { open Promise let isConfirm = uri->Js.String2.includes("/confirm") @@ -130,6 +132,13 @@ let rec intentCall = ( ~logCategory=API, (), ) + let handleOpenUrl = url => { + if isPaymentSession { + Window.location.replace(. url) + } else { + openUrl(url) + } + } fetchApi( uri, ~method_=fetchMethod, @@ -147,355 +156,383 @@ let rec intentCall = ( res ->Fetch.Response.json ->then(data => { - if isConfirm { - let paymentMethod = switch paymentType { - | Card => "CARD" - | _ => - bodyStr - ->Js.Json.parseExn - ->Utils.getDictFromJson - ->Utils.getString("payment_method_type", "") - } - handleLogging( - ~optLogger, - ~value=data->Js.Json.stringify, - ~eventName=PAYMENT_FAILED, - ~paymentMethod, - (), - ) - } - logApi( - ~optLogger, - ~url=uri, - ~data, - ~statusCode, - ~type_="err", - ~eventName, - ~logType=ERROR, - ~logCategory=API, - (), - ) - - let dict = data->getDictFromJson - let errorObj = PaymentError.itemToObjMapper(dict) - closePaymentLoaderIfAny() - postFailedSubmitResponse(~errortype=errorObj.error.type_, ~message=errorObj.error.message) - if handleUserError { - openUrl(url.href) - } - resolve() - }) - ->catch(err => { - let exceptionMessage = err->Utils.formatException - logApi( - ~optLogger, - ~url=uri, - ~statusCode, - ~type_="no_response", - ~data=exceptionMessage, - ~eventName, - ~logType=ERROR, - ~logCategory=API, - (), - ) - if counter >= 5 { - closePaymentLoaderIfAny() - postFailedSubmitResponse(~errortype="server_error", ~message="Something went wrong") - if handleUserError { - openUrl(url.href) - } - } else { - let paymentIntentID = - Js.String2.split(clientSecret, "_secret_") - ->Belt.Array.get(0) - ->Belt.Option.getWithDefault("") - let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey=confirmParam.publishableKey, ()) - let retrieveUri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}` - intentCall( - ~fetchApi, - ~uri=retrieveUri, - ~headers, - ~bodyStr, - ~confirmParam: ConfirmType.confirmParams, - ~clientSecret, - ~optLogger, - ~handleUserError, - ~paymentType, - ~iframeId, - ~fetchMethod=Get, - ~setIsManualRetryEnabled, - ~switchToCustomPod, - ~sdkHandleOneClickConfirmPayment, - ~counter=counter + 1, - ) - } - resolve() - }) - ->ignore - } else { - res - ->Fetch.Response.json - ->then(data => { - logApi(~optLogger, ~url=uri, ~statusCode, ~type_="response", ~eventName, ()) - let intent = PaymentConfirmTypes.itemToObjMapper(data->getDictFromJson) - let paymentMethod = switch paymentType { - | Card => "CARD" - | _ => intent.payment_method_type - } - - let url = urlSearch(confirmParam.return_url) - url.searchParams.set(. "payment_intent_client_secret", clientSecret) - url.searchParams.set(. "status", intent.status) - if intent.status == "requires_customer_action" { - if intent.nextAction.type_ == "redirect_to_url" { - handleLogging( - ~optLogger, - ~value="", - ~internalMetadata=intent.nextAction.redirectToUrl, - ~eventName=REDIRECTING_USER, - ~paymentMethod, - (), - ) - openUrl(intent.nextAction.redirectToUrl) - } else if intent.nextAction.type_ == "display_bank_transfer_information" { - let metadata = switch intent.nextAction.bank_transfer_steps_and_charges_details { - | Some(obj) => obj->Utils.getDictFromJson - | None => Js.Dict.empty() + Js.Promise.make( + (~resolve, ~reject as _) => { + if isConfirm { + let paymentMethod = switch paymentType { + | Card => "CARD" + | _ => + bodyStr + ->Js.Json.parseExn + ->Utils.getDictFromJson + ->Utils.getString("payment_method_type", "") + } + handleLogging( + ~optLogger, + ~value=data->Js.Json.stringify, + ~eventName=PAYMENT_FAILED, + ~paymentMethod, + (), + ) } - let dict = deepCopyDict(metadata) - dict->Js.Dict.set("data", data) - dict->Js.Dict.set("url", url.href->Js.Json.string) - handleLogging( - ~optLogger, - ~value="", - ~internalMetadata=dict->Js.Json.object_->Js.Json.stringify, - ~eventName=DISPLAY_BANK_TRANSFER_INFO_PAGE, - ~paymentMethod, - (), - ) - handlePostMessage([ - ("fullscreen", true->Js.Json.boolean), - ("param", `${intent.payment_method_type}BankTransfer`->Js.Json.string), - ("iframeId", iframeId->Js.Json.string), - ("metadata", dict->Js.Json.object_), - ]) - } else if intent.nextAction.type_ === "qr_code_information" { - let qrData = intent.nextAction.image_data_url->Belt.Option.getWithDefault("") - let expiryTime = intent.nextAction.display_to_timestamp->Belt.Option.getWithDefault(0.0) - let headerObj = Js.Dict.empty() - headers->Js.Array2.forEach( - entries => { - let (x, val) = entries - Js.Dict.set(headerObj, x, val->Js.Json.string) - }, - ) - let metaData = - [ - ("qrData", qrData->Js.Json.string), - ("paymentIntentId", clientSecret->Js.Json.string), - ("headers", headerObj->Js.Json.object_), - ("expiryTime", expiryTime->Belt.Float.toString->Js.Json.string), - ("url", url.href->Js.Json.string), - ]->Js.Dict.fromArray - handleLogging( + logApi( ~optLogger, - ~value="", - ~internalMetadata=metaData->Js.Json.object_->Js.Json.stringify, - ~eventName=DISPLAY_QR_CODE_INFO_PAGE, - ~paymentMethod, + ~url=uri, + ~data, + ~statusCode, + ~type_="err", + ~eventName, + ~logType=ERROR, + ~logCategory=API, (), ) - handlePostMessage([ - ("fullscreen", true->Js.Json.boolean), - ("param", `qrData`->Js.Json.string), - ("iframeId", iframeId->Js.Json.string), - ("metadata", metaData->Js.Json.object_), - ]) - } else if intent.nextAction.type_ === "display_voucher_information" { - let voucherData = intent.nextAction.voucher_details->Belt.Option.getWithDefault({ - download_url: "", - reference: "", - }) - let headerObj = Js.Dict.empty() - headers->Js.Array2.forEach( - entries => { - let (x, val) = entries - Js.Dict.set(headerObj, x, val->Js.Json.string) - }, - ) - let metaData = - [ - ("voucherUrl", voucherData.download_url->Js.Json.string), - ("reference", voucherData.reference->Js.Json.string), - ("returnUrl", url.href->Js.Json.string), - ("paymentMethod", paymentMethod->Js.Json.string), - ("payment_intent_data", data), - ]->Js.Dict.fromArray - handleLogging( - ~optLogger, - ~value="", - ~internalMetadata=metaData->Js.Json.object_->Js.Json.stringify, - ~eventName=DISPLAY_VOUCHER, - ~paymentMethod, - (), - ) - handlePostMessage([ - ("fullscreen", true->Js.Json.boolean), - ("param", `voucherData`->Js.Json.string), - ("iframeId", iframeId->Js.Json.string), - ("metadata", metaData->Js.Json.object_), - ]) - } else if intent.nextAction.type_ == "third_party_sdk_session_token" { - let session_token = switch intent.nextAction.session_token { - | Some(token) => token->Utils.getDictFromJson - | None => Js.Dict.empty() + + let dict = data->getDictFromJson + let errorObj = PaymentError.itemToObjMapper(dict) + if !isPaymentSession { + closePaymentLoaderIfAny() + postFailedSubmitResponse( + ~errortype=errorObj.error.type_, + ~message=errorObj.error.message, + ) } - let walletName = session_token->Utils.getString("wallet_name", "") - let message = switch walletName { - | "apple_pay" => [ - ("applePayButtonClicked", true->Js.Json.boolean), - ("applePayPresent", session_token->toJson), - ] - | "google_pay" => [("googlePayThirdPartyFlow", session_token->toJson)] - | _ => [] + if handleUserError { + handleOpenUrl(url.href) + } else { + resolve(. data) } - - handlePostMessage(message) - } else { - postFailedSubmitResponse( - ~errortype="confirm_payment_failed", - ~message="Payment failed. Try again!", + }, + )->then(resolve) + }) + ->catch(err => { + Js.Promise.make( + (~resolve, ~reject as _) => { + let exceptionMessage = err->Utils.formatException + logApi( + ~optLogger, + ~url=uri, + ~statusCode, + ~type_="no_response", + ~data=exceptionMessage, + ~eventName, + ~logType=ERROR, + ~logCategory=API, + (), ) - if uri->Js.String2.includes("force_sync=true") { - handleLogging( + if counter >= 5 { + if !isPaymentSession { + closePaymentLoaderIfAny() + postFailedSubmitResponse(~errortype="server_error", ~message="Something went wrong") + } + if handleUserError { + handleOpenUrl(url.href) + } else { + resolve(. exceptionMessage) + } + } else { + let paymentIntentID = + Js.String2.split(clientSecret, "_secret_") + ->Belt.Array.get(0) + ->Belt.Option.getWithDefault("") + let endpoint = ApiEndpoint.getApiEndPoint( + ~publishableKey=confirmParam.publishableKey, + (), + ) + let retrieveUri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}` + intentCall( + ~fetchApi, + ~uri=retrieveUri, + ~headers, + ~bodyStr, + ~confirmParam: ConfirmType.confirmParams, + ~clientSecret, ~optLogger, - ~value=intent.nextAction.type_, - ~internalMetadata=intent.nextAction.type_, - ~eventName=REDIRECTING_USER, - ~paymentMethod, - ~logType=ERROR, + ~handleUserError, + ~paymentType, + ~iframeId, + ~fetchMethod=Get, + ~setIsManualRetryEnabled, + ~switchToCustomPod, + ~sdkHandleOneClickConfirmPayment, + ~counter=counter + 1, (), ) - openUrl(url.href) + ->then( + res => { + resolve(. res) + Promise.resolve() + }, + ) + ->ignore } - } - } else if intent.status == "processing" { - if intent.nextAction.type_ == "third_party_sdk_session_token" { - let session_token = switch intent.nextAction.session_token { - | Some(token) => token->Utils.getDictFromJson - | None => Js.Dict.empty() + }, + )->then(resolve) + }) + } else { + res + ->Fetch.Response.json + ->then(data => { + Js.Promise.make( + (~resolve, ~reject as _) => { + logApi(~optLogger, ~url=uri, ~statusCode, ~type_="response", ~eventName, ()) + let intent = PaymentConfirmTypes.itemToObjMapper(data->getDictFromJson) + let paymentMethod = switch paymentType { + | Card => "CARD" + | _ => intent.payment_method_type } - let walletName = session_token->Utils.getString("wallet_name", "") - let message = switch walletName { - | "apple_pay" => [ - ("applePayButtonClicked", true->Js.Json.boolean), - ("applePayPresent", session_token->toJson), - ] - | "google_pay" => [("googlePayThirdPartyFlow", session_token->toJson)] - | _ => [] + + let url = urlSearch(confirmParam.return_url) + url.searchParams.set(. "payment_intent_client_secret", clientSecret) + url.searchParams.set(. "status", intent.status) + + let handleProcessingStatus = (paymentType, sdkHandleOneClickConfirmPayment) => { + switch (paymentType, sdkHandleOneClickConfirmPayment) { + | (Card, _) + | (Gpay, false) + | (Applepay, false) + | (Paypal, false) => + if !isPaymentSession { + postSubmitResponse(~jsonData=data, ~url=url.href) + } else { + handleOpenUrl(url.href) + } + | _ => handleOpenUrl(url.href) + } } - handlePostMessage(message) - } else { - switch (paymentType, sdkHandleOneClickConfirmPayment) { - | (Card, _) - | (Gpay, false) - | (Applepay, false) - | (Paypal, false) => - postSubmitResponse(~jsonData=data, ~url=url.href) - | _ => openUrl(url.href) + if intent.status == "requires_customer_action" { + if intent.nextAction.type_ == "redirect_to_url" { + handleLogging( + ~optLogger, + ~value="", + ~internalMetadata=intent.nextAction.redirectToUrl, + ~eventName=REDIRECTING_USER, + ~paymentMethod, + (), + ) + handleOpenUrl(intent.nextAction.redirectToUrl) + } else if intent.nextAction.type_ == "display_bank_transfer_information" { + let metadata = switch intent.nextAction.bank_transfer_steps_and_charges_details { + | Some(obj) => obj->Utils.getDictFromJson + | None => Js.Dict.empty() + } + let dict = deepCopyDict(metadata) + dict->Js.Dict.set("data", data) + dict->Js.Dict.set("url", url.href->Js.Json.string) + handleLogging( + ~optLogger, + ~value="", + ~internalMetadata=dict->Js.Json.object_->Js.Json.stringify, + ~eventName=DISPLAY_BANK_TRANSFER_INFO_PAGE, + ~paymentMethod, + (), + ) + if !isPaymentSession { + handlePostMessage([ + ("fullscreen", true->Js.Json.boolean), + ("param", `${intent.payment_method_type}BankTransfer`->Js.Json.string), + ("iframeId", iframeId->Js.Json.string), + ("metadata", dict->Js.Json.object_), + ]) + } + resolve(. data) + } else if intent.nextAction.type_ === "qr_code_information" { + let qrData = intent.nextAction.image_data_url->Belt.Option.getWithDefault("") + let expiryTime = + intent.nextAction.display_to_timestamp->Belt.Option.getWithDefault(0.0) + let headerObj = Js.Dict.empty() + headers->Js.Array2.forEach( + entries => { + let (x, val) = entries + Js.Dict.set(headerObj, x, val->Js.Json.string) + }, + ) + let metaData = + [ + ("qrData", qrData->Js.Json.string), + ("paymentIntentId", clientSecret->Js.Json.string), + ("headers", headerObj->Js.Json.object_), + ("expiryTime", expiryTime->Belt.Float.toString->Js.Json.string), + ("url", url.href->Js.Json.string), + ]->Js.Dict.fromArray + handleLogging( + ~optLogger, + ~value="", + ~internalMetadata=metaData->Js.Json.object_->Js.Json.stringify, + ~eventName=DISPLAY_QR_CODE_INFO_PAGE, + ~paymentMethod, + (), + ) + if !isPaymentSession { + handlePostMessage([ + ("fullscreen", true->Js.Json.boolean), + ("param", `qrData`->Js.Json.string), + ("iframeId", iframeId->Js.Json.string), + ("metadata", metaData->Js.Json.object_), + ]) + } + resolve(. data) + } else if intent.nextAction.type_ == "third_party_sdk_session_token" { + let session_token = switch intent.nextAction.session_token { + | Some(token) => token->Utils.getDictFromJson + | None => Js.Dict.empty() + } + let walletName = session_token->Utils.getString("wallet_name", "") + let message = switch walletName { + | "apple_pay" => [ + ("applePayButtonClicked", true->Js.Json.boolean), + ("applePayPresent", session_token->toJson), + ] + | "google_pay" => [("googlePayThirdPartyFlow", session_token->toJson)] + | _ => [] + } + + if !isPaymentSession { + handlePostMessage(message) + } + resolve(. data) + } else { + if !isPaymentSession { + postFailedSubmitResponse( + ~errortype="confirm_payment_failed", + ~message="Payment failed. Try again!", + ) + } + if uri->Js.String2.includes("force_sync=true") { + handleLogging( + ~optLogger, + ~value=intent.nextAction.type_, + ~internalMetadata=intent.nextAction.type_, + ~eventName=REDIRECTING_USER, + ~paymentMethod, + ~logType=ERROR, + (), + ) + handleOpenUrl(url.href) + } else { + resolve(. data) + } + } + } else if intent.status == "processing" { + if intent.nextAction.type_ == "third_party_sdk_session_token" { + let session_token = switch intent.nextAction.session_token { + | Some(token) => token->Utils.getDictFromJson + | None => Js.Dict.empty() + } + let walletName = session_token->Utils.getString("wallet_name", "") + let message = switch walletName { + | "apple_pay" => [ + ("applePayButtonClicked", true->Js.Json.boolean), + ("applePayPresent", session_token->toJson), + ] + | "google_pay" => [("googlePayThirdPartyFlow", session_token->toJson)] + | _ => [] + } + + if !isPaymentSession { + handlePostMessage(message) + } + } else { + handleProcessingStatus(paymentType, sdkHandleOneClickConfirmPayment) + } + resolve(. data) + } else if intent.status != "" { + if intent.status === "succeeded" { + handleLogging( + ~optLogger, + ~value=intent.status, + ~eventName=PAYMENT_SUCCESS, + ~paymentMethod, + (), + ) + } else if intent.status === "failed" { + handleLogging( + ~optLogger, + ~value=intent.status, + ~eventName=PAYMENT_FAILED, + ~paymentMethod, + (), + ) + } + if intent.status === "failed" { + setIsManualRetryEnabled(. _ => intent.manualRetryAllowed) + } + handleProcessingStatus(paymentType, sdkHandleOneClickConfirmPayment) + } else if !isPaymentSession { + postFailedSubmitResponse( + ~errortype="confirm_payment_failed", + ~message="Payment failed. Try again!", + ) + } else { + resolve(. data) } - } - } else if intent.status != "" { - if intent.status === "succeeded" { - handleLogging( - ~optLogger, - ~value=intent.status, - ~eventName=PAYMENT_SUCCESS, - ~paymentMethod, - (), - ) - } else if intent.status === "failed" { - handleLogging( - ~optLogger, - ~value=intent.status, - ~eventName=PAYMENT_FAILED, - ~paymentMethod, - (), - ) - } - if intent.status === "failed" { - setIsManualRetryEnabled(. _ => intent.manualRetryAllowed) - } - switch (paymentType, sdkHandleOneClickConfirmPayment) { - | (Card, _) - | (Gpay, false) - | (Applepay, false) - | (Paypal, false) => - postSubmitResponse(~jsonData=data, ~url=url.href) - | _ => openUrl(url.href) - } - } else { - postFailedSubmitResponse( - ~errortype="confirm_payment_failed", - ~message="Payment failed. Try again!", - ) - } - resolve() + }, + )->then(resolve) }) - ->ignore } - resolve() }) ->catch(err => { - let exceptionMessage = err->Utils.formatException - logApi( - ~optLogger, - ~url=uri, - ~eventName, - ~type_="no_response", - ~data=exceptionMessage, - ~logType=ERROR, - ~logCategory=API, - (), - ) - if counter >= 5 { + Js.Promise.make((~resolve, ~reject as _) => { let url = urlSearch(confirmParam.return_url) url.searchParams.set(. "payment_intent_client_secret", clientSecret) url.searchParams.set(. "status", "failed") - closePaymentLoaderIfAny() - postFailedSubmitResponse(~errortype="server_error", ~message="Something went wrong") - if handleUserError { - openUrl(url.href) - } - } else { - let paymentIntentID = - Js.String2.split(clientSecret, "_secret_") - ->Belt.Array.get(0) - ->Belt.Option.getWithDefault("") - let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey=confirmParam.publishableKey, ()) - let retrieveUri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}` - intentCall( - ~fetchApi, - ~uri=retrieveUri, - ~headers, - ~bodyStr, - ~confirmParam: ConfirmType.confirmParams, - ~clientSecret, + let exceptionMessage = err->Utils.formatException + logApi( ~optLogger, - ~handleUserError, - ~paymentType, - ~iframeId, - ~fetchMethod=Get, - ~setIsManualRetryEnabled, - ~switchToCustomPod, - ~sdkHandleOneClickConfirmPayment, - ~counter=counter + 1, + ~url=uri, + ~eventName, + ~type_="no_response", + ~data=exceptionMessage, + ~logType=ERROR, + ~logCategory=API, + (), ) - } - resolve() + if counter >= 5 { + if !isPaymentSession { + closePaymentLoaderIfAny() + postFailedSubmitResponse(~errortype="server_error", ~message="Something went wrong") + } + if handleUserError { + handleOpenUrl(url.href) + } else { + resolve(. exceptionMessage) + } + } else { + let paymentIntentID = + Js.String2.split(clientSecret, "_secret_") + ->Belt.Array.get(0) + ->Belt.Option.getWithDefault("") + let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey=confirmParam.publishableKey, ()) + let retrieveUri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}` + intentCall( + ~fetchApi, + ~uri=retrieveUri, + ~headers, + ~bodyStr, + ~confirmParam: ConfirmType.confirmParams, + ~clientSecret, + ~optLogger, + ~handleUserError, + ~paymentType, + ~iframeId, + ~fetchMethod=Get, + ~setIsManualRetryEnabled, + ~switchToCustomPod, + ~sdkHandleOneClickConfirmPayment, + ~counter=counter + 1, + ~isPaymentSession, + (), + ) + ->then( + res => { + resolve(. res) + Promise.resolve() + }, + ) + ->ignore + } + })->then(resolve) }) - ->ignore } let usePaymentSync = (optLogger: option, paymentType: payment) => { @@ -528,7 +565,8 @@ let usePaymentSync = (optLogger: option, paymentType: pay ~switchToCustomPod, ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, - ) + (), + )->ignore } switch list { | Loaded(_) => paymentSync() @@ -679,7 +717,8 @@ let usePaymentIntent = (optLogger: option, paymentType: p ~switchToCustomPod, ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, - ) + (), + )->ignore } } diff --git a/src/Window.res b/src/Window.res index 4b327b81c..c96077da3 100644 --- a/src/Window.res +++ b/src/Window.res @@ -125,3 +125,6 @@ let isSandbox = hostname === "beta.hyperswitch.io" let isInteg = hostname === "dev.hyperswitch.io" let isProd = hostname === "checkout.hyperswitch.io" + +type location = {replace: (. string) => unit} +@val @scope("window") external location: location = "location" diff --git a/src/orca-loader/Hyper.res b/src/orca-loader/Hyper.res index bb037fbaf..73d1802be 100644 --- a/src/orca-loader/Hyper.res +++ b/src/orca-loader/Hyper.res @@ -488,6 +488,34 @@ let make = (publishableKey, options: option, analyticsInfo: option { + open Promise + + let clientSecretId = + paymentSessionOptions + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("clientSecret")) + ->Belt.Option.flatMap(Js.Json.decodeString) + ->Belt.Option.getWithDefault("") + clientSecret := clientSecretId + Js.Promise.make((~resolve, ~reject as _) => { + logger.setClientSecret(clientSecretId) + resolve(. Js.Json.null) + }) + ->then(_ => { + logger.setLogInfo(~value=Window.href, ~eventName=PAYMENT_SESSION_INITIATED, ()) + resolve() + }) + ->ignore + + PaymentSession.make( + paymentSessionOptions, + ~clientSecret={clientSecretId}, + ~publishableKey, + ~logger=Some(logger), + ) + } + let returnObject = { confirmOneClickPayment, confirmPayment, @@ -496,6 +524,7 @@ let make = (publishableKey, options: option, analyticsInfo: option { @val external window: {..} = "window" window["Hyper"] = Hyper.make +window["Hyper"]["init"] = Hyper.make let isWordpress = window["wp"] !== Js.Json.null if !isWordpress { diff --git a/src/orca-loader/LoaderPaymentElement.res b/src/orca-loader/LoaderPaymentElement.res index df198ccf0..a2b1133cb 100644 --- a/src/orca-loader/LoaderPaymentElement.res +++ b/src/orca-loader/LoaderPaymentElement.res @@ -6,9 +6,6 @@ open OrcaUtils external eventToJson: Types.eventData => Js.Json.t = "%identity" -type location = {replace: (. string) => unit} -@val @scope("window") external location: location = "location" - @val @scope(("navigator", "clipboard")) external writeText: string => Js.Promise.t<'a> = "writeText" @@ -196,7 +193,7 @@ let make = (componentType, options, setIframeRef, iframeRef, mountPostMessage) = switch eventDataObject->getOptionalJsonFromJson("openurl") { | Some(val) => { let url = val->getStringfromjson("") - location.replace(. url) + Window.location.replace(. url) } | None => () } diff --git a/src/orca-loader/PaymentSession.res b/src/orca-loader/PaymentSession.res new file mode 100644 index 000000000..0fe768625 --- /dev/null +++ b/src/orca-loader/PaymentSession.res @@ -0,0 +1,156 @@ +open Types + +let make = (options, ~clientSecret, ~publishableKey, ~logger: option) => { + open Promise + let logger = logger->Belt.Option.getWithDefault(OrcaLogger.defaultLoggerConfig) + let switchToCustomPod = + GlobalVars.isInteg && + options + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("switchToCustomPod")) + ->Belt.Option.flatMap(Js.Json.decodeBoolean) + ->Belt.Option.getWithDefault(false) + let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey, ()) + + let defaultPaymentMethodList = ref(Js.Json.null) + + let customerDetailsPromise = PaymentHelpers.useCustomerDetails( + ~clientSecret, + ~publishableKey, + ~endpoint, + ~switchToCustomPod, + ~optLogger=Some(logger), + ) + + let getDefaultPaymentMethod = () => { + customerDetailsPromise + ->then(customerDetails => { + let customerPaymentMethods = + customerDetails + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("customer_payment_methods")) + ->Belt.Option.flatMap(Js.Json.decodeArray) + ->Belt.Option.getWithDefault([]) + ->Js.Array2.filter(customerPaymentMethod => { + customerPaymentMethod + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("default_payment_method_set")) + ->Belt.Option.flatMap(Js.Json.decodeBoolean) + ->Belt.Option.getWithDefault(false) + }) + let isGuestCustomer = + customerDetails + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("is_guest_customer")) + ->Belt.Option.getWithDefault(Js.Json.null) + let updatedCustomerDetails = + [ + ("customer_payment_methods", customerPaymentMethods->Js.Json.array), + ("is_guest_customer", isGuestCustomer), + ] + ->Js.Dict.fromArray + ->Js.Json.object_ + defaultPaymentMethodList := updatedCustomerDetails + updatedCustomerDetails->resolve + }) + ->catch(_err => { + let dict = + [("customer_payment_methods", []->Js.Json.array)]->Js.Dict.fromArray->Js.Json.object_ + let msg = [("customerPaymentMethods", dict)]->Js.Dict.fromArray + resolve(msg->Js.Json.object_) + }) + } + + let confirmWithDefault = payload => { + let customerPaymentMethod = + defaultPaymentMethodList.contents + ->Utils.getDictFromJson + ->Js.Dict.get("customer_payment_methods") + ->Belt.Option.flatMap(Js.Json.decodeArray) + ->Belt.Option.getWithDefault([]) + ->Belt.Array.get(0) + ->Belt.Option.flatMap(Js.Json.decodeObject) + ->Belt.Option.getWithDefault(Js.Dict.empty()) + let paymentToken = customerPaymentMethod->Utils.getJsonFromDict("payment_token", Js.Json.null) + let paymentMethod = customerPaymentMethod->Utils.getJsonFromDict("payment_method", Js.Json.null) + let paymentMethodType = + customerPaymentMethod->Utils.getJsonFromDict("payment_method_type", Js.Json.null) + + let confirmParams = + payload + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("confirmParams")) + ->Belt.Option.getWithDefault(Js.Json.null) + + let returnUrl = + confirmParams + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("return_url")) + ->Belt.Option.flatMap(Js.Json.decodeString) + ->Belt.Option.getWithDefault("") + + let confirmParam: ConfirmType.confirmParams = { + return_url: returnUrl, + publishableKey, + } + + let paymentIntentID = Js.String2.split(clientSecret, "_secret_")[0] + let endpoint = ApiEndpoint.getApiEndPoint( + ~publishableKey=confirmParam.publishableKey, + ~isConfirmCall=true, + (), + ) + let uri = `${endpoint}/payments/${paymentIntentID}/confirm` + let headers = [("Content-Type", "application/json"), ("api-key", confirmParam.publishableKey)] + + let paymentType: PaymentHelpers.payment = switch paymentMethodType + ->Js.Json.decodeString + ->Belt.Option.getWithDefault("") { + | "apple_pay" => Applepay + | "google_pay" => Gpay + | "debit" + | "credit" + | "" => + Card + | _ => Other + } + + let broswerInfo = BrowserSpec.broswerInfo() + + let body = [ + ("client_secret", clientSecret->Js.Json.string), + ("payment_method", paymentMethod), + ("payment_token", paymentToken), + ("payment_method_type", paymentMethodType), + ] + + let bodyStr = + body->Js.Array2.concat(broswerInfo)->Js.Dict.fromArray->Js.Json.object_->Js.Json.stringify + + PaymentHelpers.intentCall( + ~fetchApi=Utils.fetchApi, + ~uri, + ~headers, + ~bodyStr, + ~confirmParam: ConfirmType.confirmParams, + ~clientSecret, + ~optLogger=Some(logger), + ~handleUserError=false, + ~paymentType, + ~iframeId="", + ~fetchMethod=Fetch.Post, + ~setIsManualRetryEnabled={(. _) => ()}, + ~switchToCustomPod=false, + ~sdkHandleOneClickConfirmPayment=false, + ~counter=0, + ~isPaymentSession=true, + (), + ) + } + + let returnObject = { + getDefaultPaymentMethod, + confirmWithDefault, + } + returnObject +} diff --git a/src/orca-loader/Types.res b/src/orca-loader/Types.res index a37ab20b0..06e162574 100644 --- a/src/orca-loader/Types.res +++ b/src/orca-loader/Types.res @@ -39,6 +39,11 @@ type element = { create: (Js.Dict.key, Js.Json.t) => paymentElement, } +type initPaymentSession = { + getDefaultPaymentMethod: unit => Promise.t, + confirmWithDefault: Js.Json.t => Promise.t, +} + type confirmParams = {return_url: string} type confirmPaymentParams = { @@ -56,6 +61,7 @@ type hyperInstance = { retrievePaymentIntent: string => Js.Promise.t, widgets: Js.Json.t => element, paymentRequest: Js.Json.t => Js.Json.t, + initPaymentSession: Js.Json.t => initPaymentSession, } let oneClickConfirmPaymentFn = (_, _) => { @@ -115,6 +121,19 @@ let defaultElement = { create, } +let getDefaultPaymentMethod = () => { + Js.Promise.resolve(Js.Dict.empty()->Js.Json.object_) +} + +let confirmWithDefault = _confirmParams => { + Js.Promise.resolve(Js.Dict.empty()->Js.Json.object_) +} + +let defaultInitPaymentSession: initPaymentSession = { + getDefaultPaymentMethod, + confirmWithDefault, +} + let defaultHyperInstance = { confirmOneClickPayment: oneClickConfirmPaymentFn, confirmPayment: confirmPaymentFn, @@ -123,6 +142,7 @@ let defaultHyperInstance = { elements: _ev => defaultElement, widgets: _ev => defaultElement, paymentRequest: _ev => Js.Json.null, + initPaymentSession: _ev => defaultInitPaymentSession, } type eventType = diff --git a/src/orca-log-catcher/OrcaLogger.res b/src/orca-log-catcher/OrcaLogger.res index c0c9671df..0a9c2c0f6 100644 --- a/src/orca-log-catcher/OrcaLogger.res +++ b/src/orca-log-catcher/OrcaLogger.res @@ -56,6 +56,7 @@ type eventName = | DISPLAY_VOUCHER | PAYMENT_METHODS_RESPONSE | LOADER_CHANGED + | PAYMENT_SESSION_INITIATED let eventNameToStrMapper = eventName => { switch eventName { @@ -113,6 +114,7 @@ let eventNameToStrMapper = eventName => { | DISPLAY_VOUCHER => "DISPLAY_VOUCHER" | PAYMENT_METHODS_RESPONSE => "PAYMENT_METHODS_RESPONSE" | LOADER_CHANGED => "LOADER_CHANGED" + | PAYMENT_SESSION_INITIATED => "PAYMENT_SESSION_INITIATED" } } From 882f901265da600284f602ba31ac7480cbf6f84c Mon Sep 17 00:00:00 2001 From: Arush Date: Mon, 11 Mar 2024 23:06:53 +0530 Subject: [PATCH 2/2] fix: added Support for future APIs and added error handling fix #207 --- src/Utilities/PaymentHelpers.res | 35 ++++- src/Utilities/Utils.res | 13 ++ src/orca-loader/PaymentSession.res | 150 ++---------------- src/orca-loader/PaymentSessionMethods.res | 180 ++++++++++++++++++++++ src/orca-loader/Types.res | 26 +++- 5 files changed, 250 insertions(+), 154 deletions(-) create mode 100644 src/orca-loader/PaymentSessionMethods.res diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 917ddb84d..812dcd0d1 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -116,6 +116,7 @@ let rec intentCall = ( ~sdkHandleOneClickConfirmPayment, ~counter, ~isPaymentSession=false, + ~paymentSessionRedirect="if_redirect", (), ) => { open Promise @@ -199,7 +200,11 @@ let rec intentCall = ( if handleUserError { handleOpenUrl(url.href) } else { - resolve(. data) + let failedSubmitResponse = getFailedSubmitResponse( + ~errorType=errorObj.error.type_, + ~message=errorObj.error.message, + ) + resolve(. failedSubmitResponse) } }, )->then(resolve) @@ -227,7 +232,11 @@ let rec intentCall = ( if handleUserError { handleOpenUrl(url.href) } else { - resolve(. exceptionMessage) + let failedSubmitResponse = getFailedSubmitResponse( + ~errorType="server_error", + ~message="Something went wrong", + ) + resolve(. failedSubmitResponse) } } else { let paymentIntentID = @@ -293,8 +302,10 @@ let rec intentCall = ( | (Paypal, false) => if !isPaymentSession { postSubmitResponse(~jsonData=data, ~url=url.href) - } else { + } else if paymentSessionRedirect === "always" { handleOpenUrl(url.href) + } else { + resolve(. data) } | _ => handleOpenUrl(url.href) } @@ -410,7 +421,11 @@ let rec intentCall = ( ) handleOpenUrl(url.href) } else { - resolve(. data) + let failedSubmitResponse = getFailedSubmitResponse( + ~errorType="confirm_payment_failed", + ~message="Payment failed. Try again!", + ) + resolve(. failedSubmitResponse) } } } else if intent.status == "processing" { @@ -464,7 +479,11 @@ let rec intentCall = ( ~message="Payment failed. Try again!", ) } else { - resolve(. data) + let failedSubmitResponse = getFailedSubmitResponse( + ~errorType="confirm_payment_failed", + ~message="Payment failed. Try again!", + ) + resolve(. failedSubmitResponse) } }, )->then(resolve) @@ -495,7 +514,11 @@ let rec intentCall = ( if handleUserError { handleOpenUrl(url.href) } else { - resolve(. exceptionMessage) + let failedSubmitResponse = getFailedSubmitResponse( + ~errorType="server_error", + ~message="Something went wrong", + ) + resolve(. failedSubmitResponse) } } else { let paymentIntentID = diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index afad299f9..2362ff5bd 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -273,6 +273,19 @@ let postSubmitResponse = (~jsonData, ~url) => { ]) } +let getFailedSubmitResponse = (~errorType, ~message) => { + [ + ( + "error", + [("type", errorType->Js.Json.string), ("message", message->Js.Json.string)] + ->Js.Dict.fromArray + ->Js.Json.object_, + ), + ] + ->Js.Dict.fromArray + ->Js.Json.object_ +} + let toCamelCase = str => { if str->Js.String2.includes(":") { str diff --git a/src/orca-loader/PaymentSession.res b/src/orca-loader/PaymentSession.res index 0fe768625..87d485baf 100644 --- a/src/orca-loader/PaymentSession.res +++ b/src/orca-loader/PaymentSession.res @@ -1,7 +1,6 @@ open Types let make = (options, ~clientSecret, ~publishableKey, ~logger: option) => { - open Promise let logger = logger->Belt.Option.getWithDefault(OrcaLogger.defaultLoggerConfig) let switchToCustomPod = GlobalVars.isInteg && @@ -12,145 +11,16 @@ let make = (options, ~clientSecret, ~publishableKey, ~logger: optionBelt.Option.getWithDefault(false) let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey, ()) - let defaultPaymentMethodList = ref(Js.Json.null) - - let customerDetailsPromise = PaymentHelpers.useCustomerDetails( - ~clientSecret, - ~publishableKey, - ~endpoint, - ~switchToCustomPod, - ~optLogger=Some(logger), - ) - - let getDefaultPaymentMethod = () => { - customerDetailsPromise - ->then(customerDetails => { - let customerPaymentMethods = - customerDetails - ->Js.Json.decodeObject - ->Belt.Option.flatMap(x => x->Js.Dict.get("customer_payment_methods")) - ->Belt.Option.flatMap(Js.Json.decodeArray) - ->Belt.Option.getWithDefault([]) - ->Js.Array2.filter(customerPaymentMethod => { - customerPaymentMethod - ->Js.Json.decodeObject - ->Belt.Option.flatMap(x => x->Js.Dict.get("default_payment_method_set")) - ->Belt.Option.flatMap(Js.Json.decodeBoolean) - ->Belt.Option.getWithDefault(false) - }) - let isGuestCustomer = - customerDetails - ->Js.Json.decodeObject - ->Belt.Option.flatMap(x => x->Js.Dict.get("is_guest_customer")) - ->Belt.Option.getWithDefault(Js.Json.null) - let updatedCustomerDetails = - [ - ("customer_payment_methods", customerPaymentMethods->Js.Json.array), - ("is_guest_customer", isGuestCustomer), - ] - ->Js.Dict.fromArray - ->Js.Json.object_ - defaultPaymentMethodList := updatedCustomerDetails - updatedCustomerDetails->resolve - }) - ->catch(_err => { - let dict = - [("customer_payment_methods", []->Js.Json.array)]->Js.Dict.fromArray->Js.Json.object_ - let msg = [("customerPaymentMethods", dict)]->Js.Dict.fromArray - resolve(msg->Js.Json.object_) - }) - } - - let confirmWithDefault = payload => { - let customerPaymentMethod = - defaultPaymentMethodList.contents - ->Utils.getDictFromJson - ->Js.Dict.get("customer_payment_methods") - ->Belt.Option.flatMap(Js.Json.decodeArray) - ->Belt.Option.getWithDefault([]) - ->Belt.Array.get(0) - ->Belt.Option.flatMap(Js.Json.decodeObject) - ->Belt.Option.getWithDefault(Js.Dict.empty()) - let paymentToken = customerPaymentMethod->Utils.getJsonFromDict("payment_token", Js.Json.null) - let paymentMethod = customerPaymentMethod->Utils.getJsonFromDict("payment_method", Js.Json.null) - let paymentMethodType = - customerPaymentMethod->Utils.getJsonFromDict("payment_method_type", Js.Json.null) - - let confirmParams = - payload - ->Js.Json.decodeObject - ->Belt.Option.flatMap(x => x->Js.Dict.get("confirmParams")) - ->Belt.Option.getWithDefault(Js.Json.null) - - let returnUrl = - confirmParams - ->Js.Json.decodeObject - ->Belt.Option.flatMap(x => x->Js.Dict.get("return_url")) - ->Belt.Option.flatMap(Js.Json.decodeString) - ->Belt.Option.getWithDefault("") - - let confirmParam: ConfirmType.confirmParams = { - return_url: returnUrl, - publishableKey, - } - - let paymentIntentID = Js.String2.split(clientSecret, "_secret_")[0] - let endpoint = ApiEndpoint.getApiEndPoint( - ~publishableKey=confirmParam.publishableKey, - ~isConfirmCall=true, - (), - ) - let uri = `${endpoint}/payments/${paymentIntentID}/confirm` - let headers = [("Content-Type", "application/json"), ("api-key", confirmParam.publishableKey)] - - let paymentType: PaymentHelpers.payment = switch paymentMethodType - ->Js.Json.decodeString - ->Belt.Option.getWithDefault("") { - | "apple_pay" => Applepay - | "google_pay" => Gpay - | "debit" - | "credit" - | "" => - Card - | _ => Other - } - - let broswerInfo = BrowserSpec.broswerInfo() - - let body = [ - ("client_secret", clientSecret->Js.Json.string), - ("payment_method", paymentMethod), - ("payment_token", paymentToken), - ("payment_method_type", paymentMethodType), - ] - - let bodyStr = - body->Js.Array2.concat(broswerInfo)->Js.Dict.fromArray->Js.Json.object_->Js.Json.stringify - - PaymentHelpers.intentCall( - ~fetchApi=Utils.fetchApi, - ~uri, - ~headers, - ~bodyStr, - ~confirmParam: ConfirmType.confirmParams, - ~clientSecret, - ~optLogger=Some(logger), - ~handleUserError=false, - ~paymentType, - ~iframeId="", - ~fetchMethod=Fetch.Post, - ~setIsManualRetryEnabled={(. _) => ()}, - ~switchToCustomPod=false, - ~sdkHandleOneClickConfirmPayment=false, - ~counter=0, - ~isPaymentSession=true, - (), - ) + let defaultInitPaymentSession = { + getCustomerSavedPaymentMethods: _ => + PaymentSessionMethods.getCustomerSavedPaymentMethods( + ~clientSecret, + ~publishableKey, + ~endpoint, + ~logger, + ~switchToCustomPod, + ), } - let returnObject = { - getDefaultPaymentMethod, - confirmWithDefault, - } - returnObject + defaultInitPaymentSession } diff --git a/src/orca-loader/PaymentSessionMethods.res b/src/orca-loader/PaymentSessionMethods.res new file mode 100644 index 000000000..dbb085fb7 --- /dev/null +++ b/src/orca-loader/PaymentSessionMethods.res @@ -0,0 +1,180 @@ +open Types + +external customerSavedPaymentMethodsToJson: getCustomerSavedPaymentMethods => Js.Json.t = + "%identity" + +let getCustomerSavedPaymentMethods = ( + ~clientSecret, + ~publishableKey, + ~endpoint, + ~logger, + ~switchToCustomPod, +) => { + open Promise + PaymentHelpers.useCustomerDetails( + ~clientSecret, + ~publishableKey, + ~endpoint, + ~switchToCustomPod, + ~optLogger=Some(logger), + ) + ->then(customerDetails => { + let customerPaymentMethods = + customerDetails + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("customer_payment_methods")) + ->Belt.Option.flatMap(Js.Json.decodeArray) + ->Belt.Option.getWithDefault([]) + ->Js.Array2.filter(customerPaymentMethod => { + customerPaymentMethod + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("default_payment_method_set")) + ->Belt.Option.flatMap(Js.Json.decodeBoolean) + ->Belt.Option.getWithDefault(false) + }) + + switch customerPaymentMethods->Belt.Array.get(0) { + | Some(customerDefaultPaymentMethod) => + let getCustomerDefaultSavedPaymentMethodData = () => { + customerDefaultPaymentMethod + } + + let confirmWithCustomerDefaultPaymentMethod = payload => { + let customerPaymentMethod = + customerDefaultPaymentMethod + ->Js.Json.decodeObject + ->Belt.Option.getWithDefault(Js.Dict.empty()) + let paymentToken = + customerPaymentMethod->Utils.getJsonFromDict("payment_token", Js.Json.null) + let paymentMethod = + customerPaymentMethod->Utils.getJsonFromDict("payment_method", Js.Json.null) + let paymentMethodType = + customerPaymentMethod->Utils.getJsonFromDict("payment_method_type", Js.Json.null) + + let confirmParams = + payload + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("confirmParams")) + ->Belt.Option.getWithDefault(Js.Json.null) + + let redirect = + payload + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("redirect")) + ->Belt.Option.flatMap(Js.Json.decodeString) + ->Belt.Option.getWithDefault("if_required") + + let returnUrl = + confirmParams + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => x->Js.Dict.get("return_url")) + ->Belt.Option.flatMap(Js.Json.decodeString) + ->Belt.Option.getWithDefault("") + + let confirmParam: ConfirmType.confirmParams = { + return_url: returnUrl, + publishableKey, + } + + let paymentIntentID = Js.String2.split(clientSecret, "_secret_")[0]->Option.getOr("") + let endpoint = ApiEndpoint.getApiEndPoint( + ~publishableKey=confirmParam.publishableKey, + ~isConfirmCall=true, + (), + ) + let uri = `${endpoint}/payments/${paymentIntentID}/confirm` + let headers = [ + ("Content-Type", "application/json"), + ("api-key", confirmParam.publishableKey), + ] + + let paymentType: PaymentHelpers.payment = switch paymentMethodType + ->Js.Json.decodeString + ->Belt.Option.getWithDefault("") { + | "apple_pay" => Applepay + | "google_pay" => Gpay + | "debit" + | "credit" + | "" => + Card + | _ => Other + } + + let broswerInfo = BrowserSpec.broswerInfo() + + let body = [ + ("client_secret", clientSecret->Js.Json.string), + ("payment_method", paymentMethod), + ("payment_token", paymentToken), + ("payment_method_type", paymentMethodType), + ] + + let bodyStr = + body->Js.Array2.concat(broswerInfo)->Js.Dict.fromArray->Js.Json.object_->Js.Json.stringify + + PaymentHelpers.intentCall( + ~fetchApi=Utils.fetchApi, + ~uri, + ~headers, + ~bodyStr, + ~confirmParam: ConfirmType.confirmParams, + ~clientSecret, + ~optLogger=Some(logger), + ~handleUserError=false, + ~paymentType, + ~iframeId="", + ~fetchMethod=Fetch.Post, + ~setIsManualRetryEnabled={(. _) => ()}, + ~switchToCustomPod=false, + ~sdkHandleOneClickConfirmPayment=false, + ~counter=0, + ~isPaymentSession=true, + ~paymentSessionRedirect=redirect, + (), + ) + } + + { + getCustomerDefaultSavedPaymentMethodData, + confirmWithCustomerDefaultPaymentMethod, + } + ->customerSavedPaymentMethodsToJson + ->resolve + | None => { + let updatedCustomerDetails = + [ + ( + "error", + [ + ("type", "no_data"->Js.Json.string), + ( + "message", + "There is no customer default saved payment method data"->Js.Json.string, + ), + ] + ->Js.Dict.fromArray + ->Js.Json.object_, + ), + ] + ->Js.Dict.fromArray + ->Js.Json.object_ + updatedCustomerDetails->resolve + } + } + }) + ->catch(err => { + let exceptionMessage = err->Utils.formatException->Js.Json.stringify + let updatedCustomerDetails = + [ + ( + "error", + [("type", "server_error"->Js.Json.string), ("message", exceptionMessage->Js.Json.string)] + ->Js.Dict.fromArray + ->Js.Json.object_, + ), + ] + ->Js.Dict.fromArray + ->Js.Json.object_ + updatedCustomerDetails->resolve + }) +} diff --git a/src/orca-loader/Types.res b/src/orca-loader/Types.res index 06e162574..bc19dcb67 100644 --- a/src/orca-loader/Types.res +++ b/src/orca-loader/Types.res @@ -39,11 +39,13 @@ type element = { create: (Js.Dict.key, Js.Json.t) => paymentElement, } -type initPaymentSession = { - getDefaultPaymentMethod: unit => Promise.t, - confirmWithDefault: Js.Json.t => Promise.t, +type getCustomerSavedPaymentMethods = { + getCustomerDefaultSavedPaymentMethodData: unit => Js.Json.t, + confirmWithCustomerDefaultPaymentMethod: Js.Json.t => Promise.t, } +type initPaymentSession = {getCustomerSavedPaymentMethods: unit => Promise.t} + type confirmParams = {return_url: string} type confirmPaymentParams = { @@ -121,17 +123,25 @@ let defaultElement = { create, } -let getDefaultPaymentMethod = () => { - Js.Promise.resolve(Js.Dict.empty()->Js.Json.object_) +let getCustomerDefaultSavedPaymentMethodData = () => { + Js.Json.null } -let confirmWithDefault = _confirmParams => { +let confirmWithCustomerDefaultPaymentMethod = _confirmParams => { Js.Promise.resolve(Js.Dict.empty()->Js.Json.object_) } +let defaultGetCustomerSavedPaymentMethods = () => { + // TODO: After rescript migration to v11, add this without TAG using enums + // Js.Promise.resolve({ + // getCustomerDefaultSavedPaymentMethodData, + // confirmWithCustomerDefaultPaymentMethod, + // }) + Js.Promise.resolve(Js.Json.null) +} + let defaultInitPaymentSession: initPaymentSession = { - getDefaultPaymentMethod, - confirmWithDefault, + getCustomerSavedPaymentMethods: defaultGetCustomerSavedPaymentMethods, } let defaultHyperInstance = {