From 0039fbe65ec7ff958d637d00c58aed710fed5b1f Mon Sep 17 00:00:00 2001 From: Sagnik Mitra <83326850+ImSagnik007@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:43:43 +0530 Subject: [PATCH] feat: tax calculation in google pay (#750) Co-authored-by: Pritish Budhiraja Co-authored-by: Shiva Nandan --- src/Components/SavedMethods.res | 1 + src/Payments/GPay.res | 1 + src/Types/GooglePayType.res | 2 + src/Utilities/GooglePayHelpers.res | 21 ++++- src/orca-loader/Elements.res | 123 +++++++++++++++++++++++------ 5 files changed, 120 insertions(+), 28 deletions(-) diff --git a/src/Components/SavedMethods.res b/src/Components/SavedMethods.res index ae2dbdf1f..2516e9ca5 100644 --- a/src/Components/SavedMethods.res +++ b/src/Components/SavedMethods.res @@ -141,6 +141,7 @@ let make = ( GooglePayHelpers.handleGooglePayClicked( ~sessionObj=optToken, ~componentName, + ~paymentMethodListValue, ~iframeId, ~readOnly, ) diff --git a/src/Payments/GPay.res b/src/Payments/GPay.res index d9e0c69d1..26ba4e176 100644 --- a/src/Payments/GPay.res +++ b/src/Payments/GPay.res @@ -127,6 +127,7 @@ let make = ( GooglePayHelpers.handleGooglePayClicked( ~sessionObj, ~componentName, + ~paymentMethodListValue, ~iframeId, ~readOnly=options.readOnly, ) diff --git a/src/Types/GooglePayType.res b/src/Types/GooglePayType.res index a2d99aaf6..acbbf276e 100644 --- a/src/Types/GooglePayType.res +++ b/src/Types/GooglePayType.res @@ -14,6 +14,7 @@ type paymentDataRequest = { mutable shippingAddressRequired: bool, mutable emailRequired: bool, mutable shippingAddressParameters: JSON.t, + mutable callbackIntents: array, } @val @scope("Object") external assign2: (JSON.t, JSON.t) => paymentDataRequest = "assign" type element = { @@ -180,6 +181,7 @@ let getPaymentDataFromSession = (~sessionObj, ~componentName) => { paymentDataRequest.shippingAddressRequired = gpayobj.shippingAddressRequired paymentDataRequest.shippingAddressParameters = gpayobj.shippingAddressParameters->transformKeys(CamelCase) + paymentDataRequest.callbackIntents = ["SHIPPING_ADDRESS"->JSON.Encode.string] } paymentDataRequest diff --git a/src/Utilities/GooglePayHelpers.res b/src/Utilities/GooglePayHelpers.res index 04b9c9ef6..a8007b69a 100644 --- a/src/Utilities/GooglePayHelpers.res +++ b/src/Utilities/GooglePayHelpers.res @@ -151,7 +151,13 @@ let useHandleGooglePayResponse = ( }, (paymentMethodTypes, stateJson, isManualRetryEnabled, requiredFieldsBody, isWallet)) } -let handleGooglePayClicked = (~sessionObj, ~componentName, ~iframeId, ~readOnly) => { +let handleGooglePayClicked = ( + ~sessionObj, + ~componentName, + ~iframeId, + ~readOnly, + ~paymentMethodListValue: PaymentMethodsRecord.paymentMethodList, +) => { let paymentDataRequest = GooglePayType.getPaymentDataFromSession(~sessionObj, ~componentName) messageParentWindow([ ("fullscreen", true->JSON.Encode.bool), @@ -162,6 +168,10 @@ let handleGooglePayClicked = (~sessionObj, ~componentName, ~iframeId, ~readOnly) messageParentWindow([ ("GpayClicked", true->JSON.Encode.bool), ("GpayPaymentDataRequest", paymentDataRequest->Identity.anyTypeToJson), + ( + "IsTaxCalculationEnabled", + paymentMethodListValue.is_tax_calculation_enabled->JSON.Encode.bool, + ), ]) } } @@ -169,6 +179,7 @@ let handleGooglePayClicked = (~sessionObj, ~componentName, ~iframeId, ~readOnly) let useSubmitCallback = (~isWallet, ~sessionObj, ~componentName) => { let areRequiredFieldsValid = Recoil.useRecoilValueFromAtom(RecoilAtoms.areRequiredFieldsValid) let areRequiredFieldsEmpty = Recoil.useRecoilValueFromAtom(RecoilAtoms.areRequiredFieldsEmpty) + let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue) let options = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom) let {localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom) let {iframeId} = Recoil.useRecoilValueFromAtom(RecoilAtoms.keys) @@ -178,7 +189,13 @@ let useSubmitCallback = (~isWallet, ~sessionObj, ~componentName) => { let json = ev.data->safeParse let confirm = json->getDictFromJson->ConfirmType.itemToObjMapper if confirm.doSubmit && areRequiredFieldsValid && !areRequiredFieldsEmpty { - handleGooglePayClicked(~sessionObj, ~componentName, ~iframeId, ~readOnly=options.readOnly) + handleGooglePayClicked( + ~sessionObj, + ~componentName, + ~paymentMethodListValue, + ~iframeId, + ~readOnly=options.readOnly, + ) } else if areRequiredFieldsEmpty { postFailedSubmitResponse( ~errortype="validation_error", diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index a664a8750..d6aa0b596 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -915,35 +915,106 @@ let make = ( ) try { - let gPayClient = GooglePayType.google( - { - "environment": publishableKey->String.startsWith("pk_prd_") - ? "PRODUCTION" - : "TEST", - }->Identity.anyTypeToJson, - ) - - gPayClient.isReadyToPay(payRequest) - ->then(res => { - let dict = res->getDictFromJson - let isReadyToPay = getBool(dict, "result", false) - let msg = [("isReadyToPay", isReadyToPay->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() - }) - ->catch(err => { - logger.setLogInfo( - ~value=err->Identity.anyTypeToJson->JSON.stringify, - ~eventName=GOOGLE_PAY_FLOW, - ~paymentMethod="GOOGLE_PAY", - ~logType=DEBUG, - ) - resolve() - }) - ->ignore + let transactionInfo = gpayobj.transaction_info->getDictFromJson let handleGooglePayMessages = (event: Types.event) => { let evJson = event.data->anyTypeToJson + let isTaxCalculationEnabled = + evJson + ->getOptionalJsonFromJson("IsTaxCalculationEnabled") + ->Option.flatMap(JSON.Decode.bool) + ->Option.getOr(false) + + let onPaymentDataChanged = intermediatePaymentData => { + let shippingAddress = + intermediatePaymentData + ->getDictFromJson + ->getDictFromDict("shippingAddress") + ->billingContactItemToObjMapper + let newShippingAddress = + [ + ("state", shippingAddress.administrativeArea->JSON.Encode.string), + ("country", shippingAddress.countryCode->JSON.Encode.string), + ("zip", shippingAddress.postalCode->JSON.Encode.string), + ]->getJsonFromArrayOfJson + + let paymentMethodType = "google_pay"->JSON.Encode.string + + if isTaxCalculationEnabled { + TaxCalculation.calculateTax( + ~shippingAddress=[ + ("address", newShippingAddress), + ]->getJsonFromArrayOfJson, + ~logger, + ~publishableKey, + ~clientSecret, + ~paymentMethodType, + )->then(resp => { + switch resp->TaxCalculation.taxResponseToObjMapper { + | Some(taxCalculationResponse) => { + let updatePaymentRequest = + [ + ( + "newTransactionInfo", + [ + ( + "countryCode", + shippingAddress.countryCode->JSON.Encode.string, + ), + ( + "currencyCode", + transactionInfo + ->getString("currency_code", "") + ->JSON.Encode.string, + ), + ("totalPriceStatus", "FINAL"->JSON.Encode.string), + ( + "totalPrice", + taxCalculationResponse.net_amount + ->minorUnitToString + ->JSON.Encode.string, + ), + ]->getJsonFromArrayOfJson, + ), + ]->getJsonFromArrayOfJson + updatePaymentRequest->resolve + } + | None => JSON.Encode.null->resolve + } + }) + } else { + JSON.Encode.null->resolve + } + } + let gPayClient = GooglePayType.google( + { + "environment": publishableKey->String.startsWith("pk_prd_") + ? "PRODUCTION" + : "TEST", + "paymentDataCallbacks": { + "onPaymentDataChanged": onPaymentDataChanged, + }, + }->Identity.anyTypeToJson, + ) + + gPayClient.isReadyToPay(payRequest) + ->then(res => { + let dict = res->getDictFromJson + let isReadyToPay = getBool(dict, "result", false) + let msg = [("isReadyToPay", isReadyToPay->JSON.Encode.bool)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + resolve() + }) + ->catch(err => { + logger.setLogInfo( + ~value=err->Identity.anyTypeToJson->JSON.stringify, + ~eventName=GOOGLE_PAY_FLOW, + ~paymentMethod="GOOGLE_PAY", + ~logType=DEBUG, + ) + resolve() + }) + ->ignore let gpayClicked = evJson ->getOptionalJsonFromJson("GpayClicked")