giga_tcg/services/product.py

136 lines
5.2 KiB
Python

from sqlalchemy.orm import Session
from db.utils import db_transaction
from db.models import Product, File, CardManabox, Card, StagedFileProduct
from io import StringIO
import pandas as pd
from services.file import FileService
from uuid import uuid4 as uuid
import logging
logger = logging.getLogger(__name__)
class ManaboxRow:
def __init__(self, row: pd.Series):
self.name = row['name']
self.set_code = row['set_code']
self.set_name = row['set_name']
self.collector_number = row['collector_number']
self.foil = row['foil']
self.rarity = row['rarity']
self.manabox_id = row['manabox_id']
self.scryfall_id = row['scryfall_id']
self.condition = row['condition']
self.language = row['language']
self.quantity = row['quantity']
class ProductService:
def __init__(self, db: Session, file_service: FileService):
self.db = db
self.file_service = file_service
def _format_manabox_df(self, df: pd.DataFrame) -> pd.DataFrame:
# format columns
df.columns = df.columns.str.lower()
df.columns = df.columns.str.replace(' ', '_')
return df
def _manabox_file_to_df(self, file: File) -> pd.DataFrame:
with open(file.filepath, 'rb') as f:
content = f.read()
content = content.decode('utf-8')
df = pd.read_csv(StringIO(content))
df = self._format_manabox_df(df)
return df
def create_staged_product(self, file: File, card_manabox:CardManabox, row: ManaboxRow) -> StagedFileProduct:
staged_product = StagedFileProduct(
id = str(uuid()),
file_id = file.id,
product_id = card_manabox.product_id,
quantity = row.quantity
)
with db_transaction(self.db):
self.db.add(staged_product)
return staged_product
def create_card_manabox(self, manabox_row: ManaboxRow) -> CardManabox:
card_manabox = CardManabox(
product_id = str(uuid()),
name = manabox_row.name,
set_code = manabox_row.set_code,
set_name = manabox_row.set_name,
collector_number = manabox_row.collector_number,
foil = manabox_row.foil,
rarity = manabox_row.rarity,
manabox_id = manabox_row.manabox_id,
scryfall_id = manabox_row.scryfall_id,
condition = manabox_row.condition,
language = manabox_row.language
)
return card_manabox
def create_product(self, card_manabox: CardManabox) -> Product:
product = Product(
id = card_manabox.product_id,
name = card_manabox.name,
set_code = card_manabox.set_code,
set_name = card_manabox.set_name,
type = 'card',
product_line = 'mtg'
)
return product
def create_card(self, card_manabox: CardManabox) -> Card:
card = Card(
product_id = card_manabox.product_id,
number = card_manabox.collector_number,
foil = card_manabox.foil,
rarity = card_manabox.rarity,
condition = card_manabox.condition,
language = card_manabox.language,
scryfall_id = card_manabox.scryfall_id,
manabox_id = card_manabox.manabox_id
)
return card
def card_manabox_lookup_create_if_not_exist(self, manabox_row: ManaboxRow) -> CardManabox:
# query based on all fields in manabox_row
card_manabox = self.db.query(CardManabox).filter(
CardManabox.name == manabox_row.name,
CardManabox.set_code == manabox_row.set_code,
CardManabox.set_name == manabox_row.set_name,
CardManabox.collector_number == manabox_row.collector_number,
CardManabox.foil == manabox_row.foil,
CardManabox.rarity == manabox_row.rarity,
CardManabox.manabox_id == manabox_row.manabox_id,
CardManabox.scryfall_id == manabox_row.scryfall_id,
CardManabox.condition == manabox_row.condition,
CardManabox.language == manabox_row.language
).first()
if not card_manabox:
# create new card_manabox, card, and product
with db_transaction(self.db):
card_manabox = self.create_card_manabox(manabox_row)
product = self.create_product(card_manabox)
card = self.create_card(card_manabox)
self.db.add(card_manabox)
self.db.add(product)
self.db.add(card)
return card_manabox
def bg_process_manabox_file(self, file_id: str):
try:
file = self.file_service.get_file(file_id)
df = self._manabox_file_to_df(file)
for index, row in df.iterrows():
manabox_row = ManaboxRow(row)
card_manabox = self.card_manabox_lookup_create_if_not_exist(manabox_row)
staged_product = self.create_staged_product(file, card_manabox, row)
# update file status
with db_transaction(self.db):
file.status = 'prepared'
except Exception as e:
with db_transaction(self.db):
file.status = 'error'
raise e