Перейти к содержимому

Заявки с сайта - хранение, дубли, передача в CRM

Делаем так, чтобы заявка с сайта не терялась при сбое почты, не задваивалась от повторного нажатия и доходила до менеджера в любом случае.

Решение

Сначала сохраняем, потом отправляем:

$id = LeadTable::add([
'NAME' => $name, 'PHONE' => $phone, 'TEXT' => $text,
'SOURCE' => 'форма на странице ' . $page, 'STATUS' => 'new',
])->getId();
\Bitrix\Main\Mail\Event::send([...]); // письмо уже после записи

Заявку записывают в базу до всякой отправки письма. Почта отваливается регулярно, и заявка, существующая только в виде письма, в этот момент исчезает бесследно.

Отсекаем дубли и спам:

$recent = LeadTable::getList(['filter' => ['=PHONE' => $phone,
'>DATE_CREATE' => (new DateTime())->add('-5 minutes')], 'limit' => 1])->fetch();
if ($recent) { return ['status' => 'ok']; } // молча считаем повтором
if ($request->getPost('company') !== '') { return ['status' => 'ok']; } // поле-ловушка

Повторная отправка формы не должна множить заявки. Скрытое поле-ловушка отсекает простых роботов, а проверка недавней заявки с тем же телефоном - двойное нажатие кнопки нетерпеливым посетителем.

Передаём заявку дальше через очередь:

LeadQueueTable::add(['LEAD_ID' => $id, 'STATUS' => 'new']);
// отправку в CRM делает задание по расписанию, а не форма
// недоступность чужой системы не должна ломать отправку формы посетителем

В чужую систему заявка уходит через очередь, а не прямо из формы. Посетитель не должен ждать ответа чужого сервиса, а его недоступность не должна превращаться в ошибку на странице.

Замечаем пропавший поток:

$cnt = LeadTable::getList(['select' => ['CNT' => new ExpressionField('CNT', 'COUNT(%s)', 'ID')],
'filter' => ['>DATE_CREATE' => (new DateTime())->add('-1 day')]])->fetch();
if ((int)$cnt['CNT'] === 0) {
\Bitrix\Main\Mail\Event::send(['EVENT_NAME' => 'NO_LEADS', 'LID' => SITE_ID, 'C_FIELDS' => []]);
}

Пропавший поток заявок обнаруживается сам, а не через неделю от директора. Сутки без единой заявки на живом сайте - это либо праздник, либо сломанная форма, и проверить стоит оба варианта.

У заявок должен быть хозяин и понятный статус. Список без ответственного копится месяцами, и худшее, что можно узнать потом, - что половина заявок ждала ответа три недели.

Согласие на обработку данных берут на самой форме. Отметка о нём хранится вместе с заявкой: спорить об этом потом бессмысленно, если записи нет.

Источник заявки стоит писать в саму заявку. Страница, кампания и время дают ответ на вопрос, какая реклама приносит обращения, без отдельной системы аналитики.

Типичные проблемы

Заявки перестали приходить, и это заметили не сразу.

Заявка существует только в виде письма, а почта молча отвалилась. Сначала идёт запись заявки в базу, и только потом уже отправка письма.

Одна заявка приходит по три раза.

Посетитель нажал кнопку несколько раз, и каждое нажатие создало запись. Недавнюю заявку с тем же самым телефоном считают обычным повтором той отправки.

Форму завалило роботами.

На форме нет ни поля-ловушки, ни ограничения частоты отправки. Оба способа дешевле картинки с кодом и работают лучше.

Отправка формы падает с ошибкой.

Форма ходит в чужую систему прямо в момент отправки. Передачу в чужую систему выносят в очередь и делают её отдельным заданием.

Половина заявок осталась без ответа.

У списка заявок нет ни статусов, ни ответственного. Заявка без назначенного хозяина не обрабатывается вообще никем и никогда вовсе.

Частые вопросы

Инфоблок или своя таблица?

Инфоблок даёт готовый интерфейс и права, своя таблица - скорость и свои поля. Для потока в тысячи заявок вторая удобнее.

Как понять, что заявки теряются?

Сравнением числа заявок в базе и писем у менеджера. Расхождение видно в тот же день.

Нужна ли картинка с кодом?

Обычно нет: поле-ловушка и ограничение частоты отсекают почти всё. Картинка мешает живым посетителям.

Где хранить согласие на обработку данных?

Вместе с заявкой, отдельным полем с датой. Отдельный список согласий труднее сопоставить с обращением.

Смежное

Первоисточник