* @property string $phone Телефон пользователя
* @property string $kogort_date Дата когорты
* @property int $kogort_unixtime UNIX-время когорты
+ * @property int $kogort_number Номер типа когорты когорты
* @property int $status Вхождение в когорту
* @property int $contact Контакт с клиентом
* @property int $purchase Покупка
*/
class SentKogort extends \yii\db\ActiveRecord
{
+ public const KOGORT_NUMBERS = [
+ 'target' => 1,
+ 'whatsapp' => 2,
+ 'call' => 3,
+ ];
/**
* {@inheritdoc}
*/
public function rules()
{
return [
- [['phone', 'kogort_date', 'kogort_unixtime', 'created_at'], 'required'],
+ [['phone', 'kogort_date', 'kogort_unixtime', 'kogort_number', 'created_at'], 'required'],
[['kogort_date', 'created_at'], 'safe'],
[['kogort_unixtime', 'status', 'contact', 'purchase'], 'default', 'value' => null],
- [['kogort_unixtime', 'status', 'contact', 'purchase'], 'integer'],
+ [['kogort_unixtime', 'status', 'contact', 'purchase', 'kogort_number'], 'integer'],
[['phone'], 'string', 'max' => 15],
];
}
'id' => 'ID',
'phone' => 'Телефон пользователя',
'kogort_date' => 'Дата когорты',
+ 'kogort_number' => 'Номер типа когорты когорты',
'kogort_unixtime' => 'UNIX-время когорты',
'status' => 'Вхождение в когорту',
'contact' => 'Контакт с клиентом',
return $data;
}
-}
\ No newline at end of file
+ public static function formKogortByDateAndType($startDate = null, $type = 'target'): array
+ {
+ $startDate = $startDate ?? date('Y-m-d');
+
+ // Если тип whatsapp, проверяем наличие target выборки
+ if ($type === 'whatsapp') {
+ $existingTargetKogort = SentKogort::find()
+ ->select('phone')
+ ->where([
+ 'kogort_date' => $startDate,
+ 'number_kogort' => SentKogort::KOGORT_NUMBERS['target']
+ ])
+ ->column();
+
+ if (!empty($existingTargetKogort)) {
+ return self::processWhatsappKogort($existingTargetKogort, $startDate);
+ }
+ }
+
+ // Если тип call, проверяем наличие whatsapp выборки
+ if ($type === 'call') {
+ $existingWhatsappKogort = SentKogort::find()
+ ->select('phone')
+ ->where([
+ 'kogort_date' => $startDate,
+ 'number_kogort' => SentKogort::KOGORT_NUMBERS['whatsapp']
+ ])
+ ->column();
+
+ if (!empty($existingWhatsappKogort)) {
+ return self::processCallKogort($existingWhatsappKogort, $startDate);
+ }
+ }
+
+ $monthDay = date('m-d', strtotime($startDate));
+
+ $messagesSettings = UsersMessageManagement::find()
+ ->where(['active' => 1])
+ ->one();
+
+ $step1 = $messagesSettings ? $messagesSettings->day_before_step1 : 10;
+
+ $salesPhone = Sales::find()
+ ->where(new \yii\db\Expression("TO_CHAR(date, 'MM-DD') = :monthDay", [':monthDay' => $monthDay]))
+ ->distinct('phone')
+ ->select('phone')
+ ->column();
+
+ $memorableDate = UsersEvents::find()
+ ->where(new \yii\db\Expression("TO_CHAR(date, 'MM-DD') = :monthDay", [':monthDay' => $monthDay]))
+ ->distinct('phone')
+ ->select('phone')
+ ->column();
+
+ $usersArray = array_unique(array_merge($salesPhone, $memorableDate));
+
+
+ $phonesSent = SentKogort::find()
+ ->select('phone')
+ ->where(['between', 'kogort_date',
+ date('Y-m-d', strtotime("$startDate -$step1 days")),
+ date('Y-m-d', strtotime("$startDate -1 days"))])
+ ->column();
+
+ $filteredUsers = array_diff($usersArray, $phonesSent);
+ $kogortData = array_values($filteredUsers);
+
+
+ if ($type === 'target') {
+ return $kogortData;
+ }
+
+
+ return $type === 'whatsapp'
+ ? self::processWhatsappKogort($kogortData, $startDate)
+ : self::processCallKogort($kogortData, $startDate);
+ }
+
+ /**
+ * Обработка выборки для WhatsApp когорты
+ */
+ private static function processWhatsappKogort(array $phones, string $startDate): array
+ {
+ $messagesSettings = UsersMessageManagement::find()
+ ->where(['active' => 1])
+ ->one();
+
+ $step1 = $messagesSettings ? $messagesSettings->day_before_step1 : 10;
+ $step2 = $messagesSettings ? $messagesSettings->day_before_step2 : 4;
+
+ // Подзапрос базы пользователей с учетом подписки на телеграм
+ $usersQuery = (new \yii\db\Query())
+ ->select(['phone'])
+ ->from('users')
+ ->where(['phone' => $phones])
+ ->andWhere(['telegram_is_subscribed' => 0]);
+
+ // Исключаем телефоны с продажами в период от 10 до 4 дней до даты
+ $excludeSalesPhone = Sales::find()
+ ->where(['>=', 'date', date('Y-m-d', strtotime("$startDate -$step1 days"))])
+ ->andWhere(['<=', 'date', date('Y-m-d', strtotime("$startDate -$step2 days"))])
+ ->distinct('phone')
+ ->select('phone')
+ ->column();
+
+ $usersQuery->andWhere(['not in', 'phone', $excludeSalesPhone]);
+
+ return $usersQuery->column();
+ }
+
+ /**
+ * Обработка выборки для Call когорты
+ */
+ private static function processCallKogort(array $phones, string $startDate): array
+ {
+ $messagesSettings = UsersMessageManagement::find()
+ ->where(['active' => 1])
+ ->one();
+
+ $step2 = $messagesSettings ? $messagesSettings->day_before_step2 : 4;
+ $step3 = $messagesSettings ? $messagesSettings->day_before_step3 : 2;
+
+ // Подзапрос базы пользователей с учетом подписки на телеграм
+ $usersQuery = (new \yii\db\Query())
+ ->select(['phone'])
+ ->from('users')
+ ->where(['phone' => $phones])
+ ->andWhere(['telegram_is_subscribed' => 0]);
+
+ // Исключаем телефоны с продажами в период от 4 до 2 дней до даты
+ $excludeSalesPhone = Sales::find()
+ ->where(['>=', 'date', date('Y-m-d', strtotime("$startDate -$step2 days"))])
+ ->andWhere(['<=', 'date', date('Y-m-d', strtotime("$startDate -$step3 days"))])
+ ->distinct('phone')
+ ->select('phone')
+ ->column();
+
+ $usersQuery->andWhere(['not in', 'phone', $excludeSalesPhone]);
+
+ return $usersQuery->column();
+ }
+
+ public static function saveKogort(array $phones, string $startDate, int $kogort_number): array
+ {
+ $data = [];
+ $kogortPhones = SentKogort::find()
+ ->select('phone')
+ ->where(['kogort_date' => $startDate])
+ ->column();
+
+ foreach ($phones as $phone) {
+ if ($phone && !in_array($phone, $kogortPhones)) {
+ $sentKogort = new SentKogort();
+ $sentKogort->phone = $phone;
+ $sentKogort->kogort_date = $startDate;
+ $sentKogort->kogort_unixtime = (int)strtotime($startDate . ' 00:00:00');
+ $sentKogort->status = 1;
+ $sentKogort->kogort_number = $kogort_number;
+ $sentKogort->save(false);
+ }
+
+ $data[] = ['phone' => $phone];
+ }
+ return $data;
+ }
+
+ public static function prepareDataForExport(array $phones, string $startDate, string $type = 'call'): array
+ {
+ if ($type !== 'call') {
+ return array_map(function ($phone) {
+ return ['phone' => $phone];
+ }, $phones);
+ }
+
+ $users = Users::find()
+ ->where(['phone' => $phones])
+ ->all();
+
+ $data = [];
+ foreach ($users as $user) {
+ $memorableDateExists = UsersEvents::find()
+ ->where(['phone' => $user['phone']])
+ ->exists() ? 1 : 0;
+
+ $lastSale = Sales::find()
+ ->where(['phone' => $user['phone']])
+ ->orderBy(['date' => SORT_DESC])
+ ->one();
+
+ $lastDate = $lastSale ? date('d-m-Y', strtotime($lastSale->date)) : 'нет данных';
+
+ $dealsCount = Sales::find()
+ ->where(['phone' => $user['phone']])
+ ->count();
+
+ $totalSum = Sales::find()
+ ->where(['phone' => $user['phone']])
+ ->sum('summ') ?? 0;
+
+ $data[] = [
+ 'phone' => $user['phone'],
+ 'last_date' => $lastDate,
+ 'deals_count' => $dealsCount,
+ 'total_sum' => $totalSum,
+ 'memorable_date' => $memorableDateExists,
+ 'name' => $user['name']
+ ];
+ }
+
+ return $data;
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @var $time integer|null
+ */
+
+use yii\helpers\Json;
+use yii_app\records\SchedulerTaskLog;
+use yii_app\records\SentKogort;
+use yii_app\records\Users;
+use yii_app\records\UsersMessageManagement;
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+$time = $time ?? time(); // Использовать текущее время, если параметр не передан
+
+echo "time2_" . $time . "_time2 ";
+$taskNum = 34;
+$dateTask = date('Y-m-d H:i:s', $time);
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = true;
+$start = false;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+
+try {
+ if (
+ (
+ (date('j', $time) == 1 && date('H:i', $time) == "00:00") || // Старт: 1-й день месяца в 00:00
+ (date('j', $time) == 21 && date('H:i', $time) == "00:00") // Старт: 21-й день месяца в 00:00
+ || $force
+ )
+ && $enable
+ ) {
+ $dateTaskStart = date('Y-m-d H:i:s', $time);
+ $info = ' ================ test Task ' . $taskNum . ' start ================';
+ echo $info;
+ $log .= $info;
+ $log .= $time;
+
+ $schedulerTaskLog = new SchedulerTaskLog();
+ $schedulerTaskLog->setTaskNum($taskNum)
+ ->setName('Task ' . $taskNum)
+ ->setDate($dateTask)
+ ->setDateStart($dateTaskStart);
+ $validate = $schedulerTaskLog->validate();
+ if ($validate) {
+ $schedulerTaskLog->save();
+ }
+
+ // === Логика формирования когорт ===
+ $currentYear = date('Y', $time);
+ $currentMonth = date('m', $time);
+ $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $currentMonth, $currentYear);
+
+ if (date('j', $time) == 1) {
+ $startDay = 1;
+ $endDay = $daysInMonth;
+ }
+
+
+ if (date('j', $time) == 21) {
+ $startDay = 1;
+ $endDay = 10;
+ $currentMonth = ($currentMonth == 12) ? 1 : (int)$currentMonth + 1;
+ $currentYear = ($currentMonth == 1) ? (int)$currentYear + 1 : $currentYear;
+ }
+
+ for ($day = $startDay; $day <= $endDay; $day++) {
+ $currentDate = sprintf('%04d-%02d-%02d', $currentYear, $currentMonth, $day);
+
+
+ if (SentKogort::find()->where(['kogort_date' => $currentDate])->exists()) {
+ $info = "Kogort for date {$currentDate} already exists. Skipping...\n";
+ echo $info;
+ $log .= $info;
+ continue;
+ }
+
+ $kogortPhones = Users::formKogortByDateAndType($currentDate, 'target');
+
+ if (!empty($kogortPhones)) {
+ Users::saveKogort($kogortPhones, $currentDate, SentKogort::KOGORT_NUMBERS['target']);
+ $info = "Kogort for date {$currentDate} saved successfully.\n";
+ echo $info;
+ $log .= $info;
+ } else {
+ $info = "No phones found for kogort on date {$currentDate}.\n";
+ echo $info;
+ $log .= $info;
+ }
+ }
+ // === Конец логики формирования когорт ===
+
+ $info = ' ================ test Task ' . $taskNum . ' stop ================';
+ echo $info;
+ $log .= $info;
+ $log .= ' date >= ' . strtotime("-1 week", $time);
+ $dateTaskStop = date('Y-m-d H:i:s', $time);
+ } else {
+ $info = ' Task ' . $taskNum . ' skip ';
+ echo $info;
+ $log .= $info;
+ }
+} catch (Exception $e) {
+ $error = 'Exception: ' . $e->getMessage() . ' ' . $e->getFile() . ' >>> ' . $e->getLine();
+}
+
+if (empty($schedulerTaskLog)) {
+ $schedulerTaskLog = new SchedulerTaskLog();
+ $schedulerTaskLog->setTaskNum($taskNum)
+ ->setName('Task ' . $taskNum)
+ ->setDate($dateTask)
+ ->setDateStart($dateTaskStart)
+ ->setDateStop($dateTaskStop)
+ ->setDescription($description)
+ ->setError($error)
+ ->setInfo($infoText)
+ ->setLog($log);
+} else {
+ $schedulerTaskLog->setDateStop($dateTaskStop)
+ ->setDescription($description)
+ ->setError($error)
+ ->setInfo($infoText)
+ ->setLog($log);
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+ $schedulerTaskLog->save();
+}
+