mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #20898 from overleaf/em-ai-add-on-setup-recurly
Script for setting up the Assistant add-on in Recurly GitOrigin-RevId: 25a94961e4068456795b6be6b5e047efc65363fa
This commit is contained in:
parent
60cf8885b0
commit
13ecddaef1
1 changed files with 219 additions and 0 deletions
219
services/web/scripts/recurly/setup_assistant_addon.js
Normal file
219
services/web/scripts/recurly/setup_assistant_addon.js
Normal file
|
@ -0,0 +1,219 @@
|
|||
// @ts-check
|
||||
|
||||
const _ = require('lodash')
|
||||
const recurly = require('recurly')
|
||||
const minimist = require('minimist')
|
||||
const Settings = require('@overleaf/settings')
|
||||
|
||||
const ADD_ON_CODE = 'assistant'
|
||||
const ADD_ON_NAME = 'Error Assist'
|
||||
|
||||
const INDIVIDUAL_PLANS = [
|
||||
'student',
|
||||
'collaborator',
|
||||
'professional',
|
||||
'paid-personal',
|
||||
]
|
||||
const INDIVIDUAL_VARIANTS = ['', '_free_trial_7_days']
|
||||
const GROUP_PLANS = ['collaborator', 'professional']
|
||||
const GROUP_SIZES = [2, 3, 4, 5, 10, 20, 50, 100, 200, 500]
|
||||
const GROUP_SEGMENTS = ['educational', 'enterprise']
|
||||
|
||||
const ARGS = parseArgs()
|
||||
|
||||
const recurlyClient = new recurly.Client(Settings.apis.recurly.apiKey)
|
||||
|
||||
function usage() {
|
||||
console.log(`Usage: setup_assistant_addon.js [--commit]
|
||||
|
||||
This script will copy prices from the ${ADD_ON_CODE} and ${ADD_ON_CODE}-annual
|
||||
plans into the ${ADD_ON_CODE} add-on for every other plan
|
||||
|
||||
Options:
|
||||
|
||||
--commit Make actual changes to Recurly
|
||||
`)
|
||||
}
|
||||
|
||||
function parseArgs() {
|
||||
const args = minimist(process.argv.slice(2), {
|
||||
boolean: ['commit', 'help'],
|
||||
})
|
||||
|
||||
if (args.help) {
|
||||
usage()
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
return { commit: args.commit }
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const monthlyPlan = await getPlan(ADD_ON_CODE)
|
||||
if (monthlyPlan == null) {
|
||||
console.error(`Monthly plan missing in Recurly: ${ADD_ON_CODE}`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('\nMonthly prices:')
|
||||
for (const { currency, unitAmount } of monthlyPlan.currencies ?? []) {
|
||||
console.log(`- ${unitAmount} ${currency}`)
|
||||
}
|
||||
|
||||
const annualPlan = await getPlan(`${ADD_ON_CODE}-annual`)
|
||||
if (annualPlan == null) {
|
||||
console.error(`Annual plan missing in Recurly: ${ADD_ON_CODE}-annual`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('\nAnnual prices:')
|
||||
for (const { currency, unitAmount } of annualPlan.currencies ?? []) {
|
||||
console.log(`- ${unitAmount} ${currency}`)
|
||||
}
|
||||
console.log()
|
||||
|
||||
for (const { code, annual } of getPlanSpecs()) {
|
||||
const prices = annual ? annualPlan.currencies : monthlyPlan.currencies
|
||||
await setupAddOn(code, prices ?? [])
|
||||
}
|
||||
if (ARGS.commit) {
|
||||
console.log('Done')
|
||||
} else {
|
||||
console.log('This was a dry run. Re-run with --commit to apply changes.')
|
||||
}
|
||||
}
|
||||
|
||||
function* getPlanSpecs() {
|
||||
for (const plan of INDIVIDUAL_PLANS) {
|
||||
for (const variant of INDIVIDUAL_VARIANTS) {
|
||||
yield { code: `${plan}${variant}`, annual: false }
|
||||
yield { code: `${plan}-annual${variant}`, annual: true }
|
||||
}
|
||||
}
|
||||
for (const plan of GROUP_PLANS) {
|
||||
for (const size of GROUP_SIZES) {
|
||||
for (const segment of GROUP_SEGMENTS) {
|
||||
yield { code: `group_${plan}_${size}_${segment}`, annual: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update the assistant add-on for a plan
|
||||
*
|
||||
* @param {string} planCode
|
||||
* @param {recurly.AddOnPricing[]} prices
|
||||
*/
|
||||
async function setupAddOn(planCode, prices) {
|
||||
const currentAddOn = await getAddOn(planCode, ADD_ON_CODE)
|
||||
const newAddOnConfig = getAddOnConfig(prices)
|
||||
if (currentAddOn == null || currentAddOn.deletedAt != null) {
|
||||
await createAddOn(planCode, newAddOnConfig)
|
||||
} else if (_.isMatch(currentAddOn, newAddOnConfig)) {
|
||||
console.log(`No changes for plan ${planCode}`)
|
||||
} else {
|
||||
await updateAddOn(planCode, newAddOnConfig)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a plan configuration from Recurly
|
||||
*
|
||||
* @param {string} planCode
|
||||
*/
|
||||
async function getPlan(planCode) {
|
||||
try {
|
||||
return await recurlyClient.getPlan(`code-${planCode}`)
|
||||
} catch (err) {
|
||||
if (err instanceof recurly.errors.NotFoundError) {
|
||||
return null
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an add-on configuration from Recurly
|
||||
*
|
||||
* @param {string} planCode
|
||||
* @param {string} addOnCode
|
||||
*/
|
||||
async function getAddOn(planCode, addOnCode) {
|
||||
try {
|
||||
return await recurlyClient.getPlanAddOn(
|
||||
`code-${planCode}`,
|
||||
`code-${addOnCode}`
|
||||
)
|
||||
} catch (err) {
|
||||
if (err instanceof recurly.errors.NotFoundError) {
|
||||
return null
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the add-on described by the given config on the given plan
|
||||
*
|
||||
* @param {string} planCode
|
||||
* @param {recurly.AddOnCreate} config
|
||||
*/
|
||||
async function createAddOn(planCode, config) {
|
||||
if (ARGS.commit) {
|
||||
console.log(`Creating ${ADD_ON_CODE} add-on for plan ${planCode}...`)
|
||||
await recurlyClient.createPlanAddOn(`code-${planCode}`, config)
|
||||
} else {
|
||||
console.log(`Would create ${ADD_ON_CODE} add-on for plan ${planCode}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the add-on described by the given config on the given plan
|
||||
*
|
||||
* @param {string} planCode
|
||||
* @param {recurly.AddOnUpdate} config
|
||||
*/
|
||||
async function updateAddOn(planCode, config) {
|
||||
if (ARGS.commit) {
|
||||
console.log(`Updating ${ADD_ON_CODE} add-on for plan ${planCode}...`)
|
||||
await recurlyClient.updatePlanAddOn(
|
||||
`code-${planCode}`,
|
||||
`code-${ADD_ON_CODE}`,
|
||||
config
|
||||
)
|
||||
} else {
|
||||
console.log(`Would update ${ADD_ON_CODE} add-on for plan ${planCode}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an assistant add-on config
|
||||
*
|
||||
* @param {recurly.AddOnPricing[]} prices
|
||||
*/
|
||||
function getAddOnConfig(prices) {
|
||||
return {
|
||||
code: ADD_ON_CODE,
|
||||
name: ADD_ON_NAME,
|
||||
optional: true,
|
||||
currencies: prices.map(price =>
|
||||
_.pick(
|
||||
price,
|
||||
'currency',
|
||||
'unitAmount',
|
||||
'unitAmountDecimal',
|
||||
'taxInclusive'
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => {
|
||||
process.exit(0)
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
Loading…
Reference in a new issue