This commit is contained in:
2025-04-29 00:00:47 -04:00
parent 56ba750aad
commit c9bba8a26e
25 changed files with 1266 additions and 152052 deletions

View File

@ -12,6 +12,7 @@ from app.schemas.transaction import PurchaseTransactionCreate, PurchaseItem
from app.contexts.inventory_item import InventoryItemContextFactory
from app.models.tcgplayer_products import MTGJSONSKU, MTGJSONCard
from app.models.tcgplayer_products import TCGPlayerPriceHistory
from app.models.critical_error_log import CriticalErrorLog
import csv
import io
import logging
@ -349,7 +350,7 @@ class DataInitializationService(BaseService):
for price_data in archived_prices_data.get("results", []):
try:
# Get the subtype name from the price data
sub_type_name = price_data.get("subTypeName", "other")
sub_type_name = price_data.get("subTypeName", "None")
# First try to find product with the requested subtype
product = db.query(TCGPlayerProduct).filter(
@ -521,120 +522,178 @@ class DataInitializationService(BaseService):
}
async def sync_mtgjson_identifiers(self, db: Session, identifiers_data: List[dict]) -> int:
"""Sync MTGJSON identifiers data to the database"""
count = 0
with db_transaction(db):
# Load all existing UUIDs once
existing_cards = {
card.mtgjson_uuid: card
for card in db.query(MTGJSONCard).all()
}
new_cards = []
for card_data in identifiers_data:
if not isinstance(card_data, dict):
logger.debug(f"Skipping non-dict item: {card_data}")
continue
existing_card = db.query(MTGJSONCard).filter(MTGJSONCard.mtgjson_uuid == card_data.get("uuid")).first()
if existing_card:
# Update existing card
for key, value in {
uuid = card_data.get("uuid")
identifiers = card_data.get("identifiers", {})
if uuid in existing_cards:
card = existing_cards[uuid]
updates = {
"name": card_data.get("name"),
"set_code": card_data.get("setCode"),
"abu_id": card_data.get("identifiers", {}).get("abuId"),
"card_kingdom_etched_id": card_data.get("identifiers", {}).get("cardKingdomEtchedId"),
"card_kingdom_foil_id": card_data.get("identifiers", {}).get("cardKingdomFoilId"),
"card_kingdom_id": card_data.get("identifiers", {}).get("cardKingdomId"),
"cardsphere_id": card_data.get("identifiers", {}).get("cardsphereId"),
"cardsphere_foil_id": card_data.get("identifiers", {}).get("cardsphereFoilId"),
"cardtrader_id": card_data.get("identifiers", {}).get("cardtraderId"),
"csi_id": card_data.get("identifiers", {}).get("csiId"),
"mcm_id": card_data.get("identifiers", {}).get("mcmId"),
"mcm_meta_id": card_data.get("identifiers", {}).get("mcmMetaId"),
"miniaturemarket_id": card_data.get("identifiers", {}).get("miniaturemarketId"),
"mtg_arena_id": card_data.get("identifiers", {}).get("mtgArenaId"),
"mtgjson_foil_version_id": card_data.get("identifiers", {}).get("mtgjsonFoilVersionId"),
"mtgjson_non_foil_version_id": card_data.get("identifiers", {}).get("mtgjsonNonFoilVersionId"),
"mtgjson_v4_id": card_data.get("identifiers", {}).get("mtgjsonV4Id"),
"mtgo_foil_id": card_data.get("identifiers", {}).get("mtgoFoilId"),
"mtgo_id": card_data.get("identifiers", {}).get("mtgoId"),
"multiverse_id": card_data.get("identifiers", {}).get("multiverseId"),
"scg_id": card_data.get("identifiers", {}).get("scgId"),
"scryfall_id": card_data.get("identifiers", {}).get("scryfallId"),
"scryfall_card_back_id": card_data.get("identifiers", {}).get("scryfallCardBackId"),
"scryfall_oracle_id": card_data.get("identifiers", {}).get("scryfallOracleId"),
"scryfall_illustration_id": card_data.get("identifiers", {}).get("scryfallIllustrationId"),
"tcgplayer_product_id": card_data.get("identifiers", {}).get("tcgplayerProductId"),
"tcgplayer_etched_product_id": card_data.get("identifiers", {}).get("tcgplayerEtchedProductId"),
"tnt_id": card_data.get("identifiers", {}).get("tntId")
}.items():
setattr(existing_card, key, value)
"abu_id": identifiers.get("abuId"),
"card_kingdom_etched_id": identifiers.get("cardKingdomEtchedId"),
"card_kingdom_foil_id": identifiers.get("cardKingdomFoilId"),
"card_kingdom_id": identifiers.get("cardKingdomId"),
"cardsphere_id": identifiers.get("cardsphereId"),
"cardsphere_foil_id": identifiers.get("cardsphereFoilId"),
"cardtrader_id": identifiers.get("cardtraderId"),
"csi_id": identifiers.get("csiId"),
"mcm_id": identifiers.get("mcmId"),
"mcm_meta_id": identifiers.get("mcmMetaId"),
"miniaturemarket_id": identifiers.get("miniaturemarketId"),
"mtg_arena_id": identifiers.get("mtgArenaId"),
"mtgjson_foil_version_id": identifiers.get("mtgjsonFoilVersionId"),
"mtgjson_non_foil_version_id": identifiers.get("mtgjsonNonFoilVersionId"),
"mtgjson_v4_id": identifiers.get("mtgjsonV4Id"),
"mtgo_foil_id": identifiers.get("mtgoFoilId"),
"mtgo_id": identifiers.get("mtgoId"),
"multiverse_id": identifiers.get("multiverseId"),
"scg_id": identifiers.get("scgId"),
"scryfall_id": identifiers.get("scryfallId"),
"scryfall_card_back_id": identifiers.get("scryfallCardBackId"),
"scryfall_oracle_id": identifiers.get("scryfallOracleId"),
"scryfall_illustration_id": identifiers.get("scryfallIllustrationId"),
"tcgplayer_product_id": identifiers.get("tcgplayerProductId"),
"tcgplayer_etched_product_id": identifiers.get("tcgplayerEtchedProductId"),
"tnt_id": identifiers.get("tntId")
}
for k, v in updates.items():
if getattr(card, k) != v:
setattr(card, k, v)
else:
new_card = MTGJSONCard(
mtgjson_uuid=card_data.get("uuid"),
new_cards.append(MTGJSONCard(
mtgjson_uuid=uuid,
name=card_data.get("name"),
set_code=card_data.get("setCode"),
abu_id=card_data.get("identifiers", {}).get("abuId"),
card_kingdom_etched_id=card_data.get("identifiers", {}).get("cardKingdomEtchedId"),
card_kingdom_foil_id=card_data.get("identifiers", {}).get("cardKingdomFoilId"),
card_kingdom_id=card_data.get("identifiers", {}).get("cardKingdomId"),
cardsphere_id=card_data.get("identifiers", {}).get("cardsphereId"),
cardsphere_foil_id=card_data.get("identifiers", {}).get("cardsphereFoilId"),
cardtrader_id=card_data.get("identifiers", {}).get("cardtraderId"),
csi_id=card_data.get("identifiers", {}).get("csiId"),
mcm_id=card_data.get("identifiers", {}).get("mcmId"),
mcm_meta_id=card_data.get("identifiers", {}).get("mcmMetaId"),
miniaturemarket_id=card_data.get("identifiers", {}).get("miniaturemarketId"),
mtg_arena_id=card_data.get("identifiers", {}).get("mtgArenaId"),
mtgjson_foil_version_id=card_data.get("identifiers", {}).get("mtgjsonFoilVersionId"),
mtgjson_non_foil_version_id=card_data.get("identifiers", {}).get("mtgjsonNonFoilVersionId"),
mtgjson_v4_id=card_data.get("identifiers", {}).get("mtgjsonV4Id"),
mtgo_foil_id=card_data.get("identifiers", {}).get("mtgoFoilId"),
mtgo_id=card_data.get("identifiers", {}).get("mtgoId"),
multiverse_id=card_data.get("identifiers", {}).get("multiverseId"),
scg_id=card_data.get("identifiers", {}).get("scgId"),
scryfall_id=card_data.get("identifiers", {}).get("scryfallId"),
scryfall_card_back_id=card_data.get("identifiers", {}).get("scryfallCardBackId"),
scryfall_oracle_id=card_data.get("identifiers", {}).get("scryfallOracleId"),
scryfall_illustration_id=card_data.get("identifiers", {}).get("scryfallIllustrationId"),
tcgplayer_product_id=card_data.get("identifiers", {}).get("tcgplayerProductId"),
tcgplayer_etched_product_id=card_data.get("identifiers", {}).get("tcgplayerEtchedProductId"),
tnt_id=card_data.get("identifiers", {}).get("tntId")
)
db.add(new_card)
count += 1
abu_id=identifiers.get("abuId"),
card_kingdom_etched_id=identifiers.get("cardKingdomEtchedId"),
card_kingdom_foil_id=identifiers.get("cardKingdomFoilId"),
card_kingdom_id=identifiers.get("cardKingdomId"),
cardsphere_id=identifiers.get("cardsphereId"),
cardsphere_foil_id=identifiers.get("cardsphereFoilId"),
cardtrader_id=identifiers.get("cardtraderId"),
csi_id=identifiers.get("csiId"),
mcm_id=identifiers.get("mcmId"),
mcm_meta_id=identifiers.get("mcmMetaId"),
miniaturemarket_id=identifiers.get("miniaturemarketId"),
mtg_arena_id=identifiers.get("mtgArenaId"),
mtgjson_foil_version_id=identifiers.get("mtgjsonFoilVersionId"),
mtgjson_non_foil_version_id=identifiers.get("mtgjsonNonFoilVersionId"),
mtgjson_v4_id=identifiers.get("mtgjsonV4Id"),
mtgo_foil_id=identifiers.get("mtgoFoilId"),
mtgo_id=identifiers.get("mtgoId"),
multiverse_id=identifiers.get("multiverseId"),
scg_id=identifiers.get("scgId"),
scryfall_id=identifiers.get("scryfallId"),
scryfall_card_back_id=identifiers.get("scryfallCardBackId"),
scryfall_oracle_id=identifiers.get("scryfallOracleId"),
scryfall_illustration_id=identifiers.get("scryfallIllustrationId"),
tcgplayer_product_id=identifiers.get("tcgplayerProductId"),
tcgplayer_etched_product_id=identifiers.get("tcgplayerEtchedProductId"),
tnt_id=identifiers.get("tntId")
))
return count
count += 1
if new_cards:
db.bulk_save_objects(new_cards)
return count
async def sync_mtgjson_skus(self, db: Session, skus_data: dict) -> int:
"""Sync MTGJSON SKUs data to the database"""
count = 0
with db_transaction(db):
for mtgjson_uuid, product_data in skus_data['data'].items():
for sku_data in product_data:
existing_record = db.query(MTGJSONSKU).filter(MTGJSONSKU.mtgjson_uuid == mtgjson_uuid).filter(MTGJSONSKU.tcgplayer_sku_id == sku_data.get("skuId")).first()
if existing_record:
# Update existing SKU
for key, value in {
"tcgplayer_product_id": sku_data.get("productId"),
"condition": sku_data.get("condition"),
"finish": sku_data.get("finish"),
"language": sku_data.get("language"),
"printing": sku_data.get("printing"),
"normalized_printing": sku_data.get("printing").lower().replace(" ", "_") if sku_data.get("printing") else None
}.items():
setattr(existing_record, key, value)
else:
new_sku = MTGJSONSKU(
mtgjson_uuid=mtgjson_uuid,
tcgplayer_sku_id=sku_data.get("skuId"),
tcgplayer_product_id=sku_data.get("productId"),
condition=sku_data.get("condition"),
finish=sku_data.get("finish"),
language=sku_data.get("language"),
printing=sku_data.get("printing"),
normalized_printing=sku_data.get("printing").lower().replace(" ", "_") if sku_data.get("printing") else None
)
db.add(new_sku)
count += 1
sku_details_by_key = {}
for mtgjson_uuid, product_data in skus_data["data"].items():
for sku_data in product_data:
sku_id = sku_data.get("skuId")
if sku_id is None or sku_id in sku_details_by_key:
continue # Skip if missing or already added
sku_details_by_key[sku_id] = {
"mtgjson_uuid": mtgjson_uuid,
"tcgplayer_sku_id": sku_id,
"tcgplayer_product_id": sku_data.get("productId"),
"printing": sku_data.get("printing"),
"normalized_printing": sku_data.get("printing", "").lower().replace(" ", "_").replace("non_foil", "normal") if sku_data.get("printing") else None,
"condition": sku_data.get("condition"),
"finish": sku_data.get("finish"),
"language": sku_data.get("language"),
}
with db_transaction(db):
db.flush()
valid_uuids = {uuid for (uuid,) in db.query(MTGJSONCard.mtgjson_uuid).all()}
valid_product_keys = {
(product.tcgplayer_product_id, product.normalized_sub_type_name)
for product in db.query(TCGPlayerProduct.tcgplayer_product_id, TCGPlayerProduct.normalized_sub_type_name)
}
existing_sku_ids = {
sku.tcgplayer_sku_id
for sku in db.query(MTGJSONSKU.tcgplayer_sku_id).all()
}
existing = {
(sku.mtgjson_uuid, sku.tcgplayer_sku_id): sku
for sku in db.query(MTGJSONSKU).all()
}
new_skus = []
for data in sku_details_by_key.values():
sku_id = data["tcgplayer_sku_id"]
if sku_id in existing_sku_ids:
continue
mtgjson_uuid = data["mtgjson_uuid"]
product_id = data["tcgplayer_product_id"]
normalized_printing = data["normalized_printing"]
if mtgjson_uuid not in valid_uuids:
continue
if (product_id, normalized_printing) not in valid_product_keys:
continue
key = (mtgjson_uuid, sku_id)
if key in existing:
record = existing[key]
for field, value in data.items():
if field not in ("mtgjson_uuid", "tcgplayer_sku_id") and getattr(record, field) != value:
setattr(record, field, value)
else:
new_skus.append(MTGJSONSKU(**data))
count += 1
if new_skus:
db.bulk_save_objects(new_skus)
return count
return count
async def initialize_data(
self,
@ -693,19 +752,17 @@ class DataInitializationService(BaseService):
with db_transaction(db):
logger.info("Initializing inventory data...")
# set expected value
product_id1 = db.query(TCGPlayerProduct).filter(TCGPlayerProduct.tcgplayer_sku == "562118").first().id
expected_value_box = SealedExpectedValue(
product_id=product_id1,
expected_value=120.69
tcgplayer_product_id=619645,
expected_value=136.42
)
db.add(expected_value_box)
db.flush()
product_id2 = db.query(TCGPlayerProduct).filter(TCGPlayerProduct.tcgplayer_sku == "562119").first().id
expected_value_case = SealedExpectedValue(
product_id=product_id2,
expected_value=820.69
)
db.add(expected_value_case)
#db.flush()
#expected_value_case = SealedExpectedValue(
# tcgplayer_product_id=562119,
# expected_value=820.69
#)
#db.add(expected_value_case)
db.flush()
inventory_service = self.get_service("inventory")
@ -715,32 +772,38 @@ class DataInitializationService(BaseService):
transaction = await inventory_service.create_purchase_transaction(db, PurchaseTransactionCreate(
vendor_id=vendor.id,
transaction_date=datetime.now(),
items=[PurchaseItem(product_id=product_id1, unit_price=100.69, quantity=1, is_case=False),
PurchaseItem(product_id=product_id2, unit_price=800.01, quantity=2, is_case=True, num_boxes=6)],
transaction_notes="Test Transaction: 1 case and 2 boxes of foundations"
items=[PurchaseItem(product_id=619645, unit_price=100, quantity=1, is_case=False)],
transaction_notes="tdm real box test"
#PurchaseItem(product_id=562119, unit_price=800.01, quantity=2, is_case=True, num_boxes=6)],
#transaction_notes="Test Transaction: 1 case and 2 boxes of foundations"
))
logger.info(f"Transaction created: {transaction}")
case_num = 0
for item in transaction.transaction_items:
item = InventoryItemContextFactory(db).get_context(item.physical_item.inventory_item)
logger.info(f"Item: {item}")
if item.physical_item.item_type == "sealed_box":
if item.inventory_item.physical_item.item_type == "box":
manabox_service = self.get_service("manabox")
file_path = 'app/data/test_data/manabox_test_file.csv'
#file_path = 'app/data/test_data/manabox_test_file.csv'
file_path = 'app/data/test_data/tdmtest.csv'
file_bytes = open(file_path, 'rb').read()
manabox_file = await manabox_service.process_manabox_csv(db, file_bytes, {"source": "test", "description": "test"}, wait=True)
# Ensure manabox_file is a list before passing it
if not isinstance(manabox_file, list):
manabox_file = [manabox_file]
sealed_box_service = self.get_service("sealed_box")
sealed_box = sealed_box_service.get(db, item.physical_item.inventory_item.id)
success = await inventory_service.process_manabox_import_staging(db, manabox_file, sealed_box)
logger.info(f"sealed box opening success: {success}")
elif item.physical_item.item_type == "sealed_case":
box_service = self.get_service("box")
open_event = await box_service.open_box(db, item.inventory_item.physical_item, manabox_file)
# get all cards from box
cards = open_event.resulting_items if open_event.resulting_items else []
marketplace_listing_service = self.get_service("marketplace_listing")
for card in cards:
logger.info(f"card: {card}")
# create marketplace listing
await marketplace_listing_service.create_marketplace_listing(db, card.inventory_item, marketplace)
elif item.inventory_item.physical_item.item_type == "case":
if case_num == 0:
logger.info(f"sealed case {case_num} opening...")
sealed_case_service = self.get_service("sealed_case")
success = await sealed_case_service.open_sealed_case(db, item.physical_item)
case_service = self.get_service("case")
success = await case_service.open_case(db, item.inventory_item.physical_item, 562119)
logger.info(f"sealed case {case_num} opening success: {success}")
case_num += 1