]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
удаление
authorVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 6 Mar 2026 12:57:46 +0000 (15:57 +0300)
committerVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 6 Mar 2026 12:57:46 +0000 (15:57 +0300)
plan_email.md [deleted file]

diff --git a/plan_email.md b/plan_email.md
deleted file mode 100644 (file)
index fc1ac92..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-План: Улучшение системы регистрации и обработки писем Flowwow
-
-Контекст
-
-Крон-задача php yii marketplace/get-flowwow-orders читает письма от Flowwow через IMAP и создаёт/обновляет заказы в системе. Текущие проблемы:
-
-1. Нет разделения "регистрация" / "обработка" — email_status=1 ставится ДО processMessage() (строка 2203-2205), поэтому при сбое обработки письмо уже помечено как       
-   обработанное
-2. Повторная обработка невозможна — если saveEmailIfNotExists вернул null (письмо есть), processMessage() всё равно вызывается, но нет контроля завершённости обработки
-3. SEEN ставится только для новых заказов — processFlowwowOrders возвращает счётчик только для NEW (строка 2721), а SEEN зависит от $output > 0 (строка 2218). Для       
-   APPROVED/CHANGED/CANCELLED/DELIVERED SEEN не ставится
-4. Нет индексов на таблице marketplace_flowwow_emails для проверки дубликатов
-5. Нет отслеживания ошибок — если обработка упала, нет записи почему и сколько раз пытались
-6. Нет связки письмо↔заказ — невозможно из интерфейса писем найти, какие письма относятся к конкретному заказу
-
-Файлы для изменения
-┌──────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────┐
-│                           Файл                           │                                      Изменение                                       │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/migrations/m260218_*_improve_flowwow_emails.php    │ Новый — миграция: колонки + индексы                                                  │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/records/MarketplaceFlowwowEmails.php               │ Константы статусов, новые поля, relation, helper-методы                              │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/records/MarketplaceFlowwowEmailsSearch.php         │ Фильтрация по новым полям + поиск по заказу                                          │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/services/MarketplaceService.php                    │ Рефакторинг getFlowwowOrdersFromMail, saveEmailIfNotExists, fix processFlowwowOrders │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/commands/MarketplaceController.php                 │ Новый action actionRetryFlowwowEmails                                                │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/media/controllers/FlowwowController.php            │ Fix actionCheckMail (несовместимый вызов)                                            │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/views/marketplace-flowwow-emails/index.php         │ Обновление GridView: статусы, связка с заказом, поиск                                │
-├──────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
-│ erp24/controllers/MarketplaceFlowwowEmailsController.php │ Мелкие правки (если нужны для view)                                                  │
-└──────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────┘
- ---
-Шаг 1. Миграция БД
-
-Файл: erp24/migrations/m260218_000001_improve_marketplace_flowwow_emails.php
-
-Добавить в таблицу marketplace_flowwow_emails:
-┌──────────────────────┬────────────────────┬─────────────────────────────────────────────────────────────────────┐
-│       Колонка        │        Тип         │                              Описание                               │
-├──────────────────────┼────────────────────┼─────────────────────────────────────────────────────────────────────┤
-│ subject_type         │ smallint, NULL     │ Тип письма (1=NEW, 2=APPROVED, 3=CHANGED, 4=CANCELLED, 5=DELIVERED) │
-├──────────────────────┼────────────────────┼─────────────────────────────────────────────────────────────────────┤
-│ processing_attempts  │ integer, default 0 │ Счётчик попыток обработки                                           │
-├──────────────────────┼────────────────────┼─────────────────────────────────────────────────────────────────────┤
-│ processed_at         │ timestamp, NULL    │ Время успешной обработки                                            │
-├──────────────────────┼────────────────────┼─────────────────────────────────────────────────────────────────────┤
-│ error_message        │ text, NULL         │ Текст последней ошибки                                              │
-├──────────────────────┼────────────────────┼─────────────────────────────────────────────────────────────────────┤
-│ marketplace_order_id │ varchar(50), NULL  │ ID заказа (связка с marketplace_orders)                             │
-└──────────────────────┴────────────────────┴─────────────────────────────────────────────────────────────────────┘
-Индексы:
-- idx_flowwow_emails_dedup на (subject, "from", date) — ускорение проверки дубликатов
-- idx_flowwow_emails_status на (email_status) — выборка необработанных
-- idx_flowwow_emails_order на (marketplace_order_id) — связка с заказами
-
-Важно: from — зарезервированное слово PostgreSQL, использовать "from" в кавычках через raw SQL.
-
- ---
-Шаг 2. Модель MarketplaceFlowwowEmails
-
-Файл: erp24/records/MarketplaceFlowwowEmails.php
-
-2.1 Константы статусов
-public const STATUS_NEW = 0;        // Зарегистрировано, ожидает обработки
-public const STATUS_PROCESSED = 1;  // Успешно обработано
-public const STATUS_ERROR = 2;      // Ошибка (исчерпаны попытки)
-public const STATUS_RETRY = 3;      // Ожидает повторной обработки
-
-public const MAX_PROCESSING_ATTEMPTS = 5;
-
-2.2 Relation с MarketplaceOrders (связка письмо↔заказ)
-/**
-* Связь с заказом маркетплейса по marketplace_order_id.
-* Поле marketplace_order_id в emails хранит ID заказа из маркетплейса (например "123456"),
-* которому соответствует marketplace_orders.marketplace_order_id.
-  */
-  public function getOrder(): \yii\db\ActiveQuery
-  {
-  return $this->hasOne(MarketplaceOrders::class, ['marketplace_order_id' => 'marketplace_order_id'])
-  ->andWhere(['marketplace_id' => \yii_app\records\MarketplaceStore::FLOWWOW_WAREHOUSE_ID]);
-  }
-
-Это позволит:
-- Из письма перейти к заказу: $email->order
-- Из GridView показать ссылку на заказ
-
-2.3 Helper-методы
-
-- markAsProcessed(): bool — ставит STATUS_PROCESSED + processed_at
-- markAsError(string $errorMessage): bool — ставит STATUS_ERROR + error_message + инкремент attempts
-- markForRetry(string $reason): bool — ставит STATUS_RETRY + инкремент attempts
-- isRetryAllowed(): bool — processing_attempts < MAX_PROCESSING_ATTEMPTS
-- static findUnprocessed(): ActiveQuery — WHERE email_status IN (0, 3) AND processing_attempts < MAX
-- static statusLabels(): array — массив текстовых меток статусов
-- static subjectTypeLabels(): array — [1 => 'Новый заказ', 2 => 'Принят', 3 => 'Изменён', 4 => 'Отменён', 5 => 'Доставлен']
-
-2.4 Обновить rules() и attributeLabels()
-
-Добавить правила валидации и метки для новых полей.
-
- ---
-Шаг 3. Рефакторинг MarketplaceService
-
-3.1 Новый метод detectSubjectType
-private static function detectSubjectType(string $subject): ?int
-
-Определяет тип письма по теме через SUBJECT_INDEX regex patterns.
-
-3.2 Изменение saveEmailIfNotExists (строка 2260)
-
-При создании нового письма дополнительно заполнять subject_type через detectSubjectType(). Остальная логика без изменений — метод по-прежнему возвращает объект если     
-создано, null если уже существует.
-
-3.3 Рефакторинг getFlowwowOrdersFromMail (строки 2198-2242)
-
-Ключевое изменение — логика цикла обработки каждого письма:
-ДЛЯ КАЖДОГО ПИСЬМА ИЗ IMAP:
-├── saveEmailIfNotExists() → регистрация
-├── Если письмо новое (savedEmail != null):
-│   └── emailRecord = savedEmail
-├── Иначе: загружаем из БД:
-│   └── emailRecord = MarketplaceFlowwowEmails::find()->where(...)
-│
-├── Если emailRecord.email_status == STATUS_PROCESSED:
-│   ├── Только ставим SEEN на IMAP (чтобы не читать повторно)
-│   └── continue (пропускаем обработку)
-│
-├── Определяем паттерн темы → subject_index
-├── try:
-│   ├── processMessage($message) → обработка заказа
-│   ├── emailRecord->markAsProcessed() → статус ПОСЛЕ успешной обработки
-│   ├── emailRecord->marketplace_order_id = key($order)
-│   ├── imap_setflag_full(SEEN) → для ВСЕХ успешных, не только NEW
-│   └── countProcessedMessages++
-├── catch (Throwable):
-│   ├── Логирование ошибки
-│   ├── Если isRetryAllowed() → markForRetry()
-│   └── Иначе → markAsError()
-
-Что убираем:
-- Строки 2203-2205: преждевременная установка email_status = 1 ДО обработки
-- Строки 2218: условие if ($output > 0) для SEEN — теперь ставится безусловно
-
-3.4 Fix processFlowwowOrders (строка 2677)
-
-Добавить переменную $processingSuccess = false. Устанавливать в true при:
-- Создании нового заказа (строка 2719, $marketplaceOrder->save())
-- Успешном обновлении статуса (строки 2749, 2783, 2798)
-
-Изменить return (строка 2808):
-return $processingSuccess ? max($newOrdersCount, 1) : 0;
-
-Это обеспечит что $output > 0 для всех типов писем, а не только NEW.
-
-3.5 Новый метод processUnprocessedEmails
-public static function processUnprocessedEmails(?callable $progressCallback = null): array
-
-Выбирает из БД все письма со статусом STATUS_NEW или STATUS_RETRY (через findUnprocessed()), у которых заполнен subject_type, и обрабатывает каждое через
-processMessage().
-
-Возвращает: ['processed' => int, 'failed' => int, 'total' => int]
-
-Фильтр andWhere(['not', ['subject_type' => null]]) гарантирует, что старые записи (до миграции) не будут затронуты.
-
- ---
-Шаг 4. Консольная команда для retry
-
-Файл: erp24/commands/MarketplaceController.php
-
-Новый action:
-php yii marketplace/retry-flowwow-emails
-
-Вызывает MarketplaceService::processUnprocessedEmails() с progress callback в консоль. Выводит итоговую статистику.
-
- ---
-Шаг 5. Fix FlowwowController::actionCheckMail
-
-Файл: erp24/media/controllers/FlowwowController.php (строки 64-82)
-
-Текущий код несовместим: getFlowwowOrdersFromMail возвращает ['processed' => N, 'all' => M], а actionCheckMail вызывает count($messages) (вернёт 2) и
-processMessages($messages) (передаст массив с ключами 'processed'/'all' вместо писем).
-
-Исправить: убрать вызов processMessages, использовать возвращённый массив напрямую.
-
- ---
-Шаг 6. Обновить Search-модель (поиск писем по заказу)
-
-Файл: erp24/records/MarketplaceFlowwowEmailsSearch.php
-
-6.1 Новые правила фильтрации
-
-- В rules(): добавить subject_type, processing_attempts как integer; processed_at, error_message, marketplace_order_id как safe
-
-6.2 Поиск в search()
-// Фильтрация по новым полям
-$query->andFilterWhere([
-'subject_type' => $this->subject_type,
-'processing_attempts' => $this->processing_attempts,
-]);
-$query->andFilterWhere(['ilike', 'error_message', $this->error_message]);
-
-// Поиск писем по ID заказа маркетплейса
-$query->andFilterWhere(['ilike', 'marketplace_order_id', $this->marketplace_order_id]);
-
-Это позволит:
-- Ввести номер заказа Flowwow в фильтр → увидеть все письма, связанные с этим заказом
-- Фильтровать по типу письма (новый, принят, отменён и т.д.)
-- Фильтровать по статусу обработки
-
- ---
-Шаг 7. Обновить View (связка с заказами и поиск)
-
-Файл: erp24/views/marketplace-flowwow-emails/index.php
-
-7.1 Обновить статусы
-
-- Обновить отображение email_status — добавить статусы "Ошибка" (красный) и "Повтор" (синий)
-- Заменить текстовый фильтр email_status на dropdown:
-  'filter' => MarketplaceFlowwowEmails::statusLabels(),
-
-7.2 Добавить колонку "Тип письма"
-[
-'attribute' => 'subject_type',
-'value' => fn($model) => MarketplaceFlowwowEmails::subjectTypeLabels()[$model->subject_type] ?? '—',
-'filter' => MarketplaceFlowwowEmails::subjectTypeLabels(),
-],
-
-7.3 Добавить колонку "Заказ" со ссылкой
-[
-'attribute' => 'marketplace_order_id',
-'format' => 'raw',
-'value' => function ($model) {
-if (!$model->marketplace_order_id) {
-return '—';
-}
-$order = $model->order;
-if ($order) {
-return Html::a(
-'№' . $model->marketplace_order_id,
-['/marketplace-orders/view', 'id' => $order->id],
-['class' => 'btn btn-xs btn-outline-primary', 'target' => '_blank']
-);
-}
-return $model->marketplace_order_id . ' (не найден)';
-},
-'filter' => Html::input('text', 'MarketplaceFlowwowEmailsSearch[marketplace_order_id]',
-$searchModel->marketplace_order_id, ['class' => 'form-control', 'placeholder' => '№ заказа']),
-],
-
-Это даёт:
-- Поиск писем по заказу: ввести номер заказа в фильтр → увидеть ВСЕ связанные письма (создание, принятие, изменения, отмена, доставка)
-- Клик по номеру заказа → переход на страницу заказа в ERP
-- Фильтр по типу письма → например, увидеть все "отменённые" письма
-
-7.4 Добавить колонку "Попытки"
-'processing_attempts',
-
-7.5 Eager loading для оптимизации
-
-В контроллере MarketplaceFlowwowEmailsController::actionIndex добавить:
-$dataProvider->query->with(['order']);
-
- ---
-Порядок реализации
-1.  Миграция БД                              (независимый)
-2.  Модель MarketplaceFlowwowEmails           (зависит от 1)
-3.  MarketplaceFlowwowEmailsSearch            (зависит от 2)
-4.  MarketplaceService::detectSubjectType     (независимый)
-5.  MarketplaceService::saveEmailIfNotExists  (зависит от 2, 4)
-6.  MarketplaceService::processFlowwowOrders  (независимый fix)
-7.  MarketplaceService::getFlowwowOrdersFromMail (зависит от 5, 6)
-8.  MarketplaceService::processUnprocessedEmails (зависит от 2)
-9.  MarketplaceController::actionRetryFlowwowEmails (зависит от 8)
-10. FlowwowController::actionCheckMail fix   (зависит от 7)
-11. MarketplaceFlowwowEmailsController       (eager loading)
-12. View index.php                           (зависит от 2, 3, 11)
-
- ---
-Верификация
-
-1. Миграция: php yii migrate — проверить создание колонок и индексов
-2. Регистрация: запустить php yii marketplace/get-flowwow-orders, проверить что новые письма получили email_status=0, subject_type заполнен
-3. Обработка: проверить что после processMessage — email_status=1, processed_at заполнен, marketplace_order_id заполнен
-4. Повторный запуск: запустить команду снова — уже обработанные письма получают SEEN и пропускаются
-5. Retry: вручную UPDATE marketplace_flowwow_emails SET email_status=3 WHERE id=..., запустить php yii marketplace/retry-flowwow-emails — повторная обработка
-6. SEEN для всех типов: проверить что SEEN ставится для APPROVED, CANCELLED, DELIVERED (ранее не ставился)
-7. Поиск по заказу: в UI /marketplace-flowwow-emails/index ввести номер заказа Flowwow в фильтр → отображаются все связанные письма
-8. Ссылка на заказ: кликнуть по номеру заказа в колонке → переход на /marketplace-orders/view?id=...
-9. Фильтр по типу: выбрать "Отменён" в dropdown типа письма → только отменённые письма