orders
This commit is contained in:
parent
721b26ce97
commit
1bf255d0fe
1
.gitignore
vendored
1
.gitignore
vendored
@ -174,3 +174,4 @@ temp/
|
||||
.DS_Store
|
||||
*.db-journal
|
||||
cookies/
|
||||
alembic/versions/*
|
@ -328,6 +328,41 @@ class TCGPlayerGroups(Base):
|
||||
modified_on = Column(String)
|
||||
category_id = Column(Integer)
|
||||
|
||||
class Orders(Base):
|
||||
__tablename__ = 'orders'
|
||||
|
||||
id = Column(String, primary_key=True)
|
||||
order_id = Column(String, unique=True)
|
||||
buyer_name = Column(String)
|
||||
recipient_name = Column(String)
|
||||
recipient_address_one = Column(String)
|
||||
recipient_address_two = Column(String)
|
||||
recipient_city = Column(String)
|
||||
recipient_state = Column(String)
|
||||
recipient_zip = Column(String)
|
||||
recipient_country = Column(String)
|
||||
order_date = Column(String)
|
||||
status = Column(String)
|
||||
num_products = Column(Integer)
|
||||
num_cards = Column(Integer)
|
||||
product_amount = Column(Float)
|
||||
shipping_amount = Column(Float)
|
||||
gross_amount = Column(Float)
|
||||
fee_amount = Column(Float)
|
||||
net_amount = Column(Float)
|
||||
direct_fee_amount = Column(Float)
|
||||
date_created = Column(DateTime, default=datetime.now)
|
||||
date_modified = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||||
|
||||
class OrderProducts(Base):
|
||||
__tablename__ = 'order_products'
|
||||
|
||||
id = Column(String, primary_key=True)
|
||||
order_id = Column(String, ForeignKey('orders.id'))
|
||||
product_id = Column(String, ForeignKey('products.id'))
|
||||
quantity = Column(Integer)
|
||||
unit_price = Column(Float)
|
||||
|
||||
# enums
|
||||
|
||||
class RarityEnum(str, Enum):
|
||||
|
@ -10,6 +10,7 @@ from app.services.product import ProductService
|
||||
from app.services.inventory import InventoryService
|
||||
from app.services.task import TaskService
|
||||
from app.services.storage import StorageService
|
||||
from app.services.tcgplayer_api import TCGPlayerAPIService
|
||||
from app.db.database import get_db
|
||||
from app.schemas.file import CreateFileRequest
|
||||
from app.schemas.box import CreateBoxRequest, UpdateBoxRequest, CreateOpenBoxRequest
|
||||
@ -18,6 +19,10 @@ from app.schemas.box import CreateBoxRequest, UpdateBoxRequest, CreateOpenBoxReq
|
||||
DB = Annotated[Session, Depends(get_db)]
|
||||
|
||||
# Base Services (no dependencies besides DB)
|
||||
def get_tcgplayer_api_service(db: DB) -> TCGPlayerAPIService:
|
||||
"""TCGPlayerAPIService with only database dependency"""
|
||||
return TCGPlayerAPIService(db)
|
||||
|
||||
def get_file_service(db: DB) -> FileService:
|
||||
"""FileService with only database dependency"""
|
||||
return FileService(db)
|
||||
|
@ -25,10 +25,12 @@ from app.schemas.box import (
|
||||
CreateOpenBoxResponse,
|
||||
OpenBoxSchema
|
||||
)
|
||||
from app.schemas.orders import ProcessOrdersResponse
|
||||
from app.services.file import FileService
|
||||
from app.services.box import BoxService
|
||||
from app.services.task import TaskService
|
||||
from app.services.pricing import PricingService
|
||||
from app.services.tcgplayer_api import TCGPlayerAPIService
|
||||
from app.dependencies import (
|
||||
get_file_service,
|
||||
get_box_service,
|
||||
@ -37,7 +39,8 @@ from app.dependencies import (
|
||||
get_box_data,
|
||||
get_box_update_data,
|
||||
get_open_box_data,
|
||||
get_pricing_service
|
||||
get_pricing_service,
|
||||
get_tcgplayer_api_service
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -313,3 +316,23 @@ async def update_cookies(
|
||||
status_code=500,
|
||||
detail=f"Failed to update cookies: {str(e)}"
|
||||
)
|
||||
|
||||
class TCGPlayerOrderRequest(BaseModel):
|
||||
order_ids: List[str]
|
||||
|
||||
@router.post("/processOrders", response_model=ProcessOrdersResponse)
|
||||
async def process_orders(
|
||||
body: TCGPlayerOrderRequest,
|
||||
tcgplayer_api_service: TCGPlayerAPIService = Depends(get_tcgplayer_api_service),
|
||||
) -> ProcessOrdersResponse:
|
||||
"""Process TCGPlayer orders."""
|
||||
try:
|
||||
orders = tcgplayer_api_service.process_orders(body.order_ids)
|
||||
return ProcessOrdersResponse(
|
||||
status_code=200,
|
||||
success=True,
|
||||
orders=orders
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Process orders failed: {str(e)}")
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
@ -1,19 +0,0 @@
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
# FILE
|
||||
class OrderSchema(BaseModel):
|
||||
id: str = Field(..., title="id")
|
||||
filename: str = Field(..., title="filename")
|
||||
type: str = Field(..., title="type")
|
||||
filesize_kb: float = Field(..., title="filesize_kb")
|
||||
source: str = Field(..., title="source")
|
||||
status: str = Field(..., title="status")
|
||||
service: Optional[str] = Field(None, title="service")
|
||||
date_created: datetime = Field(..., title="date_created")
|
||||
date_modified: datetime = Field(..., title="date_modified")
|
||||
|
||||
# This enables ORM mode
|
||||
model_config = ConfigDict(from_attributes=True)
|
9
app/schemas/orders.py
Normal file
9
app/schemas/orders.py
Normal file
@ -0,0 +1,9 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
class OrderSchema(BaseModel):
|
||||
order_id: str
|
||||
|
||||
class ProcessOrdersResponse(BaseModel):
|
||||
status_code: int
|
||||
success: bool
|
||||
orders: list[str]
|
@ -10,7 +10,7 @@ import io
|
||||
|
||||
# Printer settings
|
||||
printer_model = "QL-1100"
|
||||
backend = 'pyusb' # Changed from network to USB
|
||||
backend = 'pyusb'
|
||||
printer = 'usb://0x04f9:0x20a7'
|
||||
|
||||
def convert_pdf_to_image(pdf_path):
|
||||
@ -45,6 +45,8 @@ def create_address_label(input_data, font_size=30, is_pdf=False):
|
||||
font = ImageFont.truetype("C:\\Windows\\Fonts\\arial.ttf", size=font_size)
|
||||
elif platform.system() == 'Darwin':
|
||||
font = ImageFont.truetype("/Library/Fonts/Arial.ttf", size=font_size)
|
||||
elif platform.system() == 'Linux':
|
||||
font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", size=font_size)
|
||||
|
||||
margin = 20
|
||||
lines = input_data.split('\n')
|
||||
@ -71,10 +73,8 @@ def print_address_label(input_data, font_size=30, is_pdf=False, label_size='29x9
|
||||
if not image:
|
||||
raise Exception("Failed to create label image")
|
||||
|
||||
# For 4x6 shipping labels from Pirate Ship
|
||||
if label_size == '4x6':
|
||||
# Resize image to fit 4x6 format if needed
|
||||
target_width = 1164 # Adjusted for 4x6 format
|
||||
target_width = 1164
|
||||
target_height = 1660
|
||||
image = image.resize((target_width, target_height), Image.LANCZOS)
|
||||
|
||||
@ -92,7 +92,6 @@ def print_address_label(input_data, font_size=30, is_pdf=False, label_size='29x9
|
||||
red=False,
|
||||
dpi_600=False,
|
||||
hq=True,
|
||||
#cut=True
|
||||
cut=False
|
||||
)
|
||||
|
||||
@ -135,33 +134,23 @@ def process_tcg_shipping_export(file_path, require_input=False, font_size=60, pr
|
||||
else:
|
||||
sleep(1)
|
||||
|
||||
# Example usage
|
||||
if __name__ == "__main__":
|
||||
# Example for regular address label
|
||||
address = """John Doe
|
||||
123 Main Street
|
||||
Apt 4B
|
||||
City, State 12345"""
|
||||
|
||||
# Example for TCG Player export
|
||||
shipping_export_file = "_TCGplayer_ShippingExport_20250201_115949.csv"
|
||||
|
||||
# Example for Pirate Ship PDF
|
||||
pirate_ship_pdf = "C:\\Users\\joshu\\Downloads\\2025-02-10---greg-creek---9400136208070411592215.pdf"
|
||||
|
||||
# Choose which type to process
|
||||
label_type = input("Enter label type (1 for regular, 2 for TCG, 3 for Pirate Ship): ")
|
||||
|
||||
if label_type == "1":
|
||||
address = input("Enter the address to print: ")
|
||||
preview_label(address, font_size=60)
|
||||
user_input = input("Press 'p' to print the label or any other key to cancel: ")
|
||||
if user_input.lower() == 'p':
|
||||
print_address_label(address, font_size=60)
|
||||
|
||||
elif label_type == "2":
|
||||
shipping_export_file = input("Enter the path to the TCG Player shipping export CSV file: ")
|
||||
process_tcg_shipping_export(shipping_export_file, font_size=60, preview=False)
|
||||
|
||||
elif label_type == "3":
|
||||
pirate_ship_pdf = input("Enter the path to the Pirate Ship PDF file: ")
|
||||
process_pirate_ship_pdf(pirate_ship_pdf, preview=True)
|
||||
user_input = input("Press 'p' to print the label or any other key to cancel: ")
|
||||
if user_input.lower() == 'p':
|
||||
|
@ -21,6 +21,7 @@ import pandas as pd
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from app.schemas.file import CreateFileRequest
|
||||
import os
|
||||
from app.services.util._docker import DockerUtil
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -53,6 +54,7 @@ class TCGPlayerService:
|
||||
self.previous_request_time = None
|
||||
self.df_util = DataframeUtil()
|
||||
self.file_service = file_service
|
||||
self.docker_util = DockerUtil()
|
||||
|
||||
def _insert_groups(self, groups):
|
||||
for group in groups:
|
||||
@ -119,47 +121,6 @@ class TCGPlayerService:
|
||||
logger.error(f"Failed to get browser cookies: {str(e)}")
|
||||
return None
|
||||
|
||||
def is_in_docker(self) -> bool:
|
||||
"""Check if we're running inside a Docker container using multiple methods"""
|
||||
# Method 1: Check cgroup
|
||||
try:
|
||||
with open('/proc/1/cgroup', 'r') as f:
|
||||
content = f.read().lower()
|
||||
if any(container_id in content for container_id in ['docker', 'containerd', 'kubepods']):
|
||||
logger.debug("Docker detected via cgroup")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not read cgroup file: {e}")
|
||||
|
||||
# Method 2: Check /.dockerenv file
|
||||
if os.path.exists('/.dockerenv'):
|
||||
logger.debug("Docker detected via /.dockerenv file")
|
||||
return True
|
||||
|
||||
# Method 3: Check environment variables
|
||||
docker_env = any(os.environ.get(var, False) for var in [
|
||||
'DOCKER_CONTAINER',
|
||||
'IN_DOCKER',
|
||||
'KUBERNETES_SERVICE_HOST', # For k8s
|
||||
'DOCKER_HOST'
|
||||
])
|
||||
if docker_env:
|
||||
logger.debug("Docker detected via environment variables")
|
||||
return True
|
||||
|
||||
# Method 4: Check container runtime
|
||||
try:
|
||||
with open('/proc/self/mountinfo', 'r') as f:
|
||||
content = f.read().lower()
|
||||
if any(rt in content for rt in ['docker', 'containerd', 'kubernetes']):
|
||||
logger.debug("Docker detected via mountinfo")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not read mountinfo: {e}")
|
||||
|
||||
logger.debug("No Docker environment detected")
|
||||
return False
|
||||
|
||||
def _send_request(self, url: str, method: str, data=None, except_302=False) -> requests.Response:
|
||||
"""Send a request with the specified cookies"""
|
||||
# Rate limiting logic
|
||||
@ -173,7 +134,7 @@ class TCGPlayerService:
|
||||
|
||||
# Move cookie initialization outside and make it more explicit
|
||||
if not self.cookies:
|
||||
if self.is_in_docker():
|
||||
if self.docker_util.is_in_docker():
|
||||
logger.debug("Running in Docker - using cookies from file")
|
||||
self.cookies = self.get_cookies_from_file()
|
||||
else:
|
||||
|
105
app/services/tcgplayer_api.py
Normal file
105
app/services/tcgplayer_api.py
Normal file
@ -0,0 +1,105 @@
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from app.db.models import Orders, OrderProducts, CardTCGPlayer
|
||||
from app.services.util._requests import RequestsUtil
|
||||
from app.services.util._docker import DockerUtil
|
||||
from app.db.utils import db_transaction
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import uuid4 as uuid
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@dataclass
|
||||
class TCGPlayerAPIConfig:
|
||||
"""Configuration for TCGPlayer API"""
|
||||
ORDER_BASE_URL: str = "https://order-management-api.tcgplayer.com/orders"
|
||||
API_VERSION: str = "?api-version=2.0"
|
||||
|
||||
class TCGPlayerAPIService:
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
self.docker_util = DockerUtil()
|
||||
self.requests_util = RequestsUtil()
|
||||
self.is_in_docker = self.docker_util.is_in_docker()
|
||||
self.config = TCGPlayerAPIConfig()
|
||||
self.cookies = self.get_cookies()
|
||||
|
||||
def get_cookies(self) -> dict:
|
||||
if self.is_in_docker:
|
||||
return self.requests_util.get_tcgplayer_cookies_from_file()
|
||||
else:
|
||||
return self.requests_util.get_tcgplayer_browser_cookies()
|
||||
|
||||
def get_order(self, order_id: str) -> dict:
|
||||
url = f"{self.config.ORDER_BASE_URL}/{order_id}{self.config.API_VERSION}"
|
||||
response = self.requests_util.send_request(url, method='GET', cookies=self.cookies)
|
||||
if response:
|
||||
return response.json()
|
||||
return None
|
||||
|
||||
def get_product_ids_from_sku(self, sku_ids: list[str]) -> dict:
|
||||
"""Get product IDs from TCGPlayer SKU IDs"""
|
||||
tcg_cards = self.db.query(CardTCGPlayer).filter(CardTCGPlayer.tcgplayer_id.in_(sku_ids)).all()
|
||||
return {card.tcgplayer_id: card.product_id for card in tcg_cards}
|
||||
|
||||
def save_order(self, order: dict):
|
||||
# check if order exists by order number
|
||||
order_number = order['orderNumber']
|
||||
existing_order = self.db.query(Orders).filter(Orders.order_id == order_number).first()
|
||||
if existing_order:
|
||||
logger.info(f"Order {order_number} already exists in database")
|
||||
return existing_order
|
||||
transaction = order['transaction']
|
||||
shipping = order['shippingAddress']
|
||||
products = order['products']
|
||||
with db_transaction(self.db):
|
||||
db_order = Orders(
|
||||
id = str(uuid()),
|
||||
order_id=order_number,
|
||||
buyer_name=order['buyerName'],
|
||||
recipient_name=shipping['recipientName'],
|
||||
recipient_address_one=shipping['addressOne'],
|
||||
recipient_address_two=shipping['addressTwo'] if 'addressTwo' in shipping else '',
|
||||
recipient_city=shipping['city'],
|
||||
recipient_state=shipping['territory'],
|
||||
recipient_zip=shipping['postalCode'],
|
||||
recipient_country=shipping['country'],
|
||||
order_date=order['createdAt'],
|
||||
status=order['status'],
|
||||
num_products=len(products),
|
||||
num_cards=sum([product['quantity'] for product in products]),
|
||||
product_amount=transaction['productAmount'],
|
||||
shipping_amount=transaction['shippingAmount'],
|
||||
gross_amount=transaction['grossAmount'],
|
||||
fee_amount=transaction['feeAmount'],
|
||||
net_amount=transaction['netAmount'],
|
||||
direct_fee_amount=transaction['directFeeAmount']
|
||||
)
|
||||
self.db.add(db_order)
|
||||
|
||||
product_ids = [product['skuId'] for product in products]
|
||||
sku_to_product_id_mapping = self.get_product_ids_from_sku(product_ids)
|
||||
order_products = []
|
||||
for product in products:
|
||||
product_id = sku_to_product_id_mapping.get(product['skuId'])
|
||||
if product_id:
|
||||
order_products.append(
|
||||
OrderProducts(
|
||||
id=str(uuid()),
|
||||
order_id=db_order.id,
|
||||
product_id=product_id,
|
||||
quantity=product['quantity'],
|
||||
unit_price=product['unitPrice']
|
||||
)
|
||||
)
|
||||
self.db.add_all(order_products)
|
||||
return db_order
|
||||
|
||||
def process_orders(self, orders: list[str]):
|
||||
processed_orders = []
|
||||
for order_id in orders:
|
||||
order = self.get_order(order_id)
|
||||
if order:
|
||||
self.save_order(order)
|
||||
processed_orders.append(order_id)
|
||||
return processed_orders
|
49
app/services/util/_docker.py
Normal file
49
app/services/util/_docker.py
Normal file
@ -0,0 +1,49 @@
|
||||
import os
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class DockerUtil:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def is_in_docker(self) -> bool:
|
||||
"""Check if we're running inside a Docker container using multiple methods"""
|
||||
# Method 1: Check cgroup
|
||||
try:
|
||||
with open('/proc/1/cgroup', 'r') as f:
|
||||
content = f.read().lower()
|
||||
if any(container_id in content for container_id in ['docker', 'containerd', 'kubepods']):
|
||||
logger.debug("Docker detected via cgroup")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not read cgroup file: {e}")
|
||||
|
||||
# Method 2: Check /.dockerenv file
|
||||
if os.path.exists('/.dockerenv'):
|
||||
logger.debug("Docker detected via /.dockerenv file")
|
||||
return True
|
||||
|
||||
# Method 3: Check environment variables
|
||||
docker_env = any(os.environ.get(var, False) for var in [
|
||||
'DOCKER_CONTAINER',
|
||||
'IN_DOCKER',
|
||||
'KUBERNETES_SERVICE_HOST', # For k8s
|
||||
'DOCKER_HOST'
|
||||
])
|
||||
if docker_env:
|
||||
logger.debug("Docker detected via environment variables")
|
||||
return True
|
||||
|
||||
# Method 4: Check container runtime
|
||||
try:
|
||||
with open('/proc/self/mountinfo', 'r') as f:
|
||||
content = f.read().lower()
|
||||
if any(rt in content for rt in ['docker', 'containerd', 'kubernetes']):
|
||||
logger.debug("Docker detected via mountinfo")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.debug(f"Could not read mountinfo: {e}")
|
||||
|
||||
logger.debug("No Docker environment detected")
|
||||
return False
|
172
app/services/util/_requests.py
Normal file
172
app/services/util/_requests.py
Normal file
@ -0,0 +1,172 @@
|
||||
from typing import Dict, Optional
|
||||
from app.services.util._docker import DockerUtil
|
||||
from enum import Enum
|
||||
import browser_cookie3
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import time
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Browser(Enum):
|
||||
"""Supported browser types for cookie extraction"""
|
||||
BRAVE = "brave"
|
||||
CHROME = "chrome"
|
||||
FIREFOX = "firefox"
|
||||
|
||||
class Method(Enum):
|
||||
"""Supported HTTP methods"""
|
||||
GET = "GET"
|
||||
POST = "POST"
|
||||
|
||||
class TCGPlayerEndpoints(Enum):
|
||||
"""Supported TCGPlayer API endpoints"""
|
||||
ORDERS = "https://order-management-api.tcgplayer.com/orders"
|
||||
|
||||
class Headers:
|
||||
ACCEPT = 'application/json, text/plain, */*'
|
||||
ACCEPT_ENCODING = 'gzip, deflate, br, zstd'
|
||||
ACCEPT_LANGUAGE = 'en-US,en;q=0.8'
|
||||
PRIORITY = 'u=1, i'
|
||||
SECCHUA = '"Not(A:Brand";v="99", "Brave";v="133", "Chromium";v="133"'
|
||||
SECCHUA_MOBILE = '?0'
|
||||
SECCHUA_PLATFORM = '"macOS"'
|
||||
SEC_FETCH_DEST = 'empty'
|
||||
SEC_FETCH_MODE = 'cors'
|
||||
SEC_FETCH_SITE = 'same-site'
|
||||
SEC_GPC = '1'
|
||||
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'
|
||||
SELLER_ORIGIN = 'https://sellerportal.tcgplayer.com'
|
||||
SELLER_REFERER = 'https://sellerportal.tcgplayer.com/'
|
||||
|
||||
class RequestHeaders:
|
||||
BASE_HEADERS = {
|
||||
'accept': Headers.ACCEPT,
|
||||
'accept-encoding': Headers.ACCEPT_ENCODING,
|
||||
'accept-language': Headers.ACCEPT_LANGUAGE,
|
||||
'priority': Headers.PRIORITY,
|
||||
'sec-ch-ua': Headers.SECCHUA,
|
||||
'sec-ch-ua-mobile': Headers.SECCHUA_MOBILE,
|
||||
'sec-ch-ua-platform': Headers.SECCHUA_PLATFORM,
|
||||
'sec-fetch-dest': Headers.SEC_FETCH_DEST,
|
||||
'sec-fetch-mode': Headers.SEC_FETCH_MODE,
|
||||
'sec-fetch-site': Headers.SEC_FETCH_SITE,
|
||||
'sec-gpc': Headers.SEC_GPC,
|
||||
'user-agent': Headers.USER_AGENT
|
||||
}
|
||||
SELLER_HEADERS = {
|
||||
'origin': Headers.SELLER_ORIGIN,
|
||||
'referer': Headers.SELLER_REFERER
|
||||
}
|
||||
|
||||
class URLHeaders:
|
||||
# combine base and seller headers
|
||||
ORDER_HEADERS = {**RequestHeaders.BASE_HEADERS, **RequestHeaders.SELLER_HEADERS}
|
||||
|
||||
class RequestsUtil:
|
||||
def __init__(self, browser_type: Browser = Browser.BRAVE):
|
||||
self.browser_type = browser_type
|
||||
self.docker_util = DockerUtil()
|
||||
|
||||
def get_tcgplayer_cookies_from_file(self) -> Dict:
|
||||
# check if cookies file exists
|
||||
if not os.path.exists('cookies/tcg_cookies.json'):
|
||||
raise ValueError("Cookies file not found")
|
||||
with open('cookies/tcg_cookies.json', 'r') as f:
|
||||
logger.debug("Loading cookies from file")
|
||||
cookies = json.load(f)
|
||||
return cookies
|
||||
|
||||
def get_tcgplayer_browser_cookies(self) -> Optional[Dict]:
|
||||
"""Retrieve cookies from the specified browser"""
|
||||
try:
|
||||
cookie_getter = getattr(browser_cookie3, self.browser_type.value, None)
|
||||
if not cookie_getter:
|
||||
raise ValueError(f"Unsupported browser type: {self.browser_type.value}")
|
||||
return cookie_getter()
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get browser cookies: {str(e)}")
|
||||
return None
|
||||
|
||||
def rate_limit(self, time_between_requests: int = 10):
|
||||
"""Rate limit requests by waiting for a specified time between requests"""
|
||||
time_diff = (datetime.now() - self.previous_request_time).total_seconds()
|
||||
if time_diff < time_between_requests:
|
||||
# logger.info(f"Waiting {time_between_requests - time_diff} seconds before next request...")
|
||||
time.sleep(time_between_requests - time_diff)
|
||||
|
||||
def send_request(self, url: str, method: str, cookies: dict, data=None) -> requests.Response:
|
||||
"""Send a request with the specified cookies"""
|
||||
|
||||
headers = self.set_headers(url)
|
||||
if not headers:
|
||||
raise ValueError("Headers not set")
|
||||
|
||||
try:
|
||||
response = requests.request(method, url, headers=headers, cookies=cookies, data=data)
|
||||
response.raise_for_status()
|
||||
self.previous_request_time = datetime.now()
|
||||
|
||||
return response
|
||||
|
||||
except requests.RequestException as e:
|
||||
logger.error(f"Request failed: {str(e)}")
|
||||
return None
|
||||
|
||||
def set_headers(self, url: str):
|
||||
# use tcgplayerendpoints enum to set headers where url partially matches enum value
|
||||
for endpoint in TCGPlayerEndpoints:
|
||||
if endpoint.value in url:
|
||||
return URLHeaders.ORDER_HEADERS
|
||||
else:
|
||||
raise ValueError(f"Endpoint not found in TCGPlayerEndpoints: {url}")
|
||||
|
||||
def old_set_headers(self, method: str) -> Dict:
|
||||
base_headers = {
|
||||
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
||||
'accept-language': 'en-US,en;q=0.8',
|
||||
'priority': 'u=0, i',
|
||||
'referer': 'https://store.tcgplayer.com/admin/pricing',
|
||||
'sec-ch-ua': '"Not A(Brand";v="8", "Chromium";v="132", "Brave";v="132"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"macOS"',
|
||||
'sec-fetch-dest': 'document',
|
||||
'sec-fetch-mode': 'navigate',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'sec-fetch-user': '?1',
|
||||
'sec-gpc': '1',
|
||||
'upgrade-insecure-requests': '1',
|
||||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36'
|
||||
}
|
||||
|
||||
if method == 'POST':
|
||||
post_headers = {
|
||||
'cache-control': 'max-age=0',
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
'origin': 'https://store.tcgplayer.com'
|
||||
}
|
||||
base_headers.update(post_headers)
|
||||
|
||||
return base_headers
|
||||
|
||||
|
||||
"""
|
||||
curl 'https://order-management-api.tcgplayer.com/orders/E576ED4C-38871F-B0277?api-version=2.0' \
|
||||
-H 'accept: application/json, text/plain, */*' \
|
||||
-H 'accept-language: en-US,en;q=0.8' \
|
||||
-b 'tcgpartner=PK=TRADECARDS&M=1; valid=set=true; product-display-settings=sort=price+shipping&size=10; TCG_Data=M=1&SearchGameNameID=magic; tcg-uuid=ab16b5f8-dd66-446d-b217-d394328a5cf1; setting=CD=US&M=1; tracking-preferences={%22version%22:1%2C%22destinations%22:{%22Actions%20Amplitude%22:false%2C%22AdWords%22:false%2C%22Google%20AdWords%20New%22:false%2C%22Google%20Enhanced%20Conversions%22:false%2C%22Google%20Tag%20Manager%22:false%2C%22Impact%20Partnership%20Cloud%22:false%2C%22Optimizely%22:false}%2C%22custom%22:{%22advertising%22:false%2C%22functional%22:false%2C%22marketingAndAnalytics%22:false}}; OAuthLoginSessionId=63b1a89d-1ac2-43f7-8e79-55a9ca5e761d; TCGAuthTicket_Production=F453BFF2FA3FAA3D1ACA23F319314F8273713DECEB06C69BB7C208A77C81559B46E1AA22A7E70FABC8D7F681A423C86870FAE318B76048CDE7BF6D73D220631B899BEBA86C422E1EBBF2ACD1921E0846F708AFE203C844031364E13B047465E7B41CB6460E4F4AAB278B614445B93E722E976688; BuyerRevalidationKey=; ASP.NET_SessionId=oouwzrh3jkhdrmaioooqhr4k; TCG_VisitorKey=431efcca-2d5b-404d-a04f-3ae979696051; __RequestVerificationToken_L2FkbWlu0=Lw1sfWh823UeJ7zRux0b1ZTI4Vg4i_dFt97a55aQpf-qBURVuwWDCJyuCxSwgLNLe9nPlfDSc1AMV5nyqhY4Q4jurxs1; fileDownloadToken=1740145585435; spDisabledUIFeatures=' \
|
||||
-H 'origin: https://sellerportal.tcgplayer.com' \
|
||||
-H 'priority: u=1, i' \
|
||||
-H 'referer: https://sellerportal.tcgplayer.com/' \
|
||||
-H 'sec-ch-ua: "Not(A:Brand";v="99", "Brave";v="133", "Chromium";v="133"' \
|
||||
-H 'sec-ch-ua-mobile: ?0' \
|
||||
-H 'sec-ch-ua-platform: "macOS"' \
|
||||
-H 'sec-fetch-dest: empty' \
|
||||
-H 'sec-fetch-mode: cors' \
|
||||
-H 'sec-fetch-site: same-site' \
|
||||
-H 'sec-gpc: 1' \
|
||||
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'
|
||||
"""
|
22
requests.md
22
requests.md
@ -2,16 +2,20 @@ curl -J http://192.168.1.41:8000/api/tcgplayer/inventory/update --remote-name
|
||||
|
||||
curl -J -X POST http://192.168.1.41:8000/api/tcgplayer/inventory/add \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"open_box_ids": ["fb629d9d-13d2-405e-9a69-6c44294d55de"]}' \
|
||||
-d '{"open_box_ids": ["02d14109-ad0c-41f9-b49f-24134f962c1a"]}' \
|
||||
--remote-name
|
||||
|
||||
curl -X POST http://192.168.1.41:8000/api/boxes \
|
||||
-F "type=draft" \
|
||||
-F "set_code=CLB" \
|
||||
-F "sku=195166181127" \
|
||||
-F "num_cards_expected=480"
|
||||
-F "type=play" \
|
||||
-F "set_code=DFT" \
|
||||
-F "sku=195166278636" \
|
||||
-F "num_cards_expected=422"
|
||||
|
||||
curl -X POST "http://192.168.1.41:8000/api/boxes/0d31b9c3-3093-438a-9e8c-b6b70a2d437e/open" \
|
||||
-F "product_id=0d31b9c3-3093-438a-9e8c-b6b70a2d437e" \
|
||||
-F "file_ids=bb4a022c-5427-49b5-b57c-0147b5e9c4a9" \
|
||||
-F "date_opened=2025-02-15"
|
||||
curl -X POST "http://192.168.1.41:8000/api/boxes/0d605f46-25b5-4784-8d45-38dec144ec8e/open" \
|
||||
-F "product_id=0d605f46-25b5-4784-8d45-38dec144ec8e" \
|
||||
-F "file_ids=61124a9d-8db3-49aa-bf56-ec0d784ca817" \
|
||||
-F "date_opened=2025-02-17"
|
||||
|
||||
curl -X POST "http://127.0.0.1:8000/api/processOrders" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"order_ids": ["E576ED4C-A1117E-6904E"]}'
|
Loading…
x
Reference in New Issue
Block a user