From 593e8960b75a734f7b689ac8b6cf7b3300e29132 Mon Sep 17 00:00:00 2001 From: zman Date: Sun, 13 Apr 2025 22:34:47 -0400 Subject: [PATCH] clean --- app.log | 25 +-- app/main.py | 44 ++--- .../external_api/mtgjson/mtgjson_service.py | 2 +- .../tcgplayer/order_management_service.py | 5 +- app/services/print_service.py | 182 ------------------ app/services/scheduler/base_scheduler.py | 10 +- 6 files changed, 40 insertions(+), 228 deletions(-) delete mode 100644 app/services/print_service.py diff --git a/app.log b/app.log index 75fd9da..bb6e189 100644 --- a/app.log +++ b/app.log @@ -1,18 +1,7 @@ -2025-04-13 17:07:45,221 - INFO - app.main - Application starting up... -2025-04-13 17:07:45,277 - INFO - app.main - Database initialized successfully -2025-04-13 17:07:51,378 - INFO - app.services.label_printer_service - Converting PDF app/data/cache/tcgplayer/orders/packing_slip_2025-04-13.pdf to images -2025-04-13 17:07:51,467 - INFO - app.services.label_printer_service - Successfully converted PDF to 3 images -2025-04-13 17:07:51,467 - INFO - app.services.label_printer_service - Processing page 1 with dimensions (1700, 2200) -2025-04-13 17:08:10,149 - INFO - app.services.label_printer_service - Processing page 2 with dimensions (1700, 2200) -2025-04-13 17:08:14,940 - INFO - app.services.label_printer_service - Processing page 3 with dimensions (1700, 2200) -2025-04-13 17:08:19,947 - INFO - app.services.label_printer_service - Converting PDF app/data/cache/tcgplayer/address_labels/E576ED4C-491FAE-B9A96_dk1241.pdf to images -2025-04-13 17:08:19,992 - INFO - app.services.label_printer_service - Successfully converted PDF to 1 images -2025-04-13 17:08:19,992 - INFO - app.services.label_printer_service - Processing page 1 with dimensions (1200, 800) -2025-04-13 17:08:23,373 - INFO - app.services.label_printer_service - Converting PDF app/data/cache/tcgplayer/address_labels/E576ED4C-F69424-87265_dk1241.pdf to images -2025-04-13 17:08:23,415 - INFO - app.services.label_printer_service - Successfully converted PDF to 1 images -2025-04-13 17:08:23,415 - INFO - app.services.label_printer_service - Processing page 1 with dimensions (1200, 800) -2025-04-13 17:08:26,780 - INFO - app.services.label_printer_service - Converting PDF app/data/cache/tcgplayer/address_labels/E576ED4C-CD078B-CE881_dk1241.pdf to images -2025-04-13 17:08:26,822 - INFO - app.services.label_printer_service - Successfully converted PDF to 1 images -2025-04-13 17:08:26,823 - INFO - app.services.label_printer_service - Processing page 1 with dimensions (1200, 800) -2025-04-13 17:08:30,128 - INFO - app.main - TCGPlayer data initialized successfully -2025-04-13 17:08:30,128 - INFO - app.main - Scheduler started successfully +2025-04-13 21:40:14,498 - INFO - app.main - Application starting up... +2025-04-13 21:40:14,714 - INFO - app.main - Database initialized successfully +2025-04-13 21:40:14,714 - INFO - app.main - TCGPlayer data initialized successfully +2025-04-13 21:40:14,715 - INFO - app.main - Scheduler started successfully +2025-04-13 21:40:17,147 - WARNING - app.services.scheduler.base_scheduler - Event loop already closed, skipping scheduler shutdown +2025-04-13 21:40:17,147 - INFO - app.main - Scheduler shut down +2025-04-13 21:40:17,148 - INFO - app.main - Database connection closed diff --git a/app/main.py b/app/main.py index 92b848e..e1534f9 100644 --- a/app/main.py +++ b/app/main.py @@ -12,7 +12,6 @@ from datetime import datetime from app.services.external_api.tcgplayer.order_management_service import OrderManagementService from app.services.address_label_service import AddressLabelService from app.services.pull_sheet_service import PullSheetService -from app.services.print_service import PrintService from app.services.label_printer_service import LabelPrinterService from app.services.regular_printer_service import RegularPrinterService # Configure logging @@ -46,7 +45,6 @@ data_init_service = DataInitializationService() order_management_service = OrderManagementService() address_label_service = AddressLabelService() pull_sheet_service = PullSheetService() -#print_service = PrintService(printer_name="MFCL2750DW-3", printer_api_url="http://192.168.1.110:8000/print") label_printer_service = LabelPrinterService(printer_api_url="http://192.168.1.110:8000") regular_printer_service = RegularPrinterService(printer_name="MFCL2750DW-3") @asynccontextmanager @@ -59,40 +57,38 @@ async def lifespan(app: FastAPI): db = SessionLocal() try: #await data_init_service.initialize_data(db, game_ids=[1, 3], init_archived_prices=False, archived_prices_start_date="2025-01-01", archived_prices_end_date=datetime.now().strftime("%Y-%m-%d"), init_categories=True, init_groups=True, init_products=True) # 1 = Magic, 3 = Pokemon - orders = await order_management_service.get_orders() - ready_orders = [order for order in orders if order.get("orderStatus") == "Ready to Ship"] - #logger.info(ready_orders) + #orders = await order_management_service.get_orders(open_only=True) - order_ids = [order.get("orderNumber") for order in ready_orders] + #order_ids = [order.get("orderNumber") for order in orders] # get only the first 3 order ids - order_ids = order_ids[:3] + #order_ids = order_ids[:3] #logger.info(order_ids) - packing_slip = await order_management_service.get_packing_slip(order_ids) - packing_slip_file = await order_management_service.save_file(packing_slip, f"packing_slip_{datetime.now().strftime('%Y-%m-%d')}.pdf") - await label_printer_service.print_file(packing_slip_file, label_size="dk1241", label_type="packing_slip") + #packing_slip = await order_management_service.get_packing_slip(order_ids) + #packing_slip_file = await order_management_service.save_file(packing_slip, f"packing_slip_{datetime.now().strftime('%Y-%m-%d')}.pdf") + #await label_printer_service.print_file(packing_slip_file, label_size="dk1241", label_type="packing_slip") #pull_sheet = await order_management_service.get_pull_sheet(order_ids) #pull_sheet_file = await order_management_service.save_file(pull_sheet, f"pull_sheet_{datetime.now().strftime('%Y-%m-%d')}.csv") #await regular_printer_service.print_file(pull_sheet_file) - shipping_csv = await order_management_service.get_shipping_csv(order_ids) - shipping_csv_file = await order_management_service.save_file(shipping_csv, f"shipping_csv_{datetime.now().strftime('%Y-%m-%d')}.csv") + #shipping_csv = await order_management_service.get_shipping_csv(order_ids) + #shipping_csv_file = await order_management_service.save_file(shipping_csv, f"shipping_csv_{datetime.now().strftime('%Y-%m-%d')}.csv") # Wait for the file to be saved before generating labels - if not shipping_csv_file: - logger.error("Failed to save shipping CSV file") - return + #if not shipping_csv_file: + # logger.error("Failed to save shipping CSV file") + # return - shipping_labels_dk1241 = address_label_service.generate_labels_from_csv(shipping_csv_file, label_type="dk1241") - if not shipping_labels_dk1241: - logger.error("Failed to generate shipping labels") - return + #shipping_labels_dk1241 = address_label_service.generate_labels_from_csv(shipping_csv_file, label_type="dk1241") + #if not shipping_labels_dk1241: + # logger.error("Failed to generate shipping labels") + # return - for label in shipping_labels_dk1241: - if not label: - logger.error("Empty label path in shipping labels list") - continue - await label_printer_service.print_file(label, label_size="dk1241", label_type="address_label") + #for label in shipping_labels_dk1241: + # if not label: + # logger.error("Empty label path in shipping labels list") + # continue + # await label_printer_service.print_file(label, label_size="dk1241", label_type="address_label") logger.info("TCGPlayer data initialized successfully") diff --git a/app/services/external_api/mtgjson/mtgjson_service.py b/app/services/external_api/mtgjson/mtgjson_service.py index 5ffe721..5beb6c6 100644 --- a/app/services/external_api/mtgjson/mtgjson_service.py +++ b/app/services/external_api/mtgjson/mtgjson_service.py @@ -272,7 +272,7 @@ class MTGJSONService: "sku_id": str(sku.get("skuId")), "product_id": str(sku.get("productId")), "condition": sku.get("condition"), - "finish": sku.get("finish", "NORMAL"), # Default to NORMAL if not specified + "finish": sku.get("finish"), "language": sku.get("language"), "printing": sku.get("printing"), "card_id": card_uuid, diff --git a/app/services/external_api/tcgplayer/order_management_service.py b/app/services/external_api/tcgplayer/order_management_service.py index 7a67d42..16b6037 100644 --- a/app/services/external_api/tcgplayer/order_management_service.py +++ b/app/services/external_api/tcgplayer/order_management_service.py @@ -20,7 +20,7 @@ class OrderManagementService(BaseTCGPlayerService): self.shipping_endpoint = f"/shipping/export{self.API_VERSION}" - async def get_orders(self): + async def get_orders(self, open_only: bool = False): search_from = 0 orders = [] while True: @@ -36,6 +36,9 @@ class OrderManagementService(BaseTCGPlayerService): "from": search_from, "size": 25 } + if open_only: + payload["filters"]["orderStatus"] = ["Processing","ReadyToShip","Received","Pulling","ReadyForPickup"] + payload["filters"]["fulfillmentTypes"] = ["Normal"] response = await self._make_request("POST", self.order_search_endpoint, data=payload, headers=self._get_headers("POST", "application/json"), auth_required=True) if len(response.get("orders")) == 0: break diff --git a/app/services/print_service.py b/app/services/print_service.py deleted file mode 100644 index 6ac5f8a..0000000 --- a/app/services/print_service.py +++ /dev/null @@ -1,182 +0,0 @@ -from typing import Optional, Union, Literal -import os -import aiohttp -import cups -from pathlib import Path -from pdf2image import convert_from_path -from brother_ql.conversion import convert -from brother_ql.raster import BrotherQLRaster -import logging -import asyncio -import time -from datetime import datetime, timedelta - -logger = logging.getLogger(__name__) - -class PrintService: - def __init__(self, printer_name: Optional[str] = None, printer_api_url: str = "http://localhost:8000/print", - min_print_interval: int = 30): - """Initialize the print service. - - Args: - printer_name: Name of the printer to use. If None, will use default printer. - printer_api_url: URL of the printer API endpoint - min_print_interval: Minimum time in seconds between print requests for label printer - """ - self.printer_name = printer_name - self.printer_api_url = printer_api_url - self.status_url = printer_api_url.replace('/print', '/status') - self.conn = cups.Connection() - self.cache_dir = Path("app/data/cache/prints") - self.cache_dir.mkdir(parents=True, exist_ok=True) - - # Rate limiting and coordination - self.min_print_interval = min_print_interval - self._last_print_time = None - self._print_lock = asyncio.Lock() - - async def _wait_for_printer_ready(self, max_wait: int = 300) -> bool: - """Wait for the printer to be ready. - - Args: - max_wait: Maximum time to wait in seconds - - Returns: - bool: True if printer is ready, False if timeout - """ - start_time = time.time() - while time.time() - start_time < max_wait: - try: - async with aiohttp.ClientSession() as session: - async with session.get(self.status_url) as response: - if response.status == 200: - data = await response.json() - if data.get('status') == 'ready': - return True - except Exception as e: - logger.warning(f"Error checking printer status: {e}") - - await asyncio.sleep(1) - - logger.error("Timeout waiting for printer to be ready") - return False - - async def print_file(self, file_path: Union[str, Path], printer_type: Literal["regular", "label"] = "regular", label_type: Optional[Literal["dk1201", "dk1241"]] = None) -> bool: - """Print a PDF or PNG file. - - Args: - file_path: Path to the PDF or PNG file - printer_type: Type of printer ("regular" or "label") - label_type: Type of label to use ("dk1201" or "dk1241"). Only used when printer_type is "label". - - Returns: - bool: True if print was successful, False otherwise - """ - try: - file_path = Path(file_path) - if not file_path.exists(): - logger.error(f"File not found: {file_path}") - return False - - if printer_type == "regular": - # For regular printers, use CUPS - printer = self.printer_name or self.conn.getDefault() - if not printer: - logger.error("No default printer found") - return False - - job_id = self.conn.printFile( - printer, - str(file_path), - f"{file_path.suffix.upper()} Print", - {} - ) - logger.info(f"Print job {job_id} submitted to printer {printer}") - return True - else: - # For label printers, we need to coordinate requests - if label_type is None: - logger.error("label_type must be specified when printing to label printer") - return False - - # Wait for printer to be ready - if not await self._wait_for_printer_ready(): - logger.error("Printer not ready after waiting") - return False - - if file_path.suffix.lower() == '.pdf': - # Convert PDF to image first - images = convert_from_path(file_path) - if not images: - logger.error(f"No images could be extracted from {file_path}") - return False - image = images[0] # Only use first page - else: - # For PNG files, we can use them directly - from PIL import Image - image = Image.open(file_path) - - # Convert to label format - qlr = BrotherQLRaster("QL-1100") - qlr.exception_on_warning = True - - # Get label size based on type - label_size = "29x90" if label_type == "dk1201" else "102x152" - - converted_image = convert( - qlr=qlr, - images=[image], - label=label_size, - rotate="0", - threshold=70.0, - dither=False, - compress=False, - red=False, - dpi_600=False, - hq=True, - cut=True - ) - - # Cache the converted binary data - cache_path = self.cache_dir / f"{file_path.stem}_{label_type}_converted.bin" - with open(cache_path, "wb") as f: - f.write(converted_image) - - # Send to API - return await self._send_print_request(cache_path) - - except Exception as e: - logger.error(f"Error printing file {file_path}: {str(e)}") - return False - - async def _send_print_request(self, file_path: Union[str, Path]) -> bool: - """Send print data to printer API. - - Args: - file_path: Path to the binary data file to send to the printer - - Returns: - bool: True if request was successful, False otherwise - """ - try: - # Read the binary data from the cache file - with open(file_path, "rb") as f: - print_data = f.read() - - # Send the request to the printer API using aiohttp - async with aiohttp.ClientSession() as session: - async with session.post( - self.printer_api_url, - data=print_data, - timeout=30 - ) as response: - if response.status == 200: - return True - else: - response_text = await response.text() - logger.error(f"Print request failed with status {response.status}: {response_text}") - return False - - except Exception as e: - logger.error(f"Error sending print request: {str(e)}") - return False diff --git a/app/services/scheduler/base_scheduler.py b/app/services/scheduler/base_scheduler.py index 40f05d3..792f414 100644 --- a/app/services/scheduler/base_scheduler.py +++ b/app/services/scheduler/base_scheduler.py @@ -51,5 +51,11 @@ class BaseScheduler: async def shutdown(self) -> None: """Shutdown the scheduler""" - self.scheduler.shutdown() - logger.info("Scheduler stopped") \ No newline at end of file + try: + self.scheduler.shutdown() + logger.info("Scheduler stopped") + except AttributeError as e: + if "'NoneType' object has no attribute 'call_soon_threadsafe'" in str(e): + logger.warning("Event loop already closed, skipping scheduler shutdown") + else: + raise \ No newline at end of file