Files
rmser/ocr-service/qr_manager.py

118 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import logging
import requests
from typing import Optional, List
from pyzbar.pyzbar import decode
from PIL import Image
import numpy as np
# Импортируем модель из parser.py
from parser import ParsedItem
API_TOKEN = "36590.yqtiephCvvkYUKM2W"
API_URL = "https://proverkacheka.com/api/v1/check/get"
logger = logging.getLogger(__name__)
def is_valid_fiscal_qr(qr_string: str) -> bool:
"""
Проверяет, соответствует ли строка формату фискального чека ФНС.
Ожидаемый формат: t=...&s=...&fn=...&i=...&fp=...&n=...
Мы проверяем наличие хотя бы 3-х ключевых параметров.
"""
if not qr_string:
return False
# Ключевые параметры, которые обязаны быть в строке чека
required_keys = ["t=", "s=", "fn="]
# Проверяем, что все ключевые параметры присутствуют
# (порядок может отличаться, поэтому проверяем вхождение каждого)
matches = [key in qr_string for key in required_keys]
return all(matches)
def detect_and_decode_qr(image: np.ndarray) -> Optional[str]:
"""
Ищет ВСЕ QR-коды на изображении и возвращает только тот,
который похож на фискальный чек.
"""
try:
pil_img = Image.fromarray(image)
# Декодируем все коды на картинке
decoded_objects = decode(pil_img)
if not decoded_objects:
logger.info("No QR codes detected on the image.")
return None
logger.info(f"Detected {len(decoded_objects)} code(s). Scanning for fiscal data...")
for obj in decoded_objects:
if obj.type == 'QRCODE':
qr_data = obj.data.decode("utf-8")
# Логируем найденное (для отладки, если вдруг формат хитрый)
# Обрезаем длинные строки, чтобы не засорять лог
log_preview = (qr_data[:75] + '..') if len(qr_data) > 75 else qr_data
logger.info(f"Checking QR content: {log_preview}")
if is_valid_fiscal_qr(qr_data):
logger.info("Valid fiscal QR found!")
return qr_data
else:
logger.info("QR skipped (not a fiscal receipt pattern).")
logger.warning("QR codes were found, but none matched the fiscal receipt format.")
return None
except Exception as e:
logger.error(f"Error during QR detection: {e}")
return None
def fetch_data_from_api(qr_raw: str) -> List[ParsedItem]:
"""
Отправляет данные QR-кода в API proverkacheka.com и парсит JSON-ответ.
"""
try:
payload = {
'qrraw': qr_raw,
'token': API_TOKEN
}
logger.info("Sending request to Check API...")
response = requests.post(API_URL, data=payload, timeout=10)
if response.status_code != 200:
logger.error(f"API Error: Status {response.status_code}")
return []
data = response.json()
if data.get('code') != 1:
logger.warning(f"API returned non-success code: {data.get('code')}")
return []
json_data = data.get('data', {}).get('json', {})
items_data = json_data.get('items', [])
parsed_items = []
for item in items_data:
price = float(item.get('price', 0)) / 100.0
total_sum = float(item.get('sum', 0)) / 100.0
quantity = float(item.get('quantity', 0))
name = item.get('name', 'Unknown')
parsed_items.append(ParsedItem(
raw_name=name,
amount=quantity,
price=price,
sum=total_sum
))
return parsed_items
except Exception as e:
logger.error(f"Error fetching/parsing API data: {e}")
return []