Необходимо было реализовать функционал отправки электронных ключей в подарок. Т.е. пользоватлеь покупает электронный ключ, оплачивает покупку и во время оплаты указывает дату/время отправки подарка и на какой email отправлять.
Вроде все нормально, повешал событие OnBeforeEventSend , в котором хотел отпинывать неактуальные письма до тех пор, пока бы не пришел их час.
Код события довольно простой (SEND_DATE -- свойство в письме, содержащее дату в которую необходимо отправить письмо):
function OnBeforeEventSend($arFields) {
if (empty($arFields['SEND_DATE'])) {
return true;
}
if (strtotime($arFields['SEND_DATE']) <= time()) {
return true;
}
return false;
}
Т.е. если дата отправки не задана, то письмо улетает без проблем. Если дата задана и еще не наступила, то откладываем письмо в недолгий ящик.
И тут пришла она, проблема! В файле /bitrix/modules/main/classes/general/event.php , в функции CEvent::HandleEvent() вызывается обработчик OnBeforeEventSend, но не важно что вернет этот обработчик, письмо отошлется.
Лирическое отступление... Разработчики ядра Битрикс, обращение к вам! Хотелось бы, что бы вы допилили логику отправки event'ов, что бы была реакция на обработчик OnBeforeEventSend .
Теперь расскажу, как я это допилил, в ядре, стыд, да. Но я это делал с надеждой, что в скором времени разработчики ядра исполнят мое пожелание, так как оно вполне логично обоснуемо!
По человечески говоря, если событие вернет false, то письмо не отправляется и статус ему присваевается N , якобы оно еще не отсылалось. Насчет устанавливаемого статуса можно поспорить, конечно, но мне было нужно именно такое поведение .
Изменил немного mysql запросы в функции CheckEvents(), добавив условие
AND (NOW() > ADDTIME(DATE_EXEC, '0:1:0') OR ISNULL(DATE_EXEC)) ORDER BY DATE_EXEC ASC
То есть, если отправка письма еще не запускалась, либо с последней отправки уже прошло 10 минут, причем отправляются сначала письма, которые еще ни разу не пытались отправиться, у них DATE_EXEC NULL и они будут в выборке первыми. Если их не выбирать первыми, то очередь отправки забьется подарочными письмами, если у вас конечно хотя бы не по 10 хитов в минуту и 10 подарочных писем всего, грубо говоря.
Получилось два запроса в итоге.
$strSql=
"SEL ECT 'x' ".
"FR OM b_event ".
"WHERE SUCCESS_EXEC='N' ".
"AND (NOW() > ADDTIME(DATE_EXEC, '0:10:0') OR ISNULL(DATE_EXEC)) ".
"ORDER BY DATE_EXEC ASC " .
"LIMIT 1";
и
$strSql = "
SELECT ID, C_FIELDS, EVENT_NAME, MESSAGE_ID, LID, DATE_FORMAT(DATE_INSERT, '%d.%m.%Y %H:%i:%s') as DATE_INSERT, DUPLICATE
FR OM b_event
WH ERE SUCCESS_EXEC='N'
AND (NOW() > ADDTIME(DATE_EXEC, '0:10:0') OR ISNULL(DATE_EXEC))
ORDER BY DATE_EXEC, ID
LIMIT ".$bulk;
Теперь все прекрасно работает, создается событие через CEvent::Send(), потом неважно где пытается отправиться письмо, вызывается обработчик события OnBeforeEventSend и если он не разрешает отправку письма, то у письма остается статус N, если же обработчик разрешает отправку, то письмо пытается отправиться с обработкой статусов стандартной F,P,0 и так далее. Вот так вот были потрачены часы жизни, что бы подумать как решить без костылей, но нет, в итоге пришлось к ним прибегнуть.
P.S. Повторюсь .
Разработчики ядра Битрикс, обращение к вам! Хотелось бы, что бы вы допилили логику отправки event'ов, что бы была реакция на обработчик OnBeforeEventSend .
Александр, проблема действительно есть, попросим разработчиков решить её.
Вам же не нужно было править ядро, достаточно было очистить получателя письма и оно бы не отправилось.
Этот совет не подходит, т.к. если очищу получателя письма, то новых попыток отправки письма не будет происходить, как раз это в ядре и реализовал.
Конечно можно очищать получателя и городить новые обработчики, но это не тот случай, когда необходимо городить огороды, достаточно сделать вменяемую реакцию на обработчик.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».