+ className="-ml-1 sticky top-0 z-10 p-1 bg-hyperswitch_background py-3 -mt-3 rounded-lg border">
topFilterUi
diff --git a/src/screens/Connectors/ConnectorMetaData/ApplePay/ApplePaySimplifiedFlow.res b/src/screens/Connectors/ConnectorMetaData/ApplePay/ApplePaySimplifiedFlow.res
index 1981c9ab5..f5e0c63b7 100644
--- a/src/screens/Connectors/ConnectorMetaData/ApplePay/ApplePaySimplifiedFlow.res
+++ b/src/screens/Connectors/ConnectorMetaData/ApplePay/ApplePaySimplifiedFlow.res
@@ -63,7 +63,7 @@ let make = (
let downloadApplePayCert = () => {
open Promise
let downloadURL = Window.env.applePayCertificateUrl->Option.getOr("")
- fetchApi(downloadURL, ~method_=Get)
+ fetchApi(downloadURL, ~method_=Get, ~xFeatureRoute=featureFlagDetails.xFeatureRoute)
->then(Fetch.Response.blob)
->then(content => {
DownloadUtils.download(
diff --git a/src/screens/Connectors/ConnectorUIUtils/PaymentMethod.res b/src/screens/Connectors/ConnectorUIUtils/PaymentMethod.res
index 0e5ebdd0b..ec20c16f4 100644
--- a/src/screens/Connectors/ConnectorUIUtils/PaymentMethod.res
+++ b/src/screens/Connectors/ConnectorUIUtils/PaymentMethod.res
@@ -57,7 +57,7 @@ module CardRenderer = {
let isProfileIdConfiguredPMAuth =
pmAuthProcessorList
- ->Array.filter(item => item.profile_id === currentProfile && item.disabled == false)
+ ->Array.filter(item => item.profile_id === currentProfile && !item.disabled)
->Array.length > 0
let shouldShowPMAuthSidebar =
diff --git a/src/screens/Connectors/ConnectorUtils.res b/src/screens/Connectors/ConnectorUtils.res
index e850669e6..fb66b51f4 100644
--- a/src/screens/Connectors/ConnectorUtils.res
+++ b/src/screens/Connectors/ConnectorUtils.res
@@ -1179,7 +1179,7 @@ let validateConnectorRequiredFields = (
vector->Js.Vector.set(index, res)
})
- let _ = Js.Vector.filterInPlace(val => val == true, vector)
+ Js.Vector.filterInPlace(val => val, vector)
if vector->Js.Vector.length === 0 {
Dict.set(newDict, "Currency", `Please enter currency`->JSON.Encode.string)
diff --git a/src/screens/Developer/APIKeys/DeveloperUtils.res b/src/screens/Developer/APIKeys/DeveloperUtils.res
index c86be45c1..3fcd18198 100644
--- a/src/screens/Developer/APIKeys/DeveloperUtils.res
+++ b/src/screens/Developer/APIKeys/DeveloperUtils.res
@@ -187,6 +187,14 @@ let threeDsRequestorUrl = FormRenderer.makeFieldInfo(
~isRequired=false,
)
+let maxAutoRetries = FormRenderer.makeFieldInfo(
+ ~label="Max Auto Retries",
+ ~name="max_auto_retries_enabled",
+ ~placeholder="Enter number of max auto retries",
+ ~customInput=InputFields.textInput(~autoComplete="off"),
+ ~isRequired=false,
+)
+
module ErrorUI = {
@react.component
let make = (~text) => {
diff --git a/src/screens/Developer/PaymentSettings/PaymentSettings.res b/src/screens/Developer/PaymentSettings/PaymentSettings.res
index de8ea36be..1d084e302 100644
--- a/src/screens/Developer/PaymentSettings/PaymentSettings.res
+++ b/src/screens/Developer/PaymentSettings/PaymentSettings.res
@@ -290,6 +290,49 @@ module CollectDetails = {
}
}
+module AutoRetries = {
+ @react.component
+ let make = () => {
+ open FormRenderer
+ open DeveloperUtils
+ open LogicUtils
+ let formState: ReactFinalForm.formState = ReactFinalForm.useFormState(
+ ReactFinalForm.useFormSubscription(["values"])->Nullable.make,
+ )
+ let form = ReactFinalForm.useForm()
+ let errorClass = "text-sm leading-4 font-medium text-start ml-1 mt-2"
+
+ let isAutoRetryEnabled =
+ formState.values->getDictFromJsonObject->getBool("is_auto_retries_enabled", false)
+
+ if !isAutoRetryEnabled {
+ form.change("max_auto_retries_enabled", JSON.Encode.null->Identity.genericTypeToJson)
+ }
+
+ <>
+
+
+
+
+
+
+ >
+ }
+}
+
@react.component
let make = (~webhookOnly=false, ~showFormOnly=false, ~profileId="") => {
open DeveloperUtils
@@ -308,11 +351,19 @@ let make = (~webhookOnly=false, ~showFormOnly=false, ~profileId="") => {
let (busiProfieDetails, setBusiProfie) = React.useState(_ => businessProfileDetails)
- let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Success)
+ let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Loading)
let (enableCustomHttpHeaders, setCustomHttpHeaders) = React.useState(_ => false)
let bgClass = webhookOnly ? "" : "bg-white dark:bg-jp-gray-lightgray_background"
let fetchBusinessProfiles = BusinessProfileHook.useFetchBusinessProfiles()
+ React.useEffect(() => {
+ if businessProfileDetails.profile_id->LogicUtils.isNonEmptyString {
+ setBusiProfie(_ => businessProfileDetails)
+ setScreenState(_ => Success)
+ }
+ None
+ }, [businessProfileDetails.profile_id])
+
let threedsConnectorList =
HyperswitchAtom.connectorListAtom
->Recoil.useRecoilValueFromAtom
@@ -325,7 +376,9 @@ let make = (~webhookOnly=false, ~showFormOnly=false, ~profileId="") => {
let fieldsToValidate = () => {
let defaultFieldsToValidate =
- [WebhookUrl, ReturnUrl]->Array.filter(urlField => urlField === WebhookUrl || !webhookOnly)
+ [WebhookUrl, ReturnUrl, MaxAutoRetries]->Array.filter(urlField =>
+ urlField === WebhookUrl || !webhookOnly
+ )
defaultFieldsToValidate
}
@@ -468,6 +521,7 @@ let make = (~webhookOnly=false, ~showFormOnly=false, ~profileId="") => {
/>
+
diff --git a/src/screens/Developer/PaymentSettings/PaymentSettingsListEntity.res b/src/screens/Developer/PaymentSettings/PaymentSettingsListEntity.res
index be776bf9f..a8e0b2145 100644
--- a/src/screens/Developer/PaymentSettings/PaymentSettingsListEntity.res
+++ b/src/screens/Developer/PaymentSettings/PaymentSettingsListEntity.res
@@ -57,6 +57,8 @@ let itemToObjMapper = dict => {
),
outgoing_webhook_custom_http_headers: None,
is_connector_agnostic_mit_enabled: None,
+ is_auto_retries_enabled: dict->getOptionBool("is_auto_retries_enabled"),
+ max_auto_retries_enabled: dict->getOptionInt("max_auto_retries_enabled"),
}
}
diff --git a/src/screens/Hooks/OMPSwitchHooks.res b/src/screens/Hooks/OMPSwitchHooks.res
index 9ebf57d99..ad576a9a4 100644
--- a/src/screens/Hooks/OMPSwitchHooks.res
+++ b/src/screens/Hooks/OMPSwitchHooks.res
@@ -8,10 +8,11 @@ let useUserInfo = () => {
let fetchApi = AuthHooks.useApiFetcher()
let {setUserInfoData, userInfo} = React.useContext(UserInfoProvider.defaultContext)
let url = `${Window.env.apiBaseUrl}/user`
+ let {xFeatureRoute} = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom
let getUserInfo = async () => {
try {
- let res = await fetchApi(`${url}`, ~method_=Get)
+ let res = await fetchApi(`${url}`, ~method_=Get, ~xFeatureRoute)
let response = await res->(res => res->Fetch.Response.json)
let userInfo = response->getDictFromJsonObject->UserInfoUtils.itemMapper
setUserInfoData(userInfo)
diff --git a/src/screens/MixpanelHook.res b/src/screens/MixpanelHook.res
index f406f9cff..fc081abf1 100644
--- a/src/screens/MixpanelHook.res
+++ b/src/screens/MixpanelHook.res
@@ -70,6 +70,7 @@ let useSendEvent = () => {
`${getHostUrl}/mixpanel/track`,
~method_=Post,
~bodyStr=`data=${body->JSON.stringifyAny->Option.getOr("")->encodeURI}`,
+ ~xFeatureRoute=featureFlagDetails.xFeatureRoute,
)
} catch {
| _ => ()
@@ -133,6 +134,7 @@ let usePageView = () => {
`${getHostUrl}/mixpanel/track`,
~method_=Post,
~bodyStr=`data=${body->JSON.stringifyAny->Option.getOr("")->encodeURI}`,
+ ~xFeatureRoute=featureFlagDetails.xFeatureRoute,
)
}
} catch {
@@ -171,11 +173,13 @@ let useSetIdentity = () => {
`${getHostUrl}/mixpanel/track`,
~method_=Post,
~bodyStr=`data=${body->JSON.stringifyAny->Option.getOr("")->encodeURI}`,
+ ~xFeatureRoute=featureFlagDetails.xFeatureRoute,
)
let _ = await fetchApi(
`${getHostUrl}/mixpanel/engage`,
~method_=Post,
~bodyStr=`data=${peopleProperties->JSON.stringifyAny->Option.getOr("")->encodeURI}`,
+ ~xFeatureRoute=featureFlagDetails.xFeatureRoute,
)
}
} catch {
diff --git a/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphTypes.res b/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphTypes.res
index 483c8915b..6c578fb19 100644
--- a/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphTypes.res
+++ b/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphTypes.res
@@ -2,7 +2,8 @@ type \"type" = string
type spacingLeft = int
type spacingRight = int
-type point = {color: string, x: string, y: float}
+type info = {index: int}
+type point = {color: string, x: string, y: float, point: info}
type pointFormatter = {points: array}
external asTooltipPointFormatter: Js_OO.Callback.arity1<'a> => pointFormatter => string =
@@ -73,6 +74,7 @@ type xAxis = {
lineWidth: lineWidth,
tickWidth: tickWidth,
labels: labels,
+ tickInterval: int,
gridLineWidth: gridLineWidth,
gridLineColor: gridLineColor,
tickmarkPlacement: tickmarkPlacement,
@@ -109,4 +111,9 @@ type lineGraphOptions = {
tooltip: tooltip,
}
-type lineGraphPayload = {categories: categories, data: data, title: title}
+type lineGraphPayload = {
+ categories: categories,
+ data: data,
+ title: title,
+ tooltipFormatter: pointFormatter => string,
+}
diff --git a/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphUtils.res b/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphUtils.res
index f0beec7da..08103d41f 100644
--- a/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphUtils.res
+++ b/src/screens/NewAnalytics/Graphs/LineGraph/LineGraphUtils.res
@@ -1,55 +1,13 @@
open LineGraphTypes
-let tooltipFormatter = (~title: LineGraphTypes.title) =>
- (
- @this
- (this: pointFormatter) => {
- let title = `${title.text}
`
- let tableItems =
- this.points
- ->Array.map(point =>
- `
-
-
${point.x}
-
${point.y->Float.toString} USD
-
`
- )
- ->Array.joinWith("")
-
- let content = `
-
- ${title}
-
- ${tableItems}
-
-
`
+let getLineGraphOptions = (lineGraphOptions: lineGraphPayload) => {
+ let {categories, data, title, tooltipFormatter} = lineGraphOptions
- `
- ${content}
-
`
- }
- )->asTooltipPointFormatter
+ let stepInterval = Js.Math.max_int(
+ Js.Math.ceil_int(categories->Array.length->Int.toFloat /. 20.0),
+ 1,
+ )
-let getLineGraphOptions = (lineGraphOptions: lineGraphPayload) => {
- let {categories, data, title} = lineGraphOptions
{
chart: {
\"type": "line",
@@ -71,6 +29,7 @@ let getLineGraphOptions = (lineGraphOptions: lineGraphPayload) => {
},
y: 35,
},
+ tickInterval: stepInterval,
gridLineWidth: 1,
gridLineColor: "#e6e6e6",
tickmarkPlacement: "on",
@@ -88,7 +47,7 @@ let getLineGraphOptions = (lineGraphOptions: lineGraphPayload) => {
backgroundColor: "transparent",
borderColor: "transparent",
borderWidth: 0.0,
- formatter: tooltipFormatter(~title),
+ formatter: tooltipFormatter,
useHTML: true,
shared: true, // Allows multiple series' data to be shown in a single tooltip
},
diff --git a/src/screens/NewAnalytics/NewAnalyticsHelper.res b/src/screens/NewAnalytics/NewAnalyticsHelper.res
index b2089d23a..3b49aab76 100644
--- a/src/screens/NewAnalytics/NewAnalyticsHelper.res
+++ b/src/screens/NewAnalytics/NewAnalyticsHelper.res
@@ -83,6 +83,7 @@ module Tabs = {
{options
->Array.mapWithIndex((tabValue, index) =>
Int.toString}
className={`px-3 py-2 ${tabValue.value->getStyle(index)} selection:bg-white`}
onClick={_ => setOption(tabValue)}>
{tabValue.label->React.string}
@@ -172,11 +173,15 @@ module StatisticsCard = {
let (bgColor, textColor) = switch direction {
| Upward => ("bg-green-light", "text-green-dark")
| Downward => ("bg-red-light", "text-red-dark")
+ | No_Change => ("bg-gray-100", "text-gray-500")
}
+
-
{`${value}%`->React.string}
+
+ {`${value->NewAnalyticsUtils.valueFormatter(Rate)}`->React.string}
+
}
@@ -206,7 +211,7 @@ module GraphHeader = {
{title->React.string}
-
+
diff --git a/src/screens/NewAnalytics/NewAnalyticsTypes.res b/src/screens/NewAnalytics/NewAnalyticsTypes.res
index 986962736..d64460341 100644
--- a/src/screens/NewAnalytics/NewAnalyticsTypes.res
+++ b/src/screens/NewAnalytics/NewAnalyticsTypes.res
@@ -1,10 +1,10 @@
type analyticsPages = Payment
type viewType = Graph | Table
-type statisticsDirection = Upward | Downward
+type statisticsDirection = Upward | Downward | No_Change
type analyticsPagesRoutes = | @as("new-analytics-payment") NewAnalyticsPayment
-type domain = [#payments]
+type domain = [#payments | #refunds | #disputes]
type dimension = [
| #connector
| #payment_method
@@ -23,6 +23,10 @@ type metrics = [
| #payment_method_type
| #card_network
| #authentication_type
+ | #smart_retried_amount
+ | #payments_success_rate
+ | #refund_success_count
+ | #dispute_status_metric
]
type granularity = [
| #G_ONEDAY
@@ -50,3 +54,11 @@ type chartEntity<'t, 'chartOption, 'data> = {
}
type optionType = {label: string, value: string}
+
+type valueType =
+ | Amount
+ | Rate
+ | Volume
+ | Latency
+ | LatencyMs
+ | No_Type
diff --git a/src/screens/NewAnalytics/NewAnalyticsUtils.res b/src/screens/NewAnalytics/NewAnalyticsUtils.res
index 533ff1b64..e24657cb7 100644
--- a/src/screens/NewAnalytics/NewAnalyticsUtils.res
+++ b/src/screens/NewAnalytics/NewAnalyticsUtils.res
@@ -72,6 +72,22 @@ let requestBody = (
]->JSON.Encode.array
}
+let valueFormatter = (value, statType: valueType) => {
+ open LogicUtils
+
+ let percentFormat = value => {
+ `${Float.toFixedWithPrecision(value, ~digits=2)}%`
+ }
+
+ switch statType {
+ | Amount => value->indianShortNum
+ | Rate => value->Js.Float.isNaN ? "-" : value->percentFormat
+ | Volume => value->indianShortNum
+ | Latency => latencyShortNum(~labelValue=value)
+ | LatencyMs => latencyShortNum(~labelValue=value, ~includeMilliseconds=true)
+ | No_Type => value->Float.toString
+ }
+}
let getComparisionTimePeriod = (~startDate, ~endDate) => {
let startingPoint = startDate->DayJs.getDayJsForString
let endingPoint = endDate->DayJs.getDayJsForString
@@ -82,3 +98,32 @@ let getComparisionTimePeriod = (~startDate, ~endDate) => {
(startTimeValue, endTimeVal)
}
+
+let calculatePercentageChange = (~primaryValue, ~secondaryValue) => {
+ open NewAnalyticsTypes
+ let change = secondaryValue -. primaryValue
+
+ if primaryValue === 0.0 || change === 0.0 {
+ (0.0, No_Change)
+ } else if change > 0.0 {
+ let diff = change /. primaryValue
+ let percentage = diff *. 100.0
+ (percentage, Upward)
+ } else {
+ let diff = change *. -1.0 /. primaryValue
+ let percentage = diff *. 100.0
+ (percentage, Downward)
+ }
+}
+
+let getToolTipConparision = (~primaryValue, ~secondaryValue) => {
+ let (value, direction) = calculatePercentageChange(~primaryValue, ~secondaryValue)
+
+ let (textColor, icon) = switch direction {
+ | Upward => ("#12B76A", "▲")
+ | Downward => ("#F04E42", "▼")
+ | No_Change => ("#A0A0A0", "")
+ }
+
+ `
${icon}${value->valueFormatter(Rate)}`
+}
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalytics.res b/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalytics.res
index b09e1b7ae..2c741f08d 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalytics.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalytics.res
@@ -3,6 +3,7 @@ let make = () => {
open NewPaymentAnalyticsEntity
+
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsEntity.res b/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsEntity.res
index 53cf83c85..b5117cd2f 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsEntity.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsEntity.res
@@ -1,4 +1,14 @@
open NewAnalyticsTypes
+// OverView section
+let overviewSectionEntity: moduleEntity = {
+ requestBodyConfig: {
+ delta: true,
+ metrics: [],
+ },
+ title: "OverView Section",
+ domain: #payments,
+}
+
// Payments Lifecycle
let paymentsLifeCycleEntity: moduleEntity = {
requestBodyConfig: {
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsUtils.res b/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsUtils.res
index 6c55e94ab..72d525b3f 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsUtils.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/NewPaymentAnalyticsUtils.res
@@ -18,8 +18,12 @@ let getMonthName = month => {
}
}
-let getCategories = (data: array
, key: string) => {
- data->Array.map(item => {
+let getCategories = (data: JSON.t, index: int, key: string) => {
+ data
+ ->getArrayFromJson([])
+ ->getValueFromArray(index, []->JSON.Encode.array)
+ ->getArrayFromJson([])
+ ->Array.map(item => {
let value = item->getDictFromJsonObject->getString(key, "")
if value->isNonEmptyString && key == "time_bucket" {
@@ -127,19 +131,71 @@ let getMetaDataValue = (~data, ~index, ~key) => {
->getFloat(key, 0.0)
}
-let calculatePercentageChange = (~primaryValue, ~secondaryValue) => {
- open NewAnalyticsTypes
- let change = secondaryValue -. primaryValue
-
- if change > 0.0 {
- let diff = change /. primaryValue
- let percentage = diff *. 100.0
- (percentage->Float.toString, Upward)
- } else if change < 0.0 {
- let diff = change *. -1.0 /. primaryValue
- let percentage = diff *. 100.0
- (percentage->Float.toString, Downward)
- } else {
- ("0", Upward)
- }
+open LineGraphTypes
+let tooltipFormatter = (~secondaryCategories, ~title, ~metricType) => {
+ open NewAnalyticsUtils
+
+ (
+ @this
+ (this: pointFormatter) => {
+ let title = `${title}
`
+
+ let defaultValue = {color: "", x: "", y: 0.0, point: {index: 0}}
+ let primartPoint = this.points->getValueFromArray(0, defaultValue)
+ let secondaryPoint = this.points->getValueFromArray(1, defaultValue)
+
+ let getRowsHtml = (~iconColor, ~date, ~value, ~comparisionComponent="") => {
+ let valueString = valueFormatter(value, metricType)
+ `
+
+
${date}${comparisionComponent}
+
${valueString}
+
`
+ }
+
+ let tableItems =
+ [
+ getRowsHtml(~iconColor=primartPoint.color, ~date=primartPoint.x, ~value=primartPoint.y),
+ getRowsHtml(
+ ~iconColor=secondaryPoint.color,
+ ~date=secondaryCategories->getValueFromArray(secondaryPoint.point.index, ""),
+ ~value=secondaryPoint.y,
+ ~comparisionComponent=getToolTipConparision(
+ ~primaryValue=primartPoint.y,
+ ~secondaryValue=secondaryPoint.y,
+ ),
+ ),
+ ]->Array.joinWith("")
+
+ let content = `
+
+ ${title}
+
+ ${tableItems}
+
+
`
+
+ `
+ ${content}
+
`
+ }
+ )->asTooltipPointFormatter
}
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycle.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycle.res
index e3123ef4f..688342bce 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycle.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycle.res
@@ -63,15 +63,15 @@ let make = (
}, (startTimeVal, endTimeVal))
-
} customUI={
}>
-
+
+ } customUI={}>
-
-
+
+
}
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycleUtils.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycleUtils.res
index 610419c1a..da5e98053 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycleUtils.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsLifeCycle/PaymentsLifeCycleUtils.res
@@ -34,12 +34,12 @@ let paymentsLifeCycleMapper = (
let customerAwaited = data.customerAwaited // DropOff2
let attemptedPayments = pending + customerAwaited + success + failure
let pmAwaited = data.pmAwaited // Dropoff1
- let totalPayment = pmAwaited + attemptedPayments + cancelled
+ let _totalPayment = pmAwaited + attemptedPayments + cancelled
let disputed = data.disputed
let processedData = [
- ("Payments Initiated", "Success", totalPayment, "#E4EFFF"),
+ ("Payments Initiated", "Success", success, "#E4EFFF"),
("Payments Initiated", "Non-terminal state", customerAwaited, "#E4EFFF"),
("Success", "Dispute Raised", disputed, "#F7E0E0"),
("Success", "Refunds Issued", refunded, "#E4EFFF"),
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSection.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSection.res
new file mode 100644
index 000000000..c5b2abd54
--- /dev/null
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSection.res
@@ -0,0 +1,238 @@
+open NewAnalyticsTypes
+
+module SmartRetryCard = {
+ open NewAnalyticsHelper
+ open NewPaymentsOverviewSectionTypes
+ open NewPaymentsOverviewSectionUtils
+ open NewAnalyticsUtils
+ @react.component
+ let make = (~metric, ~data) => {
+ let config = getInfo(~metric)
+
+ let primaryValue = getValueFromObj(data, 0, metric)
+ let secondaryValue = getValueFromObj(data, 1, metric)
+
+ let (value, direction) = calculatePercentageChange(~primaryValue, ~secondaryValue)
+
+
+
+
{config.titleText->React.string}
+
+
+
+
+ {`Saved ${valueFormatter(primaryValue, config.valueType)}`->React.string}
+
+
+
+
+
+
{config.description->React.string}
+
+
+
+ }
+}
+
+module OverViewStat = {
+ open NewAnalyticsHelper
+ open NewAnalyticsUtils
+ open NewPaymentsOverviewSectionTypes
+ open NewPaymentsOverviewSectionUtils
+ @react.component
+ let make = (~metric, ~data) => {
+ let config = getInfo(~metric)
+
+ let primaryValue = getValueFromObj(data, 0, metric)
+ let secondaryValue = getValueFromObj(data, 1, metric)
+
+ let (value, direction) = calculatePercentageChange(~primaryValue, ~secondaryValue)
+
+
+
+
+
+
+ {valueFormatter(primaryValue, config.valueType)->React.string}
+
+
+
+
+
+
+
+
{config.titleText->React.string}
+
{config.description->React.string}
+
+
+
+ }
+}
+
+@react.component
+let make = (~entity: moduleEntity) => {
+ open NewPaymentsOverviewSectionUtils
+ open LogicUtils
+ open APIUtils
+ open NewAnalyticsHelper
+ let getURL = useGetURL()
+ let updateDetails = useUpdateMethod()
+ let (data, setData) = React.useState(_ => []->JSON.Encode.array)
+ let {filterValueJson} = React.useContext(FilterContext.filterContext)
+ let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Loading)
+ let startTimeVal = filterValueJson->getString("startTime", "")
+ let endTimeVal = filterValueJson->getString("endTime", "")
+
+ let getData = async () => {
+ setScreenState(_ => PageLoaderWrapper.Loading)
+ try {
+ let primaryData = defaultValue->Dict.copy
+ let secondaryData = defaultValue->Dict.copy
+
+ let urlV1Payments = getURL(
+ ~entityName=ANALYTICS_PAYMENTS,
+ ~methodType=Post,
+ ~id=Some((#payments: domain :> string)),
+ )
+
+ let urlV1Refunds = getURL(
+ ~entityName=ANALYTICS_PAYMENTS,
+ ~methodType=Post,
+ ~id=Some((#refunds: domain :> string)),
+ )
+
+ let urlV2Payments = getURL(
+ ~entityName=ANALYTICS_PAYMENTS_V2,
+ ~methodType=Post,
+ ~id=Some((#payments: domain :> string)),
+ )
+
+ // primary date range
+ let primaryBodyV2Payments = getPayload(
+ ~entity,
+ ~metrics=[#smart_retried_amount, #payments_success_rate],
+ ~startTime=startTimeVal,
+ ~endTime=endTimeVal,
+ )
+
+ let primaryBodyV1Payments = getPayload(
+ ~entity,
+ ~metrics=[#payment_processed_amount],
+ ~startTime=startTimeVal,
+ ~endTime=endTimeVal,
+ )
+
+ let primaryBodyV1Refunds = getPayload(
+ ~entity,
+ ~metrics=[#refund_success_count],
+ ~startTime=startTimeVal,
+ ~endTime=endTimeVal,
+ )
+
+ let primaryResponseV1Payments = await updateDetails(
+ urlV1Payments,
+ primaryBodyV1Payments,
+ Post,
+ )
+ let primaryResponseV1Refunds = await updateDetails(urlV1Refunds, primaryBodyV1Refunds, Post)
+ let primaryResponseV2Payments = await updateDetails(
+ urlV2Payments,
+ primaryBodyV2Payments,
+ Post,
+ )
+
+ let primaryDataV1Payments = primaryResponseV1Payments->parseResponse
+ let primaryDataV1Refunds = primaryResponseV1Refunds->parseResponse
+ let primaryDataV2Payments = primaryResponseV2Payments->parseResponse
+
+ primaryData->setValue(~data=primaryDataV1Payments, ~ids=[#payment_processed_amount])
+ primaryData->setValue(~data=primaryDataV1Refunds, ~ids=[#refund_success_count])
+ primaryData->setValue(
+ ~data=primaryDataV2Payments,
+ ~ids=[#smart_retried_amount, #payments_success_rate],
+ )
+
+ // secondary date range
+ let (prevStartTime, prevEndTime) = NewAnalyticsUtils.getComparisionTimePeriod(
+ ~startDate=startTimeVal,
+ ~endDate=endTimeVal,
+ )
+
+ let secondaryBodyV2Payments = getPayload(
+ ~entity,
+ ~metrics=[#smart_retried_amount, #payments_success_rate],
+ ~startTime=prevStartTime,
+ ~endTime=prevEndTime,
+ )
+
+ let secondaryBodyV1Payments = getPayload(
+ ~entity,
+ ~metrics=[#payment_processed_amount],
+ ~startTime=prevStartTime,
+ ~endTime=prevEndTime,
+ )
+
+ let secondaryBodyV1Refunds = getPayload(
+ ~entity,
+ ~metrics=[#refund_success_count],
+ ~startTime=prevStartTime,
+ ~endTime=prevEndTime,
+ )
+
+ let secondaryResponseV1Payments = await updateDetails(
+ urlV1Payments,
+ secondaryBodyV1Payments,
+ Post,
+ )
+ let secondaryResponseV1Refunds = await updateDetails(
+ urlV1Refunds,
+ secondaryBodyV1Refunds,
+ Post,
+ )
+ let secondaryResponseV2Payments = await updateDetails(
+ urlV2Payments,
+ secondaryBodyV2Payments,
+ Post,
+ )
+
+ let secondaryDataV1Payments = secondaryResponseV1Payments->parseResponse
+ let secondaryDataV1Refunds = secondaryResponseV1Refunds->parseResponse
+ let secondaryDataV2Payments = secondaryResponseV2Payments->parseResponse
+
+ secondaryData->setValue(~data=secondaryDataV1Payments, ~ids=[#payment_processed_amount])
+ secondaryData->setValue(~data=secondaryDataV1Refunds, ~ids=[#refund_success_count])
+ secondaryData->setValue(
+ ~data=secondaryDataV2Payments,
+ ~ids=[#smart_retried_amount, #payments_success_rate],
+ )
+
+ setData(_ =>
+ [primaryData->JSON.Encode.object, secondaryData->JSON.Encode.object]->JSON.Encode.array
+ )
+
+ setScreenState(_ => PageLoaderWrapper.Success)
+ } catch {
+ | _ => setScreenState(_ => PageLoaderWrapper.Success)
+ }
+ }
+
+ React.useEffect(() => {
+ if startTimeVal->isNonEmptyString && endTimeVal->isNonEmptyString {
+ getData()->ignore
+ }
+ None
+ }, [startTimeVal, endTimeVal])
+
+ }>
+ // Need to modify
+
+
+}
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSectionTypes.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSectionTypes.res
new file mode 100644
index 000000000..b999a137d
--- /dev/null
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSectionTypes.res
@@ -0,0 +1,13 @@
+type dataObj = {
+ smart_retried_amount: float,
+ payments_success_rate: float,
+ payment_processed_amount: float,
+ refund_success_count: float,
+ dispute_status_metric: float,
+}
+
+type singleStatConfig = {
+ titleText: string,
+ description: string,
+ valueType: NewAnalyticsTypes.valueType,
+}
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSectionUtils.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSectionUtils.res
new file mode 100644
index 000000000..10f82165c
--- /dev/null
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsOverviewSection/NewPaymentsOverviewSectionUtils.res
@@ -0,0 +1,92 @@
+open NewPaymentsOverviewSectionTypes
+let defaultValue =
+ {
+ smart_retried_amount: 0.0,
+ payments_success_rate: 0.0,
+ payment_processed_amount: 0.0,
+ refund_success_count: 0.0,
+ dispute_status_metric: 0.0,
+ }
+ ->Identity.genericTypeToJson
+ ->LogicUtils.getDictFromJsonObject
+
+let getPayload = (~entity, ~metrics, ~startTime, ~endTime) => {
+ open NewAnalyticsTypes
+ NewAnalyticsUtils.requestBody(
+ ~dimensions=[],
+ ~startTime,
+ ~endTime,
+ ~delta=entity.requestBodyConfig.delta,
+ ~filters=entity.requestBodyConfig.filters,
+ ~metrics,
+ ~customFilter=entity.requestBodyConfig.customFilter,
+ ~applyFilterFor=entity.requestBodyConfig.applyFilterFor,
+ )
+}
+
+let parseResponse = response => {
+ open LogicUtils
+ response
+ ->getDictFromJsonObject
+ ->getArrayFromDict("queryData", [])
+ ->getValueFromArray(0, Dict.make()->JSON.Encode.object)
+ ->getDictFromJsonObject
+}
+
+open NewAnalyticsTypes
+let setValue = (dict, ~data, ~ids: array) => {
+ open LogicUtils
+
+ ids->Array.forEach(id => {
+ dict->Dict.set(
+ (id: metrics :> string),
+ data
+ ->getFloat((id: metrics :> string), 0.0)
+ ->JSON.Encode.float,
+ )
+ })
+}
+
+let getInfo = (~metric) => {
+ switch metric {
+ | #smart_retried_amount => {
+ titleText: "Total Payment Savings",
+ description: "Amount saved via payment retries",
+ valueType: Amount,
+ }
+ | #payments_success_rate => {
+ titleText: "Total Authorization Rate",
+ description: "Overall successful payment intents divided by total payment intents excluding dropoffs",
+ valueType: Rate,
+ }
+ | #payment_processed_amount => {
+ titleText: "Total Payments Processed",
+ description: "The total amount of payments processed in the selected time range",
+ valueType: Amount,
+ }
+ | #refund_success_count => {
+ titleText: "Total Refunds Processed",
+ description: "The total amount of refund payments processed in the selected time range",
+ valueType: Amount,
+ }
+ | #dispute_status_metric => {
+ titleText: "All Disputes",
+ description: "Total number of disputes irrespective of status in the selected time range",
+ valueType: Volume,
+ }
+ | _ => {
+ titleText: "",
+ description: "",
+ valueType: No_Type,
+ }
+ }
+}
+
+let getValueFromObj = (data, index, metric) => {
+ open LogicUtils
+ data
+ ->getArrayFromJson([])
+ ->getValueFromArray(index, Dict.make()->JSON.Encode.object)
+ ->getDictFromJsonObject
+ ->getFloat((metric: metrics :> string), 0.0)
+}
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessed.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessed.res
index af930d7b1..c0074d531 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessed.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessed.res
@@ -47,6 +47,7 @@ module TableModule = {
module PaymentsProcessedHeader = {
open NewAnalyticsTypes
+ open NewAnalyticsUtils
open NewPaymentAnalyticsUtils
@react.component
let make = (
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessedUtils.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessedUtils.res
index de1fc8321..d72548a7a 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessedUtils.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsProcessed/PaymentsProcessedUtils.res
@@ -8,12 +8,8 @@ let paymentsProcessedMapper = (
~yKey: string,
): LineGraphTypes.lineGraphPayload => {
open LineGraphTypes
- let categories =
- data
- ->getArrayFromJson([])
- ->getValueFromArray(0, []->JSON.Encode.array)
- ->getArrayFromJson([])
- ->getCategories(yKey)
+ let primaryCategories = data->getCategories(0, yKey)
+ let secondaryCategories = data->getCategories(1, yKey)
let lineGraphData =
data
@@ -26,7 +22,16 @@ let paymentsProcessedMapper = (
let title = {
text: "Payments Processed",
}
- {categories, data: lineGraphData, title}
+ {
+ categories: primaryCategories,
+ data: lineGraphData,
+ title,
+ tooltipFormatter: tooltipFormatter(
+ ~secondaryCategories,
+ ~title="Payments Processed",
+ ~metricType=Amount,
+ ),
+ }
}
// Need to modify
let getMetaData = json =>
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRate.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRate.res
index 919d02308..273b20b75 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRate.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRate.res
@@ -5,6 +5,7 @@ open PaymentsSuccessRateUtils
module PaymentsSuccessRateHeader = {
open NewPaymentAnalyticsUtils
+ open NewAnalyticsUtils
@react.component
let make = (~data, ~keyValue, ~granularity, ~setGranularity) => {
let setGranularity = value => {
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRateUtils.res b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRateUtils.res
index 32df32822..e2546b5ec 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRateUtils.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/PaymentsSuccessRate/PaymentsSuccessRateUtils.res
@@ -19,12 +19,8 @@ let paymentsSuccessRateMapper = (
~yKey: string,
): LineGraphTypes.lineGraphPayload => {
open LineGraphTypes
- let categories =
- data
- ->getArrayFromJson([])
- ->getValueFromArray(0, []->JSON.Encode.array)
- ->getArrayFromJson([])
- ->getCategories(yKey)
+ let primaryCategories = data->getCategories(0, yKey)
+ let secondaryCategories = data->getCategories(1, yKey)
let lineGraphData =
data
@@ -37,7 +33,16 @@ let paymentsSuccessRateMapper = (
let title = {
text: "Payments Success Rate",
}
- {categories, data: lineGraphData, title}
+ {
+ categories: primaryCategories,
+ data: lineGraphData,
+ title,
+ tooltipFormatter: tooltipFormatter(
+ ~secondaryCategories,
+ ~title="Payments Success Rate",
+ ~metricType=Rate,
+ ),
+ }
}
open NewAnalyticsTypes
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistribution.res b/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistribution.res
index a727add6a..2cae95ba3 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistribution.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistribution.res
@@ -107,7 +107,7 @@ let make = (
->getArrayFromDict("queryData", [])
if arr->Array.length > 0 {
- setpaymentsDistribution(_ => responseData->JSON.Encode.array)
+ setpaymentsDistribution(_ => [responseData->JSON.Encode.array]->JSON.Encode.array)
setScreenState(_ => PageLoaderWrapper.Success)
} else {
setScreenState(_ => PageLoaderWrapper.Custom)
diff --git a/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistributionUtils.res b/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistributionUtils.res
index c7d1f9770..da9c40e44 100644
--- a/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistributionUtils.res
+++ b/src/screens/NewAnalytics/PaymentAnalytics/SuccessfulPaymentsDistribution/SuccessfulPaymentsDistributionUtils.res
@@ -18,10 +18,7 @@ let successfulPaymentsDistributionMapper = (
~yKey: string,
): BarGraphTypes.barGraphPayload => {
open BarGraphTypes
- let categories =
- data
- ->getArrayFromJson([])
- ->getCategories(yKey)
+ let categories = data->getCategories(0, yKey)
let barGraphData = getBarGraphObj(
~array=data->getArrayFromJson([]),
diff --git a/src/screens/OMPSwitch/MerchantSwitch.res b/src/screens/OMPSwitch/MerchantSwitch.res
index 53184838c..cd15d9ffc 100644
--- a/src/screens/OMPSwitch/MerchantSwitch.res
+++ b/src/screens/OMPSwitch/MerchantSwitch.res
@@ -162,7 +162,7 @@ let make = () => {
let customHRTagStyle = "border-t border-blue-830"
let customPadding = "py-1 w-full"
let customStyle = "w-56 text-gray-200 bg-blue-840 dark:bg-black hover:bg-popover-background-hover hover:text-gray-100 !w-full"
-
+ let customScrollStyle = "max-h-72 overflow-scroll px-1 pt-1"
React.useEffect(() => {
getMerchantList()->ignore
None
@@ -198,6 +198,7 @@ let make = () => {
customDropdownOuterClass="!border-none !w-full"
fullLength=true
toggleChevronState
+ customScrollStyle
/>
diff --git a/src/screens/OMPSwitch/OMPSwitchHelper.res b/src/screens/OMPSwitch/OMPSwitchHelper.res
index bbe839e6e..39a2b8788 100644
--- a/src/screens/OMPSwitch/OMPSwitchHelper.res
+++ b/src/screens/OMPSwitch/OMPSwitchHelper.res
@@ -24,7 +24,14 @@ module ListBaseComp = {
module AddNewMerchantProfileButton = {
@react.component
- let make = (~user, ~setShowModal, ~customPadding="", ~customStyle="", ~customHRTagStyle="") => {
+ let make = (
+ ~user,
+ ~setShowModal,
+ ~customPadding="",
+ ~customStyle="",
+ ~customHRTagStyle="",
+ ~addItemBtnStyle="",
+ ) => {
let userPermissionJson = Recoil.useRecoilValueFromAtom(HyperswitchAtom.userPermissionAtom)
let cursorStyles = PermissionUtils.cursorStyles(userPermissionJson.merchantDetailsManage)
+ className={`${cursorStyles} ${customPadding} ${addItemBtnStyle}`}>
{<>
{
setArrow(prev => !prev)
}
+ let customScrollStyle = "max-h-72 overflow-scroll px-1 pt-1"
+
{
customDropdownOuterClass="!border-none !w-full"
fullLength=true
toggleChevronState
+ customScrollStyle
/>
{
}
}
}
-
- let customPadding = "px-1 py-1"
let customStyle = "text-blue-500 bg-white dark:bg-black hover:bg-jp-gray-100 text-nowrap w-full"
-
+ let addItemBtnStyle = "border border-t-0 w-full"
+ let customScrollStyle = "max-h-72 overflow-scroll px-1 pt-1 border border-b-0"
+ let dropdownContainerStyle = "min-w-[15rem] rounded-md border border-1"
let profileSwitch = async value => {
try {
setShowSwitchingProfile(_ => true)
@@ -189,13 +189,15 @@ let make = () => {
/>}
baseComponentCustomStyle="bg-white"
bottomComponent={}
optionClass="text-gray-600 text-fs-14"
selectClass="text-gray-600 text-fs-14"
customDropdownOuterClass="!border-none !w-full"
fullLength=true
toggleChevronState
+ customScrollStyle
+ dropdownContainerStyle
/>
diff --git a/src/screens/SDKPayment/WebSDK.res b/src/screens/SDKPayment/WebSDK.res
index 7cfcf8c71..5a1dd0bef 100644
--- a/src/screens/SDKPayment/WebSDK.res
+++ b/src/screens/SDKPayment/WebSDK.res
@@ -61,6 +61,7 @@ module CheckoutForm = {
~bodyStr=val->JSON.stringifyAny->Option.getOr(""),
~headers=[("Access-Control-Allow-Origin", "*")]->Dict.fromArray,
~method_=Post,
+ ~xFeatureRoute=false,
)
->then(res => res->Fetch.Response.json)
->then(json => {
diff --git a/src/screens/Settings/BusinessMapping/BusinessMappingEntity.res b/src/screens/Settings/BusinessMapping/BusinessMappingEntity.res
index f0bcc8909..1da14c9df 100644
--- a/src/screens/Settings/BusinessMapping/BusinessMappingEntity.res
+++ b/src/screens/Settings/BusinessMapping/BusinessMappingEntity.res
@@ -151,6 +151,8 @@ let itemToObjMapper = dict => {
),
outgoing_webhook_custom_http_headers: None,
is_connector_agnostic_mit_enabled: None,
+ is_auto_retries_enabled: dict->getOptionBool("is_auto_retries_enabled"),
+ max_auto_retries_enabled: dict->getOptionInt("max_auto_retries_enabled"),
}
}
diff --git a/src/screens/Settings/ComplianceCertificates/Compliance.res b/src/screens/Settings/ComplianceCertificates/Compliance.res
index 6d932f9e9..e84518aa8 100644
--- a/src/screens/Settings/ComplianceCertificates/Compliance.res
+++ b/src/screens/Settings/ComplianceCertificates/Compliance.res
@@ -23,7 +23,7 @@ let make = () => {
let showToast = ToastState.useShowToast()
let fetchApi = AuthHooks.useApiFetcher()
let (buttonState, setButtonState) = React.useState(_ => Button.Normal)
-
+ let {xFeatureRoute} = HyperswitchAtom.featureFlagAtom->Recoil.useRecoilValueFromAtom
let downloadPDF = _ => {
setButtonState(_ => Button.Loading)
let currentDate =
@@ -37,7 +37,7 @@ let make = () => {
// For local testing this condition is added
if downloadURL->LogicUtils.isNonEmptyString {
open Promise
- fetchApi(downloadURL, ~method_=Get)
+ fetchApi(downloadURL, ~method_=Get, ~xFeatureRoute)
->then(resp => {
Fetch.Response.blob(resp)
})
diff --git a/src/screens/Settings/HSwitchSettingTypes.res b/src/screens/Settings/HSwitchSettingTypes.res
index d23951d4a..2df5db9de 100644
--- a/src/screens/Settings/HSwitchSettingTypes.res
+++ b/src/screens/Settings/HSwitchSettingTypes.res
@@ -104,6 +104,7 @@ type validationFields =
| AuthetnticationConnectors(array)
| ThreeDsRequestorUrl
| UnknownValidateFields(string)
+ | MaxAutoRetries
type formStateType = Preview | Edit
type fieldType = {
@@ -153,6 +154,8 @@ type profileEntity = {
always_collect_billing_details_from_wallet_connector: option,
is_connector_agnostic_mit_enabled: option,
outgoing_webhook_custom_http_headers: option>,
+ is_auto_retries_enabled: option,
+ max_auto_retries_enabled: option,
}
type twoFaType = RecoveryCode | Totp
diff --git a/src/screens/Settings/MerchantAccountUtils.res b/src/screens/Settings/MerchantAccountUtils.res
index 61aea6b10..b3141bc95 100644
--- a/src/screens/Settings/MerchantAccountUtils.res
+++ b/src/screens/Settings/MerchantAccountUtils.res
@@ -19,6 +19,8 @@ let parseBussinessProfileJson = (profileRecord: profileEntity) => {
collect_billing_details_from_wallet_connector,
always_collect_billing_details_from_wallet_connector,
always_collect_shipping_details_from_wallet_connector,
+ is_auto_retries_enabled,
+ max_auto_retries_enabled,
} = profileRecord
let profileInfo =
@@ -45,6 +47,9 @@ let parseBussinessProfileJson = (profileRecord: profileEntity) => {
always_collect_shipping_details_from_wallet_connector,
)
+ profileInfo->setOptionBool("is_auto_retries_enabled", is_auto_retries_enabled)
+ profileInfo->setOptionInt("max_auto_retries_enabled", max_auto_retries_enabled)
+
profileInfo->setDictNull("webhook_url", webhook_details.webhook_url)
profileInfo->setOptionString("webhook_version", webhook_details.webhook_version)
profileInfo->setOptionString("webhook_username", webhook_details.webhook_username)
@@ -189,6 +194,17 @@ let getBusinessProfilePayload = (values: JSON.t) => {
"always_collect_billing_details_from_wallet_connector",
valuesDict->getOptionBool("always_collect_billing_details_from_wallet_connector"),
)
+
+ profileDetailsDict->setOptionBool(
+ "is_auto_retries_enabled",
+ valuesDict->getOptionBool("is_auto_retries_enabled"),
+ )
+
+ profileDetailsDict->setOptionInt(
+ "max_auto_retries_enabled",
+ valuesDict->getOptionInt("max_auto_retries_enabled"),
+ )
+
profileDetailsDict->setOptionBool(
"is_connector_agnostic_mit_enabled",
valuesDict->getOptionBool("is_connector_agnostic_mit_enabled"),
@@ -308,6 +324,7 @@ let validationFieldsMapper = key => {
| AuthetnticationConnectors(_) => "authentication_connectors"
| ThreeDsRequestorUrl => "three_ds_requestor_url"
| UnknownValidateFields(key) => key
+ | MaxAutoRetries => "max_auto_retries_enabled"
}
}
@@ -394,6 +411,14 @@ let validateCustom = (key, errors, value, isLiveMode) => {
Dict.set(errors, key->validationFieldsMapper, "Please Enter Valid URL"->JSON.Encode.string)
}
}
+ | MaxAutoRetries =>
+ if !RegExp.test(%re("/^[1-5]$/"), value) {
+ Dict.set(
+ errors,
+ key->validationFieldsMapper,
+ "Please enter integer value from 1 to 5"->JSON.Encode.string,
+ )
+ }
| _ => ()
}
@@ -464,6 +489,8 @@ let defaultValueForBusinessProfile = {
always_collect_billing_details_from_wallet_connector: None,
outgoing_webhook_custom_http_headers: None,
is_connector_agnostic_mit_enabled: None,
+ is_auto_retries_enabled: None,
+ max_auto_retries_enabled: None,
}
let getValueFromBusinessProfile = businessProfileValue => {
diff --git a/src/server/health.mjs b/src/server/health.mjs
index e69e5ff1b..06538e2a8 100644
--- a/src/server/health.mjs
+++ b/src/server/health.mjs
@@ -16,9 +16,6 @@ let checkHealth = async (res) => {
let indexFile = "dist/hyperswitch/index.html";
let data = Fs.readFileSync(indexFile, { encoding: "utf8" });
- if (data.includes(``)) {
- output.env_config = true;
- }
if (data.includes(``)) {
output.app_file = true;
}
diff --git a/src/utils/LogicUtils.res b/src/utils/LogicUtils.res
index f320970f0..89b12d803 100644
--- a/src/utils/LogicUtils.res
+++ b/src/utils/LogicUtils.res
@@ -335,6 +335,9 @@ let setOptionArray = (dict, key, optionArray) =>
let setOptionDict = (dict, key, optionDictValue) =>
optionDictValue->Option.mapOr((), value => dict->Dict.set(key, value->JSON.Encode.object))
+let setOptionInt = (dict, key, optionInt) =>
+ optionInt->Option.mapOr((), int => dict->Dict.set(key, int->JSON.Encode.int))
+
let capitalizeString = str => {
String.toUpperCase(String.charAt(str, 0)) ++ Js.String2.substringToEnd(str, ~from=1)
}
diff --git a/src/utils/Mappers/BusinessProfileMapper.res b/src/utils/Mappers/BusinessProfileMapper.res
index d4861683c..7eccf42d0 100644
--- a/src/utils/Mappers/BusinessProfileMapper.res
+++ b/src/utils/Mappers/BusinessProfileMapper.res
@@ -54,6 +54,8 @@ let businessProfileTypeMapper = values => {
outgoing_webhook_custom_http_headers: !(outgoingWebhookHeades->isEmptyDict)
? Some(outgoingWebhookHeades)
: None,
+ is_auto_retries_enabled: jsonDict->getOptionBool("is_auto_retries_enabled"),
+ max_auto_retries_enabled: jsonDict->getOptionInt("max_auto_retries_enabled"),
}
businessProfile
}