mirror of
https://github.com/documenso/documenso.git
synced 2025-11-24 13:41:30 +10:00
feat: billing
This commit is contained in:
@ -1,7 +1,10 @@
|
||||
import { syncMemberCountWithStripeSeatPlan } from '@documenso/ee/server-only/stripe/update-subscription-item-quantity';
|
||||
import { ORGANISATION_MEMBER_ROLE_PERMISSIONS_MAP } from '@documenso/lib/constants/organisations';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { validateIfSubscriptionIsRequired } from '@documenso/lib/utils/billing';
|
||||
import { buildOrganisationWhereQuery } from '@documenso/lib/utils/organisations';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { OrganisationMemberInviteStatus } from '@documenso/prisma/client';
|
||||
|
||||
import { authenticatedProcedure } from '../trpc';
|
||||
import {
|
||||
@ -30,76 +33,73 @@ type DeleteOrganisationMembersProps = {
|
||||
organisationMemberIds: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes multiple organisation members.
|
||||
*
|
||||
* This logic is also used to leave a team (hence strange logic).
|
||||
*/
|
||||
export const deleteOrganisationMembers = async ({
|
||||
userId,
|
||||
organisationId,
|
||||
organisationMemberIds,
|
||||
}: DeleteOrganisationMembersProps) => {
|
||||
const membersToDelete = await prisma.organisationMember.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: organisationMemberIds,
|
||||
},
|
||||
const organisation = await prisma.organisation.findFirst({
|
||||
where: buildOrganisationWhereQuery(
|
||||
organisationId,
|
||||
userId,
|
||||
ORGANISATION_MEMBER_ROLE_PERMISSIONS_MAP['MANAGE_ORGANISATION'],
|
||||
),
|
||||
include: {
|
||||
subscription: true,
|
||||
organisationClaim: true,
|
||||
members: {
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
},
|
||||
},
|
||||
invites: {
|
||||
where: {
|
||||
status: OrganisationMemberInviteStatus.PENDING,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Prevent the user from deleting other users if they do not have permission.
|
||||
if (membersToDelete.some((member) => member.userId !== userId)) {
|
||||
const organisation = await prisma.organisation.findFirst({
|
||||
where: buildOrganisationWhereQuery(
|
||||
organisationId,
|
||||
userId,
|
||||
ORGANISATION_MEMBER_ROLE_PERMISSIONS_MAP['MANAGE_ORGANISATION'],
|
||||
),
|
||||
});
|
||||
|
||||
if (!organisation) {
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED);
|
||||
}
|
||||
if (!organisation) {
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// Todo: Orgs - Handle seats.
|
||||
await prisma.$transaction(
|
||||
async (tx) => {
|
||||
await tx.organisationMember.deleteMany({
|
||||
where: {
|
||||
id: {
|
||||
in: organisationMemberIds,
|
||||
},
|
||||
organisationId,
|
||||
},
|
||||
});
|
||||
const { organisationClaim } = organisation;
|
||||
|
||||
// Todo: orgs handle removing groups
|
||||
|
||||
// if (IS_BILLING_ENABLED() && team.subscription) {
|
||||
// const numberOfSeats = await tx.teamMember.count({
|
||||
// where: {
|
||||
// teamId,
|
||||
// },
|
||||
// });
|
||||
|
||||
// await updateSubscriptionItemQuantity({
|
||||
// priceId: team.subscription.priceId,
|
||||
// subscriptionId: team.subscription.planId,
|
||||
// quantity: numberOfSeats,
|
||||
// });
|
||||
// }
|
||||
|
||||
// await jobs.triggerJob({
|
||||
// name: 'send.team-member-left.email',
|
||||
// payload: {
|
||||
// teamId,
|
||||
// memberUserId: leavingUser.id,
|
||||
// },
|
||||
// });
|
||||
},
|
||||
{ timeout: 30_000 },
|
||||
const membersToDelete = organisation.members.filter((member) =>
|
||||
organisationMemberIds.includes(member.id),
|
||||
);
|
||||
|
||||
const subscription = validateIfSubscriptionIsRequired(organisation.subscription);
|
||||
|
||||
const inviteCount = organisation.invites.length;
|
||||
const newMemberCount = organisation.members.length + inviteCount - membersToDelete.length;
|
||||
|
||||
if (subscription) {
|
||||
await syncMemberCountWithStripeSeatPlan(subscription, organisationClaim, newMemberCount);
|
||||
}
|
||||
|
||||
await prisma.$transaction(async (tx) => {
|
||||
await tx.organisationMember.deleteMany({
|
||||
where: {
|
||||
id: {
|
||||
in: organisationMemberIds,
|
||||
},
|
||||
organisationId,
|
||||
},
|
||||
});
|
||||
|
||||
// Todo: orgs
|
||||
// await jobs.triggerJob({
|
||||
// name: 'send.team-member-left.email',
|
||||
// payload: {
|
||||
// teamId,
|
||||
// memberUserId: leavingUser.id,
|
||||
// },
|
||||
// });
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user