recurly-pricing.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { SubscriptionPricingState } from '@recurly/recurly-js'
  2. import { PriceForDisplayData } from '../../../../../types/subscription/plan'
  3. import { CurrencyCode } from '../../../../../types/subscription/currency'
  4. import {
  5. getRecurlyGroupPlanCode,
  6. getConsolidatedGroupPlanCode,
  7. } from './recurly-group-plan-code'
  8. import { debugConsole } from '@/utils/debugging'
  9. import { formatCurrency } from '@/shared/utils/currency'
  10. import { getJSON } from '../../../infrastructure/fetch-json'
  11. let groupPlanPerUserPrices: Record<string, number> | undefined
  12. function queryRecurlyPlanPrice(planCode: string, currency: CurrencyCode) {
  13. return new Promise(resolve => {
  14. recurly.Pricing.Subscription()
  15. .plan(planCode, { quantity: 1 })
  16. .currency(currency)
  17. .catch(debugConsole.error)
  18. .done(response => {
  19. if (response) {
  20. resolve(response)
  21. } else {
  22. resolve(undefined)
  23. }
  24. })
  25. })
  26. }
  27. export function formatPriceForDisplayData(
  28. price: string,
  29. taxRate: number,
  30. currencyCode: CurrencyCode,
  31. locale: string
  32. ): PriceForDisplayData {
  33. const totalPriceExTax = parseFloat(price)
  34. let taxAmount = totalPriceExTax * taxRate
  35. if (isNaN(taxAmount)) {
  36. taxAmount = 0
  37. }
  38. const totalWithTax = totalPriceExTax + taxAmount
  39. return {
  40. totalForDisplay: formatCurrency(totalWithTax, currencyCode, locale, true),
  41. totalAsNumber: totalWithTax,
  42. subtotal: formatCurrency(totalPriceExTax, currencyCode, locale),
  43. tax: formatCurrency(taxAmount, currencyCode, locale),
  44. includesTax: taxAmount !== 0,
  45. }
  46. }
  47. function getPerUserDisplayPrice(
  48. totalPrice: number,
  49. currency: CurrencyCode,
  50. size: string,
  51. locale: string
  52. ): string {
  53. return formatCurrency(totalPrice / parseInt(size), currency, locale, true)
  54. }
  55. export async function loadDisplayPriceWithTaxPromise(
  56. planCode: string,
  57. currencyCode: CurrencyCode,
  58. taxRate: number,
  59. locale: string
  60. ) {
  61. if (!recurly) return
  62. const price = (await queryRecurlyPlanPrice(
  63. planCode,
  64. currencyCode
  65. )) as SubscriptionPricingState['price']
  66. if (price)
  67. return formatPriceForDisplayData(
  68. price.next.total,
  69. taxRate,
  70. currencyCode,
  71. locale
  72. )
  73. }
  74. export async function loadGroupDisplayPriceWithTaxForRecurlyPromise(
  75. groupPlanCode: string,
  76. currencyCode: CurrencyCode,
  77. taxRate: number,
  78. size: string,
  79. usage: string,
  80. locale: string
  81. ) {
  82. if (!recurly) return
  83. const planCode = getRecurlyGroupPlanCode(groupPlanCode, size, usage)
  84. const price = await loadDisplayPriceWithTaxPromise(
  85. planCode,
  86. currencyCode,
  87. taxRate,
  88. locale
  89. )
  90. if (price) {
  91. price.perUserDisplayPrice = getPerUserDisplayPrice(
  92. price.totalAsNumber,
  93. currencyCode,
  94. size,
  95. locale
  96. )
  97. }
  98. return price
  99. }
  100. export async function loadGroupDisplayPriceWithTaxForStripePromise(
  101. groupPlanCode: string,
  102. currencyCode: CurrencyCode,
  103. taxRate: number,
  104. size: string,
  105. usage: string,
  106. locale: string
  107. ) {
  108. if (!groupPlanPerUserPrices) {
  109. groupPlanPerUserPrices = await getJSON<Record<string, number>>(
  110. `/user/subscription/group/group-plan-per-user-prices?currency=${currencyCode}`
  111. )
  112. }
  113. const planCode = getConsolidatedGroupPlanCode(groupPlanCode, usage)
  114. if (!(planCode in groupPlanPerUserPrices)) {
  115. throw new Error(
  116. `Group plan code ${planCode} not found in groupPlanPerUserPrices`
  117. )
  118. }
  119. const subtotalPrice = groupPlanPerUserPrices[planCode] * parseInt(size)
  120. const result = formatPriceForDisplayData(
  121. subtotalPrice.toString(),
  122. taxRate,
  123. currencyCode,
  124. locale
  125. )
  126. result.perUserDisplayPrice = formatCurrency(
  127. groupPlanPerUserPrices[planCode],
  128. currencyCode,
  129. locale,
  130. true
  131. )
  132. return result
  133. }