plans.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Creates data for localizedPlanPricing object in settings.overrides.saas.js
  2. // and plans object in main/plans.js
  3. const csv = require('csv/sync')
  4. const fs = require('fs')
  5. const path = require('path')
  6. const minimist = require('minimist')
  7. function readCSVFile(fileName) {
  8. // Pick the csv file
  9. const filePath = path.resolve(__dirname, fileName)
  10. const input = fs.readFileSync(filePath, 'utf8')
  11. const rawRecords = csv.parse(input, { columns: true })
  12. return rawRecords
  13. }
  14. function readJSONFile(fileName) {
  15. const filePath = path.resolve(__dirname, fileName)
  16. const file = fs.readFileSync(filePath)
  17. const plans = JSON.parse(file)
  18. // convert the plans JSON from recurly to an array of
  19. // objects matching the spreadsheet format
  20. const result = []
  21. for (const plan of plans) {
  22. const newRow = { plan_code: plan.code }
  23. for (const price of plan.currencies) {
  24. newRow[price.currency] = price.unitAmount
  25. }
  26. result.push(newRow)
  27. }
  28. return result
  29. }
  30. // Mapping of [output_keys]:[actual_keys]
  31. const plansMap = {
  32. student: 'student',
  33. personal: 'paid-personal',
  34. collaborator: 'collaborator',
  35. professional: 'professional',
  36. }
  37. const currencies = [
  38. 'AUD',
  39. 'BRL',
  40. 'CAD',
  41. 'CHF',
  42. 'CLP',
  43. 'COP',
  44. 'DKK',
  45. 'EUR',
  46. 'GBP',
  47. 'INR',
  48. 'MXN',
  49. 'NOK',
  50. 'NZD',
  51. 'PEN',
  52. 'SEK',
  53. 'SGD',
  54. 'USD',
  55. ]
  56. function generatePlans(workSheetJSON) {
  57. // localizedPlanPricing object for settings.overrides.saas.js
  58. const localizedPlanPricing = {}
  59. // plans object for main/plans.js
  60. for (const currency of currencies) {
  61. localizedPlanPricing[currency] = {
  62. free: {
  63. monthly: 0,
  64. annual: 0,
  65. },
  66. }
  67. for (const [outputKey, actualKey] of Object.entries(plansMap)) {
  68. const monthlyPlan = workSheetJSON.find(
  69. data => data.plan_code === actualKey
  70. )
  71. if (!monthlyPlan) throw new Error(`Missing plan: ${actualKey}`)
  72. if (!(currency in monthlyPlan))
  73. throw new Error(
  74. `Missing currency "${currency}" for plan "${actualKey}"`
  75. )
  76. const actualKeyAnnual = `${actualKey}-annual`
  77. const annualPlan = workSheetJSON.find(
  78. data => data.plan_code === actualKeyAnnual
  79. )
  80. if (!annualPlan) throw new Error(`Missing plan: ${actualKeyAnnual}`)
  81. if (!(currency in annualPlan))
  82. throw new Error(
  83. `Missing currency "${currency}" for plan "${actualKeyAnnual}"`
  84. )
  85. const monthly = Number(monthlyPlan[currency])
  86. const monthlyTimesTwelve = Number(monthlyPlan[currency] * 12)
  87. const annual = Number(annualPlan[currency])
  88. localizedPlanPricing[currency] = {
  89. ...localizedPlanPricing[currency],
  90. [outputKey]: { monthly, monthlyTimesTwelve, annual },
  91. }
  92. }
  93. }
  94. return { localizedPlanPricing }
  95. }
  96. function generateGroupPlans(workSheetJSON) {
  97. const groupPlans = workSheetJSON.filter(data =>
  98. data.plan_code.startsWith('group')
  99. )
  100. const sizes = ['2', '3', '4', '5', '10', '20', '50']
  101. const result = {}
  102. for (const type1 of ['educational', 'enterprise']) {
  103. result[type1] = {}
  104. for (const type2 of ['professional', 'collaborator']) {
  105. result[type1][type2] = {}
  106. for (const currency of currencies) {
  107. result[type1][type2][currency] = {}
  108. for (const size of sizes) {
  109. const planCode = `group_${type2}_${size}_${type1}`
  110. const plan = groupPlans.find(data => data.plan_code === planCode)
  111. if (!plan) throw new Error(`Missing plan: ${planCode}`)
  112. result[type1][type2][currency][size] = {
  113. price_in_cents: plan[currency] * 100,
  114. }
  115. }
  116. }
  117. }
  118. }
  119. return result
  120. }
  121. const argv = minimist(process.argv.slice(2), {
  122. string: ['output', 'file'],
  123. alias: { o: 'output', f: 'file' },
  124. })
  125. let input
  126. if (argv.file) {
  127. const ext = path.extname(argv.file)
  128. switch (ext) {
  129. case '.csv':
  130. input = readCSVFile(argv.file)
  131. break
  132. case '.json':
  133. input = readJSONFile(argv.file)
  134. break
  135. default:
  136. console.log('Invalid file type: must be csv or json')
  137. }
  138. } else {
  139. console.log('usage: node plans.js -f <file.csv|file.json> -o <dir>')
  140. process.exit(1)
  141. }
  142. // removes quotes from object keys
  143. const formatJS = obj =>
  144. JSON.stringify(obj, null, 2).replace(/"([^"]+)":/g, '$1:')
  145. const formatJSON = obj => JSON.stringify(obj, null, 2)
  146. function writeFile(outputFile, data) {
  147. console.log(`Writing ${outputFile}`)
  148. fs.writeFileSync(outputFile, data)
  149. }
  150. const { localizedPlanPricing } = generatePlans(input)
  151. const groupPlans = generateGroupPlans(input)
  152. if (argv.output) {
  153. const dir = argv.output
  154. // check if output directory exists
  155. if (!fs.existsSync(dir)) {
  156. console.log(`Creating output directory ${dir}`)
  157. fs.mkdirSync(dir)
  158. }
  159. // check if output directory is a directory and report error if not
  160. if (!fs.lstatSync(dir).isDirectory()) {
  161. console.error(`Error: output dir ${dir} is not a directory`)
  162. process.exit(1)
  163. }
  164. writeFile(`${dir}/localizedPlanPricing.json`, formatJS(localizedPlanPricing))
  165. writeFile(`${dir}/groups.json`, formatJSON(groupPlans))
  166. } else {
  167. console.log('LOCALIZED', localizedPlanPricing)
  168. console.log('GROUP PLANS', JSON.stringify(groupPlans, null, 2))
  169. }
  170. console.log('Completed!')