-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add entitlement table and sso stripe feature #8608
Conversation
packages/twenty-server/src/engine/core-modules/billing/billing.controller.ts
Show resolved
Hide resolved
event.data, | ||
); | ||
} catch (error) { | ||
res.status(500).end(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
catch (BillingCustomerNotFoundException) { 404)
catch(error) { 500 }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for catch(error) { 500 }
just catch (BillingCustomerNotFoundException) { 404)
} catch (error) { | ||
res.status(500).end(); | ||
|
||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be useless
@@ -3,7 +3,7 @@ import { ArgsType, Field } from '@nestjs/graphql'; | |||
import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; | |||
import Stripe from 'stripe'; | |||
|
|||
import { SubscriptionInterval } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; | |||
import { SubscriptionInterval } from 'src/engine/core-modules/billing/enums/subcription-interval.enum'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefix with billing
billing-subscription-interval.enum
@@ -2,7 +2,7 @@ import { ArgsType, Field } from '@nestjs/graphql'; | |||
|
|||
import { IsNotEmpty, IsString } from 'class-validator'; | |||
|
|||
import { AvailableProduct } from 'src/engine/core-modules/billing/interfaces/available-product.interface'; | |||
import { AvailableProduct } from 'src/engine/core-modules/billing/enums/available-product.enum'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
CUSTOMER_SUBSCRIPTION_UPDATED = 'customer.subscription.updated', | ||
CUSTOMER_SUBSCRIPTION_DELETED = 'customer.subscription.deleted', | ||
SETUP_INTENT_SUCCEEDED = 'setup_intent.succeeded', | ||
CUSTOMER_ACTIVE_ENTITLEMENT = 'entitlements.active_entitlement_summary.updated', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CUSTOMER_ACTIVE_ENTITLEMENT_UDPATED
@@ -148,6 +97,23 @@ export class BillingSubscriptionService { | |||
} | |||
} | |||
|
|||
async getWorkspaceEntitlementByKey( | |||
workspaceId: string, | |||
lookupKey: FeatureStripeLookupKey, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
key: BillingEntitlementKey
value: true, | ||
}); | ||
|
||
if (!entitlement?.value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
split to be fully explicit
if (entitlement === undefined) { return false; }
return entitlement.value
@@ -0,0 +1,3 @@ | |||
export enum FeatureStripeLookupKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see comment below
SSO
packages/twenty-server/src/engine/core-modules/billing/services/billing-webhook.service.ts
Show resolved
Hide resolved
const workspaceId = billingSubscription.workspaceId; | ||
const stripeCustomerId = data.object.customer; | ||
|
||
const currentEntitlements = data.object.entitlements.data.map( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currentEntitlement ==> activeEntitlement everywhere
currentEntitlements => activeEntitlementKeys
Great work! |
Thanks @anamarn for your contribution! |
TLDR
Added Billing Entitlement table, based on stripe customer.ActiveEntitlements webhook event. In this table it has a key value pair with each key being the stripe feature lookup key and the value a boolean. We use this table in order to see if SSO or other feaures are enabled by workspace.
In order to test: twenty-server
Billing:
Auth:
Stripe Webhook:
Migration:
In order to test: twenty site
Considerations
The data from the Entitlement table is updated based on the stripe webhook responses, and we use the customerActiveEntitlemet response to update the info on the table, however this event doesnt have the metadata containing the workspaceId. Because we cannot control at wich order the webhook send events, we force a server error if the entitlements are updated before the BillingSubscription. Stripe resends the event based on a exponential backoff (for more info see https://docs.stripe.com/webhooks#retries ) because we are in test mode Stripe retries three times over a few hours. So if the BillingEntitlement is not updated it is completely normal and it will be updated when stripe resends the event.