262 lines
12 KiB
Python
262 lines
12 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
Скрипт для исправления черновика bddb6815-8e17-4d54-a721-5e94382942c7
|
|||
|
|
Добавляет documents_required и обновляет статус с учётом уже загруженного договора
|
|||
|
|
"""
|
|||
|
|
import asyncio
|
|||
|
|
import asyncpg
|
|||
|
|
import json
|
|||
|
|
from datetime import datetime
|
|||
|
|
|
|||
|
|
# Параметры подключения к БД
|
|||
|
|
POSTGRES_HOST = "147.45.189.234"
|
|||
|
|
POSTGRES_PORT = 5432
|
|||
|
|
POSTGRES_DB = "default_db"
|
|||
|
|
POSTGRES_USER = "gen_user"
|
|||
|
|
POSTGRES_PASSWORD = "2~~9_^kVsU?2\\S"
|
|||
|
|
|
|||
|
|
CLAIM_ID = "bddb6815-8e17-4d54-a721-5e94382942c7"
|
|||
|
|
|
|||
|
|
DOCUMENTS_REQUIRED = [
|
|||
|
|
{
|
|||
|
|
"id": "contract",
|
|||
|
|
"name": "Договор или заказ",
|
|||
|
|
"hints": "Фото или скан подписанного договора или квитанции",
|
|||
|
|
"accept": ["pdf", "jpg", "png"],
|
|||
|
|
"priority": 1,
|
|||
|
|
"required": True
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "payment",
|
|||
|
|
"name": "Чек или подтверждение оплаты",
|
|||
|
|
"hints": "Копия кассового чека, онлайн-платежа или квитанции",
|
|||
|
|
"accept": ["pdf", "jpg", "png"],
|
|||
|
|
"priority": 1,
|
|||
|
|
"required": True
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "correspondence",
|
|||
|
|
"name": "Переписка",
|
|||
|
|
"hints": "Скриншоты сообщений, писем, жалоб",
|
|||
|
|
"accept": ["pdf", "jpg", "png"],
|
|||
|
|
"priority": 2,
|
|||
|
|
"required": False
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "evidence_photo",
|
|||
|
|
"name": "Фото доказательства",
|
|||
|
|
"hints": "Фото дефектов товара, видео процесса ремонта или передачи",
|
|||
|
|
"accept": ["jpg", "png", "pdf"],
|
|||
|
|
"priority": 2,
|
|||
|
|
"required": False
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def fix_draft():
|
|||
|
|
"""Исправляет черновик: добавляет documents_required и обновляет статус"""
|
|||
|
|
conn = await asyncpg.connect(
|
|||
|
|
host=POSTGRES_HOST,
|
|||
|
|
port=POSTGRES_PORT,
|
|||
|
|
database=POSTGRES_DB,
|
|||
|
|
user=POSTGRES_USER,
|
|||
|
|
password=POSTGRES_PASSWORD
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# Получаем текущее состояние черновика
|
|||
|
|
row = await conn.fetchrow("""
|
|||
|
|
SELECT id, status_code, payload
|
|||
|
|
FROM clpr_claims
|
|||
|
|
WHERE id::text = $1 OR payload->>'claim_id' = $1
|
|||
|
|
ORDER BY updated_at DESC
|
|||
|
|
LIMIT 1
|
|||
|
|
""", CLAIM_ID)
|
|||
|
|
|
|||
|
|
if not row:
|
|||
|
|
print(f"❌ Черновик {CLAIM_ID} не найден!")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
payload = row['payload'] if isinstance(row['payload'], dict) else json.loads(row['payload'])
|
|||
|
|
current_status = row['status_code']
|
|||
|
|
|
|||
|
|
print(f"📋 Текущее состояние черновика:")
|
|||
|
|
print(f" - status_code: {current_status}")
|
|||
|
|
print(f" - documents_required: {len(payload.get('documents_required', []))} шт.")
|
|||
|
|
print(f" - documents_uploaded: {len(payload.get('documents_uploaded', []))} шт.")
|
|||
|
|
print(f" - documents_meta: {len(payload.get('documents_meta', []))} шт.")
|
|||
|
|
|
|||
|
|
# Проверяем documents_meta на наличие загруженных документов
|
|||
|
|
documents_meta = payload.get('documents_meta', [])
|
|||
|
|
existing_documents_uploaded = payload.get('documents_uploaded', [])
|
|||
|
|
|
|||
|
|
# Функция для определения типа документа (сначала по field_label, потом по field_name)
|
|||
|
|
def get_document_type(field_label: str, field_name: str) -> str:
|
|||
|
|
field_label_lower = field_label.lower()
|
|||
|
|
# ✅ СНАЧАЛА проверяем field_label (более точный способ)
|
|||
|
|
if 'договор' in field_label_lower or 'заказ' in field_label_lower:
|
|||
|
|
return 'contract'
|
|||
|
|
elif 'чек' in field_label_lower or 'оплат' in field_label_lower:
|
|||
|
|
return 'payment'
|
|||
|
|
elif 'переписк' in field_label_lower:
|
|||
|
|
return 'correspondence'
|
|||
|
|
elif 'доказательств' in field_label_lower or 'фото' in field_label_lower:
|
|||
|
|
return 'evidence_photo'
|
|||
|
|
# ✅ ПОТОМ проверяем field_name (fallback)
|
|||
|
|
elif 'uploads[0]' in field_name:
|
|||
|
|
return 'contract'
|
|||
|
|
elif 'uploads[1]' in field_name:
|
|||
|
|
return 'payment'
|
|||
|
|
elif 'uploads[2]' in field_name:
|
|||
|
|
return 'correspondence'
|
|||
|
|
elif 'uploads[3]' in field_name:
|
|||
|
|
return 'evidence_photo'
|
|||
|
|
else:
|
|||
|
|
return 'unknown'
|
|||
|
|
|
|||
|
|
# ✅ Объединяем существующие documents_uploaded с documents_meta
|
|||
|
|
# Создаём мапу file_id -> doc_meta для быстрого поиска
|
|||
|
|
meta_by_file_id = {}
|
|||
|
|
if documents_meta:
|
|||
|
|
print(f"\n🔍 Найдено {len(documents_meta)} документов в documents_meta")
|
|||
|
|
for doc_meta in documents_meta:
|
|||
|
|
file_id = doc_meta.get('file_id', '')
|
|||
|
|
if file_id:
|
|||
|
|
meta_by_file_id[file_id] = doc_meta
|
|||
|
|
|
|||
|
|
# ✅ Пересоздаём documents_uploaded: объединяем существующие с данными из documents_meta
|
|||
|
|
documents_uploaded = []
|
|||
|
|
seen_file_ids = set()
|
|||
|
|
|
|||
|
|
# Сначала обрабатываем documents_meta (приоритет)
|
|||
|
|
for doc_meta in documents_meta:
|
|||
|
|
file_id = doc_meta.get('file_id', '')
|
|||
|
|
if not file_id or file_id in seen_file_ids:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
field_label = doc_meta.get('field_label', '')
|
|||
|
|
field_name = doc_meta.get('field_name', '')
|
|||
|
|
doc_type = get_document_type(field_label, field_name)
|
|||
|
|
|
|||
|
|
if doc_type != 'unknown':
|
|||
|
|
seen_file_ids.add(file_id)
|
|||
|
|
documents_uploaded.append({
|
|||
|
|
"id": doc_type,
|
|||
|
|
"type": doc_type,
|
|||
|
|
"file_id": file_id,
|
|||
|
|
"file_name": doc_meta.get('file_name', ''),
|
|||
|
|
"original_file_name": doc_meta.get('original_file_name', ''),
|
|||
|
|
"uploaded_at": doc_meta.get('uploaded_at', datetime.utcnow().isoformat()),
|
|||
|
|
"ocr_status": "completed",
|
|||
|
|
"files_count": doc_meta.get('files_count', 1),
|
|||
|
|
"pages": doc_meta.get('pages', None)
|
|||
|
|
})
|
|||
|
|
print(f" ✅ Из documents_meta: {doc_type} ({field_label}) - {doc_meta.get('original_file_name', 'N/A')}")
|
|||
|
|
|
|||
|
|
# Затем добавляем существующие documents_uploaded, которых нет в documents_meta
|
|||
|
|
for existing_doc in existing_documents_uploaded:
|
|||
|
|
file_id = existing_doc.get('file_id', '')
|
|||
|
|
if not file_id or file_id in seen_file_ids:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
# Если есть в documents_meta - пропускаем (уже обработали)
|
|||
|
|
if file_id in meta_by_file_id:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
# Используем существующий тип или пытаемся определить по file_name
|
|||
|
|
doc_type = existing_doc.get('type') or existing_doc.get('id') or 'unknown'
|
|||
|
|
|
|||
|
|
# Если тип неправильный (например, contract вместо payment), пытаемся определить по file_name
|
|||
|
|
if doc_type == 'contract' and 'chek' in file_id.lower():
|
|||
|
|
doc_type = 'payment'
|
|||
|
|
elif doc_type == 'contract' and 'dogovor' in file_id.lower():
|
|||
|
|
doc_type = 'contract'
|
|||
|
|
|
|||
|
|
seen_file_ids.add(file_id)
|
|||
|
|
documents_uploaded.append({
|
|||
|
|
"id": doc_type,
|
|||
|
|
"type": doc_type,
|
|||
|
|
"file_id": file_id,
|
|||
|
|
"file_name": existing_doc.get('file_name', ''),
|
|||
|
|
"original_file_name": existing_doc.get('original_file_name', ''),
|
|||
|
|
"uploaded_at": existing_doc.get('uploaded_at', datetime.utcnow().isoformat()),
|
|||
|
|
"ocr_status": existing_doc.get('ocr_status', 'completed'),
|
|||
|
|
"files_count": existing_doc.get('files_count', 1),
|
|||
|
|
"pages": existing_doc.get('pages', None)
|
|||
|
|
})
|
|||
|
|
print(f" ✅ Из существующих: {doc_type} - {existing_doc.get('original_file_name', 'N/A')}")
|
|||
|
|
|
|||
|
|
# Определяем current_doc_index (индекс следующего документа для загрузки)
|
|||
|
|
# Убираем дубликаты по типу документа
|
|||
|
|
uploaded_types = list(set([doc.get('id') or doc.get('type') for doc in documents_uploaded]))
|
|||
|
|
current_doc_index = 0
|
|||
|
|
|
|||
|
|
# Находим первый незагруженный документ
|
|||
|
|
for idx, doc_req in enumerate(DOCUMENTS_REQUIRED):
|
|||
|
|
if doc_req['id'] not in uploaded_types:
|
|||
|
|
current_doc_index = idx
|
|||
|
|
break
|
|||
|
|
else:
|
|||
|
|
# Все документы загружены
|
|||
|
|
current_doc_index = len(DOCUMENTS_REQUIRED)
|
|||
|
|
|
|||
|
|
# Определяем новый статус (учитываем уникальные типы документов)
|
|||
|
|
uploaded_unique_types = len(uploaded_types)
|
|||
|
|
if uploaded_unique_types >= len(DOCUMENTS_REQUIRED):
|
|||
|
|
new_status = 'draft_docs_complete'
|
|||
|
|
elif uploaded_unique_types > 0:
|
|||
|
|
new_status = 'draft_docs_progress'
|
|||
|
|
else:
|
|||
|
|
new_status = 'draft_new'
|
|||
|
|
|
|||
|
|
# Обновляем payload
|
|||
|
|
payload['documents_required'] = DOCUMENTS_REQUIRED
|
|||
|
|
payload['documents_uploaded'] = documents_uploaded
|
|||
|
|
payload['current_doc_index'] = current_doc_index
|
|||
|
|
|
|||
|
|
print(f"\n📝 Обновление черновика:")
|
|||
|
|
print(f" - documents_required: {len(DOCUMENTS_REQUIRED)} документов")
|
|||
|
|
print(f" - documents_uploaded: {len(documents_uploaded)} документов")
|
|||
|
|
print(f" - current_doc_index: {current_doc_index} (следующий документ: {DOCUMENTS_REQUIRED[current_doc_index]['name'] if current_doc_index < len(DOCUMENTS_REQUIRED) else 'все загружены'})")
|
|||
|
|
print(f" - status_code: {current_status} → {new_status}")
|
|||
|
|
|
|||
|
|
# Обновляем черновик
|
|||
|
|
await conn.execute("""
|
|||
|
|
UPDATE clpr_claims
|
|||
|
|
SET
|
|||
|
|
status_code = $1,
|
|||
|
|
payload = $2::jsonb,
|
|||
|
|
updated_at = now()
|
|||
|
|
WHERE id::text = $3 OR payload->>'claim_id' = $3
|
|||
|
|
""", new_status, json.dumps(payload, ensure_ascii=False), CLAIM_ID)
|
|||
|
|
|
|||
|
|
print(f"\n✅ Черновик исправлен!")
|
|||
|
|
|
|||
|
|
# Проверяем результат
|
|||
|
|
row_after = await conn.fetchrow("""
|
|||
|
|
SELECT
|
|||
|
|
id::text,
|
|||
|
|
status_code,
|
|||
|
|
jsonb_array_length(COALESCE(payload->'documents_required', '[]'::jsonb)) as docs_required_count,
|
|||
|
|
jsonb_array_length(COALESCE(payload->'documents_uploaded', '[]'::jsonb)) as docs_uploaded_count,
|
|||
|
|
(payload->>'current_doc_index')::int as current_doc_index
|
|||
|
|
FROM clpr_claims
|
|||
|
|
WHERE id::text = $1 OR payload->>'claim_id' = $1
|
|||
|
|
ORDER BY updated_at DESC
|
|||
|
|
LIMIT 1
|
|||
|
|
""", CLAIM_ID)
|
|||
|
|
|
|||
|
|
print(f"\n📊 Результат:")
|
|||
|
|
print(f" - status_code: {row_after['status_code']}")
|
|||
|
|
print(f" - documents_required count: {row_after['docs_required_count']}")
|
|||
|
|
print(f" - documents_uploaded count: {row_after['docs_uploaded_count']}")
|
|||
|
|
print(f" - current_doc_index: {row_after['current_doc_index']}")
|
|||
|
|
|
|||
|
|
finally:
|
|||
|
|
await conn.close()
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
asyncio.run(fix_draft())
|
|||
|
|
|