mirror of
https://github.com/documenso/documenso
synced 2026-04-21 13:27:18 +00:00
fix: revert canceled individual subscriptions to free claim (#2483)
## Description Resolves an issue where individual plan customers who cancel are not correctly put down to the free plan. To resolve this, we delete the subscription on the stripe subscription delete webhook. Since the customerId is stored on the organisation they can still access their old invoices.
This commit is contained in:
parent
066e6bc847
commit
9bcb240895
1 changed files with 71 additions and 1 deletions
|
|
@ -1,19 +1,89 @@
|
|||
import { SubscriptionStatus } from '@prisma/client';
|
||||
|
||||
import { createOrganisationClaimUpsertData } from '@documenso/lib/server-only/organisation/create-organisation';
|
||||
import type { Stripe } from '@documenso/lib/server-only/stripe';
|
||||
import { INTERNAL_CLAIM_ID, internalClaims } from '@documenso/lib/types/subscription';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { extractStripeClaimId } from './on-subscription-updated';
|
||||
|
||||
export type OnSubscriptionDeletedOptions = {
|
||||
subscription: Stripe.Subscription;
|
||||
};
|
||||
|
||||
export const onSubscriptionDeleted = async ({ subscription }: OnSubscriptionDeletedOptions) => {
|
||||
await prisma.subscription.update({
|
||||
const existingSubscription = await prisma.subscription.findUnique({
|
||||
where: {
|
||||
planId: subscription.id,
|
||||
},
|
||||
include: {
|
||||
organisation: {
|
||||
include: {
|
||||
organisationClaim: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// If the subscription doesn't exist, we don't need to do anything.
|
||||
if (!existingSubscription) {
|
||||
return;
|
||||
}
|
||||
|
||||
const subscriptionClaimId = await extractClaimIdFromStripeSubscription(subscription);
|
||||
|
||||
// Individuals get their subscription deleted so they can return to the
|
||||
// free plan.
|
||||
if (subscriptionClaimId === INTERNAL_CLAIM_ID.INDIVIDUAL) {
|
||||
await prisma.$transaction(async (tx) => {
|
||||
await tx.subscription.delete({
|
||||
where: {
|
||||
id: existingSubscription.id,
|
||||
},
|
||||
});
|
||||
|
||||
await tx.organisationClaim.update({
|
||||
where: {
|
||||
id: existingSubscription.organisation.organisationClaim.id,
|
||||
},
|
||||
data: {
|
||||
originalSubscriptionClaimId: INTERNAL_CLAIM_ID.FREE,
|
||||
...createOrganisationClaimUpsertData(internalClaims[INTERNAL_CLAIM_ID.FREE]),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// For all other cases, mark the subscription as inactive since
|
||||
// they should still have a "Personal" account.
|
||||
await prisma.subscription.update({
|
||||
where: {
|
||||
id: existingSubscription.id,
|
||||
},
|
||||
data: {
|
||||
status: SubscriptionStatus.INACTIVE,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the claim ID from the Stripe subscription.
|
||||
*
|
||||
* Returns `null` if no claim ID found.
|
||||
*/
|
||||
const extractClaimIdFromStripeSubscription = async (subscription: Stripe.Subscription) => {
|
||||
const deletedItem = subscription.items.data[0];
|
||||
|
||||
if (!deletedItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return await extractStripeClaimId(deletedItem.price);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue