Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
sender.php
1<?php
10
11use Bitrix\Main;
36
37Loc::loadMessages(__FILE__);
38
43class Sender
44{
45 const RESULT_NONE = 0;
46 const RESULT_SENT = 1;
47 const RESULT_CONTINUE = 2;
48 const RESULT_ERROR = 3;
49 const RESULT_WAIT = 4;
51
54
56 protected $letter;
58 protected $message;
59
61 protected $timeout;
63 protected $timeAtStart;
64
66 protected $limit;
68 protected $sentCount = 0;
69
71 protected $checkStatusStep = 25;
73 protected $checkStatusCounter = 0;
74
76 protected $isPrevented = false;
77
79 protected $isTrigger = false;
80
82 protected $isReiterate = false;
83
85 protected $mailingId;
87 protected $postingId;
89 protected $letterId;
91 protected $status;
93 protected $sendCount = 0;
95 protected $resultCode = self::RESULT_NONE;
96
101
107 public function __construct(Letter $letter)
108 {
109 $this->letter = $letter;
110 $this->checkStatusStep = (int)Option::get('sender', 'send_check_status_step', $this->checkStatusStep);
111
112 $this->message = $letter->getMessage();
113 $this->message->getConfiguration()->set('LETTER_ID', $this->letter->getId());
114 }
115
123 public function setLimit($limit)
124 {
125 $this->limit = $limit;
126
127 return $this;
128 }
129
137 public function setTimeout($timeout)
138 {
139 $this->timeout = $timeout;
140
141 return $this;
142 }
143
149 public function getResultCode()
150 {
151 return $this->resultCode;
152 }
153
160 public function send()
161 {
162 $this->load($this->letter->get('POSTING_ID'));
163
164 if (!$this->postingId)
165 {
166 $this->resultCode = self::RESULT_ERROR;
167
168 AddMessage2Log('Mailing without id','sender');
169
170 return;
171 }
172
173 if ($this->threadStrategy->isProcessLimited())
174 {
175 $this->resultCode = static::RESULT_CONTINUE;
176 return;
177 }
178
179 $threadState = $this->threadStrategy->checkThreads();
180
181 $this->startTime();
182
183 $this->isConsentSupport = $this->letter
184 ->getMessage()
185 ->getConfiguration()
186 ->get('APPROVE_CONFIRMATION') === 'Y';
187
188 $this->threadStrategy->setPostingId($this->postingId);
189
190 if ($threadState === AbstractThreadStrategy::THREAD_NEEDED)
191 {
192 $this->threadStrategy->fillThreads();
193 }
194
195 $this->threadStrategy->lockThread();
196 $threadId = $this->threadStrategy->getThreadId();
197
198 // lock posting for exclude double parallel sending
199 if (is_null($threadId))
200 {
201 if (!$this->threadStrategy->hasUnprocessedThreads())
202 {
203 // update status of posting
204 $status = self::updateActualStatus(
205 $this->postingId,
206 $this->isPrevented()
207 );
208
209 $this->finalizePosting($status);
210 return;
211 }
212
213 $this->resultCode = static::RESULT_CONTINUE;
214 return;
215 }
216
217 if (static::lock($this->postingId, $threadId) === false)
218 {
219 $this->threadStrategy->updateStatus(PostingThreadTable::STATUS_NEW);
220 throw new DB\Exception(Loc::getMessage('SENDER_POSTING_MANAGER_ERR_LOCK'));
221 }
222
223 if ($this->status == PostingTable::STATUS_NEW && $threadId !== 0)
224 {
225 $this->resultCode = static::RESULT_CONTINUE;
226 $this->threadStrategy->updateStatus(PostingThreadTable::STATUS_NEW);
227 static::unlock($this->postingId, $threadId);
228 return;
229 }
230
231 // posting not in right status
232 if (!$this->initRecipients())
233 {
234 $this->resultCode = static::RESULT_WAITING_RECIPIENT;
235 $this->threadStrategy->updateStatus(PostingThreadTable::STATUS_NEW);
236 static::unlock($this->postingId, $threadId);
237 return;
238 }
239
240 $this->changeStatusToPart();
241
242 // posting competed by status SENT_WITH_ERROR
243 if ($this->status === PostingTable::STATUS_SENT_WITH_ERRORS)
244 {
245 $this->resultCode = static::RESULT_SENT;
246 $this->threadStrategy->updateStatus(PostingThreadTable::STATUS_DONE);
247 static::unlock($this->postingId, $threadId);
248 return;
249 }
250
251 // posting not in right status
252 if ($this->status != PostingTable::STATUS_PART)
253 {
254 AddMessage2Log('Status does not equal Part. PostingId: ' . $this->postingId,'sender');
255 $this->resultCode = static::RESULT_ERROR;
256 $this->threadStrategy->updateStatus(PostingThreadTable::STATUS_NEW);
257 static::unlock($this->postingId, $threadId);
258 return;
259 }
260
261 if ($this->isTransportLimitsExceeded())
262 {
263 $this->resultCode = static::RESULT_CONTINUE;
264 static::unlock($this->postingId, $threadId);
265
266 return;
267 }
268
269 $threadRecipients = $this->threadStrategy->getRecipients($this->limit);
270 $recipients = static::getRecipientsToSend($threadRecipients);
271 if (($count = count($recipients))> 0)
272 {
273 $this->message->getTransport()->setSendCount($count);
274 if (!$this->message->getTransport()->start())
275 {
276 $this->prevent();
277 }
278 }
279
280 $this->sendToRecipients($recipients);
281
282
283 $this->message->getTransport()->end();
284
285 // unlock posting for exclude double parallel sending
286 self::unlock($this->postingId, $threadId);
287 // update status of posting
288 $status = self::updateActualStatus(
289 $this->postingId,
290 $this->isPrevented(),
291 $this->threadStrategy->hasUnprocessedThreads()
292 );
293
294 $threadStatus = (
295 $threadRecipients->getSelectedRowsCount() === 0 ?
298 );
299
300 $this->threadStrategy->updateStatus($threadStatus);
301
302 if ($threadId < $this->threadStrategy->lastThreadId())
303 {
304 $this->resultCode = static::RESULT_CONTINUE;
305
306 return;
307 }
308
309 if ($this->threadStrategy->hasUnprocessedThreads())
310 {
311 $this->resultCode = static::RESULT_CONTINUE;
312
313 return;
314 }
315
316 $this->finalizePosting($status);
317 }
318
326 public function load($postingId)
327 {
328 $postingDb = PostingTable::getList(
329 [
330 'select' => [
331 'ID',
332 'STATUS',
333 'MAILING_ID',
334 'MAILING_CHAIN_ID',
335 'MAILING_CHAIN_REITERATE' => 'MAILING_CHAIN.REITERATE',
336 'MAILING_CHAIN_IS_TRIGGER' => 'MAILING_CHAIN.IS_TRIGGER',
337 'COUNT_SEND_ALL'
338 ],
339 'filter' => [
340 '=ID' => $postingId,
341 '=MAILING.ACTIVE' => 'Y',
342 '=MAILING_CHAIN.STATUS' => [
343 Model\LetterTable::STATUS_SEND,
344 Model\LetterTable::STATUS_PLAN,
345 ],
346 ]
347 ]
348 );
349 if ($postingData = $postingDb->fetch())
350 {
351 $this->postingId = $postingData['ID'];
352 $this->status = $postingData['STATUS'];
353
354 $this->mailingId = $postingData['MAILING_ID'];
355 $this->letterId = $postingData['MAILING_CHAIN_ID'];
356 $this->sendCount = $postingData['COUNT_SEND_ALL'];
357
358 $this->isReiterate = $postingData['MAILING_CHAIN_REITERATE'] == 'Y';
359 $this->isTrigger = $postingData['MAILING_CHAIN_IS_TRIGGER'] == 'Y';
360 }
361 }
362
368 public function startTime()
369 {
370 if (!$this->timeout)
371 {
372 return;
373 }
374
375 $this->timeAtStart = getmicrotime();
376 @set_time_limit(0);
377 }
378
379 protected function initRecipients(): bool
380 {
381 // if posting in new status, then import recipients from groups
382 // and set right status for sending
383
384 if (!$this->postingId)
385 {
386 return true;
387 }
388
389 if ($this->isTrigger)
390 {
391 return true;
392 }
393
394 if ($this->status !== PostingTable::STATUS_NEW)
395 {
396 return true;
397 }
398
399 return Builder::create()->run($this->postingId);
400 }
401
402 protected function changeStatusToPart()
403 {
404 if (!$this->postingId)
405 {
406 return;
407 }
408
409 if ($this->status == PostingTable::STATUS_PART)
410 {
411 return;
412 }
413
414 if (
415 ($this->status !== PostingTable::STATUS_NEW)
416 && !$this->isTrigger
417 )
418 {
419 return;
420 }
421 $onBeforeStartResult = $this->message->onBeforeStart();
422 if ($onBeforeStartResult->isSuccess())
423 {
424 $this->status = PostingTable::STATUS_PART;
425 Model\PostingTable::update($this->postingId, ['STATUS' => $this->status]);
426 }
427 else
428 {
429 static::updateActualStatus($this->postingId, true);
430 }
431
432 $errorMessage = implode(', ', $onBeforeStartResult->getErrorMessages());
433 if($errorMessage <> '')
434 {
435 Model\LetterTable::update($this->letterId, ['ERROR_MESSAGE' => $errorMessage]);
436 }
437 }
438
447 public static function updateActualStatus($postingId, $isPrevented = false, $awaitThread = false)
448 {
449 //set status and delivered and error emails
451 'LOGIC' => 'OR',
452 [
453 '@STATUS' => [
458 ],
459 ],
460 [
462 '>=DATE_SENT' => (new Type\DateTime())->add("- 1 week")
463 ]
464 ]);
465 $hasStatusError = array_key_exists(PostingRecipientTable::SEND_RESULT_ERROR, $statusList);
466 $hasStatusNone = array_key_exists(PostingRecipientTable::SEND_RESULT_NONE, $statusList);
467 $hasStatusWait = array_key_exists(PostingRecipientTable::SEND_RESULT_WAIT_ACCEPT, $statusList);
468 if ($isPrevented)
469 {
471 }
472 elseif (!$hasStatusNone && !$awaitThread && !$hasStatusWait)
473 {
475 }
476 else
477 {
479 }
480
481 $postingUpdateFields = [
482 'STATUS' => $status,
483 'DATE_SENT' => $status == PostingTable::STATUS_PART ? null : new Type\DateTime(),
484 'COUNT_SEND_ALL' => 0
485 ];
486
487 $recipientStatusToPostingFieldMap = PostingTable::getRecipientStatusToPostingFieldMap();
488 foreach ($recipientStatusToPostingFieldMap as $recipientStatus => $postingFieldName)
489 {
490 if (!array_key_exists($recipientStatus, $statusList))
491 {
492 $statusList[$recipientStatus] = 0;
493 }
494 $postingUpdateFields[$postingFieldName] = $statusList[$recipientStatus];
495 }
496 $postingUpdateFields['COUNT_SEND_ALL'] = array_sum($statusList);
497 Model\PostingTable::update($postingId, $postingUpdateFields);
498
499 return $status;
500 }
501
510 public static function lock($id, $threadId = 0)
511 {
512 $id = intval($id);
513 $threadId = intval($threadId);
514
515 $lockName = self::getSendpostLockName($id, $threadId);
516
517 return Application::getInstance()->getConnection()->lock($lockName);
518 }
519
528 private static function getSendpostLockName(int $id, int $threadId): string
529 {
530 return "sendpost_{$id}_{$threadId}";
531 }
532
539 {
540 return $this->message->getTransport()->isLimitsExceeded($this->message);
541 }
542
548 public function getExceededLimiter()
549 {
550 return $this->message->getTransport()->getExceededLimiter($this->message);
551 }
552
553 protected function prevent()
554 {
555 return $this->isPrevented = true;
556 }
557
564 private function sendToRecipients($recipients)
565 {
566 $sendResult = null;
567 $dataToInsert = [];
568 try
569 {
570 foreach ($recipients as $recipient)
571 {
572 if ($this->isPrevented() || $this->isStoppedOnRun())
573 {
574 break;
575 }
576
577 $this->setPostingDateSend();
578 $eventData = [];
579 if ($this->canDenySendToRecipient($recipient))
580 {
581 $this->updateRecipientStatus($recipient['ID'],PostingRecipientTable::SEND_RESULT_ERROR);
582 $sendResult = false;
583 $eventData = $this->executeEvent($recipient, $sendResult);
584 }
585 elseif($this->canSendMessageToRecipient($recipient))
586 {
587 $sendResult = $this->sendToRecipient($recipient);
588 if ($this->isPrevented())
589 {
590 break;
591 }
592 $sendResultStatus = ($sendResult ?
595 );
596 $this->updateRecipientStatus($recipient['ID'],$sendResultStatus);
597 $eventData = $this->executeEvent($recipient, $sendResult);
598 }
599 elseif ($this->canSendConsentToRecipient($recipient))
600 {
601 $sendResult = $this->executeConsentToRecipient($recipient);
602 $sendResultStatus = (
603 $sendResult ?
606 );
607 $this->updateRecipientStatus($recipient['ID'],$sendResultStatus);
608 }
609
610 $dataToInsert[] = $eventData;
611
612 if (Bitrix24\Service::isCloud() && $eventData['SEND_RESULT'] && $this->letter->getMessage()->getCode() === Message\iBase::CODE_MAIL)
613 {
614 Bitrix24\Limitation\DailyLimit::increment();
615 }
616 // limit executing script by time
617 if ($this->isTimeout() || $this->isLimitExceeded() || $this->isTransportLimitsExceeded())
618 {
619 break;
620 }
621 // increment sending statistic
622 $this->sentCount++;
623 }
624 } catch(\Exception $e)
625 {}
626
627 try
628 {
629 if($dataToInsert)
630 {
631 Integration\EventHandler::onAfterPostingSendRecipientMultiple(
632 $dataToInsert,
633 $this->letter
634 );
635 }
636 } catch(\Exception $e)
637 {
638
639 }
640
641 return $sendResult;
642 }
643
644 protected function isPrevented()
645 {
646 return $this->isPrevented;
647 }
648
649 protected function isStoppedOnRun()
650 {
651 // check pause or stop status
652 if (++$this->checkStatusCounter < $this->checkStatusStep)
653 {
654 return false;
655 }
656
657 $checkStatusDb = Model\LetterTable::getList(
658 [
659 'select' => ['ID'],
660 'filter' => [
661 '=ID' => $this->letterId,
662 '=STATUS' => Model\LetterTable::STATUS_SEND
663 ]
664 ]
665 );
666 if (!$checkStatusDb->fetch())
667 {
668 return true;
669 }
670
671 $this->checkStatusCounter = 0;
672
673 return false;
674 }
675
676 protected function setPostingDateSend()
677 {
678 if ($this->letter->get('DATE_SEND'))
679 {
680 return;
681 }
682
683 Model\PostingTable::update($this->postingId, ['DATE_SEND' => new Type\DateTime()]);
684 }
685
686 protected function sendToRecipient($recipient)
687 {
688 self::applyRecipientToMessage($this->message, $recipient);
689
690 // event before sending
691 $eventSendParams = [
692 'FIELDS' => $this->message->getFields(),
693 'TRACK_READ' => $this->message->getReadTracker()->getArray(),
694 'TRACK_CLICK' => $this->message->getClickTracker()->getArray(),
695 'MAILING_CHAIN_ID' => $this->letter->getId()
696 ];
697 $linkDomain = $this->message->getReadTracker()->getLinkDomain();
698 if ($linkDomain)
699 {
700 $eventSendParams['LINK_DOMAIN'] = $linkDomain;
701 }
702 $event = new Main\Event('sender', 'OnBeforePostingSendRecipient', [$eventSendParams]);
703 $event->send();
704 foreach ($event->getResults() as $eventResult)
705 {
706 if ($eventResult->getType() == Main\EventResult::ERROR)
707 {
708 return false;
709 }
710
711 if (is_array($eventResult->getParameters()))
712 {
713 $eventSendParams = array_merge($eventSendParams, $eventResult->getParameters());
714 }
715 }
716 if (count($event->getResults()) > 0)
717 {
718 $this->message->setFields($eventSendParams['FIELDS']);
719 $this->message->getReadTracker()->setArray($eventSendParams['TRACK_READ']);
720 $this->message->getReadTracker()->setArray($eventSendParams['TRACK_CLICK']);
721 }
722
723 try
724 {
725 $sendResult = $this->message->send();
726 }
727 catch (Main\Mail\StopException $e)
728 {
729 $sendResult = false;
730 $this->prevent();
731 }
732
733 return $sendResult;
734 }
735
745 public static function applyRecipientToMessage(Adapter $message, array $recipient, $isTest = false)
746 {
747 $siteId = MailingTable::getMailingSiteId($recipient['CAMPAIGN_ID'] ? : Campaign::getDefaultId(SITE_ID));
748 $message->getReadTracker()->setModuleId('sender')->setFields(['RECIPIENT_ID' => $recipient["ID"]])
749 ->setHandlerUri(Option::get('sender', 'read_link'))->setSiteId($siteId);
750 $message->getClickTracker()->setModuleId('sender')->setFields(['RECIPIENT_ID' => $recipient["ID"]])
751 ->setUriParameters(['bx_sender_conversion_id' => $recipient["ID"]])->setHandlerUri(
752 Option::get('sender', 'click_link')
753 )->setSiteId($siteId);
754 $message->getUnsubTracker()->setModuleId('sender')->setFields(
755 [
756 'RECIPIENT_ID' => $recipient['ID'],
757 'CONTACT_ID' => $recipient['CONTACT_ID'] ?? '',
758 'MAILING_ID' => $recipient['CAMPAIGN_ID'] ?? 0,
759 'EMAIL' => $message->getRecipientCode(),
760 'CODE' => $message->getRecipientCode(),
761 'TEST' => $isTest ? 'Y' : 'N'
762 ]
763 )->setHandlerUri(Option::get('sender', 'unsub_link'))->setSiteId($siteId);
764
765 $fields = self::prepareRecipientFields($recipient);
766 $message->setFields($fields);
767 $message->setRecipientId($recipient['ID']);
768 $message->setRecipientCode($recipient['CONTACT_CODE']);
769 $message->setRecipientType(Recipient\Type::getCode($recipient['CONTACT_TYPE_ID'] ?? ''));
770 $message->setRecipientData($recipient);
771 }
772
773 protected static function prepareRecipientFields($recipient)
774 {
775 // create name from email
776 if (empty($recipient["NAME"]))
777 {
778 $recipient["NAME"] = Recipient\Field::getDefaultName();
779 }
780 $recipient["MAILING_CHAIN_ID"] ??= 0;
781 $senderChainId = (int)$recipient["MAILING_CHAIN_ID"] > 0 ? (int)$recipient["MAILING_CHAIN_ID"]
782 : (int)$recipient['CAMPAIGN_ID'];
783
784 // prepare params for send
785 $fields = [
786 'EMAIL_TO' => $recipient['CONTACT_CODE'] ?? '',
787 'NAME' => $recipient['NAME'] ?? '',
788 'USER_ID' => $recipient["USER_ID"] ?? '',
789 'SENDER_CHAIN_ID' => $senderChainId,
790 'SENDER_CHAIN_CODE' => 'sender_chain_item_'.$senderChainId
791 ];
792
793 if (is_array($recipient['FIELDS']) && count($recipient) > 0)
794 {
795 $fields = $fields + $recipient['FIELDS'];
796 }
797
798 return $fields;
799 }
800
806 public function isTimeout()
807 {
808 if (!$this->timeout)
809 {
810 return false;
811 }
812
813 return (getmicrotime() - $this->timeAtStart >= $this->timeout);
814 }
815
821 public function isLimitExceeded()
822 {
823 if (!$this->limit)
824 {
825 return false;
826 }
827
828 return ($this->sentCount > $this->limit);
829 }
830
839 public static function unlock($id, $threadId = 0)
840 {
841 $id = intval($id);
842 $threadId = intval($threadId);
843
844 $lockName = self::getSendpostLockName($id, $threadId);
845
846 return Application::getInstance()->getConnection()->unlock($lockName);
847 }
848
853 {
854 return $this->threadStrategy;
855 }
856
862 public function setThreadStrategy(IThreadStrategy $threadStrategy): Sender
863 {
864 $this->threadStrategy = $threadStrategy;
865 return $this;
866 }
867
871 public function getMessage()
872 : Adapter
873 {
874 return $this->message;
875 }
876 protected function canDenySendToRecipient($recipient) : bool
877 {
878 return (
879 empty($recipient['CONTACT_CODE']) ||
880 $recipient['CONTACT_BLACKLISTED'] === 'Y' ||
881 $recipient['CONTACT_UNSUBSCRIBED'] === 'Y' ||
882 $recipient['CONTACT_MAILING_UNSUBSCRIBED'] === 'Y' ||
883 Consent::isUnsub(
884 $recipient['CONTACT_CONSENT_STATUS'],
885 $recipient['CONTACT_CONSENT_REQUEST'],
886 $this->message->getTransport()->getCode()
887 ) &&
888 $this->needConsent()
889 );
890 }
891 protected function canSendConsentToRecipient($recipient) : bool
892 {
893 return (
894 in_array($recipient['CONTACT_CONSENT_STATUS'], [
897 ) &&
898 !Consent::checkIfConsentRequestLimitExceeded(
899 $recipient['CONTACT_CONSENT_REQUEST'],
900 $this->message->getTransport()->getCode()
901 ) &&
902 $this->needConsent()
903 );
904 }
905 protected function canSendMessageToRecipient($recipient) : bool
906 {
907 return (
908 $recipient['CONTACT_CONSENT_STATUS'] === ContactTable::CONSENT_STATUS_ACCEPT ||
909 !$this->needConsent()
910 );
911 }
912 protected function executeConsentToRecipient($recipient)
913 {
914 $sendResult = null;
915 $sendResult = $this->message->getTransport()->sendConsent(
916 $this->letter->getMessage(), $recipient + ['RECIPIENT_ID' => $recipient['ID'], 'SITE_ID' => SITE_ID]
917 );
918
919 if($sendResult)
920 {
922 $recipient['CONTACT_ID'],
924 );
925
926 if (Bitrix24\Service::isCloud())
927 {
928 Bitrix24\Limitation\DailyLimit::increment();
929 }
930 }
931 return $sendResult;
932 }
933
934 protected function executeEvent($recipient, $success)
935 {
936 $eventData = [
937 'SEND_RESULT' => $success,
938 'RECIPIENT' => $recipient,
939 'POSTING' => [
940 'ID' => $this->postingId,
941 'STATUS' => $this->status,
942 'MAILING_ID' => $this->mailingId,
943 'MAILING_CHAIN_ID' => $this->letterId,
944 ]
945 ];
946
947 return $eventData;
948 }
949
950 protected function needConsent(): bool
951 {
952 static $needConsentMessage;
953 if (!isset($needConsentMessage))
954 {
955 $needConsentMessage = $this->isConsentSupport;
956 }
957 return $needConsentMessage;
958 }
959
960 protected function updateRecipientStatus($primary, $status)
961 {
962 Model\Posting\RecipientTable::update(
963 $primary,
964 [
965 'STATUS' => $status,
966 'DATE_SENT' => new Type\DateTime()
967 ]
968 );
969 }
970
971 protected static function getRecipientsToSend(\Bitrix\Main\ORM\Query\Result $result)
972 {
973 return array_filter(iterator_to_array($result),
974 function ($recipient)
975 {
976 return $recipient['STATUS'] === PostingRecipientTable::SEND_RESULT_NONE;
977 });
978 }
979
985 private function finalizePosting(string $status): void
986 {
987 if (!PostingRecipientTable::hasUnprocessed($this->postingId))
988 {
989 $onAfterEndResult = $this->message->onAfterEnd();
990 if (!$onAfterEndResult->isSuccess())
991 {
992 $this->resultCode = static::RESULT_CONTINUE;
993
994 return;
995 }
996 $errorMessage = implode(', ', $onAfterEndResult->getErrorMessages());
997 if (strlen($errorMessage))
998 {
999 Model\LetterTable::update($this->letterId, ['ERROR_MESSAGE' => $errorMessage]);
1000 }
1001 }
1002
1003 // set result code to continue or end of sending
1004 $isContinue = $status == PostingTable::STATUS_PART;
1005 $this->resultCode = $isContinue ? static::RESULT_CONTINUE : static::RESULT_SENT;
1006
1007 if ($this->resultCode == static::RESULT_SENT)
1008 {
1009 $this->resultCode = !$this->threadStrategy->finalize() ? static::RESULT_CONTINUE : static::RESULT_SENT;
1010 TimeLineJob::addEventAgent($this->letterId);
1011 }
1012 }
1013}
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static updateConsentStatus($primary, string $contactStatus)
Definition contact.php:314
static getDefaultId($siteId=null)
Definition campaign.php:63
static getMailingSiteId($mailingId)
Definition mailing.php:659
updateRecipientStatus($primary, $status)
Definition sender.php:960
executeEvent($recipient, $success)
Definition sender.php:934
setThreadStrategy(IThreadStrategy $threadStrategy)
Definition sender.php:862
static prepareRecipientFields($recipient)
Definition sender.php:773
canSendMessageToRecipient($recipient)
Definition sender.php:905
static updateActualStatus($postingId, $isPrevented=false, $awaitThread=false)
Definition sender.php:447
canDenySendToRecipient($recipient)
Definition sender.php:876
executeConsentToRecipient($recipient)
Definition sender.php:912
canSendConsentToRecipient($recipient)
Definition sender.php:891
static unlock($id, $threadId=0)
Definition sender.php:839
__construct(Letter $letter)
Definition sender.php:107
static applyRecipientToMessage(Adapter $message, array $recipient, $isTest=false)
Definition sender.php:745
static getRecipientsToSend(\Bitrix\Main\ORM\Query\Result $result)
Definition sender.php:971
static lock($id, $threadId=0)
Definition sender.php:510
static hasUnprocessed($postingId, $threadId=null)
Definition posting.php:815
static getRecipientCountByStatus($id, ?array $customFilter=null)
Definition posting.php:253
static getRecipientStatusToPostingFieldMap()
Definition posting.php:321