feat: Поддержка batch-обработки документов и умного парсинга S3 путей
Изменения в /api/n8n/documents/attach: ✅ Принимает массив документов (не одиночный объект) ✅ Умная обработка S3 путей: - /bucket/path → https://s3.twcstorage.ru/bucket/path - bucket/path → https://s3.twcstorage.ru/bucket/path - https://... → без изменений ✅ Поддержка обоих форматов полей: - file / file_url - filename / file_name ✅ Batch-обработка с детальной статистикой ✅ Возвращает результаты для каждого документа отдельно ✅ Логирование успешных и неуспешных операций Формат ответа: { total_processed: N, successful: M, failed: K, results: [...], errors: [...] } Тесты: - TEST_REAL_DATA.sh - тест с реальными данными из n8n - TEST_QUICK.sh - быстрые тесты Документация обновлена с примерами batch-обработки
This commit is contained in:
@@ -12,21 +12,47 @@ POST https://crm.clientright.ru/api/n8n/documents/attach
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Параметры запроса
|
## 📋 Формат входных данных
|
||||||
|
|
||||||
### Обязательные:
|
**Тип:** JSON массив документов
|
||||||
| Параметр | Тип | Описание | Пример |
|
|
||||||
|----------|-----|----------|--------|
|
|
||||||
| `contact_id` | string | ID контакта в vTiger | `"320096"` |
|
|
||||||
| `project_id` | string | ID проекта (полиса) в vTiger | `"396874"` |
|
|
||||||
| `file_url` | string | Полный URL файла в S3 | `"https://s3.twcstorage.ru/..."` |
|
|
||||||
| `file_name` | string | Имя файла | `"boarding_pass.pdf"` |
|
|
||||||
|
|
||||||
### Опциональные:
|
```json
|
||||||
| Параметр | Тип | Описание | Пример |
|
[
|
||||||
|----------|-----|----------|--------|
|
{
|
||||||
| `ticket_id` | string | ID заявки в HelpDesk<br/>**Если указан → привязка к заявке**<br/>**Если не указан → привязка к проекту** | `"396935"` |
|
"claim_id": "CLM-2025-11-02-WNRZZZ",
|
||||||
| `file_type` | string | Описание типа документа | `"flight_delay_boarding_or_ticket"` |
|
"event_type": "delay_flight",
|
||||||
|
"contact_id": "320096",
|
||||||
|
"project_id": "396868",
|
||||||
|
"ticket_id": "396936",
|
||||||
|
"filename": "boarding_pass.pdf",
|
||||||
|
"file_type": "flight_delay_boarding_or_ticket",
|
||||||
|
"file": "/bucket/path/to/file.pdf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Поля документа:
|
||||||
|
|
||||||
|
| Параметр | Тип | Обязательно | Описание | Пример |
|
||||||
|
|----------|-----|-------------|----------|--------|
|
||||||
|
| `contact_id` | string | ✅ Да | ID контакта в vTiger | `"320096"` |
|
||||||
|
| `project_id` | string | ✅ Да | ID проекта (полиса) в vTiger | `"396874"` |
|
||||||
|
| `file` или `file_url` | string | ✅ Да | Путь к файлу в S3 (с/без хоста) | `"/bucket/path/file.pdf"` |
|
||||||
|
| `filename` или `file_name` | string | ✅ Да | Имя файла | `"boarding_pass.pdf"` |
|
||||||
|
| `ticket_id` | string | ⚠️ Опц. | ID заявки<br/>**Если указан → HelpDesk**<br/>**Если НЕ указан → Project** | `"396935"` |
|
||||||
|
| `file_type` | string | ⚠️ Опц. | Тип документа | `"flight_delay_boarding_or_ticket"` |
|
||||||
|
| `claim_id` | string | ⚠️ Опц. | ID заявки (для логирования) | `"CLM-2025-11-02-..."` |
|
||||||
|
| `event_type` | string | ⚠️ Опц. | Тип события (для логирования) | `"delay_flight"` |
|
||||||
|
|
||||||
|
### 🔧 Умная обработка путей:
|
||||||
|
|
||||||
|
Эндпоинт автоматически определяет формат пути и добавляет хост S3 если нужно:
|
||||||
|
|
||||||
|
| Входной формат | Обработка | Результат |
|
||||||
|
|----------------|-----------|-----------|
|
||||||
|
| `/bucket/path/file.pdf` | ➕ Добавляем хост | `https://s3.twcstorage.ru/bucket/path/file.pdf` |
|
||||||
|
| `bucket/path/file.pdf` | ➕ Добавляем `/` и хост | `https://s3.twcstorage.ru/bucket/path/file.pdf` |
|
||||||
|
| `https://s3.twcstorage.ru/...` | ✅ Уже полный URL | `https://s3.twcstorage.ru/...` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -58,76 +84,137 @@ POST https://crm.clientright.ru/api/n8n/documents/attach
|
|||||||
|
|
||||||
## 📤 Примеры запросов
|
## 📤 Примеры запросов
|
||||||
|
|
||||||
### 1️⃣ Привязка к проекту (без заявки)
|
### 1️⃣ Один документ к заявке (реальный пример)
|
||||||
|
|
||||||
Используется когда файл относится к полису в целом, но еще нет конкретной заявки.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '[
|
||||||
|
{
|
||||||
|
"claim_id": "CLM-2025-11-02-WNRZZZ",
|
||||||
|
"event_type": "delay_flight",
|
||||||
"contact_id": "320096",
|
"contact_id": "320096",
|
||||||
"project_id": "396874",
|
"project_id": "396868",
|
||||||
"file_url": "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/test/policy_scan.pdf",
|
"ticket_id": "396936",
|
||||||
"file_name": "policy_E1000-302538529.pdf",
|
"filename": "flight_delay_boarding_or_ticket.pdf",
|
||||||
"file_type": "Скан полиса ERV"
|
"file_type": "flight_delay_boarding_or_ticket",
|
||||||
}'
|
"file": "/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/crm2/CRM_Active_Files/Documents/HelpDesk/ЗАЯВКА_827_396936/flight_delay_boarding_or_ticket.pdf"
|
||||||
|
}
|
||||||
|
]'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ответ:**
|
**Ответ:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"result": {
|
"total_processed": 1,
|
||||||
"document_id": "15x396940",
|
"successful": 1,
|
||||||
"document_numeric_id": "396940",
|
"failed": 0,
|
||||||
"attached_to": "project", // ✅ Привязан к проекту
|
"results": [
|
||||||
"attached_to_id": "396874",
|
{
|
||||||
"file_name": "policy_E1000-302538529.pdf",
|
"document_id": "15x396941",
|
||||||
"file_type": "Скан полиса ERV",
|
"document_numeric_id": "396941",
|
||||||
|
"attached_to": "ticket",
|
||||||
|
"attached_to_id": "396936",
|
||||||
|
"file_name": "flight_delay_boarding_or_ticket.pdf",
|
||||||
|
"file_type": "flight_delay_boarding_or_ticket",
|
||||||
"s3_bucket": "f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c",
|
"s3_bucket": "f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c",
|
||||||
"s3_key": "clientright/test/policy_scan.pdf",
|
"s3_key": "crm2/CRM_Active_Files/Documents/HelpDesk/ЗАЯВКА_827_396936/flight_delay_boarding_or_ticket.pdf",
|
||||||
"file_size": 125840,
|
"file_size": 85320,
|
||||||
"message": "Документ создан с правильными S3 метаданными и привязан к проекту"
|
"message": "Документ создан с правильными S3 метаданными и привязан к проекту"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"errors": null
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2️⃣ Привязка к заявке (HelpDesk)
|
### 2️⃣ Несколько документов за раз (batch)
|
||||||
|
|
||||||
Используется когда файл относится к конкретной заявке (страховому случаю).
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '[
|
||||||
|
{
|
||||||
"contact_id": "320096",
|
"contact_id": "320096",
|
||||||
"project_id": "396874",
|
"project_id": "396868",
|
||||||
"ticket_id": "396935", // ✅ Указан ticket_id
|
"ticket_id": "396936",
|
||||||
"file_url": "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/test/boarding_pass.pdf",
|
"filename": "boarding_pass.pdf",
|
||||||
"file_name": "boarding_pass_20251102.pdf",
|
"file_type": "flight_delay_boarding_or_ticket",
|
||||||
"file_type": "flight_delay_boarding_or_ticket"
|
"file": "/bucket/path/boarding_pass.pdf"
|
||||||
}'
|
},
|
||||||
|
{
|
||||||
|
"contact_id": "320096",
|
||||||
|
"project_id": "396868",
|
||||||
|
"ticket_id": "396936",
|
||||||
|
"filename": "delay_confirmation.pdf",
|
||||||
|
"file_type": "flight_delay_confirmation",
|
||||||
|
"file": "/bucket/path/delay_confirmation.pdf"
|
||||||
|
}
|
||||||
|
]'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ответ:**
|
**Ответ:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"result": {
|
"total_processed": 2,
|
||||||
|
"successful": 2,
|
||||||
|
"failed": 0,
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
"document_id": "15x396941",
|
"document_id": "15x396941",
|
||||||
"document_numeric_id": "396941",
|
"attached_to": "ticket",
|
||||||
"attached_to": "ticket", // ✅ Привязан к заявке
|
"file_name": "boarding_pass.pdf",
|
||||||
"attached_to_id": "396935",
|
"...": "..."
|
||||||
"file_name": "boarding_pass_20251102.pdf",
|
},
|
||||||
"file_type": "flight_delay_boarding_or_ticket",
|
{
|
||||||
"s3_bucket": "f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c",
|
"document_id": "15x396942",
|
||||||
"s3_key": "clientright/test/boarding_pass.pdf",
|
"attached_to": "ticket",
|
||||||
"file_size": 85320,
|
"file_name": "delay_confirmation.pdf",
|
||||||
"message": "Документ создан с правильными S3 метаданными и привязан к проекту"
|
"...": "..."
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"errors": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3️⃣ Привязка к проекту (без ticket_id)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '[
|
||||||
|
{
|
||||||
|
"contact_id": "320096",
|
||||||
|
"project_id": "396874",
|
||||||
|
"filename": "policy_scan.pdf",
|
||||||
|
"file_type": "Скан полиса ERV",
|
||||||
|
"file": "https://s3.twcstorage.ru/bucket/path/policy.pdf"
|
||||||
|
}
|
||||||
|
]'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"total_processed": 1,
|
||||||
|
"successful": 1,
|
||||||
|
"failed": 0,
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"document_id": "15x396940",
|
||||||
|
"attached_to": "project",
|
||||||
|
"attached_to_id": "396874",
|
||||||
|
"file_name": "policy_scan.pdf",
|
||||||
|
"...": "..."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"errors": null
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
33
TEST_QUICK.sh
Executable file
33
TEST_QUICK.sh
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Быстрый тест привязки документа
|
||||||
|
|
||||||
|
echo "🧪 Тест 1: Привязка к проекту (БЕЗ заявки)"
|
||||||
|
echo "=========================================="
|
||||||
|
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"contact_id": "320096",
|
||||||
|
"project_id": "396874",
|
||||||
|
"file_url": "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/test/test_doc.pdf",
|
||||||
|
"file_name": "test_project_doc.pdf",
|
||||||
|
"file_type": "Тестовый документ для проекта"
|
||||||
|
}' | jq .
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo "🧪 Тест 2: Привязка к заявке (С ticket_id)"
|
||||||
|
echo "=========================================="
|
||||||
|
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"contact_id": "320096",
|
||||||
|
"project_id": "396874",
|
||||||
|
"ticket_id": "396935",
|
||||||
|
"file_url": "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/test/test_doc.pdf",
|
||||||
|
"file_name": "test_ticket_doc.pdf",
|
||||||
|
"file_type": "flight_delay_boarding_or_ticket"
|
||||||
|
}' | jq .
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Тесты завершены!"
|
||||||
|
|
||||||
31
TEST_REAL_DATA.sh
Executable file
31
TEST_REAL_DATA.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Тест с реальными данными из n8n
|
||||||
|
|
||||||
|
echo "🧪 Тест привязки документа с реальными данными"
|
||||||
|
echo "=============================================="
|
||||||
|
|
||||||
|
curl -X POST "https://crm.clientright.ru/api/n8n/documents/attach" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '[
|
||||||
|
{
|
||||||
|
"claim_id": "CLM-2025-11-02-WNRZZZ",
|
||||||
|
"event_type": "delay_flight",
|
||||||
|
"contact_id": "320096",
|
||||||
|
"project_id": "396868",
|
||||||
|
"ticket_id": "396936",
|
||||||
|
"filename": "flight_delay_boarding_or_ticket.pdf",
|
||||||
|
"file_type": "flight_delay_boarding_or_ticket",
|
||||||
|
"file": "/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/crm2/CRM_Active_Files/Documents/HelpDesk/ЗАЯВКА_827_396936/flight_delay_boarding_or_ticket.pdf"
|
||||||
|
}
|
||||||
|
]' | jq .
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Тест завершен!"
|
||||||
|
echo ""
|
||||||
|
echo "Ожидаемый результат:"
|
||||||
|
echo " - success: true"
|
||||||
|
echo " - total_processed: 1"
|
||||||
|
echo " - successful: 1"
|
||||||
|
echo " - attached_to: ticket"
|
||||||
|
echo " - attached_to_id: 396936"
|
||||||
|
|
||||||
@@ -249,55 +249,96 @@ async def proxy_create_claim(request: Request):
|
|||||||
@router.post("/documents/attach")
|
@router.post("/documents/attach")
|
||||||
async def attach_document_to_crm(request: Request):
|
async def attach_document_to_crm(request: Request):
|
||||||
"""
|
"""
|
||||||
Привязывает загруженный файл к проекту или заявке в vTiger CRM
|
Привязывает загруженные файлы к проекту или заявке в vTiger CRM
|
||||||
|
|
||||||
Входные данные:
|
Входные данные (массив документов):
|
||||||
- contact_id: ID контакта
|
[
|
||||||
- project_id: ID проекта (обязательно)
|
{
|
||||||
- ticket_id: ID заявки (опционально, если указан - привязываем к заявке)
|
"claim_id": "CLM-2025-11-02-WNRZZZ",
|
||||||
- file_url: URL файла в S3
|
"contact_id": "320096",
|
||||||
- file_name: Имя файла
|
"project_id": "396868",
|
||||||
- file_type: Тип файла (описание, например: "flight_delay_boarding_or_ticket")
|
"ticket_id": "396936", // Опционально
|
||||||
|
"filename": "boarding_pass.pdf",
|
||||||
|
"file_type": "flight_delay_boarding_or_ticket",
|
||||||
|
"file": "/bucket/path/to/file.pdf" // Без хоста, добавим https://s3.twcstorage.ru
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
Логика:
|
Логика:
|
||||||
- Если указан ticket_id → привязываем к HelpDesk (заявке)
|
- Если указан ticket_id → привязываем к HelpDesk (заявке)
|
||||||
- Иначе → привязываем к Project (проекту)
|
- Иначе → привязываем к Project (проекту)
|
||||||
"""
|
"""
|
||||||
CRM_UPLOAD_ENDPOINT = "https://crm.clientright.ru/upload_documents_to_crm.php"
|
CRM_UPLOAD_ENDPOINT = "https://crm.clientright.ru/upload_documents_to_crm.php"
|
||||||
|
S3_HOST = "https://s3.twcstorage.ru"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
body = await request.json()
|
body = await request.json()
|
||||||
|
|
||||||
contact_id = body.get('contact_id')
|
# Поддерживаем как массив, так и одиночный объект
|
||||||
project_id = body.get('project_id')
|
documents_array = body if isinstance(body, list) else [body]
|
||||||
ticket_id = body.get('ticket_id') # Опционально
|
|
||||||
file_url = body.get('file_url')
|
|
||||||
file_name = body.get('file_name')
|
|
||||||
file_type = body.get('file_type', 'Документ')
|
|
||||||
|
|
||||||
# Валидация обязательных полей
|
logger.info(f"📎 Attaching {len(documents_array)} document(s)")
|
||||||
if not all([contact_id, project_id, file_url, file_name]):
|
|
||||||
|
# Обрабатываем каждый документ
|
||||||
|
processed_documents = []
|
||||||
|
for idx, doc in enumerate(documents_array):
|
||||||
|
contact_id = doc.get('contact_id')
|
||||||
|
project_id = doc.get('project_id')
|
||||||
|
ticket_id = doc.get('ticket_id') # Опционально
|
||||||
|
|
||||||
|
# Поддерживаем оба формата: file_url и file
|
||||||
|
file_path = doc.get('file') or doc.get('file_url')
|
||||||
|
if not file_path:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=400,
|
status_code=400,
|
||||||
detail="Обязательные поля: contact_id, project_id, file_url, file_name"
|
detail=f"Document #{idx}: отсутствует поле 'file' или 'file_url'"
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"📎 Attaching document: {file_name} (type: {file_type})")
|
# Строим полный S3 URL если это путь без хоста
|
||||||
logger.info(f" Contact: {contact_id}, Project: {project_id}, Ticket: {ticket_id or 'N/A'}")
|
if file_path.startswith('/'):
|
||||||
|
file_url = S3_HOST + file_path
|
||||||
|
elif not file_path.startswith('http'):
|
||||||
|
file_url = S3_HOST + '/' + file_path
|
||||||
|
else:
|
||||||
|
file_url = file_path
|
||||||
|
|
||||||
# Формируем payload для upload_documents_to_crm.php
|
# Поддерживаем оба формата: file_name и filename
|
||||||
upload_payload = {
|
file_name = doc.get('filename') or doc.get('file_name')
|
||||||
"documents": [
|
if not file_name:
|
||||||
{
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"Document #{idx}: отсутствует поле 'filename' или 'file_name'"
|
||||||
|
)
|
||||||
|
|
||||||
|
file_type = doc.get('file_type', 'Документ')
|
||||||
|
|
||||||
|
# Валидация обязательных полей
|
||||||
|
if not all([contact_id, project_id]):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"Document #{idx}: обязательные поля: contact_id, project_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(f" [{idx+1}/{len(documents_array)}] {file_name} (type: {file_type})")
|
||||||
|
logger.info(f" Contact: {contact_id}, Project: {project_id}, Ticket: {ticket_id or 'N/A'}")
|
||||||
|
logger.info(f" File URL: {file_url}")
|
||||||
|
|
||||||
|
processed_documents.append({
|
||||||
"file_url": file_url,
|
"file_url": file_url,
|
||||||
"file_name": file_name,
|
"file_name": file_name,
|
||||||
"upload_description": file_type,
|
"upload_description": file_type,
|
||||||
"contactid": int(contact_id),
|
"contactid": int(contact_id),
|
||||||
"pages": 1
|
"pages": 1
|
||||||
}
|
})
|
||||||
],
|
|
||||||
"projectid": int(project_id),
|
# Берем общие параметры из первого документа
|
||||||
"ticket_id": int(ticket_id) if ticket_id else None, # Передаем ticket_id если есть
|
first_doc = documents_array[0]
|
||||||
|
|
||||||
|
# Формируем payload для upload_documents_to_crm.php
|
||||||
|
upload_payload = {
|
||||||
|
"documents": processed_documents,
|
||||||
|
"projectid": int(first_doc.get('project_id')),
|
||||||
|
"ticket_id": int(first_doc.get('ticket_id')) if first_doc.get('ticket_id') else None,
|
||||||
"user_id": 1
|
"user_id": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,31 +361,53 @@ async def attach_document_to_crm(request: Request):
|
|||||||
|
|
||||||
# Проверяем успешность
|
# Проверяем успешность
|
||||||
if result.get('success') and result.get('results'):
|
if result.get('success') and result.get('results'):
|
||||||
first_result = result['results'][0]
|
results_array = result['results']
|
||||||
|
|
||||||
if first_result.get('status') == 'success':
|
# Обрабатываем результаты для каждого документа
|
||||||
crm_result = first_result.get('crm_result', {})
|
processed_results = []
|
||||||
|
errors = []
|
||||||
|
|
||||||
return {
|
for idx, res in enumerate(results_array):
|
||||||
"success": True,
|
if res.get('status') == 'success':
|
||||||
"result": {
|
crm_result = res.get('crm_result', {})
|
||||||
|
|
||||||
|
processed_results.append({
|
||||||
"document_id": crm_result.get('document_id'),
|
"document_id": crm_result.get('document_id'),
|
||||||
"document_numeric_id": crm_result.get('document_numeric_id'),
|
"document_numeric_id": crm_result.get('document_numeric_id'),
|
||||||
"attached_to": "ticket" if ticket_id else "project",
|
"attached_to": "ticket" if res.get('ticket_id') else "project",
|
||||||
"attached_to_id": ticket_id if ticket_id else project_id,
|
"attached_to_id": res.get('ticket_id') or res.get('projectid'),
|
||||||
"file_name": file_name,
|
"file_name": res.get('file_name'),
|
||||||
"file_type": file_type,
|
"file_type": res.get('description'),
|
||||||
"s3_bucket": crm_result.get('s3_bucket'),
|
"s3_bucket": crm_result.get('s3_bucket'),
|
||||||
"s3_key": crm_result.get('s3_key'),
|
"s3_key": crm_result.get('s3_key'),
|
||||||
"file_size": crm_result.get('file_size'),
|
"file_size": crm_result.get('file_size'),
|
||||||
"message": crm_result.get('message')
|
"message": crm_result.get('message')
|
||||||
}
|
})
|
||||||
|
|
||||||
|
logger.info(f" ✅ [{idx+1}] {res.get('file_name')} → {crm_result.get('document_id')}")
|
||||||
|
else:
|
||||||
|
# Ошибка для конкретного документа
|
||||||
|
error_msg = res.get('crm_result', {}).get('message', 'Unknown error')
|
||||||
|
errors.append({
|
||||||
|
"file_name": res.get('file_name'),
|
||||||
|
"error": error_msg
|
||||||
|
})
|
||||||
|
logger.error(f" ❌ [{idx+1}] {res.get('file_name')}: {error_msg}")
|
||||||
|
|
||||||
|
# Если есть хотя бы один успешный результат - считаем успехом
|
||||||
|
if processed_results:
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"total_processed": len(results_array),
|
||||||
|
"successful": len(processed_results),
|
||||||
|
"failed": len(errors),
|
||||||
|
"results": processed_results,
|
||||||
|
"errors": errors if errors else None
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
# Ошибка в CRM
|
# Все документы упали с ошибкой
|
||||||
error_msg = first_result.get('crm_result', {}).get('message', 'Unknown error')
|
logger.error(f"❌ All documents failed: {errors}")
|
||||||
logger.error(f"❌ CRM error: {error_msg}")
|
raise HTTPException(status_code=500, detail=f"Все документы не удалось привязать: {errors}")
|
||||||
raise HTTPException(status_code=500, detail=f"CRM error: {error_msg}")
|
|
||||||
else:
|
else:
|
||||||
logger.error(f"❌ Unexpected CRM response: {result}")
|
logger.error(f"❌ Unexpected CRM response: {result}")
|
||||||
raise HTTPException(status_code=500, detail="Неожиданный ответ от CRM")
|
raise HTTPException(status_code=500, detail="Неожиданный ответ от CRM")
|
||||||
|
|||||||
Reference in New Issue
Block a user