fix(sms): send form confirmations to the lead number

Lead-only website forms had no person mobile, so the confirmation was marked sent without a number. Use the lead phone and send the full text.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-31 16:41:41 +03:30
co-authored by Cursor
parent 8d01bce0c2
commit 590f8114cc
5 changed files with 91 additions and 19 deletions
@@ -21,6 +21,7 @@ import {
buildSendAts,
cancelTriggersFor,
clipSms,
customerPhone,
} from './message-automation.util';
export type MessageAutomationContext = {
@@ -354,13 +355,15 @@ export class MessageAutomationsService {
},
})
: null;
const lead = await this.lookupLead(job);
const personName = person
? [person.firstName, person.lastName].filter(Boolean).join(' ').trim()
: '';
const phone = customerPhone(person, lead);
const vars = {
title: job.entityTitle,
name: personName || job.entityTitle,
phone: person?.mobile || person?.phone || '',
name: personName || lead?.contactName?.trim() || lead?.title || job.entityTitle,
phone,
date: formatJalaliDayFa(new Date()),
company: person?.company?.name ?? '',
};
@@ -405,26 +408,59 @@ export class MessageAutomationsService {
}
if (targetPerson && wantSms) {
await this.sendSms(person?.mobile || person?.phone, smsText, {
if (!phone) {
throw new Error('شماره مشتری یا سرنخ برای پیامک پیدا نشد');
}
const sent = await this.sendSms(phone, smsText, {
organizationId: job.organizationId,
personId: job.personId,
leadId: lead?.id ?? null,
ruleId: job.ruleId || job.rule.id || '',
});
if (!sent) {
throw new Error('ارسال پیامک به مشتری یا سرنخ ناموفق بود');
}
}
}
/** سرنخ همان پرونده، یا سرنخی که به این شخص تبدیل شده. */
private async lookupLead(job: {
organizationId: string;
entityId: string;
personId: string | null;
}) {
return this.prisma.lead.findFirst({
where: {
organizationId: job.organizationId,
OR: [
{ id: job.entityId },
...(job.personId ? [{ convertedPersonId: job.personId }] : []),
],
},
select: {
id: true,
mobile: true,
phone: true,
contactName: true,
title: true,
},
orderBy: { createdAt: 'desc' },
});
}
private async sendSms(
mobile: string | null | undefined,
text: string,
log: {
organizationId: string;
personId?: string | null;
leadId?: string | null;
ruleId: string;
},
) {
if (!mobile) {
): Promise<boolean> {
if (!mobile?.trim()) {
this.logger.warn('Message automation SMS skipped: no mobile');
return;
return false;
}
const result = await this.sms.send({
organizationId: log.organizationId,
@@ -432,10 +468,11 @@ export class MessageAutomationsService {
text,
source: 'automation',
});
if (log.personId) {
if (log.personId || log.leadId) {
await this.outboundSms.record({
organizationId: log.organizationId,
personId: log.personId,
leadId: log.leadId,
mobile,
body: text,
source: 'automation',
@@ -448,7 +485,9 @@ export class MessageAutomationsService {
this.logger.warn(
`Message automation SMS failed: ${result.reason ?? 'unknown'}`,
);
return false;
}
return true;
}
private toData(