Merge pull request #23366 from overleaf/ii-flexible-licensing-add-seats-for-all-legacy-plans

[web] Add seats feature for smaller groups

GitOrigin-RevId: 7b0d1ea61eaaf603610d5fd8df399c00d328be70
This commit is contained in:
ilkin-overleaf
2025-02-04 12:59:38 +02:00
committed by Copybot
parent 098d91f0bb
commit 667b97664c
7 changed files with 641 additions and 260 deletions

View File

@@ -42,7 +42,7 @@ for (const [usage, planData] of Object.entries(groups)) {
// Generate plans in settings
for (const size of sizes) {
let plan = {
const plan = {
planCode: `group_${planCode}_${size}_${usage}`,
name: `${
Settings.appName
@@ -55,18 +55,12 @@ for (const [usage, planData] of Object.entries(groups)) {
features: Settings.features[planCode],
groupPlan: true,
membersLimit: parseInt(size),
// Unlock flexible licensing for all plans
// Add the `membersLimitAddOn` to all group plans
membersLimitAddOn: 'additional-license',
// Unlock flexible licensing for all group plans
canUseFlexibleLicensing: true,
}
// Add the `membersLimitAddOn` only to group plans of 5 or greater size
if (size >= 5) {
plan = {
...plan,
membersLimitAddOn: 'additional-license',
}
}
Settings.plans.push(plan)
}
}

View File

@@ -128,7 +128,6 @@ async function addSeatsToGroupSubscription(req, res) {
req
)
await SubscriptionGroupHandler.promises.ensureFlexibleLicensingEnabled(plan)
await SubscriptionGroupHandler.promises.ensureAddSeatsEnabled(plan)
res.render('subscriptions/add-seats', {
subscriptionId: subscription._id,

View File

@@ -63,12 +63,6 @@ async function ensureFlexibleLicensingEnabled(plan) {
}
}
async function ensureAddSeatsEnabled(plan) {
if (!plan?.membersLimitAddOn) {
throw new Error('The group plan does not support adding seats')
}
}
async function getUsersGroupSubscriptionDetails(req) {
const userId = SessionManager.getLoggedInUserId(req.session)
const subscription =
@@ -96,7 +90,6 @@ async function _addSeatsSubscriptionChange(req) {
const { recurlySubscription, plan } =
await getUsersGroupSubscriptionDetails(req)
await ensureFlexibleLicensingEnabled(plan)
await ensureAddSeatsEnabled(plan)
const userId = SessionManager.getLoggedInUserId(req.session)
const currentAddonQuantity =
recurlySubscription.addOns.find(
@@ -121,7 +114,7 @@ async function _addSeatsSubscriptionChange(req) {
if (isLegacyPriceApplicable) {
const pattern =
/^group_(collaborator|professional)_(5|10|20|50)_(educational|enterprise)$/
/^group_(collaborator|professional)_(2|3|4|5|10|20|50)_(educational|enterprise)$/
const [, planCode, size, usage] = plan.planCode.match(pattern)
const currency = recurlySubscription.currency
const legacyPriceInCents =
@@ -255,7 +248,6 @@ module.exports = {
removeUserFromGroup: callbackify(removeUserFromGroup),
replaceUserReferencesInGroups: callbackify(replaceUserReferencesInGroups),
ensureFlexibleLicensingEnabled: callbackify(ensureFlexibleLicensingEnabled),
ensureAddSeatsEnabled: callbackify(ensureAddSeatsEnabled),
getTotalConfirmedUsersInGroup: callbackify(getTotalConfirmedUsersInGroup),
isUserPartOfGroup: callbackify(isUserPartOfGroup),
getGroupPlanUpgradePreview: callbackify(getGroupPlanUpgradePreview),
@@ -264,7 +256,6 @@ module.exports = {
removeUserFromGroup,
replaceUserReferencesInGroups,
ensureFlexibleLicensingEnabled,
ensureAddSeatsEnabled,
getTotalConfirmedUsersInGroup,
isUserPartOfGroup,
getUsersGroupSubscriptionDetails,

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,63 @@
{
"educational": {
"professional": {
"2": {
"AUD": 321,
"BRL": 699,
"CAD": 314,
"CHF": 279,
"CLP": 168693,
"COP": 552930,
"DKK": 1665,
"EUR": 258,
"GBP": 223,
"INR": 6719,
"MXN": 4129,
"NOK": 2008,
"NZD": 321,
"PEN": 671,
"SEK": 2008,
"SGD": 363,
"USD": 279
},
"3": {
"AUD": 321,
"BRL": 699,
"CAD": 314,
"CHF": 279,
"CLP": 168693,
"COP": 552930,
"DKK": 1665,
"EUR": 258,
"GBP": 223,
"INR": 6719,
"MXN": 4129,
"NOK": 2008,
"NZD": 321,
"PEN": 671,
"SEK": 2008,
"SGD": 363,
"USD": 279
},
"4": {
"AUD": 321,
"BRL": 699,
"CAD": 314,
"CHF": 279,
"CLP": 168693,
"COP": 552930,
"DKK": 1665,
"EUR": 258,
"GBP": 223,
"INR": 6719,
"MXN": 4129,
"NOK": 2008,
"NZD": 321,
"PEN": 671,
"SEK": 2008,
"SGD": 363,
"USD": 279
},
"5": {
"AUD": 321,
"BRL": 699,
@@ -79,6 +136,63 @@
}
},
"collaborator": {
"2": {
"AUD": 167,
"BRL": 349,
"CAD": 160,
"CHF": 139,
"CLP": 77693,
"COP": 272930,
"DKK": 839,
"EUR": 125,
"GBP": 111,
"INR": 3219,
"MXN": 2029,
"NOK": 1014,
"NZD": 167,
"PEN": 321,
"SEK": 1014,
"SGD": 181,
"USD": 139
},
"3": {
"AUD": 167,
"BRL": 349,
"CAD": 160,
"CHF": 139,
"CLP": 77693,
"COP": 272930,
"DKK": 839,
"EUR": 125,
"GBP": 111,
"INR": 3219,
"MXN": 2029,
"NOK": 1014,
"NZD": 167,
"PEN": 321,
"SEK": 1014,
"SGD": 181,
"USD": 139
},
"4": {
"AUD": 167,
"BRL": 349,
"CAD": 160,
"CHF": 139,
"CLP": 77693,
"COP": 272930,
"DKK": 839,
"EUR": 125,
"GBP": 111,
"INR": 3219,
"MXN": 2029,
"NOK": 1014,
"NZD": 167,
"PEN": 321,
"SEK": 1014,
"SGD": 181,
"USD": 139
},
"5": {
"AUD": 167,
"BRL": 349,
@@ -159,6 +273,63 @@
},
"enterprise": {
"professional": {
"2": {
"AUD": 321,
"BRL": 699,
"CAD": 314,
"CHF": 499,
"CLP": 168693,
"COP": 552930,
"DKK": 1665,
"EUR": 258,
"GBP": 223,
"INR": 6719,
"MXN": 4129,
"NOK": 2008,
"NZD": 321,
"PEN": 671,
"SEK": 2008,
"SGD": 363,
"USD": 279
},
"3": {
"AUD": 321,
"BRL": 699,
"CAD": 314,
"CHF": 499,
"CLP": 168693,
"COP": 552930,
"DKK": 1665,
"EUR": 258,
"GBP": 223,
"INR": 6719,
"MXN": 4129,
"NOK": 2008,
"NZD": 321,
"PEN": 671,
"SEK": 2008,
"SGD": 363,
"USD": 279
},
"4": {
"AUD": 321,
"BRL": 699,
"CAD": 314,
"CHF": 499,
"CLP": 168693,
"COP": 552930,
"DKK": 1665,
"EUR": 258,
"GBP": 223,
"INR": 6719,
"MXN": 4129,
"NOK": 2008,
"NZD": 321,
"PEN": 671,
"SEK": 2008,
"SGD": 363,
"USD": 279
},
"5": {
"AUD": 321,
"BRL": 699,
@@ -237,6 +408,63 @@
}
},
"collaborator": {
"2": {
"AUD": 167,
"BRL": 349,
"CAD": 160,
"CHF": 139,
"CLP": 77693,
"COP": 272930,
"DKK": 839,
"EUR": 125,
"GBP": 111,
"INR": 3219,
"MXN": 2029,
"NOK": 1014,
"NZD": 167,
"PEN": 321,
"SEK": 1014,
"SGD": 181,
"USD": 139
},
"3": {
"AUD": 167,
"BRL": 349,
"CAD": 160,
"CHF": 139,
"CLP": 77693,
"COP": 272930,
"DKK": 839,
"EUR": 125,
"GBP": 111,
"INR": 3219,
"MXN": 2029,
"NOK": 1014,
"NZD": 167,
"PEN": 321,
"SEK": 1014,
"SGD": 181,
"USD": 139
},
"4": {
"AUD": 167,
"BRL": 349,
"CAD": 160,
"CHF": 139,
"CLP": 77693,
"COP": 272930,
"DKK": 839,
"EUR": 125,
"GBP": 111,
"INR": 3219,
"MXN": 2029,
"NOK": 1014,
"NZD": 167,
"PEN": 321,
"SEK": 1014,
"SGD": 181,
"USD": 139
},
"5": {
"AUD": 167,
"BRL": 349,

View File

@@ -56,7 +56,6 @@ describe('SubscriptionGroupController', function () {
.stub()
.resolves(this.createSubscriptionChangeData),
ensureFlexibleLicensingEnabled: sinon.stub().resolves(),
ensureAddSeatsEnabled: sinon.stub().resolves(),
getGroupPlanUpgradePreview: sinon
.stub()
.resolves(this.previewSubscriptionChangeData),
@@ -337,9 +336,6 @@ describe('SubscriptionGroupController', function () {
this.SubscriptionGroupHandler.promises.ensureFlexibleLicensingEnabled
.calledWith(this.plan)
.should.equal(true)
this.SubscriptionGroupHandler.promises.ensureAddSeatsEnabled
.calledWith(this.plan)
.should.equal(true)
page.should.equal('subscriptions/add-seats')
props.subscriptionId.should.equal(this.subscriptionId)
props.groupName.should.equal(this.subscription.teamName)
@@ -379,21 +375,6 @@ describe('SubscriptionGroupController', function () {
this.Controller.addSeatsToGroupSubscription(this.req, res)
})
it('should redirect to subscription page when "add seats" is not enabled', function (done) {
this.SubscriptionGroupHandler.promises.ensureAddSeatsEnabled = sinon
.stub()
.rejects()
const res = {
redirect: url => {
url.should.equal('/user/subscription')
done()
},
}
this.Controller.addSeatsToGroupSubscription(this.req, res)
})
})
describe('previewAddSeatsSubscriptionChange', function () {

View File

@@ -506,22 +506,6 @@ describe('SubscriptionGroupHandler', function () {
})
})
describe('ensureAddSeatsEnabled', function () {
it('should throw if the subscription can not use the "add seats" feature', async function () {
await expect(
this.Handler.promises.ensureAddSeatsEnabled({})
).to.be.rejectedWith('The group plan does not support adding seats')
})
it('should not throw if the subscription can use the "add seats" feature', async function () {
await expect(
this.Handler.promises.ensureAddSeatsEnabled({
membersLimitAddOn: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
})
).to.not.be.rejected
})
})
describe('upgradeGroupPlan', function () {
it('should upgrade the subscription for flexible licensing group plans', async function () {
this.SubscriptionLocator.promises.getUsersSubscription = sinon