fix(leads): keep a future follow-up as an activity on the lead

A scheduled follow-up only stored a date, and activities opened from a lead were not linked back, so they disappeared from the lead.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-03 16:19:32 +03:30
co-authored by Cursor
parent c26353624e
commit c337b0b4c7
6 changed files with 89 additions and 20 deletions
+42 -7
View File
@@ -810,14 +810,14 @@ export class LeadsService {
? `تماس ثبت شد — ${dto.outcome}`
: 'تماس ثبت شد';
await this.addEvent(actor, id, 'call', title, dto.body ?? null);
const followAt = this.parseFollowUpAt(dto.nextFollowUpAt);
if (followAt) {
await this.createLeadFollowUpActivity(actor, before, followAt, dto.body);
}
const data: Prisma.LeadUpdateInput = {
lastContactAt: new Date(),
...(dto.nextFollowUpAt !== undefined
? {
nextFollowUpAt: dto.nextFollowUpAt
? new Date(dto.nextFollowUpAt)
: null,
}
? { nextFollowUpAt: followAt }
: {}),
};
if (dto.stageId) data.stage = { connect: { id: dto.stageId } };
@@ -856,8 +856,10 @@ export class LeadsService {
nextFollowUpAt: string,
body?: string,
): Promise<LeadDto> {
await this.findAccessible(actor, id);
const at = new Date(nextFollowUpAt);
const lead = await this.findAccessible(actor, id);
const at = this.parseFollowUpAt(nextFollowUpAt);
if (!at) throw new BadRequestException('زمان پیگیری نامعتبر است');
await this.createLeadFollowUpActivity(actor, lead, at, body);
await this.addEvent(
actor,
id,
@@ -878,6 +880,39 @@ export class LeadsService {
return this.toDto(row);
}
/** پیگیری آینده باید خودش یک فعالیت باز و متصل به لید باشد، نه فقط یک تاریخ. */
private parseFollowUpAt(value?: string | null): Date | null {
if (!value) return null;
const at = new Date(value);
if (Number.isNaN(at.getTime())) {
throw new BadRequestException('زمان پیگیری نامعتبر است');
}
return at;
}
private async createLeadFollowUpActivity(
actor: Actor,
lead: { id: string; title: string; assigneeId: string | null },
dueAt: Date,
body?: string | null,
) {
const allowOthers = await actorCanAssignToOthers(this.prisma, actor, 'activities');
const assigneeId = allowOthers && lead.assigneeId ? lead.assigneeId : actor.userId;
await this.prisma.activity.create({
data: {
organizationId: actor.organizationId,
type: 'task',
title: `پیگیری: ${lead.title}`.slice(0, 200),
description: body?.trim() || null,
dueAt,
leadId: lead.id,
assigneeId,
assignees: { connect: [{ id: assigneeId }] },
createdById: actor.userId,
},
});
}
async archive(actor: Actor, ids: string[]): Promise<number> {
if (!elevated(actor.role) && ids.length > 1) {
throw new BadRequestException('حذف گروهی فقط برای مدیر');