From e74d0c727aa0240f196b4fa5594d83ea89e7bc75 Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma Date: Fri, 19 Jun 2026 10:25:07 +0530 Subject: [PATCH] feat(billing): let locale-eligible accounts choose USD or BRL before subscribing --- .../dashboard/api/enterprise/account.js | 4 ++ .../dashboard/i18n/locale/en/settings.json | 4 ++ .../dashboard/settings/billing/Index.vue | 46 +++++++++++++++++-- .../dashboard/store/modules/accounts.js | 15 +++++- app/policies/account_policy.rb | 4 ++ config/locales/en.yml | 2 + config/routes.rb | 1 + .../enterprise/api/v1/accounts_controller.rb | 31 +++++++++++-- enterprise/app/models/enterprise/account.rb | 10 ++++ 9 files changed, 109 insertions(+), 8 deletions(-) diff --git a/app/javascript/dashboard/api/enterprise/account.js b/app/javascript/dashboard/api/enterprise/account.js index 2810410bd..03456a288 100644 --- a/app/javascript/dashboard/api/enterprise/account.js +++ b/app/javascript/dashboard/api/enterprise/account.js @@ -14,6 +14,10 @@ class EnterpriseAccountAPI extends ApiClient { return axios.post(`${this.url}subscription`); } + selectBillingCurrency(currency) { + return axios.post(`${this.url}select_billing_currency`, { currency }); + } + getLimits() { return axios.get(`${this.url}limits`); } diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json index 0b74f7f13..0e3341ef9 100644 --- a/app/javascript/dashboard/i18n/locale/en/settings.json +++ b/app/javascript/dashboard/i18n/locale/en/settings.json @@ -454,6 +454,10 @@ "CURRENCY": "Currency" }, "CURRENCY": { + "SELECT": { + "TITLE": "Choose your billing currency", + "DESCRIPTION": "Select the currency you'd like to be billed in. This can't be changed once your subscription is created." + }, "OPTIONS": { "USD": "US Dollar (USD)", "BRL": "Brazilian Real (BRL)" diff --git a/app/javascript/dashboard/routes/dashboard/settings/billing/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/billing/Index.vue index 8a27096f6..4adcc6b59 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/billing/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/billing/Index.vue @@ -39,6 +39,10 @@ const BILLING_REFRESH_ATTEMPTED = 'billing_refresh_attempted'; const isWaitingForBilling = ref(false); const purchaseCreditsModalRef = ref(null); +// Currency selection shown to new accounts whose locale supports a non-USD currency. +const currencySelectionRequired = ref(false); +const currencyOptions = ref([]); + const customAttributes = computed(() => { return currentAccount.value.custom_attributes || {}; }); @@ -88,7 +92,9 @@ const hasABillingPlan = computed(() => { const fetchAccountDetails = async () => { if (!hasABillingPlan.value) { - await store.dispatch('accounts/subscription'); + const data = await store.dispatch('accounts/subscription'); + currencySelectionRequired.value = !!data?.currency_selection_required; + currencyOptions.value = data?.currency_options || []; } // Always fetch limits for billing page to show credit usage fetchLimits(); @@ -107,6 +113,9 @@ const handleBillingPageLogic = async () => { // If cloud user, fetch account details first await fetchAccountDetails(); + // Waiting on the user to pick a billing currency — don't auto-refresh. + if (currencySelectionRequired.value) return; + // If still no billing plan after fetch if (!hasABillingPlan.value) { // If we haven't attempted refresh yet, do it once @@ -128,6 +137,13 @@ const handleBillingPageLogic = async () => { } }; +const onSelectCurrency = async code => { + await store.dispatch('accounts/selectBillingCurrency', code); + currencySelectionRequired.value = false; + // Currency stored and customer creation kicked off — resume the standard wait flow. + await handleBillingPageLogic(); +}; + const onClickBillingPortal = () => { store.dispatch('accounts/checkout'); }; @@ -158,7 +174,9 @@ onMounted(handleBillingPageLogic); ? $t('BILLING_SETTINGS.NO_BILLING_USER') : $t('ATTRIBUTES_MGMT.LOADING') " - :no-records-found="!hasABillingPlan && !isWaitingForBilling" + :no-records-found=" + !hasABillingPlan && !isWaitingForBilling && !currencySelectionRequired + " :no-records-message="$t('BILLING_SETTINGS.NO_BILLING_USER')" >