mirror of
https://github.com/documenso/documenso.git
synced 2026-06-22 04:12:06 +10:00
3887aa67c8
Replace per-event webhook handlers with a single sync function that fetches the current state from Stripe and converges the local subscription, claim, and organisation type. - Create organisations upfront before checkout, restricted as "pending payment" until the first payment syncs - Add rate-limited subscription sync route, triggered on checkout success so the UI doesn't wait on webhooks - Surface pending payment state in banner, billing table, and limits
59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
import type { Subscription } from '@documenso/prisma/generated/zod/modelSchema/SubscriptionSchema';
|
|
import { OrganisationType } from '@prisma/client';
|
|
|
|
import { IS_BILLING_ENABLED } from '../constants/app';
|
|
import { AppError, AppErrorCode } from '../errors/app-error';
|
|
import { INTERNAL_CLAIM_ID } from '../types/subscription';
|
|
|
|
/**
|
|
* Throws an error if billing is enabled and no subscription is found.
|
|
*/
|
|
export const validateIfSubscriptionIsRequired = (subscription?: Subscription | null) => {
|
|
const isBillingEnabled = IS_BILLING_ENABLED();
|
|
|
|
if (!isBillingEnabled) {
|
|
return;
|
|
}
|
|
|
|
if (isBillingEnabled && !subscription) {
|
|
throw new AppError(AppErrorCode.NOT_FOUND, {
|
|
message: 'Subscription not found',
|
|
});
|
|
}
|
|
|
|
return subscription;
|
|
};
|
|
|
|
type PendingPaymentOrganisation = {
|
|
type: OrganisationType;
|
|
subscription?: unknown;
|
|
organisationClaim: {
|
|
originalSubscriptionClaimId: string | null;
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Whether the organisation was created ahead of a paid checkout and is still awaiting
|
|
* its first successful payment.
|
|
*
|
|
* Such organisations have no subscription row and still carry the copied "free" claim,
|
|
* and must be treated as restricted until the Stripe webhook sync activates them.
|
|
*
|
|
* Always returns false when billing is disabled (self-hosted).
|
|
*/
|
|
export const isOrganisationPendingPayment = (organisation: PendingPaymentOrganisation) => {
|
|
if (!IS_BILLING_ENABLED()) {
|
|
return false;
|
|
}
|
|
|
|
if (organisation.type !== OrganisationType.ORGANISATION) {
|
|
return false;
|
|
}
|
|
|
|
if (organisation.subscription) {
|
|
return false;
|
|
}
|
|
|
|
return organisation.organisationClaim.originalSubscriptionClaimId === INTERNAL_CLAIM_ID.FREE;
|
|
};
|