mirror of
https://github.com/overleaf/overleaf.git
synced 2025-02-03 00:11:33 +00:00
Enable additional currencies when purchasing (or upgrading to) a group plan (#4884)
* Add script to fetch group data pricing from Recurly * Update groups pricing data using script to fetch prices from Recurly * Add additional currencies to saas settings * Refactor group plans upgrade modal to use shared options from settings GitOrigin-RevId: 6d13d5b152d01e0399f9d2b8f6f8bf99784589e8
This commit is contained in:
parent
7288c05075
commit
5e61fce3b4
6 changed files with 441 additions and 138 deletions
|
@ -8,6 +8,9 @@ const Path = require('path')
|
|||
// It is also used by scripts/recurly/sync_recurly.rb, which will make sure
|
||||
// Recurly has a plan configured for all the groups, and that the prices are
|
||||
// up to date with the data in groups.json.
|
||||
// Alternatively, scripts/recurly/get_recurly_group_prices.rb can be used to
|
||||
// fetch pricing data and generate a groups.json using the current Recurly
|
||||
// prices
|
||||
const data = fs.readFileSync(
|
||||
Path.join(__dirname, '/../../../templates/plans/groups.json')
|
||||
)
|
||||
|
|
|
@ -160,6 +160,7 @@ async function userSubscriptionPage(req, res) {
|
|||
managedPublishers,
|
||||
v1SubscriptionStatus,
|
||||
currentInstitutionsWithLicence,
|
||||
groupPlanModalOptions,
|
||||
}
|
||||
res.render('subscriptions/dashboard', data)
|
||||
}
|
||||
|
|
|
@ -1,104 +1,42 @@
|
|||
{
|
||||
"enterprise": {
|
||||
"collaborator": {
|
||||
"USD": {
|
||||
"2": 252,
|
||||
"3": 376,
|
||||
"4": 495,
|
||||
"5": 615,
|
||||
"10": 1170,
|
||||
"20": 2160,
|
||||
"50": 4950
|
||||
},
|
||||
"EUR": {
|
||||
"2": 235,
|
||||
"3": 352,
|
||||
"4": 468,
|
||||
"5": 584,
|
||||
"10": 1090,
|
||||
"20": 2015,
|
||||
"50": 4620
|
||||
},
|
||||
"GBP": {
|
||||
"2": 198,
|
||||
"3": 296,
|
||||
"4": 394,
|
||||
"5": 492,
|
||||
"10": 935,
|
||||
"20": 1730,
|
||||
"50": 3960
|
||||
}
|
||||
},
|
||||
"professional": {
|
||||
"USD": {
|
||||
"2": 504,
|
||||
"3": 752,
|
||||
"4": 990,
|
||||
"5": 1230,
|
||||
"10": 2340,
|
||||
"20": 4320,
|
||||
"50": 9900
|
||||
},
|
||||
"EUR": {
|
||||
"2": 470,
|
||||
"3": 704,
|
||||
"4": 936,
|
||||
"5": 1168,
|
||||
"10": 2185,
|
||||
"20": 4030,
|
||||
"50": 9240
|
||||
},
|
||||
"GBP": {
|
||||
"2": 396,
|
||||
"3": 592,
|
||||
"4": 788,
|
||||
"5": 984,
|
||||
"10": 1870,
|
||||
"20": 3455,
|
||||
"50": 7920
|
||||
}
|
||||
}
|
||||
},
|
||||
"educational": {
|
||||
"collaborator": {
|
||||
"USD": {
|
||||
"2": 252,
|
||||
"3": 376,
|
||||
"4": 495,
|
||||
"5": 615,
|
||||
"10": 695,
|
||||
"20": 1295,
|
||||
"50": 2970
|
||||
},
|
||||
"EUR": {
|
||||
"2": 235,
|
||||
"3": 352,
|
||||
"4": 468,
|
||||
"5": 584,
|
||||
"10": 655,
|
||||
"20": 1210,
|
||||
"50": 2770
|
||||
},
|
||||
"GBP": {
|
||||
"2": 198,
|
||||
"3": 296,
|
||||
"4": 394,
|
||||
"5": 492,
|
||||
"10": 560,
|
||||
"20": 1035,
|
||||
"50": 2375
|
||||
}
|
||||
},
|
||||
"professional": {
|
||||
"USD": {
|
||||
"AUD": {
|
||||
"2": 604,
|
||||
"3": 906,
|
||||
"4": 1208,
|
||||
"5": 1510,
|
||||
"10": 1685,
|
||||
"20": 3110,
|
||||
"50": 7130
|
||||
},
|
||||
"CAD": {
|
||||
"2": 570,
|
||||
"3": 854,
|
||||
"4": 1138,
|
||||
"5": 1420,
|
||||
"10": 1590,
|
||||
"20": 2940,
|
||||
"50": 6730
|
||||
},
|
||||
"CHF": {
|
||||
"2": 504,
|
||||
"3": 752,
|
||||
"4": 990,
|
||||
"5": 1230,
|
||||
"10": 1390,
|
||||
"3": 756,
|
||||
"4": 1008,
|
||||
"5": 1260,
|
||||
"10": 1405,
|
||||
"20": 2590,
|
||||
"50": 5940
|
||||
},
|
||||
"DKK": {
|
||||
"2": 3024,
|
||||
"3": 4536,
|
||||
"4": 6048,
|
||||
"5": 7560,
|
||||
"10": 8425,
|
||||
"20": 15550,
|
||||
"50": 35640
|
||||
},
|
||||
"EUR": {
|
||||
"2": 470,
|
||||
"3": 704,
|
||||
|
@ -116,7 +54,357 @@
|
|||
"10": 1125,
|
||||
"20": 2075,
|
||||
"50": 4750
|
||||
},
|
||||
"NOK": {
|
||||
"2": 3696,
|
||||
"3": 5544,
|
||||
"4": 7392,
|
||||
"5": 9240,
|
||||
"10": 10295,
|
||||
"20": 19010,
|
||||
"50": 43560
|
||||
},
|
||||
"NZD": {
|
||||
"2": 604,
|
||||
"3": 906,
|
||||
"4": 1208,
|
||||
"5": 1510,
|
||||
"10": 1685,
|
||||
"20": 3110,
|
||||
"50": 7130
|
||||
},
|
||||
"SEK": {
|
||||
"2": 3696,
|
||||
"3": 5544,
|
||||
"4": 7392,
|
||||
"5": 9240,
|
||||
"10": 10295,
|
||||
"20": 19010,
|
||||
"50": 43560
|
||||
},
|
||||
"SGD": {
|
||||
"2": 672,
|
||||
"3": 1008,
|
||||
"4": 1344,
|
||||
"5": 1680,
|
||||
"10": 1870,
|
||||
"20": 3455,
|
||||
"50": 7920
|
||||
},
|
||||
"USD": {
|
||||
"2": 504,
|
||||
"3": 752,
|
||||
"4": 990,
|
||||
"5": 1230,
|
||||
"10": 1390,
|
||||
"20": 2590,
|
||||
"50": 5940
|
||||
}
|
||||
},
|
||||
"collaborator": {
|
||||
"AUD": {
|
||||
"2": 302,
|
||||
"3": 453,
|
||||
"4": 604,
|
||||
"5": 755,
|
||||
"10": 840,
|
||||
"20": 1555,
|
||||
"50": 3565
|
||||
},
|
||||
"CAD": {
|
||||
"2": 285,
|
||||
"3": 427,
|
||||
"4": 569,
|
||||
"5": 710,
|
||||
"10": 795,
|
||||
"20": 1470,
|
||||
"50": 3365
|
||||
},
|
||||
"CHF": {
|
||||
"2": 252,
|
||||
"3": 378,
|
||||
"4": 504,
|
||||
"5": 630,
|
||||
"10": 700,
|
||||
"20": 1295,
|
||||
"50": 2970
|
||||
},
|
||||
"DKK": {
|
||||
"2": 1512,
|
||||
"3": 2268,
|
||||
"4": 3024,
|
||||
"5": 3780,
|
||||
"10": 4210,
|
||||
"20": 7775,
|
||||
"50": 17820
|
||||
},
|
||||
"EUR": {
|
||||
"2": 235,
|
||||
"3": 352,
|
||||
"4": 468,
|
||||
"5": 584,
|
||||
"10": 655,
|
||||
"20": 1210,
|
||||
"50": 2770
|
||||
},
|
||||
"GBP": {
|
||||
"2": 198,
|
||||
"3": 296,
|
||||
"4": 394,
|
||||
"5": 492,
|
||||
"10": 560,
|
||||
"20": 1035,
|
||||
"50": 2375
|
||||
},
|
||||
"NOK": {
|
||||
"2": 1848,
|
||||
"3": 2772,
|
||||
"4": 3696,
|
||||
"5": 4620,
|
||||
"10": 5150,
|
||||
"20": 9505,
|
||||
"50": 21780
|
||||
},
|
||||
"NZD": {
|
||||
"2": 302,
|
||||
"3": 453,
|
||||
"4": 604,
|
||||
"5": 755,
|
||||
"10": 840,
|
||||
"20": 1555,
|
||||
"50": 3565
|
||||
},
|
||||
"SEK": {
|
||||
"2": 1848,
|
||||
"3": 2772,
|
||||
"4": 3696,
|
||||
"5": 4620,
|
||||
"10": 5150,
|
||||
"20": 9505,
|
||||
"50": 21780
|
||||
},
|
||||
"SGD": {
|
||||
"2": 336,
|
||||
"3": 504,
|
||||
"4": 672,
|
||||
"5": 840,
|
||||
"10": 935,
|
||||
"20": 1730,
|
||||
"50": 3960
|
||||
},
|
||||
"USD": {
|
||||
"2": 252,
|
||||
"3": 376,
|
||||
"4": 495,
|
||||
"5": 615,
|
||||
"10": 695,
|
||||
"20": 1295,
|
||||
"50": 2970
|
||||
}
|
||||
}
|
||||
},
|
||||
"enterprise": {
|
||||
"professional": {
|
||||
"AUD": {
|
||||
"2": 604,
|
||||
"3": 906,
|
||||
"4": 1208,
|
||||
"5": 1510,
|
||||
"10": 2810,
|
||||
"20": 5185,
|
||||
"50": 11880
|
||||
},
|
||||
"CAD": {
|
||||
"2": 570,
|
||||
"3": 854,
|
||||
"4": 1138,
|
||||
"5": 1420,
|
||||
"10": 2650,
|
||||
"20": 4895,
|
||||
"50": 11220
|
||||
},
|
||||
"CHF": {
|
||||
"2": 504,
|
||||
"3": 756,
|
||||
"4": 1008,
|
||||
"5": 1260,
|
||||
"10": 2340,
|
||||
"20": 4320,
|
||||
"50": 9900
|
||||
},
|
||||
"DKK": {
|
||||
"2": 3024,
|
||||
"3": 4536,
|
||||
"4": 6048,
|
||||
"5": 7560,
|
||||
"10": 14040,
|
||||
"20": 25920,
|
||||
"50": 59400
|
||||
},
|
||||
"EUR": {
|
||||
"2": 470,
|
||||
"3": 704,
|
||||
"4": 936,
|
||||
"5": 1168,
|
||||
"10": 2185,
|
||||
"20": 4030,
|
||||
"50": 9240
|
||||
},
|
||||
"GBP": {
|
||||
"2": 396,
|
||||
"3": 592,
|
||||
"4": 788,
|
||||
"5": 984,
|
||||
"10": 1870,
|
||||
"20": 3455,
|
||||
"50": 7920
|
||||
},
|
||||
"NOK": {
|
||||
"2": 3696,
|
||||
"3": 5544,
|
||||
"4": 7392,
|
||||
"5": 9240,
|
||||
"10": 17160,
|
||||
"20": 31680,
|
||||
"50": 72600
|
||||
},
|
||||
"NZD": {
|
||||
"2": 604,
|
||||
"3": 906,
|
||||
"4": 1208,
|
||||
"5": 1510,
|
||||
"10": 2810,
|
||||
"20": 5185,
|
||||
"50": 11880
|
||||
},
|
||||
"SEK": {
|
||||
"2": 3696,
|
||||
"3": 5544,
|
||||
"4": 7392,
|
||||
"5": 9240,
|
||||
"10": 17160,
|
||||
"20": 31680,
|
||||
"50": 72600
|
||||
},
|
||||
"SGD": {
|
||||
"2": 672,
|
||||
"3": 1008,
|
||||
"4": 1344,
|
||||
"5": 1680,
|
||||
"10": 3120,
|
||||
"20": 5760,
|
||||
"50": 13200
|
||||
},
|
||||
"USD": {
|
||||
"2": 504,
|
||||
"3": 752,
|
||||
"4": 990,
|
||||
"5": 1230,
|
||||
"10": 2340,
|
||||
"20": 4320,
|
||||
"50": 9900
|
||||
}
|
||||
},
|
||||
"collaborator": {
|
||||
"AUD": {
|
||||
"2": 302,
|
||||
"3": 453,
|
||||
"4": 604,
|
||||
"5": 755,
|
||||
"10": 1405,
|
||||
"20": 2590,
|
||||
"50": 5940
|
||||
},
|
||||
"CAD": {
|
||||
"2": 285,
|
||||
"3": 427,
|
||||
"4": 569,
|
||||
"5": 710,
|
||||
"10": 1325,
|
||||
"20": 2450,
|
||||
"50": 5610
|
||||
},
|
||||
"CHF": {
|
||||
"2": 252,
|
||||
"3": 378,
|
||||
"4": 504,
|
||||
"5": 630,
|
||||
"10": 1170,
|
||||
"20": 2160,
|
||||
"50": 4950
|
||||
},
|
||||
"DKK": {
|
||||
"2": 1512,
|
||||
"3": 2268,
|
||||
"4": 3024,
|
||||
"5": 3780,
|
||||
"10": 7020,
|
||||
"20": 12960,
|
||||
"50": 29700
|
||||
},
|
||||
"EUR": {
|
||||
"2": 235,
|
||||
"3": 352,
|
||||
"4": 468,
|
||||
"5": 584,
|
||||
"10": 1090,
|
||||
"20": 2015,
|
||||
"50": 4620
|
||||
},
|
||||
"GBP": {
|
||||
"2": 198,
|
||||
"3": 296,
|
||||
"4": 394,
|
||||
"5": 492,
|
||||
"10": 935,
|
||||
"20": 1730,
|
||||
"50": 3960
|
||||
},
|
||||
"NOK": {
|
||||
"2": 1848,
|
||||
"3": 2772,
|
||||
"4": 3696,
|
||||
"5": 4620,
|
||||
"10": 8580,
|
||||
"20": 15840,
|
||||
"50": 36300
|
||||
},
|
||||
"NZD": {
|
||||
"2": 302,
|
||||
"3": 453,
|
||||
"4": 604,
|
||||
"5": 755,
|
||||
"10": 1405,
|
||||
"20": 2590,
|
||||
"50": 5940
|
||||
},
|
||||
"SEK": {
|
||||
"2": 1848,
|
||||
"3": 2772,
|
||||
"4": 3696,
|
||||
"5": 4620,
|
||||
"10": 8580,
|
||||
"20": 15840,
|
||||
"50": 36300
|
||||
},
|
||||
"SGD": {
|
||||
"2": 336,
|
||||
"3": 504,
|
||||
"4": 672,
|
||||
"5": 840,
|
||||
"10": 1560,
|
||||
"20": 2880,
|
||||
"50": 6600
|
||||
},
|
||||
"USD": {
|
||||
"2": 252,
|
||||
"3": 376,
|
||||
"4": 495,
|
||||
"5": 615,
|
||||
"10": 1170,
|
||||
"20": 2160,
|
||||
"50": 4950
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ block append meta
|
|||
meta(name="ol-subscription" data-type="json" content=personalSubscription)
|
||||
meta(name="ol-recomendedCurrency" content=personalSubscription.recurly.currency)
|
||||
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
|
||||
meta(name="ol-groupPlanModalOptions" data-type="json" content=groupPlanModalOptions)
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content(ng-cloak)
|
||||
|
|
|
@ -21,6 +21,8 @@ import App from '../base'
|
|||
import getMeta from '../utils/meta'
|
||||
const SUBSCRIPTION_URL = '/user/subscription/update'
|
||||
|
||||
const GROUP_PLAN_MODAL_OPTIONS = getMeta('ol-groupPlanModalOptions')
|
||||
|
||||
const ensureRecurlyIsSetup = _.once(() => {
|
||||
if (typeof recurly === 'undefined' || !recurly) {
|
||||
return false
|
||||
|
@ -102,7 +104,11 @@ App.controller('ChangePlanToGroupFormController', function ($scope, $modal) {
|
|||
const subscription = getMeta('ol-subscription')
|
||||
const currency = subscription.recurly.currency
|
||||
|
||||
if (['USD', 'GBP', 'EUR'].includes(currency)) {
|
||||
const validCurrencies = GROUP_PLAN_MODAL_OPTIONS.currencies.map(
|
||||
item => item.code
|
||||
)
|
||||
|
||||
if (validCurrencies.includes(currency)) {
|
||||
$scope.isValidCurrencyForUpgrade = true
|
||||
}
|
||||
|
||||
|
@ -123,48 +129,7 @@ App.controller('ChangePlanToGroupFormController', function ($scope, $modal) {
|
|||
App.controller(
|
||||
'GroupPlansModalUpgradeController',
|
||||
function ($scope, $modal, $location, $http, RecurlyPricing) {
|
||||
$scope.options = {
|
||||
plan_codes: [
|
||||
{
|
||||
display: 'Collaborator',
|
||||
code: 'collaborator',
|
||||
},
|
||||
{
|
||||
display: 'Professional',
|
||||
code: 'professional',
|
||||
},
|
||||
],
|
||||
currencies: [
|
||||
{
|
||||
display: 'USD ($)',
|
||||
code: 'USD',
|
||||
},
|
||||
{
|
||||
display: 'GBP (£)',
|
||||
code: 'GBP',
|
||||
},
|
||||
{
|
||||
display: 'EUR (€)',
|
||||
code: 'EUR',
|
||||
},
|
||||
],
|
||||
currencySymbols: {
|
||||
USD: '$',
|
||||
EUR: '€',
|
||||
GBP: '£',
|
||||
},
|
||||
sizes: [2, 3, 4, 5, 10, 20, 50],
|
||||
usages: [
|
||||
{
|
||||
display: 'Enterprise',
|
||||
code: 'enterprise',
|
||||
},
|
||||
{
|
||||
display: 'Educational',
|
||||
code: 'educational',
|
||||
},
|
||||
],
|
||||
}
|
||||
$scope.options = GROUP_PLAN_MODAL_OPTIONS
|
||||
|
||||
$scope.prices = getMeta('ol-groupPlans')
|
||||
|
||||
|
|
45
services/web/scripts/recurly/get_recurly_group_prices.js
Normal file
45
services/web/scripts/recurly/get_recurly_group_prices.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Get prices from Recurly in GroupPlansData format, ie to update:
|
||||
// app/templates/plans/groups.json
|
||||
//
|
||||
// Usage example:
|
||||
// node scripts/recurly/get_recurly_group_prices.js
|
||||
|
||||
const recurly = require('recurly')
|
||||
const Settings = require('@overleaf/settings')
|
||||
|
||||
const recurlySettings = Settings.apis.recurly
|
||||
const recurlyApiKey = recurlySettings ? recurlySettings.apiKey : undefined
|
||||
|
||||
const client = new recurly.Client(recurlyApiKey)
|
||||
|
||||
async function getRecurlyGroupPrices() {
|
||||
const prices = {}
|
||||
const plans = client.listPlans({ params: { limit: 200 } })
|
||||
for await (const plan of plans.each()) {
|
||||
if (plan.code.substr(0, 6) === 'group_') {
|
||||
const [, type, size, usage] = plan.code.split('_')
|
||||
plan.currencies.forEach(planPricing => {
|
||||
const { currency, unitAmount } = planPricing
|
||||
prices[usage] = prices[usage] || {}
|
||||
prices[usage][type] = prices[usage][type] || {}
|
||||
prices[usage][type][currency] = prices[usage][type][currency] || {}
|
||||
prices[usage][type][currency][size] = unitAmount
|
||||
})
|
||||
}
|
||||
}
|
||||
return prices
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const prices = await getRecurlyGroupPrices()
|
||||
console.log(JSON.stringify(prices, undefined, 2))
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => {
|
||||
process.exit(0)
|
||||
})
|
||||
.catch(error => {
|
||||
console.error({ error })
|
||||
process.exit(1)
|
||||
})
|
Loading…
Reference in a new issue