Просмотр исходного кода

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
Thomas 4 лет назад
Родитель
Сommit
5e61fce3b4

+ 3 - 0
services/web/app/src/Features/Subscription/GroupPlansData.js

@@ -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')
 )

+ 1 - 0
services/web/app/src/Features/Subscription/SubscriptionController.js

@@ -160,6 +160,7 @@ async function userSubscriptionPage(req, res) {
     managedPublishers,
     v1SubscriptionStatus,
     currentInstitutionsWithLicence,
+    groupPlanModalOptions,
   }
   res.render('subscriptions/dashboard', data)
 }

+ 346 - 58
services/web/app/templates/plans/groups.json

@@ -1,44 +1,246 @@
 {
-  "enterprise": {
-    "collaborator": {
+  "educational": {
+    "professional": {
+      "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": 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,
+        "4": 936,
+        "5": 1168,
+        "10": 1310,
+        "20": 2420,
+        "50": 5545
+      },
+      "GBP": {
+        "2": 396,
+        "3": 592,
+        "4": 788,
+        "5": 984,
+        "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": 376,
-        "4": 495,
-        "5": 615,
-        "10": 1170,
-        "20": 2160,
-        "50": 4950
+        "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": 1090,
-        "20": 2015,
-        "50": 4620
+        "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": {
-      "USD": {
+      "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": 752,
-        "4": 990,
-        "5": 1230,
+        "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,
@@ -56,67 +258,153 @@
         "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
       }
-    }
-  },
-  "educational": {
+    },
     "collaborator": {
-      "USD": {
+      "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": 376,
-        "4": 495,
-        "5": 615,
-        "10": 695,
-        "20": 1295,
-        "50": 2970
+        "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": 655,
-        "20": 1210,
-        "50": 2770
+        "10": 1090,
+        "20": 2015,
+        "50": 4620
       },
       "GBP": {
         "2": 198,
         "3": 296,
         "4": 394,
         "5": 492,
-        "10": 560,
-        "20": 1035,
-        "50": 2375
-      }
-    },
-    "professional": {
-      "USD": {
-        "2": 504,
-        "3": 752,
-        "4": 990,
-        "5": 1230,
-        "10": 1390,
+        "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
       },
-      "EUR": {
-        "2": 470,
-        "3": 704,
-        "4": 936,
-        "5": 1168,
-        "10": 1310,
-        "20": 2420,
-        "50": 5545
+      "SEK": {
+        "2": 1848,
+        "3": 2772,
+        "4": 3696,
+        "5": 4620,
+        "10": 8580,
+        "20": 15840,
+        "50": 36300
       },
-      "GBP": {
-        "2": 396,
-        "3": 592,
-        "4": 788,
-        "5": 984,
-        "10": 1125,
-        "20": 2075,
-        "50": 4750
+      "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
       }
     }
   }
-}
+}

+ 1 - 0
services/web/app/views/subscriptions/dashboard.pug

@@ -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)

+ 8 - 43
services/web/frontend/js/main/subscription-dashboard.js

@@ -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 - 0
services/web/scripts/recurly/get_recurly_group_prices.js

@@ -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)
+  })