mirror of
https://github.com/documenso/documenso.git
synced 2026-07-14 06:47:10 +10:00
04f6e76178
Stop sending automated reminders after a configurable threshold (default 5) and reset the count on manual resend.
110 lines
3.4 KiB
TypeScript
110 lines
3.4 KiB
TypeScript
import { prisma } from '@documenso/prisma';
|
|
import { DocumentDistributionMethod, RecipientRole, SendStatus, SigningStatus } from '@prisma/client';
|
|
|
|
import { resolveNextReminderAt, ZEnvelopeReminderSettings } from '../../constants/envelope-reminder';
|
|
|
|
/**
|
|
* Compute and store `nextReminderAt` for a single recipient.
|
|
*
|
|
* Pass `resetReminderCount: true` to restart the reminder cycle (e.g. on a
|
|
* manual resend): the count is zeroed and the schedule recomputed as if the
|
|
* request was freshly sent at `sentAt`.
|
|
*/
|
|
export const updateRecipientNextReminder = async (options: {
|
|
recipientId: number;
|
|
envelopeId: string;
|
|
sentAt: Date;
|
|
lastReminderSentAt: Date | null;
|
|
reminderCount?: number;
|
|
resetReminderCount?: boolean;
|
|
reminderSettings?: ReturnType<typeof ZEnvelopeReminderSettings.parse> | null;
|
|
}) => {
|
|
const { recipientId, envelopeId, sentAt, lastReminderSentAt, reminderCount = 0, resetReminderCount } = options;
|
|
|
|
let settings = options.reminderSettings;
|
|
|
|
if (settings === undefined) {
|
|
const envelope = await prisma.envelope.findFirst({
|
|
where: { id: envelopeId },
|
|
select: { documentMeta: { select: { reminderSettings: true } } },
|
|
});
|
|
|
|
settings = envelope?.documentMeta?.reminderSettings
|
|
? ZEnvelopeReminderSettings.parse(envelope.documentMeta.reminderSettings)
|
|
: null;
|
|
}
|
|
|
|
const nextReminderAt = resolveNextReminderAt({
|
|
config: settings,
|
|
sentAt,
|
|
lastReminderSentAt,
|
|
reminderCount: resetReminderCount ? 0 : reminderCount,
|
|
});
|
|
|
|
await prisma.recipient.update({
|
|
where: { id: recipientId },
|
|
data: {
|
|
nextReminderAt,
|
|
...(resetReminderCount ? { reminderCount: 0 } : {}),
|
|
},
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Recompute `nextReminderAt` for all active (unsigned, sent) recipients
|
|
* of a given envelope. Call when document-level reminder settings change.
|
|
*/
|
|
export const recomputeNextReminderForEnvelope = async (envelopeId: string) => {
|
|
const envelope = await prisma.envelope.findFirst({
|
|
where: { id: envelopeId },
|
|
select: {
|
|
documentMeta: {
|
|
select: { reminderSettings: true, distributionMethod: true },
|
|
},
|
|
},
|
|
});
|
|
|
|
// No reminders for manually distributed documents.
|
|
const isEmailDistribution = envelope?.documentMeta?.distributionMethod !== DocumentDistributionMethod.NONE;
|
|
|
|
const settings =
|
|
isEmailDistribution && envelope?.documentMeta?.reminderSettings
|
|
? ZEnvelopeReminderSettings.parse(envelope.documentMeta.reminderSettings)
|
|
: null;
|
|
|
|
const now = new Date();
|
|
|
|
const recipients = await prisma.recipient.findMany({
|
|
where: {
|
|
envelopeId,
|
|
signingStatus: SigningStatus.NOT_SIGNED,
|
|
sendStatus: SendStatus.SENT,
|
|
sentAt: { not: null },
|
|
role: { not: RecipientRole.CC },
|
|
// Don't reschedule reminders for recipients whose deadline has passed.
|
|
OR: [{ expiresAt: null }, { expiresAt: { gt: now } }],
|
|
},
|
|
select: { id: true, sentAt: true, lastReminderSentAt: true, reminderCount: true },
|
|
});
|
|
|
|
await Promise.all(
|
|
recipients.map(async (recipient) => {
|
|
if (!recipient.sentAt) {
|
|
return;
|
|
}
|
|
|
|
const nextReminderAt = resolveNextReminderAt({
|
|
config: settings,
|
|
sentAt: recipient.sentAt,
|
|
lastReminderSentAt: recipient.lastReminderSentAt,
|
|
reminderCount: recipient.reminderCount,
|
|
});
|
|
|
|
await prisma.recipient.update({
|
|
where: { id: recipient.id },
|
|
data: { nextReminderAt },
|
|
});
|
|
}),
|
|
);
|
|
};
|