Skip to content

Commit 7aeb15c

Browse files
committed
Allow a team without subscription to go unmanaged
1 parent 881fbea commit 7aeb15c

3 files changed

Lines changed: 60 additions & 30 deletions

File tree

forge/ee/db/controllers/Subscription.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ module.exports = {
2828
return newSubscription
2929
}
3030
},
31+
createUnmanagedSubscription: async function (app, team) {
32+
const newSubscription = await app.db.models.Subscription.create({
33+
customer: '',
34+
subscription: '',
35+
status: app.db.models.Subscription.STATUS.UNMANAGED
36+
})
37+
await newSubscription.setTeam(team)
38+
return newSubscription
39+
},
3140
createTrialSubscription: async function (app, team, trialEndsAt) {
3241
const newSubscription = await app.db.models.Subscription.create({
3342
customer: '',

forge/ee/lib/billing/index.js

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -525,40 +525,46 @@ module.exports.init = async function (app) {
525525
enableManualBilling: async (team) => {
526526
app.log.info(`Enabling manual billing for team ${team.hashid}`)
527527
const subscription = await team.getSubscription()
528-
const existingSubscription = subscription.subscription
529-
subscription.subscription = ''
530-
subscription.status = app.db.models.Subscription.STATUS.UNMANAGED
531-
subscription.trialEndsAt = null
532-
subscription.trialStatus = app.db.models.Subscription.TRIAL_STATUS.ENDED
533-
await subscription.save()
528+
if (subscription) {
529+
const existingSubscription = subscription.subscription
530+
subscription.subscription = ''
531+
subscription.status = app.db.models.Subscription.STATUS.UNMANAGED
532+
subscription.trialEndsAt = null
533+
subscription.trialStatus = app.db.models.Subscription.TRIAL_STATUS.ENDED
534+
await subscription.save()
534535

535-
// Now we have marked the local subscription as unmanaged, we need to
536-
// check to see if there is a stripe subscription to cancel
537-
if (existingSubscription) {
538-
try {
539-
const stripeSubscription = await stripe.subscriptions.retrieve(existingSubscription)
540-
if (stripeSubscription && stripeSubscription.status !== 'canceled') {
541-
app.log.info(`Canceling existing subscription ${existingSubscription} for team ${team.hashid}`)
542-
// There is an existing subscription to cancel
543-
try {
544-
// We do not use `app.billing.closeSubscription` because
545-
// that expects a Subscription object. However, we've already
546-
// updated the local Subscription object to remove the information
547-
// needed by closeSubscription. This is to ensure when the
548-
// stripe callback arrives we don't trigger a suspension of
549-
// the team resources.
550-
await stripe.subscriptions.del(existingSubscription, {
551-
invoice_now: true,
552-
prorate: true
553-
})
554-
} catch (err) {
555-
app.log.warn(`Error canceling existing subscription ${existingSubscription} for team ${team.hashid}: ${err.toString()}`)
536+
// Now we have marked the local subscription as unmanaged, we need to
537+
// check to see if there is a stripe subscription to cancel
538+
if (existingSubscription) {
539+
try {
540+
const stripeSubscription = await stripe.subscriptions.retrieve(existingSubscription)
541+
if (stripeSubscription && stripeSubscription.status !== 'canceled') {
542+
app.log.info(`Canceling existing subscription ${existingSubscription} for team ${team.hashid}`)
543+
// There is an existing subscription to cancel
544+
try {
545+
// We do not use `app.billing.closeSubscription` because
546+
// that expects a Subscription object. However, we've already
547+
// updated the local Subscription object to remove the information
548+
// needed by closeSubscription. This is to ensure when the
549+
// stripe callback arrives we don't trigger a suspension of
550+
// the team resources.
551+
await stripe.subscriptions.del(existingSubscription, {
552+
invoice_now: true,
553+
prorate: true
554+
})
555+
} catch (err) {
556+
app.log.warn(`Error canceling existing subscription ${existingSubscription} for team ${team.hashid}: ${err.toString()}`)
557+
}
556558
}
559+
} catch (err) {
560+
// Could not find a matching stripe subscription - that's means
561+
// we have nothing cancel
557562
}
558-
} catch (err) {
559-
// Could not find a matching stripe subscription - that's means
560-
// we have nothing cancel
561563
}
564+
} else {
565+
// If the team bailed out of setting up stripe, they will not have
566+
// a subscription.
567+
await app.db.controllers.Subscription.createUnmanagedSubscription(team)
562568
}
563569
},
564570
updateTrialSettings: async (team, settings) => {

test/unit/forge/ee/lib/billing/index_spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,21 @@ describe('Billing', function () {
361361
stripe.subscriptions.del.called.should.be.true()
362362
stripe.subscriptions.del.lastCall.args[0].should.equal('sub_1234')
363363
})
364+
it('puts team without existing subscription into unmanaged mode', async function () {
365+
const team1 = await app.factory.createTeam({ name: 'UnmanagedTeam2' })
366+
await team1.addUser(app.user, { through: { role: Roles.Owner } })
367+
368+
await app.billing.enableManualBilling(team1)
369+
370+
const sub = await team1.getSubscription()
371+
// Check the updated states for an unmanaged subscription are correct
372+
sub.isActive().should.be.false()
373+
sub.isUnmanaged().should.be.true()
374+
sub.isTrial().should.be.false()
375+
sub.isTrialEnded().should.be.true()
376+
sub.subscription.should.equal('')
377+
sub.customer.should.equal('')
378+
})
364379
})
365380

366381
describe('addProject', function () {

0 commit comments

Comments
 (0)