dodalem backend dzialajacy

This commit is contained in:
2026-04-20 23:21:16 +02:00
parent 4707a49e06
commit 5361806f34
9 changed files with 468 additions and 303 deletions

139
backend/mayo/client.py Normal file
View File

@@ -0,0 +1,139 @@
import httpx
import logging
from typing import List, Optional
from .exceptions import MayoConnectionError, MayoResponseError, MayoAuthError, MayoOrderNotFound
from .parser import MayoParser
from .models import MayoSearchResult, MayoGuitarDetails, MayoResponse
logger = logging.getLogger(__name__)
class MayoClient:
def __init__(self, base_url: str, login: str, password: str, db: str = "1"):
self.base_url = base_url.rstrip("/")
self.credentials = {
"login": login,
"pass": password,
"baza": db,
}
self.client: httpx.AsyncClient | None = None
async def __aenter__(self):
self.client = httpx.AsyncClient(
base_url=self.base_url,
follow_redirects=True,
timeout=30.0,
)
try:
await self.login()
return self
except Exception:
await self.client.aclose()
self.client = None
raise
async def __aexit__(self, exc_type, exc_val, exc_tb):
if self.client is not None:
await self.client.aclose()
self.client = None
def _require_client(self) -> httpx.AsyncClient:
if self.client is None:
raise RuntimeError(
"HTTP client is not initialized. Use 'async with MayoClient(...) as client:' first."
)
return self.client
async def login(self):
client = self._require_client()
try:
response = await client.post("/login.php", data=self.credentials)
response.raise_for_status()
except httpx.TimeoutException as exc:
raise MayoConnectionError(
f"Mayo connection failed during login: timeout for {self.base_url}/login.php"
) from exc
except httpx.RequestError as exc:
raise MayoConnectionError(
f"Mayo connection failed during login: {exc}"
) from exc
except httpx.HTTPStatusError as exc:
raise MayoResponseError(
f"Mayo returned HTTP {exc.response.status_code} during login"
) from exc
if "Zaloguj się" in response.text or "login" in str(response.url):
raise MayoAuthError(
"Mayo login failed: invalid credentials or login page was returned again"
)
logger.info("✅ Zalogowano poprawnie do systemu Mayo.")
async def search_order(self, order_number: str) -> List[MayoSearchResult]:
"""Wyszukuje zamówienia na podstawie numeru."""
# Formatowanie numeru zamówienia (np. 0027)
formatted_nr = str(order_number).zfill(4)
params = {
"filtr": "1",
"strona": "0",
"sort_order": "1"
}
payload = {
"zaw": "",
"r_od": "",
"nr_zam": formatted_nr,
"typ_kl": "",
"klient": "",
"r_do": "",
"row_count": "25"
}
client = self._require_client()
response = await client.post("/index.php", params=params, data=payload)
return MayoParser.parse_search_results(response.text, self.base_url)
async def get_guitar_links(self, order_url: str) -> List[str]:
"""Pobiera listę linków do konkretnych instrumentów w zamówieniu."""
client = self._require_client()
response = await client.get(order_url)
return MayoParser.parse_guitar_links(response.text, self.base_url)
async def get_guitar_details(self, guitar_url: str) -> MayoGuitarDetails:
"""Pobiera szczegóły konkretnego instrumentu."""
client = self._require_client()
response = await client.get(guitar_url)
return MayoParser.parse_specification(response.text)
async def get_full_order_data(self, order_num: str, year: str, item_idx: str) -> MayoResponse:
orders = await self.search_order(order_num)
order = next((order for order in orders if order.order_id == f"{order_num}/{year}"), None)
if order is None:
raise MayoOrderNotFound(f"Order {order_num}/{year} was not found")
guitars_url = await self.get_guitar_links(order.url)
guitar_index = int(item_idx) - 1
if guitar_index < 0 or guitar_index >= len(guitars_url):
raise MayoOrderNotFound(
f"Product {order_num}/{year}/{item_idx} was not found"
)
guitar_url = guitars_url[guitar_index]
details = await self.get_guitar_details(guitar_url)
return MayoResponse(
order_number=details.order_number,
completion_date=details.completion_date,
prod_list=order.prod_list,
url=guitar_url,
client=details.client,
model=details.model,
spec=details.spec,
)