Files
Verso/services/web/app/src/Features/Subscription/SubscriptionHelper.js
T
Kristina 4eee7cd6ef [web] rm annual-prices-monthly-rates split test (#26727)
* [web] rm annual-prices-monthly-rates split test

- rm monthly rates treatment
- rm unused translations
- rm unused supporting functions
- rm unused styles

GitOrigin-RevId: 5901853245cd9b01ee9e4774154d29ae8f5fcae5
2025-07-03 08:06:13 +00:00

153 lines
4.3 KiB
JavaScript

const { formatCurrency } = require('../../util/currency')
const GroupPlansData = require('./GroupPlansData')
const { isStandaloneAiAddOnPlanCode } = require('./PaymentProviderEntities')
/**
* If the user changes to a less expensive plan, we shouldn't apply the change immediately.
* This is to avoid unintended/artifical credits on users Recurly accounts.
*/
function shouldPlanChangeAtTermEnd(oldPlan, newPlan, isInTrial) {
if (isInTrial) {
// we should always upgrade or downgrade immediately if actively in trial
return false
}
if (
oldPlan.annual === newPlan.annual &&
isStandaloneAiAddOnPlanCode(oldPlan.planCode) &&
!isStandaloneAiAddOnPlanCode(newPlan.planCode)
) {
// changing from an standalone AI add-on plan to a non-AI plan should not be considered a downgrade
return false
}
return oldPlan.price_in_cents > newPlan.price_in_cents
}
/**
* @import { CurrencyCode } from '../../../../types/subscription/currency'
*/
/**
* @typedef {Object} PlanToPrice
* @property {string} collaborator
* @property {string} professional
*/
/**
* @typedef {Object} LocalizedGroupPrice
* @property {PlanToPrice} price
* @property {PlanToPrice} pricePerUser
*/
/**
* @param {CurrencyCode} recommendedCurrency
* @param {string} locale
* @returns {LocalizedGroupPrice}
*/
function generateInitialLocalizedGroupPrice(recommendedCurrency, locale) {
const INITIAL_LICENSE_SIZE = 2
// the price is in cents, so divide by 100 to get the value
const collaboratorPrice =
GroupPlansData.enterprise.collaborator[recommendedCurrency][
INITIAL_LICENSE_SIZE
].price_in_cents / 100
const collaboratorPricePerUser = collaboratorPrice / INITIAL_LICENSE_SIZE
const professionalPrice =
GroupPlansData.enterprise.professional[recommendedCurrency][
INITIAL_LICENSE_SIZE
].price_in_cents / 100
const professionalPricePerUser = professionalPrice / INITIAL_LICENSE_SIZE
/**
* @param {number} price
* @returns {string}
*/
const formatPrice = price =>
formatCurrency(price, recommendedCurrency, locale, true)
return {
price: {
collaborator: formatPrice(collaboratorPrice),
professional: formatPrice(professionalPrice),
},
pricePerUser: {
collaborator: formatPrice(collaboratorPricePerUser),
professional: formatPrice(professionalPricePerUser),
},
}
}
function isPaidSubscription(subscription) {
const hasRecurlySubscription =
subscription?.recurlySubscription_id &&
subscription?.recurlySubscription_id !== ''
const hasStripeSubscription =
subscription?.paymentProvider?.subscriptionId &&
subscription?.paymentProvider?.subscriptionId !== ''
return !!(subscription && (hasRecurlySubscription || hasStripeSubscription))
}
function isIndividualActivePaidSubscription(subscription) {
return (
isPaidSubscription(subscription) &&
subscription?.groupPlan === false &&
subscription?.recurlyStatus?.state !== 'canceled' &&
subscription?.paymentProvider?.state !== 'canceled'
)
}
function getPaymentProviderSubscriptionId(subscription) {
if (subscription?.recurlySubscription_id) {
return subscription.recurlySubscription_id
}
if (subscription?.paymentProvider?.subscriptionId) {
return subscription.paymentProvider.subscriptionId
}
return null
}
function getPaidSubscriptionState(subscription) {
if (subscription?.recurlyStatus?.state) {
return subscription.recurlyStatus.state
}
if (subscription?.paymentProvider?.state) {
return subscription.paymentProvider.state
}
return null
}
function getSubscriptionTrialStartedAt(subscription) {
if (subscription?.recurlyStatus?.trialStartedAt) {
return subscription.recurlyStatus?.trialStartedAt
}
return subscription?.paymentProvider?.trialStartedAt
}
function getSubscriptionTrialEndsAt(subscription) {
if (subscription?.recurlyStatus?.trialEndsAt) {
return subscription.recurlyStatus?.trialEndsAt
}
return subscription?.paymentProvider?.trialEndsAt
}
function isInTrial(trialEndsAt) {
if (!trialEndsAt) {
return false
}
return trialEndsAt.getTime() > Date.now()
}
module.exports = {
shouldPlanChangeAtTermEnd,
generateInitialLocalizedGroupPrice,
isPaidSubscription,
isIndividualActivePaidSubscription,
getPaymentProviderSubscriptionId,
getPaidSubscriptionState,
getSubscriptionTrialStartedAt,
getSubscriptionTrialEndsAt,
isInTrial,
}