qr-manager fixed for both qr-codes

This commit is contained in:
2025-11-29 13:26:41 +03:00
parent 91923b8616
commit da62ea5b98
3 changed files with 131 additions and 12 deletions

View File

@@ -5,33 +5,67 @@ from pyzbar.pyzbar import decode
from PIL import Image
import numpy as np
# Импортируем модель из parser.py, чтобы типы совпадали!
# Импортируем модель из 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-код на изображении и вернуть его сырое содержимое.
Ищет ВСЕ QR-коды на изображении и возвращает только тот,
который похож на фискальный чек.
"""
try:
# Pyzbar лучше работает с PIL Image
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")
logger.info(f"QR Code detected: {qr_data}")
return qr_data
# Логируем найденное (для отладки, если вдруг формат хитрый)
# Обрезаем длинные строки, чтобы не засорять лог
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
@@ -55,7 +89,6 @@ def fetch_data_from_api(qr_raw: str) -> List[ParsedItem]:
data = response.json()
# Проверяем успешность ответа (code: 1 - успех)
if data.get('code') != 1:
logger.warning(f"API returned non-success code: {data.get('code')}")
return []
@@ -66,7 +99,6 @@ def fetch_data_from_api(qr_raw: str) -> List[ParsedItem]:
parsed_items = []
for item in items_data:
# API возвращает цены в копейках (int), нужно делить на 100
price = float(item.get('price', 0)) / 100.0
total_sum = float(item.get('sum', 0)) / 100.0
quantity = float(item.get('quantity', 0))