mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-11 23:20:47 +02:00
[web] display all Stripe accounts on admin panel (#29625)
* refactor PaymentService.getPaymentProviderAdminUrl to be more useful * display all stripe customer accounts * mv change segment modal to each account * stripeSubscriptionData -> stripeCustomerData GitOrigin-RevId: 4c1a277f5073ee7cb12f4596210ba4f8624451b8
This commit is contained in:
@@ -653,6 +653,7 @@ export class PaymentProviderAccount {
|
||||
* @param {boolean} [props.hasPastDueInvoice]
|
||||
* @param {object} [props.metadata]
|
||||
* @param {string} [props.metadata.userId]
|
||||
* @param {string} [props.metadata.segment]
|
||||
*/
|
||||
constructor(props) {
|
||||
this.code = props.code
|
||||
|
||||
@@ -799,24 +799,6 @@ async function terminateSubscriptionByUuid(subscriptionUuid) {
|
||||
return subscription
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Recurly admin dashboard url for a user
|
||||
*
|
||||
* @param {string} userId
|
||||
* @returns {string}
|
||||
*/
|
||||
function getCustomerAdminUrlFromUserId(userId) {
|
||||
const isStagOrDev =
|
||||
Settings.siteUrl.includes('dev-overleaf') ||
|
||||
Settings.siteUrl.includes('stag-overleaf')
|
||||
|
||||
if (isStagOrDev) {
|
||||
return `https://sharelatex-sandbox.recurly.com/accounts/${userId}`
|
||||
}
|
||||
|
||||
return `https://sharelatex.recurly.com/accounts/${userId}`
|
||||
}
|
||||
|
||||
export default {
|
||||
errors: recurly.errors,
|
||||
|
||||
@@ -841,7 +823,6 @@ export default {
|
||||
getPastDueInvoices: callbackify(getPastDueInvoices),
|
||||
failInvoice: callbackify(failInvoice),
|
||||
terminateSubscriptionByUuid: callbackify(terminateSubscriptionByUuid),
|
||||
getCustomerAdminUrlFromUserId,
|
||||
|
||||
promises: {
|
||||
getSubscription,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// @ts-check
|
||||
|
||||
const Settings = require('@overleaf/settings')
|
||||
const { formatCurrency } = require('../../util/currency')
|
||||
const GroupPlansData = require('./GroupPlansData')
|
||||
const { isStandaloneAiAddOnPlanCode } = require('./AiHelper')
|
||||
@@ -196,11 +199,67 @@ function isInTrial(trialEndsAt) {
|
||||
return trialEndsAt.getTime() > Date.now()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Recurly customer admin URL
|
||||
* @param {string | null} customerId - The customer ID in Recurly
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function getRecurlyCustomerAdminUrl(customerId) {
|
||||
if (customerId == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isStagOrDev =
|
||||
Settings.siteUrl.includes('dev-overleaf') ||
|
||||
Settings.siteUrl.includes('stag-overleaf')
|
||||
|
||||
const baseUrl = isStagOrDev
|
||||
? 'https://sharelatex-sandbox.recurly.com'
|
||||
: 'https://sharelatex.recurly.com'
|
||||
|
||||
return `${baseUrl}/accounts/${customerId}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Stripe customer admin URL
|
||||
* @param {string | null} customerId - The customer ID in Stripe
|
||||
* @param {string} service - The Stripe service ('stripe-us' or 'stripe-uk')
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function getStripeCustomerAdminUrl(customerId, service) {
|
||||
if (customerId == null || service == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
let accountId = null
|
||||
if (service === 'stripe-us') {
|
||||
accountId = Settings.apis.stripeUS?.accountId
|
||||
} else if (service === 'stripe-uk') {
|
||||
accountId = Settings.apis.stripeUK?.accountId
|
||||
}
|
||||
|
||||
if (accountId == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isStagOrDev =
|
||||
Settings.siteUrl.includes('dev-overleaf') ||
|
||||
Settings.siteUrl.includes('stag-overleaf')
|
||||
|
||||
const baseUrl = isStagOrDev
|
||||
? `https://dashboard.stripe.com/${accountId}/test`
|
||||
: `https://dashboard.stripe.com/${accountId}`
|
||||
|
||||
return `${baseUrl}/customers/${customerId}`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
shouldPlanChangeAtTermEnd,
|
||||
generateInitialLocalizedGroupPrice,
|
||||
isPaidSubscription,
|
||||
isIndividualActivePaidSubscription,
|
||||
getRecurlyCustomerAdminUrl,
|
||||
getStripeCustomerAdminUrl,
|
||||
getPaymentProviderSubscriptionId,
|
||||
getPaidSubscriptionState,
|
||||
getSubscriptionTrialStartedAt,
|
||||
|
||||
@@ -275,15 +275,17 @@ export interface Meta {
|
||||
annual?: string
|
||||
monthlyTimesTwelve?: string
|
||||
}
|
||||
'ol-stripeAccountId': string
|
||||
'ol-stripePublicKeyUK': string
|
||||
'ol-stripePublicKeyUS': string
|
||||
'ol-stripeSubscriptionData': {
|
||||
'ol-stripeCustomerData': Array<{
|
||||
customerId: string
|
||||
subscriptionId: string
|
||||
subscriptionState: string | null
|
||||
paymentProviderService: StripePaymentProviderService | null
|
||||
segment: string | null
|
||||
}
|
||||
managementUrl: string
|
||||
segment?: string | null
|
||||
error?: string
|
||||
}>
|
||||
'ol-stripePublicKeyUK': string
|
||||
'ol-stripePublicKeyUS': string
|
||||
'ol-subscription': any // TODO: mixed types, split into two fields
|
||||
'ol-subscriptionChangePreview': SubscriptionChangePreview
|
||||
'ol-subscriptionCreationPreview': SubscriptionCreationPreview
|
||||
|
||||
@@ -789,31 +789,4 @@ describe('RecurlyClient', function () {
|
||||
expect(invoices).to.deep.equal(pastDueInvoices)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getCustomerAdminUrlFromUserId', function () {
|
||||
it('should return staging URL for dev-overleaf sites', async function (ctx) {
|
||||
ctx.settings.siteUrl = 'https://dev-overleaf.example.com'
|
||||
const userId = 'user-123'
|
||||
const url = await ctx.RecurlyClient.getCustomerAdminUrlFromUserId(userId)
|
||||
expect(url).to.equal(
|
||||
'https://sharelatex-sandbox.recurly.com/accounts/user-123'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return staging URL for stag-overleaf sites', async function (ctx) {
|
||||
ctx.settings.siteUrl = 'https://stag-overleaf.example.com'
|
||||
const userId = 'user-456'
|
||||
const url = await ctx.RecurlyClient.getCustomerAdminUrlFromUserId(userId)
|
||||
expect(url).to.equal(
|
||||
'https://sharelatex-sandbox.recurly.com/accounts/user-456'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return production URL for production sites', async function (ctx) {
|
||||
ctx.settings.siteUrl = 'https://www.overleaf.com'
|
||||
const userId = 'user-789'
|
||||
const url = await ctx.RecurlyClient.getCustomerAdminUrlFromUserId(userId)
|
||||
expect(url).to.equal('https://sharelatex.recurly.com/accounts/user-789')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -692,4 +692,204 @@ describe('SubscriptionHelper', function () {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getRecurlyCustomerAdminUrl', function () {
|
||||
beforeEach(function () {
|
||||
this.settings.siteUrl = 'https://www.overleaf.com'
|
||||
})
|
||||
|
||||
it('should return production Recurly account URL', function () {
|
||||
const result =
|
||||
this.SubscriptionHelper.getRecurlyCustomerAdminUrl('user_789')
|
||||
expect(result).to.equal(
|
||||
'https://sharelatex.recurly.com/accounts/user_789'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return sandbox Recurly account URL for dev environment', function () {
|
||||
this.settings.siteUrl = 'https://dev-overleaf.com'
|
||||
const result =
|
||||
this.SubscriptionHelper.getRecurlyCustomerAdminUrl('user_789')
|
||||
expect(result).to.equal(
|
||||
'https://sharelatex-sandbox.recurly.com/accounts/user_789'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return sandbox Recurly account URL for staging environment', function () {
|
||||
this.settings.siteUrl = 'https://stag-overleaf.com'
|
||||
const result =
|
||||
this.SubscriptionHelper.getRecurlyCustomerAdminUrl('user_789')
|
||||
expect(result).to.equal(
|
||||
'https://sharelatex-sandbox.recurly.com/accounts/user_789'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return null if customerId is null', function () {
|
||||
const result = this.SubscriptionHelper.getRecurlyCustomerAdminUrl(null)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if customerId is undefined', function () {
|
||||
const result =
|
||||
this.SubscriptionHelper.getRecurlyCustomerAdminUrl(undefined)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should handle empty string customerId', function () {
|
||||
const result = this.SubscriptionHelper.getRecurlyCustomerAdminUrl('')
|
||||
expect(result).to.equal('https://sharelatex.recurly.com/accounts/')
|
||||
})
|
||||
})
|
||||
|
||||
describe('getStripeCustomerAdminUrl', function () {
|
||||
beforeEach(function () {
|
||||
this.settings.siteUrl = 'https://www.overleaf.com'
|
||||
this.settings.apis = {
|
||||
stripeUS: { accountId: 'acct_us_123' },
|
||||
stripeUK: { accountId: 'acct_uk_456' },
|
||||
}
|
||||
})
|
||||
|
||||
describe('stripe-us', function () {
|
||||
it('should return production Stripe US customer URL', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.equal(
|
||||
'https://dashboard.stripe.com/acct_us_123/customers/cus_us_789'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return test Stripe US customer URL for dev environment', function () {
|
||||
this.settings.siteUrl = 'https://dev-overleaf.com'
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.equal(
|
||||
'https://dashboard.stripe.com/acct_us_123/test/customers/cus_us_789'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return test Stripe US customer URL for staging environment', function () {
|
||||
this.settings.siteUrl = 'https://stag-overleaf.com'
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.equal(
|
||||
'https://dashboard.stripe.com/acct_us_123/test/customers/cus_us_789'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('stripe-uk', function () {
|
||||
it('should return production Stripe UK customer URL', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_uk_123',
|
||||
'stripe-uk'
|
||||
)
|
||||
expect(result).to.equal(
|
||||
'https://dashboard.stripe.com/acct_uk_456/customers/cus_uk_123'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return test Stripe UK customer URL for dev environment', function () {
|
||||
this.settings.siteUrl = 'https://dev-overleaf.com'
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_uk_123',
|
||||
'stripe-uk'
|
||||
)
|
||||
expect(result).to.equal(
|
||||
'https://dashboard.stripe.com/acct_uk_456/test/customers/cus_uk_123'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('should return null if accountId is missing', function () {
|
||||
this.settings.apis.stripeUS = {}
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if customerId is null', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
null,
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if service is null', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
null
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if customerId is undefined', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
undefined,
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if service is undefined', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
undefined
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if both customerId and service are null', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
null,
|
||||
null
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if accountId is missing for UK', function () {
|
||||
this.settings.apis.stripeUK = {}
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_uk_789',
|
||||
'stripe-uk'
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should return null if apis object is missing', function () {
|
||||
this.settings.apis = {}
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
|
||||
it('should handle empty string customerId', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'',
|
||||
'stripe-us'
|
||||
)
|
||||
expect(result).to.equal(
|
||||
'https://dashboard.stripe.com/acct_us_123/customers/'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return null if service is not stripe-us or stripe-uk', function () {
|
||||
const result = this.SubscriptionHelper.getStripeCustomerAdminUrl(
|
||||
'cus_us_789',
|
||||
'some-other-service'
|
||||
)
|
||||
expect(result).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user