This commit is contained in:
David Nguyen
2026-08-26 12:10:29 +10:00
parent 9dc83bdb06
commit 6db71b13d4
70 changed files with 5964 additions and 892 deletions
@@ -38,7 +38,9 @@ import { createDocumentAuthOptions, createRecipientAuthOptions } from '../../uti
import { buildTeamWhereQuery } from '../../utils/teams';
import { incrementDocumentId, incrementTemplateId } from '../envelope/increment-id';
import { assertOrganisationRatesAndLimits } from '../rate-limit/assert-organisation-rates-and-limits';
import { assertCompatibleRecipientGrouping } from '../signature-level/assert-compatible-recipient-grouping';
import { assertCompatibleRecipientRole } from '../signature-level/assert-compatible-recipient-role';
import { assignDefaultRecipientSigningOrders } from '../signature-level/assign-default-recipient-signing-orders';
import { resolveSignatureLevel } from '../signature-level/resolve-signature-level';
import { getTeamSettings } from '../team/get-team-settings';
import { assertUserNotDisabledById } from '../user/assert-user-not-disabled';
@@ -280,6 +282,32 @@ export const createEnvelope = async ({
assertCompatibleRecipientRole({ signatureLevel, role: recipient.role });
}
const parsedDefaultRecipients =
settings.defaultRecipients && !bypassDefaultRecipients
? ZDefaultRecipientsSchema.parse(settings.defaultRecipients)
: [];
const defaultRecipients: CreateEnvelopeRecipientOptions[] = parsedDefaultRecipients.map((recipient) => ({
email: recipient.email,
name: recipient.name,
role: recipient.role,
}));
// Team default recipients carry no signing order, which on a TSP envelope
// would land them all in the shared tail step — a signing group — so they
// are numbered after the payload's highest order.
const orderedDefaultRecipients = assignDefaultRecipientSigningOrders({
signatureLevel,
payloadRecipients: data.recipients ?? [],
defaultRecipients,
});
const allRecipientsToCreate = [...(data.recipients || []), ...orderedDefaultRecipients];
// The grouping assertion runs against the COMBINED set the envelope will
// actually hold, not just the payload.
assertCompatibleRecipientGrouping({ signatureLevel, recipients: allRecipientsToCreate });
const visibility = visibilityOverride || settings.documentVisibility;
const emailId = meta?.emailId;
@@ -403,21 +431,8 @@ export const createEnvelope = async ({
const firstEnvelopeItem = envelope.envelopeItems[0];
const defaultRecipients =
settings.defaultRecipients && !bypassDefaultRecipients
? ZDefaultRecipientsSchema.parse(settings.defaultRecipients)
: [];
const mappedDefaultRecipients: CreateEnvelopeRecipientOptions[] = defaultRecipients.map((recipient) => ({
email: recipient.email,
name: recipient.name,
role: recipient.role,
}));
const allRecipients = [...(data.recipients || []), ...mappedDefaultRecipients];
await Promise.all(
allRecipients.map(async (recipient) => {
allRecipientsToCreate.map(async (recipient) => {
const recipientAuthOptions = createRecipientAuthOptions({
accessAuth: recipient.accessAuth ?? [],
actionAuth: recipient.actionAuth ?? [],
@@ -5,13 +5,14 @@ import EnvelopeSchema from '@documenso/prisma/generated/zod/modelSchema/Envelope
import SignatureSchema from '@documenso/prisma/generated/zod/modelSchema/SignatureSchema';
import TeamSchema from '@documenso/prisma/generated/zod/modelSchema/TeamSchema';
import UserSchema from '@documenso/prisma/generated/zod/modelSchema/UserSchema';
import { DocumentSigningOrder, DocumentStatus, EnvelopeType, RecipientRole, SigningStatus } from '@prisma/client';
import { DocumentSigningOrder, DocumentStatus, EnvelopeType, SigningStatus } from '@prisma/client';
import { z } from 'zod';
import { AppError, AppErrorCode } from '../../errors/app-error';
import type { TDocumentAuthMethods } from '../../types/document-auth';
import { ZEnvelopeFieldSchema, ZFieldSchema } from '../../types/field';
import { ZRecipientLiteSchema } from '../../types/recipient';
import { isRecipientTurnBySigningOrder } from '../../utils/recipient-groups';
import { isRecipientExpired } from '../../utils/recipients';
import { isRecipientAuthorized } from '../document/is-recipient-authorized';
import { getTeamSettings } from '../team/get-team-settings';
@@ -260,23 +261,9 @@ export const getEnvelopeForRecipientSigning = async ({
},
});
let isRecipientsTurn = true;
const currentRecipientIndex = envelope.recipients.findIndex((r) => r.token === token);
if (envelope.documentMeta.signingOrder === DocumentSigningOrder.SEQUENTIAL && currentRecipientIndex !== -1) {
for (let i = 0; i < currentRecipientIndex; i++) {
// CC recipients have no action to take, so they can never block the flow.
if (envelope.recipients[i].role === RecipientRole.CC) {
continue;
}
if (envelope.recipients[i].signingStatus !== SigningStatus.SIGNED) {
isRecipientsTurn = false;
break;
}
}
}
const isRecipientsTurn =
envelope.documentMeta.signingOrder !== DocumentSigningOrder.SEQUENTIAL ||
isRecipientTurnBySigningOrder(envelope.recipients, recipient);
const sender = settings.includeSenderDetails
? {