Add geo-pricing split test for enabling LATAM currencies (#13663)
* Implement LATAM geo-pricing split test * Hide Paypal if currency is one of INR, COP, CLP, PEN * Only send the LATAM/INR banner events when banner is rendered * Workaround in Subscription dashboard for CLP not having minor units GitOrigin-RevId: a677086a7762900563558126d2f81a4c57bbe9d7
This commit is contained in:
@@ -364,7 +364,11 @@ async function projectListPage(req, res, next) {
|
||||
}
|
||||
|
||||
let showINRBanner = false
|
||||
let showLATAMBanner = false
|
||||
let recommendedCurrency
|
||||
if (usersBestSubscription?.type === 'free') {
|
||||
const { currencyCode, countryCode } =
|
||||
await GeoIpLookup.promises.getCurrencyCode(req.ip)
|
||||
try {
|
||||
const inrGeoPricingAssignment =
|
||||
await SplitTestHandler.promises.getAssignment(
|
||||
@@ -372,14 +376,32 @@ async function projectListPage(req, res, next) {
|
||||
res,
|
||||
'geo-pricing-inr'
|
||||
)
|
||||
const geoDetails = await GeoIpLookup.promises.getDetails(req.ip)
|
||||
showINRBanner =
|
||||
inrGeoPricingAssignment.variant === 'inr' &&
|
||||
geoDetails?.country_code === 'IN'
|
||||
inrGeoPricingAssignment.variant === 'inr' && countryCode === 'IN'
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
{ err: error },
|
||||
'Failed to get INR geo pricing lookup or assignment'
|
||||
'Failed to get geo-pricing-inr split test assignment'
|
||||
)
|
||||
}
|
||||
try {
|
||||
const latamGeoPricingAssignment =
|
||||
await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'geo-pricing-latam'
|
||||
)
|
||||
showLATAMBanner =
|
||||
latamGeoPricingAssignment.variant === 'latam' &&
|
||||
['BR', 'MX', 'CO', 'CL', 'PE'].includes(countryCode)
|
||||
// LATAM Banner needs to know which currency to display
|
||||
if (showLATAMBanner) {
|
||||
recommendedCurrency = currencyCode
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
{ err: error },
|
||||
'Failed to get geo-pricing-latam split test assignment'
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -402,6 +424,8 @@ async function projectListPage(req, res, next) {
|
||||
groupsAndEnterpriseBannerVariant,
|
||||
showWritefullPromoBanner,
|
||||
showINRBanner,
|
||||
showLATAMBanner,
|
||||
recommendedCurrency,
|
||||
projectDashboardReact: true, // used in navbar
|
||||
welcomePageRedesignVariant: welcomePageRedesignAssignment.variant,
|
||||
groupSubscriptionsPendingEnrollment:
|
||||
|
||||
@@ -58,8 +58,12 @@ async function plansPage(req, res) {
|
||||
if (GeoIpLookup.isValidCurrencyParam(queryCurrency)) {
|
||||
currency = queryCurrency
|
||||
}
|
||||
const { recommendedCurrency, countryCode, geoPricingTestVariant } =
|
||||
await _getRecommendedCurrency(req, res)
|
||||
const {
|
||||
recommendedCurrency,
|
||||
countryCode,
|
||||
geoPricingINRTestVariant,
|
||||
geoPricingLATAMTestVariant,
|
||||
} = await _getRecommendedCurrency(req, res)
|
||||
if (recommendedCurrency && currency == null) {
|
||||
currency = recommendedCurrency
|
||||
}
|
||||
@@ -108,8 +112,14 @@ async function plansPage(req, res) {
|
||||
currency: recommendedCurrency,
|
||||
'remove-personal-plan-page': removePersonalPlanAssingment?.variant,
|
||||
countryCode,
|
||||
'geo-pricing-inr-group': geoPricingTestVariant,
|
||||
'geo-pricing-inr-group': geoPricingINRTestVariant,
|
||||
'geo-pricing-inr-page': currency === 'INR' ? 'inr' : 'default',
|
||||
'geo-pricing-latam-group': geoPricingLATAMTestVariant,
|
||||
'geo-pricing-latam-page': ['BRL', 'MXN', 'COP', 'CLP', 'PEN'].includes(
|
||||
currency
|
||||
)
|
||||
? 'latam'
|
||||
: 'default',
|
||||
})
|
||||
|
||||
res.render(`subscriptions/plans-marketing/${directory}/plans-marketing-v2`, {
|
||||
@@ -264,8 +274,12 @@ async function userSubscriptionPage(req, res) {
|
||||
|
||||
async function interstitialPaymentPage(req, res) {
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
const { recommendedCurrency, countryCode, geoPricingTestVariant } =
|
||||
await _getRecommendedCurrency(req, res)
|
||||
const {
|
||||
recommendedCurrency,
|
||||
countryCode,
|
||||
geoPricingINRTestVariant,
|
||||
geoPricingLATAMTestVariant,
|
||||
} = await _getRecommendedCurrency(req, res)
|
||||
|
||||
const hasSubscription =
|
||||
await LimitationsManager.promises.userHasV1OrV2Subscription(user)
|
||||
@@ -300,9 +314,15 @@ async function interstitialPaymentPage(req, res) {
|
||||
{
|
||||
currency: recommendedCurrency,
|
||||
countryCode,
|
||||
'geo-pricing-inr-group': geoPricingTestVariant,
|
||||
'geo-pricing-inr-group': geoPricingINRTestVariant,
|
||||
'geo-pricing-inr-page':
|
||||
recommendedCurrency === 'INR' ? 'inr' : 'default',
|
||||
'geo-pricing-latam-group': geoPricingLATAMTestVariant,
|
||||
'geo-pricing-latam-page': ['BRL', 'MXN', 'COP', 'CLP', 'PEN'].includes(
|
||||
recommendedCurrency
|
||||
)
|
||||
? 'latam'
|
||||
: 'default',
|
||||
'remove-personal-plan-page': removePersonalPlanAssingment?.variant,
|
||||
}
|
||||
)
|
||||
@@ -665,10 +685,10 @@ async function _getRecommendedCurrency(req, res) {
|
||||
)
|
||||
const countryCode = currencyLookup.countryCode
|
||||
let recommendedCurrency = currencyLookup.currencyCode
|
||||
let assignment
|
||||
let assignmentINR, assignmentLATAM
|
||||
// for #12703
|
||||
try {
|
||||
assignment = await SplitTestHandler.promises.getAssignment(
|
||||
assignmentINR = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'geo-pricing-inr'
|
||||
@@ -679,15 +699,35 @@ async function _getRecommendedCurrency(req, res) {
|
||||
'Failed to get assignment for geo-pricing-inr test'
|
||||
)
|
||||
}
|
||||
// for #13559
|
||||
try {
|
||||
assignmentLATAM = await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'geo-pricing-latam'
|
||||
)
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
{ err: error },
|
||||
'Failed to get assignment for geo-pricing-latam test'
|
||||
)
|
||||
}
|
||||
// if the user has been detected as located in India (thus recommended INR as currency)
|
||||
// but is not part of the geo pricing test, we fall back to the default currency instead
|
||||
if (recommendedCurrency === 'INR' && assignment?.variant !== 'inr') {
|
||||
if (recommendedCurrency === 'INR' && assignmentINR?.variant !== 'inr') {
|
||||
recommendedCurrency = GeoIpLookup.DEFAULT_CURRENCY_CODE
|
||||
}
|
||||
if (
|
||||
['BRL', 'MXN', 'COP', 'CLP', 'PEN'].includes(recommendedCurrency) &&
|
||||
assignmentLATAM?.variant !== 'latam'
|
||||
) {
|
||||
recommendedCurrency = GeoIpLookup.DEFAULT_CURRENCY_CODE
|
||||
}
|
||||
return {
|
||||
recommendedCurrency,
|
||||
countryCode,
|
||||
geoPricingTestVariant: assignment?.variant,
|
||||
geoPricingINRTestVariant: assignmentINR?.variant,
|
||||
geoPricingLATAMTestVariant: assignmentLATAM?.variant,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,24 @@ const currencySymbols = {
|
||||
CHF: 'Fr',
|
||||
SGD: '$',
|
||||
INR: '₹',
|
||||
BRL: 'R$',
|
||||
MXN: '$',
|
||||
COP: '$',
|
||||
CLP: '$',
|
||||
PEN: 'S/',
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatPrice(priceInCents, currency) {
|
||||
if (!currency) {
|
||||
currency = 'USD'
|
||||
} else if (currency === 'CLP') {
|
||||
// CLP doesn't have minor units, recurly stores the whole major unit without cents
|
||||
return priceInCents.toLocaleString('es-CL', {
|
||||
style: 'currency',
|
||||
currency,
|
||||
minimumFractionDigits: 0,
|
||||
})
|
||||
}
|
||||
let string = String(Math.round(priceInCents))
|
||||
if (string.length === 2) {
|
||||
|
||||
@@ -19,11 +19,21 @@ const currencyMappings = {
|
||||
SE: 'SEK',
|
||||
SG: 'SGD',
|
||||
IN: 'INR',
|
||||
BR: 'BRL',
|
||||
MX: 'MXN',
|
||||
CO: 'COP',
|
||||
CL: 'CLP',
|
||||
PE: 'PEN',
|
||||
}
|
||||
|
||||
const validCurrencyParams = Object.values(currencyMappings).concat([
|
||||
'EUR',
|
||||
'INR',
|
||||
'BRL',
|
||||
'MXN',
|
||||
'COP',
|
||||
'CLP',
|
||||
'PEN',
|
||||
])
|
||||
|
||||
// Countries which would likely prefer Euro's
|
||||
|
||||
@@ -29,6 +29,8 @@ block append meta
|
||||
meta(name="ol-showWritefullPromoBanner" data-type="boolean" content=showWritefullPromoBanner)
|
||||
meta(name="ol-groupsAndEnterpriseBannerVariant" data-type="string" content=groupsAndEnterpriseBannerVariant)
|
||||
meta(name="ol-showINRBanner" data-type="boolean" content=showINRBanner)
|
||||
meta(name="ol-showLATAMBanner" data-type="boolean" content=showLATAMBanner)
|
||||
meta(name="ol-recommendedCurrency" data-type="string" content=recommendedCurrency)
|
||||
meta(name="ol-welcomePageRedesignVariant" data-type="string" content=welcomePageRedesignVariant)
|
||||
meta(name="ol-groupSubscriptionsPendingEnrollment" data-type="json" content=groupSubscriptionsPendingEnrollment)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user