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 []