2025-10-17 19:53:05 +03:00
|
|
|
|
# 🛡️ Защита от дубликатов в системе парсинга судов
|
|
|
|
|
|
|
|
|
|
|
|
## 📋 Обзор
|
|
|
|
|
|
|
|
|
|
|
|
Система имеет **3 уровня защиты** от создания дубликатов:
|
|
|
|
|
|
|
|
|
|
|
|
### 1️⃣ Уровень событий в таблице `subject`
|
|
|
|
|
|
**Файл:** `parsers/BaseCourtParser.php` (метод `saveEvent`)
|
|
|
|
|
|
|
|
|
|
|
|
**Логика:**
|
|
|
|
|
|
- Проверяет наличие события по 3 полям: `event_name`, `event_date`, `publication_date`
|
|
|
|
|
|
- Если событие найдено → **НЕ сохраняет** в БД и возвращает `false`
|
|
|
|
|
|
- Если `skip_duplicate_check=true` → пропускает проверку (только для тестов!)
|
|
|
|
|
|
|
|
|
|
|
|
**SQL запрос:**
|
|
|
|
|
|
```sql
|
|
|
|
|
|
SELECT COUNT(*) FROM subject
|
|
|
|
|
|
WHERE event_name = ?
|
|
|
|
|
|
AND event_date = ?
|
|
|
|
|
|
AND publication_date = ?
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2️⃣ Уровень уведомлений в `vtiger_vdnotifierpro`
|
|
|
|
|
|
**Файлы:**
|
|
|
|
|
|
- `parsers/MoscowCourtParser.php` (метод `createCourtEventNotification`)
|
|
|
|
|
|
- `parsers/RegionalCourtParser.php` (метод `createCourtEventNotification`)
|
|
|
|
|
|
|
|
|
|
|
|
**Логика:**
|
|
|
|
|
|
- Проверяет наличие уведомления по: `userid`, `crmid` (project_id), точное совпадение `title`
|
|
|
|
|
|
- Если уведомление **непрочитано** (status=5) → **обновляет время** (modifiedtime)
|
|
|
|
|
|
- Если уведомление **прочитано** (status≠5) → **НЕ создаёт дубликат**
|
|
|
|
|
|
- Если уведомления нет → **создаёт новое**
|
|
|
|
|
|
|
|
|
|
|
|
**SQL запросы:**
|
|
|
|
|
|
```sql
|
|
|
|
|
|
-- Проверка существующего уведомления
|
|
|
|
|
|
SELECT id, status FROM vtiger_vdnotifierpro
|
|
|
|
|
|
WHERE userid = ?
|
|
|
|
|
|
AND crmid = ?
|
|
|
|
|
|
AND title = ?
|
|
|
|
|
|
ORDER BY id DESC LIMIT 1
|
|
|
|
|
|
|
|
|
|
|
|
-- Обновление времени (если непрочитано)
|
|
|
|
|
|
UPDATE vtiger_vdnotifierpro
|
|
|
|
|
|
SET modifiedtime = NOW()
|
|
|
|
|
|
WHERE id = ?
|
|
|
|
|
|
|
|
|
|
|
|
-- Создание нового (если не найдено)
|
|
|
|
|
|
INSERT INTO vtiger_vdnotifierpro
|
|
|
|
|
|
(userid, modulename, crmid, modiuserid, link, title, action, modifiedtime, status)
|
|
|
|
|
|
VALUES (?, 'Project', ?, 0, ?, ?, '', NOW(), 5)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3️⃣ Уровень событий в CRM календаре
|
|
|
|
|
|
**Файл:** `CreateCourtEvent_v2.php`
|
|
|
|
|
|
|
|
|
|
|
|
**Логика:**
|
|
|
|
|
|
- Не проверяет дубликаты напрямую
|
|
|
|
|
|
- Полагается на защиту уровня 1 (таблица `subject`)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## ✅ Что нужно сделать для продакшена
|
|
|
|
|
|
|
|
|
|
|
|
### **1. НЕ передавать параметр `skip_duplicate_check=true`**
|
|
|
|
|
|
|
|
|
|
|
|
❌ **ПЛОХО (для тестов):**
|
|
|
|
|
|
```php
|
|
|
|
|
|
$params = [
|
|
|
|
|
|
'project_id' => 364118,
|
|
|
|
|
|
'case_number' => '02-1182/312/2025',
|
|
|
|
|
|
'skip_duplicate_check' => 'true' // ← УБРАТЬ ЭТО!
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
✅ **ХОРОШО (для продакшена):**
|
|
|
|
|
|
```php
|
|
|
|
|
|
$params = [
|
|
|
|
|
|
'project_id' => 364118,
|
|
|
|
|
|
'case_number' => '02-1182/312/2025',
|
|
|
|
|
|
'skip_duplicate_check' => 'false' // ← или не передавать вообще (по умолчанию false)
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### **2. Убедиться, что параметр по умолчанию `false`**
|
|
|
|
|
|
|
|
|
|
|
|
В файле `ParseAndCreateEvent.php` (строка 58):
|
|
|
|
|
|
```php
|
|
|
|
|
|
'skip_duplicate_check' => $params['skip_duplicate_check'] ?? 'false'
|
|
|
|
|
|
```
|
|
|
|
|
|
✅ Это уже настроено правильно!
|
|
|
|
|
|
|
|
|
|
|
|
### **3. Убедиться, что в CRM workflow не передаётся `skip_duplicate_check=true`**
|
|
|
|
|
|
|
|
|
|
|
|
Проверьте ваши workflow, которые вызывают `ParseAndCreateEvent.php` или `parscourt.php`.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🧪 Тестирование защиты от дубликатов
|
|
|
|
|
|
|
|
|
|
|
|
### Тест 1: События в таблице `subject`
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Запустить парсинг 2 раза подряд
|
|
|
|
|
|
curl "https://crm.clientright.ru/parscourt.php" \
|
|
|
|
|
|
-d "project_id=364118" \
|
|
|
|
|
|
-d "case_number=02-1182/312/2025" \
|
|
|
|
|
|
-d "link1=https://mos-sud.ru/..." \
|
|
|
|
|
|
-d "status=test"
|
|
|
|
|
|
|
|
|
|
|
|
# Проверить, что в таблице subject только 1 запись
|
|
|
|
|
|
mysql -u ci20465_72new -p -D ci20465_72new \
|
|
|
|
|
|
-e "SELECT COUNT(*) FROM subject WHERE case_number = '02-1182/312/2025'"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Тест 2: Уведомления в `vtiger_vdnotifierpro`
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Запустить парсинг 2 раза подряд
|
|
|
|
|
|
curl "https://crm.clientright.ru/ParseAndCreateEvent.php?project_id=364118&..."
|
|
|
|
|
|
|
|
|
|
|
|
# Проверить, что создано только 1 уведомление
|
|
|
|
|
|
mysql -u ci20465_72new -p -D ci20465_72new \
|
|
|
|
|
|
-e "SELECT id, title, status, modifiedtime FROM vtiger_vdnotifierpro WHERE crmid = 364118 ORDER BY id DESC LIMIT 5"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Ожидаемый результат:**
|
|
|
|
|
|
- При первом запуске: создаётся уведомление (status=5)
|
|
|
|
|
|
- При втором запуске (если не прочитано): обновляется `modifiedtime`, status остаётся 5
|
|
|
|
|
|
- При втором запуске (если прочитано): ничего не происходит, дубликат НЕ создаётся
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 📊 Статусы уведомлений в VDNotifierPro
|
|
|
|
|
|
|
|
|
|
|
|
| Status | Значение | Действие при повторном парсинге |
|
|
|
|
|
|
|--------|-----------------|---------------------------------------|
|
|
|
|
|
|
| 5 | Непрочитано | Обновить время (`modifiedtime`) |
|
|
|
|
|
|
| 6 | Прочитано | Не создавать дубликат |
|
|
|
|
|
|
| Другое | Удалено/Архив | Не создавать дубликат |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🔍 Отладка
|
|
|
|
|
|
|
|
|
|
|
|
### Проверить логи парсера
|
|
|
|
|
|
```bash
|
|
|
|
|
|
tail -50 /var/www/fastuser/data/www/crm.clientright.ru/logs/parser.log
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Что искать:**
|
|
|
|
|
|
- `Дубликат найден для события:` - событие не сохранено (защита работает)
|
|
|
|
|
|
- `Обновлено время непрочитанного уведомления ID:` - уведомление обновлено (защита работает)
|
|
|
|
|
|
- `Уведомление ID: X уже существует (статус: Y), дубликат не создан` - дубликат предотвращён (защита работает)
|
|
|
|
|
|
- `⚠️ ТЕСТОВЫЙ РЕЖИМ: Проверка дубликатов отключена` - защита ОТКЛЮЧЕНА (только для тестов!)
|
|
|
|
|
|
|
|
|
|
|
|
### Проверить существующие уведомления
|
|
|
|
|
|
```sql
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
id,
|
|
|
|
|
|
userid,
|
|
|
|
|
|
crmid,
|
|
|
|
|
|
title,
|
|
|
|
|
|
status,
|
|
|
|
|
|
modifiedtime
|
|
|
|
|
|
FROM vtiger_vdnotifierpro
|
|
|
|
|
|
WHERE crmid = 364118 -- ваш project_id
|
|
|
|
|
|
AND title LIKE '%Событие суда%'
|
|
|
|
|
|
ORDER BY id DESC
|
|
|
|
|
|
LIMIT 10;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## ⚠️ ВАЖНО!
|
|
|
|
|
|
|
|
|
|
|
|
### ❌ **НЕ ДЕЛАТЬ:**
|
|
|
|
|
|
1. Не передавать `skip_duplicate_check=true` в продакшене
|
|
|
|
|
|
2. Не удалять проверки дубликатов из кода
|
|
|
|
|
|
3. Не изменять логику проверки без тестирования
|
|
|
|
|
|
|
|
|
|
|
|
### ✅ **РЕКОМЕНДУЕТСЯ:**
|
|
|
|
|
|
1. Использовать `skip_duplicate_check=false` (по умолчанию)
|
|
|
|
|
|
2. Регулярно проверять логи на наличие `⚠️ ТЕСТОВЫЙ РЕЖИМ`
|
|
|
|
|
|
3. Мониторить количество уведомлений для одного проекта
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🎯 Итог
|
|
|
|
|
|
|
|
|
|
|
|
При правильной настройке (`skip_duplicate_check=false` или не передавать вообще) система:
|
|
|
|
|
|
- ✅ **НЕ создаёт** дубликаты событий в таблице `subject`
|
|
|
|
|
|
- ✅ **НЕ создаёт** дубликаты уведомлений в `vtiger_vdnotifierpro`
|
|
|
|
|
|
- ✅ **Обновляет время** непрочитанных уведомлений
|
|
|
|
|
|
- ✅ **Игнорирует** повторные запуски для прочитанных уведомлений
|
|
|
|
|
|
|
|
|
|
|
|
**Защита работает на всех трёх уровнях!** 🛡️
|
|
|
|
|
|
|
2025-10-20 17:17:34 +03:00
|
|
|
|
|