2023-07-31 19:00:52 +03:00
// @ts-ignore
2021-09-09 13:48:23 +03:00
const { VersionMismatchError } = require ( '@tryghost/errors' ) ;
2023-07-31 19:00:52 +03:00
// @ts-ignore
2022-11-17 16:33:46 +03:00
const debug = require ( '@tryghost/debug' ) ( 'stripe' ) ;
2021-09-09 13:48:23 +03:00
const Stripe = require ( 'stripe' ) . Stripe ;
2023-07-31 19:00:52 +03:00
// @ts-ignore
2021-09-09 13:48:23 +03:00
const LeakyBucket = require ( 'leaky-bucket' ) ;
2023-07-18 12:41:42 +03:00
/ * S t r i p e h a s t h e f o l l o w i n g r a t e l i m i t s :
* - For most APIs , 100 read requests per second in live mode , 25 read requests per second in test mode
* - For search , 20 requests per second in both live and test modes
* /
2021-09-09 13:48:23 +03:00
const EXPECTED _API _EFFICIENCY = 0.95 ;
2023-07-18 12:41:42 +03:00
const EXPECTED _SEARCH _API _EFFICIENCY = 0.15 ;
2021-09-09 13:48:23 +03:00
const STRIPE _API _VERSION = '2020-08-27' ;
/ * *
* @ typedef { import ( 'stripe' ) . Stripe . Customer } ICustomer
* @ typedef { import ( 'stripe' ) . Stripe . DeletedCustomer } IDeletedCustomer
* @ typedef { import ( 'stripe' ) . Stripe . Product } IProduct
* @ typedef { import ( 'stripe' ) . Stripe . Plan } IPlan
* @ typedef { import ( 'stripe' ) . Stripe . Price } IPrice
* @ typedef { import ( 'stripe' ) . Stripe . WebhookEndpoint } IWebhookEndpoint
* /
/ * *
2022-01-11 19:47:59 +03:00
* @ typedef { object } IStripeAPIConfig
2021-09-09 13:48:23 +03:00
* @ prop { string } secretKey
* @ prop { string } publicKey
* @ prop { boolean } enablePromoCodes
2023-02-28 10:09:52 +03:00
* @ prop { boolean } enableAutomaticTax
2022-02-09 16:00:39 +03:00
* @ prop { string } checkoutSessionSuccessUrl
* @ prop { string } checkoutSessionCancelUrl
* @ prop { string } checkoutSetupSessionSuccessUrl
* @ prop { string } checkoutSetupSessionCancelUrl
2022-04-04 08:31:53 +03:00
* @ prop { boolean } param . testEnv - indicates if the module is run in test environment ( note , NOT the test mode )
2021-09-09 13:48:23 +03:00
* /
2022-01-11 19:47:59 +03:00
module . exports = class StripeAPI {
2021-09-09 13:48:23 +03:00
/ * *
2022-01-11 19:47:59 +03:00
* StripeAPI
2021-09-09 13:48:23 +03:00
* /
2024-04-04 17:17:14 +03:00
constructor ( deps ) {
2021-09-09 13:48:23 +03:00
/** @type {Stripe} */
this . _stripe = null ;
this . _configured = false ;
2024-04-04 17:17:14 +03:00
this . labs = deps . labs ;
2021-09-09 13:48:23 +03:00
}
2024-04-04 17:05:01 +03:00
get PAYMENT _METHOD _TYPES ( ) {
2024-04-04 17:17:14 +03:00
if ( this . labs . isSet ( 'additionalPaymentMethods' ) ) {
return undefined ;
} else {
return [ 'card' ] ;
}
2024-04-04 17:05:01 +03:00
}
2021-09-09 13:48:23 +03:00
get configured ( ) {
return this . _configured ;
}
2022-04-04 08:31:53 +03:00
get testEnv ( ) {
return this . _config . testEnv ;
}
2021-09-09 13:48:23 +03:00
get mode ( ) {
return this . _testMode ? 'test' : 'live' ;
}
/ * *
2022-01-11 19:47:59 +03:00
* @ param { IStripeAPIConfig } config
2021-09-09 13:48:23 +03:00
* @ returns { void }
* /
configure ( config ) {
2022-01-13 17:48:51 +03:00
if ( ! config ) {
this . _stripe = null ;
this . _configured = false ;
return ;
}
2021-09-09 13:48:23 +03:00
this . _stripe = new Stripe ( config . secretKey , {
apiVersion : STRIPE _API _VERSION
} ) ;
this . _config = config ;
this . _testMode = config . secretKey && config . secretKey . startsWith ( 'sk_test_' ) ;
if ( this . _testMode ) {
this . _rateLimitBucket = new LeakyBucket ( EXPECTED _API _EFFICIENCY * 25 , 1 ) ;
} else {
this . _rateLimitBucket = new LeakyBucket ( EXPECTED _API _EFFICIENCY * 100 , 1 ) ;
}
2023-07-18 12:41:42 +03:00
this . _searchRateLimitBucket = new LeakyBucket ( EXPECTED _SEARCH _API _EFFICIENCY * 100 , 1 ) ;
2021-09-09 13:48:23 +03:00
this . _configured = true ;
}
2021-09-28 14:35:23 +03:00
/ * *
* @ param { object } options
* /
async createCoupon ( options ) {
await this . _rateLimitBucket . throttle ( ) ;
const coupon = await this . _stripe . coupons . create ( options ) ;
return coupon ;
}
2022-03-09 17:41:59 +03:00
/ * *
* @ param { string } id
*
* @ returns { Promise < IProduct > }
* /
async getProduct ( id ) {
await this . _rateLimitBucket . throttle ( ) ;
const product = await this . _stripe . products . retrieve ( id ) ;
return product ;
}
2021-09-09 13:48:23 +03:00
/ * *
* @ param { object } options
* @ param { string } options . name
*
* @ returns { Promise < IProduct > }
* /
async createProduct ( options ) {
await this . _rateLimitBucket . throttle ( ) ;
const product = await this . _stripe . products . create ( options ) ;
return product ;
}
/ * *
* @ param { object } options
* @ param { string } options . product
* @ param { boolean } options . active
* @ param { string } options . nickname
* @ param { string } options . currency
2023-07-31 19:00:52 +03:00
* @ param { number } [ options . amount ]
* @ param { { enabled : boolean ; maximum ? : number ; minimum ? : number ; preset ? : number ; } } [ options . custom _unit _amount ]
2021-09-09 13:48:23 +03:00
* @ param { 'recurring' | 'one-time' } options . type
2023-07-31 19:00:52 +03:00
* @ param { Stripe . Price . Recurring . Interval | null } [ options . interval ]
2021-09-09 13:48:23 +03:00
*
* @ returns { Promise < IPrice > }
* /
async createPrice ( options ) {
await this . _rateLimitBucket . throttle ( ) ;
const price = await this . _stripe . prices . create ( {
currency : options . currency ,
product : options . product ,
unit _amount : options . amount ,
active : options . active ,
nickname : options . nickname ,
2023-07-31 19:00:52 +03:00
// @ts-ignore
custom _unit _amount : options . custom _unit _amount , // missing in .d.ts definitions in the Stripe node version we use, but should be supported in Stripe API at this version (:
recurring : options . type === 'recurring' && options . interval ? {
2021-09-09 13:48:23 +03:00
interval : options . interval
} : undefined
} ) ;
return price ;
}
/ * *
* @ param { string } id
* @ param { object } options
2023-07-31 19:00:52 +03:00
* @ param { boolean } [ options . active ]
2022-10-16 10:43:35 +03:00
* @ param { string } [ options . nickname ]
2021-09-09 13:48:23 +03:00
*
* @ returns { Promise < IPrice > }
* /
async updatePrice ( id , options ) {
await this . _rateLimitBucket . throttle ( ) ;
const price = await this . _stripe . prices . update ( id , {
active : options . active ,
nickname : options . nickname
} ) ;
return price ;
}
/ * *
* @ param { string } id
* @ param { object } options
* @ param { string } options . name
*
* @ returns { Promise < IProduct > }
* /
async updateProduct ( id , options ) {
await this . _rateLimitBucket . throttle ( ) ;
const product = await this . _stripe . products . update ( id , {
name : options . name
} ) ;
return product ;
}
/ * *
* @ param { string } id
* @ param { import ( 'stripe' ) . Stripe . CustomerRetrieveParams } options
*
* @ returns { Promise < ICustomer | IDeletedCustomer > }
* /
async getCustomer ( id , options = { } ) {
debug ( ` getCustomer( ${ id } , ${ JSON . stringify ( options ) } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
if ( options . expand ) {
options . expand . push ( 'subscriptions' ) ;
} else {
options . expand = [ 'subscriptions' ] ;
}
const customer = await this . _stripe . customers . retrieve ( id , options ) ;
debug ( ` getCustomer( ${ id } , ${ JSON . stringify ( options ) } ) -> Success ` ) ;
return customer ;
} catch ( err ) {
debug ( ` getCustomer( ${ id } , ${ JSON . stringify ( options ) } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* @ deprecated
* @ param { any } member
*
* @ returns { Promise < ICustomer > }
* /
async getCustomerForMemberCheckoutSession ( member ) {
await member . related ( 'stripeCustomers' ) . fetch ( ) ;
const customers = member . related ( 'stripeCustomers' ) ;
for ( const data of customers . models ) {
try {
const customer = await this . getCustomer ( data . get ( 'customer_id' ) ) ;
if ( ! customer . deleted ) {
return /** @type {ICustomer} */ ( customer ) ;
}
} catch ( err ) {
debug ( ` Ignoring Error getting customer for member ${ err . message } ` ) ;
}
}
debug ( ` Creating customer for member ${ member . get ( 'email' ) } ` ) ;
const customer = await this . createCustomer ( {
email : member . get ( 'email' )
} ) ;
return customer ;
}
2023-07-13 14:20:54 +03:00
/ * *
* Finds a Stripe Customer ID based on the provided email address . Returns null if no customer is found .
* @ param { string } email
* @ see https : //stripe.com/docs/api/customers/search
*
* @ returns { Promise < string | null > } Stripe Customer ID , if found
* /
async getCustomerIdByEmail ( email ) {
2023-07-18 12:41:42 +03:00
await this . _searchRateLimitBucket . throttle ( ) ;
2023-07-13 14:20:54 +03:00
try {
const result = await this . _stripe . customers . search ( {
query : ` email:" ${ email } " ` ,
limit : 10 ,
expand : [ 'data.subscriptions' ]
} ) ;
const customers = result . data ;
// No customer found, return null
if ( customers . length === 0 ) {
return ;
}
// Return the only customer found
if ( customers . length === 1 ) {
return customers [ 0 ] . id ;
}
// Multiple customers found, return the one with the most recent subscription
if ( customers . length > 1 ) {
let latestCustomer = customers [ 0 ] ;
let latestSubscriptionTime = 0 ;
for ( let customer of customers ) {
// skip customers with no subscriptions
if ( ! customer . subscriptions || ! customer . subscriptions . data || customer . subscriptions . data . length === 0 ) {
continue ;
}
// find the customer with the most recent subscription
for ( let subscription of customer . subscriptions . data ) {
2023-07-18 12:41:42 +03:00
if ( subscription . current _period _end && subscription . current _period _end > latestSubscriptionTime ) {
latestSubscriptionTime = subscription . current _period _end ;
2023-07-13 14:20:54 +03:00
latestCustomer = customer ;
}
}
}
return latestCustomer . id ;
}
} catch ( err ) {
debug ( ` getCustomerByEmail( ${ email } ) -> ${ err . type } : ${ err . message } ` ) ;
}
}
2021-09-09 13:48:23 +03:00
/ * *
* @ param { import ( 'stripe' ) . Stripe . CustomerCreateParams } options
*
* @ returns { Promise < ICustomer > }
* /
async createCustomer ( options = { } ) {
debug ( ` createCustomer( ${ JSON . stringify ( options ) } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
const customer = await this . _stripe . customers . create ( options ) ;
debug ( ` createCustomer( ${ JSON . stringify ( options ) } ) -> Success ` ) ;
return customer ;
} catch ( err ) {
debug ( ` createCustomer( ${ JSON . stringify ( options ) } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* @ param { string } id
* @ param { string } email
*
* @ returns { Promise < ICustomer > }
* /
async updateCustomerEmail ( id , email ) {
debug ( ` updateCustomerEmail( ${ id } , ${ email } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
const customer = await this . _stripe . customers . update ( id , { email } ) ;
debug ( ` updateCustomerEmail( ${ id } , ${ email } ) -> Success ` ) ;
return customer ;
} catch ( err ) {
debug ( ` updateCustomerEmail( ${ id } , ${ email } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* createWebhook .
*
* @ param { string } url
* @ param { import ( 'stripe' ) . Stripe . WebhookEndpointUpdateParams . EnabledEvent [ ] } events
*
* @ returns { Promise < IWebhookEndpoint > }
* /
async createWebhookEndpoint ( url , events ) {
debug ( ` createWebhook( ${ url } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
const webhook = await this . _stripe . webhookEndpoints . create ( {
url ,
enabled _events : events ,
api _version : STRIPE _API _VERSION
} ) ;
debug ( ` createWebhook( ${ url } ) -> Success ` ) ;
return webhook ;
} catch ( err ) {
debug ( ` createWebhook( ${ url } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* @ param { string } id
*
* @ returns { Promise < void > }
* /
async deleteWebhookEndpoint ( id ) {
debug ( ` deleteWebhook( ${ id } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
await this . _stripe . webhookEndpoints . del ( id ) ;
debug ( ` deleteWebhook( ${ id } ) -> Success ` ) ;
return ;
} catch ( err ) {
debug ( ` deleteWebhook( ${ id } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* @ param { string } id
* @ param { string } url
* @ param { import ( 'stripe' ) . Stripe . WebhookEndpointUpdateParams . EnabledEvent [ ] } events
*
* @ returns { Promise < IWebhookEndpoint > }
* /
async updateWebhookEndpoint ( id , url , events ) {
debug ( ` updateWebhook( ${ id } , ${ url } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
const webhook = await this . _stripe . webhookEndpoints . update ( id , {
url ,
enabled _events : events
} ) ;
if ( webhook . api _version !== STRIPE _API _VERSION ) {
2022-02-15 15:27:22 +03:00
throw new VersionMismatchError ( { message : 'Webhook has incorrect api_version' } ) ;
2021-09-09 13:48:23 +03:00
}
debug ( ` updateWebhook( ${ id } , ${ url } ) -> Success ` ) ;
return webhook ;
} catch ( err ) {
debug ( ` updateWebhook( ${ id } , ${ url } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* parseWebhook .
*
* @ param { string } body
* @ param { string } signature
* @ param { string } secret
*
* @ returns { import ( 'stripe' ) . Stripe . Event }
* /
parseWebhook ( body , signature , secret ) {
debug ( ` parseWebhook( ${ body } , ${ signature } , ${ secret } ) ` ) ;
try {
const event = this . _stripe . webhooks . constructEvent ( body , signature , secret ) ;
debug ( ` parseWebhook( ${ body } , ${ signature } , ${ secret } ) -> Success ${ event . type } ` ) ;
return event ;
} catch ( err ) {
debug ( ` parseWebhook( ${ body } , ${ signature } , ${ secret } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* @ param { string } priceId
* @ param { ICustomer } customer
*
* @ param { object } options
* @ param { Object . < String , any > } options . metadata
* @ param { string } options . successUrl
* @ param { string } options . cancelUrl
* @ param { string } options . customerEmail
2022-08-05 12:58:01 +03:00
* @ param { number } options . trialDays
2021-10-21 19:06:36 +03:00
* @ param { string } [ options . coupon ]
2021-09-09 13:48:23 +03:00
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Checkout . Session > }
* /
async createCheckoutSession ( priceId , customer , options ) {
const metadata = options . metadata || undefined ;
2023-01-06 07:44:56 +03:00
const customerId = customer ? customer . id : undefined ;
2021-09-09 13:48:23 +03:00
const customerEmail = customer ? customer . email : options . customerEmail ;
2023-07-18 12:41:42 +03:00
2021-09-09 13:48:23 +03:00
await this . _rateLimitBucket . throttle ( ) ;
2021-09-28 14:35:23 +03:00
let discounts ;
if ( options . coupon ) {
2021-10-21 19:06:36 +03:00
discounts = [ { coupon : options . coupon } ] ;
2021-09-28 14:35:23 +03:00
}
2022-08-05 12:58:01 +03:00
const subscriptionData = {
trial _from _plan : true ,
items : [ {
plan : priceId
} ]
} ;
/ * *
* ` trial_from_plan ` is deprecated .
* Replaces it in favor of custom trial period days stored in Ghost
* /
2022-08-09 06:37:16 +03:00
if ( typeof options . trialDays === 'number' && options . trialDays > 0 ) {
2022-08-05 12:58:01 +03:00
delete subscriptionData . trial _from _plan ;
subscriptionData . trial _period _days = options . trialDays ;
}
2023-01-06 07:44:56 +03:00
let stripeSessionOptions = {
2024-04-04 17:05:01 +03:00
payment _method _types : this . PAYMENT _METHOD _TYPES ,
2022-02-09 16:00:39 +03:00
success _url : options . successUrl || this . _config . checkoutSessionSuccessUrl ,
cancel _url : options . cancelUrl || this . _config . checkoutSessionCancelUrl ,
2021-09-09 13:48:23 +03:00
// @ts-ignore - we need to update to latest stripe library to correctly use newer features
2021-09-28 14:35:23 +03:00
allow _promotion _codes : discounts ? undefined : this . _config . enablePromoCodes ,
2023-02-28 10:09:52 +03:00
automatic _tax : {
enabled : this . _config . enableAutomaticTax
} ,
2021-09-09 13:48:23 +03:00
metadata ,
2021-09-28 14:35:23 +03:00
discounts ,
2021-09-09 13:48:23 +03:00
/ *
line _items : [ {
price : priceId
} ]
* /
// This is deprecated and using the old way of doing things with Plans.
// It should be replaced with the line_items entry above when possible,
// however, this would lose the "trial from plan" feature which has also
// been deprecated by Stripe
2022-08-05 12:58:01 +03:00
subscription _data : subscriptionData
2023-01-06 07:44:56 +03:00
} ;
/ * W e a r e o n l y a l l o w e d t o s p e c i f y o n e o f t h e s e ; e m a i l w i l l b e p u l l e d f r o m
customer object on Stripe side if that object already exists . * /
if ( customerId ) {
stripeSessionOptions . customer = customerId ;
} else {
stripeSessionOptions . customer _email = customerEmail ;
}
2024-05-16 03:47:23 +03:00
if ( customerId && this . _config . enableAutomaticTax ) {
stripeSessionOptions . customer _update = { address : 'auto' } ;
}
2023-07-31 19:00:52 +03:00
// @ts-ignore
2023-01-06 07:44:56 +03:00
const session = await this . _stripe . checkout . sessions . create ( stripeSessionOptions ) ;
2021-09-09 13:48:23 +03:00
return session ;
}
2023-07-31 19:00:52 +03:00
/ * *
* @ param { object } options
* @ param { Object . < String , any > } options . metadata
* @ param { string } options . successUrl
* @ param { string } options . cancelUrl
* @ param { string } [ options . customer ]
* @ param { string } [ options . customerEmail ]
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Checkout . Session > }
* /
async createDonationCheckoutSession ( { priceId , successUrl , cancelUrl , metadata , customer , customerEmail } ) {
await this . _rateLimitBucket . throttle ( ) ;
/ * *
* @ type { Stripe . Checkout . SessionCreateParams }
* /
const stripeSessionOptions = {
mode : 'payment' ,
success _url : successUrl || this . _config . checkoutSessionSuccessUrl ,
cancel _url : cancelUrl || this . _config . checkoutSessionCancelUrl ,
automatic _tax : {
enabled : this . _config . enableAutomaticTax
} ,
metadata ,
customer : customer ? customer . id : undefined ,
2023-08-03 23:45:57 +03:00
customer _email : ! customer && customerEmail ? customerEmail : undefined ,
2023-08-09 11:17:54 +03:00
submit _type : 'pay' ,
2023-07-31 19:00:52 +03:00
invoice _creation : {
enabled : true ,
invoice _data : {
// Make sure we pass the data through to the invoice
metadata : {
ghost _donation : true ,
... metadata
}
}
} ,
line _items : [ {
price : priceId ,
quantity : 1
} ]
} ;
2024-05-16 03:47:23 +03:00
if ( customer && this . _config . enableAutomaticTax ) {
stripeSessionOptions . customer _update = { address : 'auto' } ;
}
2023-07-31 19:00:52 +03:00
// @ts-ignore
const session = await this . _stripe . checkout . sessions . create ( stripeSessionOptions ) ;
return session ;
}
2021-09-09 13:48:23 +03:00
/ * *
* @ param { ICustomer } customer
* @ param { object } options
2024-05-08 21:56:17 +03:00
* @ param { string } options . successUrl
* @ param { string } options . cancelUrl
* @ param { string } options . currency - 3 - letter ISO code in lowercase , e . g . ` usd `
2021-09-09 13:48:23 +03:00
* @ returns { Promise < import ( 'stripe' ) . Stripe . Checkout . Session > }
* /
async createCheckoutSetupSession ( customer , options ) {
await this . _rateLimitBucket . throttle ( ) ;
const session = await this . _stripe . checkout . sessions . create ( {
mode : 'setup' ,
2024-04-04 17:05:01 +03:00
payment _method _types : this . PAYMENT _METHOD _TYPES ,
2022-02-09 16:00:39 +03:00
success _url : options . successUrl || this . _config . checkoutSetupSessionSuccessUrl ,
cancel _url : options . cancelUrl || this . _config . checkoutSetupSessionCancelUrl ,
2021-09-09 13:48:23 +03:00
customer _email : customer . email ,
setup _intent _data : {
metadata : {
customer _id : customer . id
}
2024-05-08 21:56:17 +03:00
} ,
// Note: this is required for dynamic payment methods
// https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-currency
currency : this . labs . isSet ( 'additionalPaymentMethods' ) ? options . currency : undefined
2021-09-09 13:48:23 +03:00
} ) ;
return session ;
}
getPublicKey ( ) {
return this . _config . publicKey ;
}
/ * *
* getPrice
*
* @ param { string } id
* @ param { object } options
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Price > }
* /
async getPrice ( id , options = { } ) {
debug ( ` getPrice( ${ id } , ${ JSON . stringify ( options ) } ) ` ) ;
return await this . _stripe . prices . retrieve ( id , options ) ;
}
/ * *
* getSubscription .
*
* @ param { string } id
* @ param { import ( 'stripe' ) . Stripe . SubscriptionRetrieveParams } options
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async getSubscription ( id , options = { } ) {
debug ( ` getSubscription( ${ id } , ${ JSON . stringify ( options ) } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
const subscription = await this . _stripe . subscriptions . retrieve ( id , options ) ;
debug ( ` getSubscription( ${ id } , ${ JSON . stringify ( options ) } ) -> Success ` ) ;
return subscription ;
} catch ( err ) {
debug ( ` getSubscription( ${ id } , ${ JSON . stringify ( options ) } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* cancelSubscription .
*
* @ param { string } id
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async cancelSubscription ( id ) {
debug ( ` cancelSubscription( ${ id } ) ` ) ;
try {
await this . _rateLimitBucket . throttle ( ) ;
const subscription = await this . _stripe . subscriptions . del ( id ) ;
debug ( ` cancelSubscription( ${ id } ) -> Success ` ) ;
return subscription ;
} catch ( err ) {
debug ( ` cancelSubscription( ${ id } ) -> ${ err . type } ` ) ;
throw err ;
}
}
/ * *
* @ param { string } id - The ID of the Subscription to modify
* @ param { string } [ reason = '' ] - The user defined cancellation reason
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async cancelSubscriptionAtPeriodEnd ( id , reason = '' ) {
await this . _rateLimitBucket . throttle ( ) ;
const subscription = await this . _stripe . subscriptions . update ( id , {
cancel _at _period _end : true ,
metadata : {
cancellation _reason : reason
}
} ) ;
return subscription ;
}
/ * *
* @ param { string } id - The ID of the Subscription to modify
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async continueSubscriptionAtPeriodEnd ( id ) {
await this . _rateLimitBucket . throttle ( ) ;
const subscription = await this . _stripe . subscriptions . update ( id , {
cancel _at _period _end : false ,
metadata : {
cancellation _reason : null
}
} ) ;
return subscription ;
}
2021-11-09 12:12:13 +03:00
/ * *
* @ param { string } id - The ID of the subscription to remove coupon from
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async removeCouponFromSubscription ( id ) {
await this . _rateLimitBucket . throttle ( ) ;
const subscription = await this . _stripe . subscriptions . update ( id , {
coupon : ''
} ) ;
return subscription ;
}
2021-09-09 13:48:23 +03:00
/ * *
* @ param { string } subscriptionId - The ID of the Subscription to modify
* @ param { string } id - The ID of the SubscriptionItem
* @ param { string } price - The ID of the new Price
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async updateSubscriptionItemPrice ( subscriptionId , id , price ) {
await this . _rateLimitBucket . throttle ( ) ;
const subscription = await this . _stripe . subscriptions . update ( subscriptionId , {
2021-10-01 13:27:09 +03:00
proration _behavior : 'always_invoice' ,
2021-09-09 13:48:23 +03:00
items : [ {
id ,
price
} ] ,
cancel _at _period _end : false ,
metadata : {
cancellation _reason : null
}
} ) ;
return subscription ;
}
/ * *
* @ param { string } customer - The ID of the Customer to create the subscription for
* @ param { string } price - The ID of the new Price
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async createSubscription ( customer , price ) {
await this . _rateLimitBucket . throttle ( ) ;
const subscription = await this . _stripe . subscriptions . create ( {
customer ,
items : [ { price } ]
} ) ;
return subscription ;
}
/ * *
* @ param { string } id
* @ param { import ( 'stripe' ) . Stripe . SetupIntentRetrieveParams } options
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . SetupIntent > }
* /
async getSetupIntent ( id , options = { } ) {
await this . _rateLimitBucket . throttle ( ) ;
return await this . _stripe . setupIntents . retrieve ( id , options ) ;
}
/ * *
* @ param { string } customer
* @ param { string } paymentMethod
*
* @ returns { Promise < void > }
* /
async attachPaymentMethodToCustomer ( customer , paymentMethod ) {
await this . _rateLimitBucket . throttle ( ) ;
await this . _stripe . paymentMethods . attach ( paymentMethod , { customer } ) ;
return ;
}
/ * *
* @ param { string } id
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . PaymentMethod | null > }
* /
async getCardPaymentMethod ( id ) {
await this . _rateLimitBucket . throttle ( ) ;
const paymentMethod = await this . _stripe . paymentMethods . retrieve ( id ) ;
if ( paymentMethod . type !== 'card' ) {
return null ;
}
return paymentMethod ;
}
/ * *
* @ param { string } subscription
* @ param { string } paymentMethod
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async updateSubscriptionDefaultPaymentMethod ( subscription , paymentMethod ) {
await this . _rateLimitBucket . throttle ( ) ;
return await this . _stripe . subscriptions . update ( subscription , {
default _payment _method : paymentMethod
} ) ;
}
2023-10-20 10:52:08 +03:00
/ * *
* @ param { string } id - The ID of the subscription to cancel the trial for
*
* @ returns { Promise < import ( 'stripe' ) . Stripe . Subscription > }
* /
async cancelSubscriptionTrial ( id ) {
await this . _rateLimitBucket . throttle ( ) ;
return this . _stripe . subscriptions . update ( id , {
trial _end : 'now'
} ) ;
}
2021-09-09 13:48:23 +03:00
} ;