clean
This commit is contained in:
parent
18b32c8514
commit
593e8960b7
25
app.log
25
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
|
||||
|
44
app/main.py
44
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")
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -51,5 +51,11 @@ class BaseScheduler:
|
||||
|
||||
async def shutdown(self) -> None:
|
||||
"""Shutdown the scheduler"""
|
||||
self.scheduler.shutdown()
|
||||
logger.info("Scheduler stopped")
|
||||
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
|
Loading…
x
Reference in New Issue
Block a user