helpers.mjs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /* eslint-disable @overleaf/require-script-runner */
  2. // This file contains helper functions used by other scripts.
  3. // The scripts that import these helpers should use Script Runner.
  4. /**
  5. * @import Stripe from 'stripe'
  6. * @import { getRegionClient } from '../../modules/subscriptions/app/src/StripeClient.mjs'
  7. */
  8. /**
  9. * @export
  10. * @typedef {Object} CSVSubscriptionChange
  11. * @property {string} subscription_id
  12. * @property {string} current_lookup_key
  13. * @property {string} new_lookup_key
  14. * @property {string} current_add_on_lookup_key
  15. * @property {string} new_add_on_lookup_key
  16. */
  17. /**
  18. * @export
  19. * @typedef {'renewal' | 'now'} Timeframe
  20. */
  21. /**
  22. * @export
  23. * @typedef {ReturnType<typeof getRegionClient>} StripeClient
  24. */
  25. /**
  26. * Custom error class for reportable errors that should be written to CSV output
  27. */
  28. export class ReportError extends Error {
  29. /**
  30. * @param {string} status - The error status code for CSV output
  31. * @param {string} message - The error message
  32. */
  33. constructor(status, message) {
  34. super(message)
  35. this.status = status
  36. }
  37. }
  38. /**
  39. * Gets the product ID from a Stripe Subscription Item
  40. *
  41. * @param {Stripe.SubscriptionItem | Stripe.SubscriptionSchedule.Phase.Item} item
  42. * @returns {string}
  43. */
  44. export function getProductIdFromItem(item) {
  45. const product =
  46. typeof item.price === 'string'
  47. ? null
  48. : 'product' in item.price
  49. ? item.price.product
  50. : null
  51. return typeof product === 'string' ? product : (product?.id ?? '')
  52. }
  53. /**
  54. * Gets the price ID from a Stripe Subscription Item
  55. *
  56. * @param {Stripe.SubscriptionItem | Stripe.SubscriptionSchedule.Phase.Item} item
  57. * @returns {string}
  58. */
  59. export function getPriceIdFromItem(item) {
  60. return typeof item.price === 'string' ? item.price : (item.price?.id ?? '')
  61. }
  62. /**
  63. * Gets the product ID from a Stripe Price object
  64. *
  65. * @param {Stripe.Price} price
  66. * @returns {string}
  67. */
  68. export function getProductIdFromPrice(price) {
  69. return typeof price.product === 'string'
  70. ? price.product
  71. : (price.product?.id ?? '')
  72. }
  73. /**
  74. * Sleep function to respect Stripe rate limits (100 requests per second)
  75. */
  76. export async function rateLimitSleep() {
  77. return new Promise(resolve => setTimeout(resolve, 50))
  78. }
  79. /**
  80. * Convert amount to minor units (cents for most currencies)
  81. * Some currencies like JPY, KRW, CLP, VND don't have cents
  82. *
  83. * Copied from services/web/frontend/js/shared/utils/currency.ts
  84. *
  85. * @param {number} amount - Amount in major units (dollars, euros, etc.)
  86. * @param {string} currency - Currency code (lowercase)
  87. * @returns {number} Amount in minor units
  88. */
  89. export function convertToMinorUnits(amount, currency) {
  90. const isNoCentsCurrency = ['clp', 'jpy', 'krw', 'vnd'].includes(
  91. currency.toLowerCase()
  92. )
  93. // Determine the multiplier based on currency
  94. let multiplier = 100 // default for most currencies (2 decimal places)
  95. if (isNoCentsCurrency) {
  96. multiplier = 1 // no decimal places
  97. }
  98. // Convert and round to an integer
  99. return Math.round(amount * multiplier)
  100. }
  101. /**
  102. * Convert amount from minor units (cents for most currencies)
  103. * Some currencies like JPY, KRW, CLP, VND don't have cents
  104. *
  105. * Copied from services/web/modules/subscriptions/app/src/StripeClient.mjs
  106. *
  107. * @param {number} amount - price in the smallest currency unit (e.g. dollar cents, CLP units, ...)
  108. * @param {StripeCurrencyCode} currency - currency code
  109. * @return {number}
  110. */
  111. export function convertFromMinorUnits(amount, currency) {
  112. const isNoCentsCurrency = ['clp', 'jpy', 'krw', 'vnd'].includes(
  113. currency.toLowerCase()
  114. )
  115. return isNoCentsCurrency ? amount : amount / 100
  116. }