from app.services.base_service import BaseService from sqlalchemy.orm import Session from app.db.database import transaction from app.schemas.file import FileInDB from app.models.tcgplayer_products import TCGPlayerProduct, MTGJSONCard, MTGJSONSKU from app.models.critical_error_log import CriticalErrorLog from app.models.manabox_import_staging import ManaboxImportStaging from typing import Dict, Any, Union, List import csv import logging from datetime import datetime import asyncio logger = logging.getLogger(__name__) class ManaboxService(BaseService): def __init__(self): super().__init__(None) async def process_manabox_csv(self, db: Session, bytes: bytes, metadata: Dict[str, Any], wait: bool = False) -> Union[bool, List[FileInDB]]: # save file file = await self.file_service.save_file( db=db, file_data=bytes, filename=f"manabox_{datetime.now().strftime('%Y%m%d%H%M%S')}.csv", subdir="manabox", file_type="manabox", content_type="text/csv", metadata=metadata ) # Create the background task task = asyncio.create_task(self._process_file_background(db, file)) # If wait is True, wait for the task to complete and return the file if wait: await task return_value = await self.file_service.get_file(db, file.id) return [return_value] if return_value else [] return True async def _process_file_background(self, db: Session, file: FileInDB): try: # Read the CSV file with open(file.path, 'r') as csv_file: reader = csv.DictReader(csv_file) # skip header row next(reader) for row in reader: # match scryfall id to mtgjson scryfall id, make sure only one distinct tcgplayer id mtg_json = db.query(MTGJSONCard).filter(MTGJSONCard.scryfall_id == row['Scryfall ID']).all() # count distinct tcgplayer ids cd_tcgplayer_ids = db.query(MTGJSONCard.tcgplayer_sku_id).filter(MTGJSONCard.scryfall_id == row['Scryfall ID']).distinct().count() if cd_tcgplayer_ids != 1: logger.error(f"Error: multiple TCGplayer IDs found for scryfall id: {row['Scryfall ID']} found {cd_tcgplayer_ids} ids expected 1") with transaction(db): critical_error_log = CriticalErrorLog( error_message=f"Error: multiple TCGplayer IDs found for scryfall id: {row['Scryfall ID']} found {cd_tcgplayer_ids} ids expected 1" ) db.add(critical_error_log) continue else: mtg_json = mtg_json[0] # get tcgplayer sku id from mtgjson skus language = 'ENGLISH' if row['Language'] == 'en' else 'JAPANESE' if row['Language'] == 'ja' else None if row['Foil'].lower() == 'etched': printing = 'FOIL' tcgplayer_sku = db.query(MTGJSONSKU).filter(MTGJSONSKU.tcgplayer_sku_id == mtg_json.tcgplayer_etched_sku_id).filter(MTGJSONSKU.condition == row['Condition'].replace('_', ' ').upper()).filter(MTGJSONSKU.printing == printing).filter(MTGJSONSKU.language == language).distinct().all() else: printing = 'FOIL' if row['Foil'].lower() == 'foil' else 'NON FOIL' tcgplayer_sku = db.query(MTGJSONSKU).filter(MTGJSONSKU.tcgplayer_sku_id == mtg_json.tcgplayer_sku_id).filter(MTGJSONSKU.condition == row['Condition'].replace('_', ' ').upper()).filter(MTGJSONSKU.printing == printing).filter(MTGJSONSKU.language == language).distinct().all() # count distinct tcgplayer skus if len(tcgplayer_sku) == 0: logger.error(f"Error: No TCGplayer SKU found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}") with transaction(db): critical_error_log = CriticalErrorLog( error_message=f"Error: No TCGplayer SKU found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}" ) db.add(critical_error_log) continue elif len(tcgplayer_sku) > 1: logger.error(f"Error: {len(tcgplayer_sku)} TCGplayer SKUs found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}") with transaction(db): critical_error_log = CriticalErrorLog( error_message=f"Error: {len(tcgplayer_sku)} TCGplayer SKUs found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}" ) db.add(critical_error_log) continue else: tcgplayer_sku = tcgplayer_sku[0] # look up tcgplayer product data for sku tcgplayer_product = db.query(TCGPlayerProduct).filter(TCGPlayerProduct.tcgplayer_product_id == tcgplayer_sku.tcgplayer_product_id).filter(TCGPlayerProduct.condition == row['Condition'].replace('_', ' ').upper()).filter(TCGPlayerProduct.language == language).filter(TCGPlayerProduct.printing == printing).first() quantity = int(row['Quantity']) with transaction(db): manabox_import_staging = ManaboxImportStaging( file_id=file.id, product_id=tcgplayer_product.id, quantity=quantity, created_at=datetime.now(), updated_at=datetime.now() ) db.add(manabox_import_staging) except Exception as e: logger.error(f"Error processing file: {str(e)}") with transaction(db): critical_error_log = CriticalErrorLog( error_message=f"Error processing file: {str(e)}" ) db.add(critical_error_log)