PlansLocator.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // TODO: This file may be deleted when Stripe is fully implemented to all users, so, consider deleting it
  2. const Settings = require('@overleaf/settings')
  3. const logger = require('@overleaf/logger')
  4. /**
  5. * @typedef {import('../../../../types/subscription/plan').RecurlyPlanCode} RecurlyPlanCode
  6. * @typedef {import('../../../../types/subscription/plan').RecurlyAddOnCode} RecurlyAddOnCode
  7. * @typedef {import('../../../../types/subscription/plan').StripeLookupKey} StripeLookupKey
  8. * @typedef {import('stripe').Stripe.Price.Recurring.Interval} BillingCycleInterval
  9. */
  10. function ensurePlansAreSetupCorrectly() {
  11. Settings.plans.forEach(plan => {
  12. if (typeof plan.price_in_cents !== 'number') {
  13. logger.fatal({ plan }, 'missing price on plan')
  14. process.exit(1)
  15. }
  16. if (plan.price) {
  17. logger.fatal({ plan }, 'unclear price attribute on plan')
  18. process.exit(1)
  19. }
  20. if (plan.price_in_unit) {
  21. logger.fatal({ plan }, 'deprecated price_in_unit attribute on plan')
  22. process.exit(1)
  23. }
  24. })
  25. }
  26. const recurlyPlanCodeToStripeLookupKey = {
  27. collaborator: 'collaborator_may2025',
  28. 'collaborator-annual': 'collaborator_annual_may2025',
  29. collaborator_free_trial_7_days: 'collaborator_may2025',
  30. professional: 'professional_may2025',
  31. 'professional-annual': 'professional_annual_may2025',
  32. professional_free_trial_7_days: 'professional_may2025',
  33. student: 'student_may2025',
  34. 'student-annual': 'student_annual_may2025',
  35. student_free_trial_7_days: 'student_may2025',
  36. // TODO: change all group plans' lookup_keys to match the UK account after they have been added
  37. group_collaborator: 'group_standard_enterprise',
  38. group_collaborator_educational: 'group_standard_educational',
  39. group_professional: 'group_professional_enterprise',
  40. group_professional_educational: 'group_professional_educational',
  41. assistant: 'assistant_may2025',
  42. 'assistant-annual': 'assistant_annual_may2025',
  43. }
  44. /**
  45. *
  46. * @param {RecurlyPlanCode} recurlyPlanCode
  47. * @returns {StripeLookupKey}
  48. */
  49. function mapRecurlyPlanCodeToStripeLookupKey(recurlyPlanCode) {
  50. return recurlyPlanCodeToStripeLookupKey[recurlyPlanCode]
  51. }
  52. /**
  53. *
  54. * @param {RecurlyAddOnCode} recurlyAddOnCode
  55. * @param {BillingCycleInterval} billingCycleInterval
  56. * @returns {StripeLookupKey|null}
  57. */
  58. function mapRecurlyAddOnCodeToStripeLookupKey(
  59. recurlyAddOnCode,
  60. billingCycleInterval
  61. ) {
  62. // Recurly always uses 'assistant' as the code regardless of the subscription duration
  63. if (recurlyAddOnCode === 'assistant') {
  64. if (billingCycleInterval === 'month') {
  65. return 'assistant_may2025'
  66. }
  67. if (billingCycleInterval === 'year') {
  68. return 'assistant_annual_may2025'
  69. }
  70. }
  71. return null
  72. }
  73. const recurlyPlanCodeToPlanTypeAndPeriod = {
  74. collaborator: { planType: 'individual', period: 'monthly' },
  75. 'collaborator-annual': { planType: 'individual', period: 'annual' },
  76. collaborator_free_trial_7_days: { planType: 'individual', period: 'monthly' },
  77. professional: { planType: 'individual', period: 'monthly' },
  78. 'professional-annual': { planType: 'individual', period: 'annual' },
  79. professional_free_trial_7_days: {
  80. planType: 'individual',
  81. period: 'monthly',
  82. },
  83. student: { planType: 'student', period: 'monthly' },
  84. 'student-annual': { planType: 'student', period: 'annual' },
  85. student_free_trial_7_days: { planType: 'student', period: 'monthly' },
  86. group_collaborator: { planType: 'group', period: 'annual' },
  87. group_collaborator_educational: { planType: 'group', period: 'annual' },
  88. group_professional: { planType: 'group', period: 'annual' },
  89. group_professional_educational: { planType: 'group', period: 'annual' },
  90. assistant: { planType: null, period: 'monthly' },
  91. 'assistant-annual': { planType: null, period: 'annual' },
  92. }
  93. /**
  94. *
  95. * @param {RecurlyPlanCode} recurlyPlanCode
  96. * @returns {{ planType: 'individual' | 'group' | 'student' | null, period: 'annual' | 'monthly'}}
  97. */
  98. function getPlanTypeAndPeriodFromRecurlyPlanCode(recurlyPlanCode) {
  99. return recurlyPlanCodeToPlanTypeAndPeriod[recurlyPlanCode]
  100. }
  101. function findLocalPlanInSettings(planCode) {
  102. for (const plan of Settings.plans) {
  103. if (plan.planCode === planCode) {
  104. return plan
  105. }
  106. }
  107. return null
  108. }
  109. module.exports = {
  110. ensurePlansAreSetupCorrectly,
  111. findLocalPlanInSettings,
  112. mapRecurlyPlanCodeToStripeLookupKey,
  113. mapRecurlyAddOnCodeToStripeLookupKey,
  114. getPlanTypeAndPeriodFromRecurlyPlanCode,
  115. }