diff --git a/app/data/assets/templates/pull_sheet.html b/app/data/assets/templates/pull_sheet.html
index d269a79..41fa118 100644
--- a/app/data/assets/templates/pull_sheet.html
+++ b/app/data/assets/templates/pull_sheet.html
@@ -90,6 +90,12 @@ tr:hover {
text-align: center;
}
+.color-identity {
+ width: 40px;
+ text-align: center;
+ font-weight: bold;
+}
+
.product-name {
width: 200px;
}
@@ -119,6 +125,7 @@ tbody tr:hover {
Set |
Rarity |
Card # |
+ Colors |
@@ -129,6 +136,7 @@ tbody tr:hover {
{{ item.set }} |
{{ item.rarity }} |
{{ item.card_number }} |
+ {{ item.color_identity }} |
{% endfor %}
diff --git a/app/services/__init__.py b/app/services/__init__.py
index a01907e..8e49d1c 100644
--- a/app/services/__init__.py
+++ b/app/services/__init__.py
@@ -35,5 +35,6 @@ __all__ = [
'OrderManagementService',
'TCGPlayerInventoryService',
'PricingService',
- 'MarketplaceListingService'
+ 'MarketplaceListingService',
+ 'ScryfallService'
]
\ No newline at end of file
diff --git a/app/services/external_api/scryfall/scryfall_service.py b/app/services/external_api/scryfall/scryfall_service.py
new file mode 100644
index 0000000..2cb7109
--- /dev/null
+++ b/app/services/external_api/scryfall/scryfall_service.py
@@ -0,0 +1,11 @@
+from app.services.external_api.base_external_service import BaseExternalService
+
+class ScryfallService(BaseExternalService):
+ def __init__(self):
+ super().__init__(base_url="https://api.scryfall.com/")
+
+ async def get_color_identity(self, scryfall_id: str) -> str:
+ """Get the color identity of a card from Scryfall API"""
+ endpoint = f"cards/{scryfall_id}"
+ results = await self._make_request("GET", endpoint)
+ return results['color_identity']
\ No newline at end of file
diff --git a/app/services/pull_sheet_service.py b/app/services/pull_sheet_service.py
index d7b828e..ab6664f 100644
--- a/app/services/pull_sheet_service.py
+++ b/app/services/pull_sheet_service.py
@@ -1,4 +1,5 @@
from typing import List, Dict
+import json
import pandas as pd
from datetime import datetime
from pathlib import Path
@@ -9,7 +10,7 @@ import asyncio
from app.schemas.file import FileInDB
from app.services.base_service import BaseService
from sqlalchemy.orm import Session
-
+from app.models.tcgplayer_products import TCGPlayerProduct, TCGPlayerGroup, MTGJSONSKU, MTGJSONCard
logger = logging.getLogger(__name__)
@@ -48,7 +49,7 @@ class PullSheetService(BaseService):
"""
try:
# Read and process CSV data
- items = await self._read_and_process_csv(file.path)
+ items = await self._read_and_process_csv(db, file.path)
# Prepare template data
template_data = {
@@ -79,8 +80,51 @@ class PullSheetService(BaseService):
except Exception as e:
logger.error(f"Error generating pull sheet PDF: {str(e)}")
raise
+
+ async def _get_color_identity(self, db: Session, row: pd.Series) -> str:
+ """Get color identity from a row.
+
+ Args:
+ row: pandas Series
+ """
+ # get category id from set name
+ group_id = db.query(TCGPlayerGroup).filter(TCGPlayerGroup.name == row['Set']).first().group_id
+ # format number
+ number = str(int(row['Number'])) if 'Number' in row and pd.notna(row['Number']) and '/' not in str(row['Number']) else str(row['Number']) if 'Number' in row and pd.notna(row['Number']) and '/' in str(row['Number']) else ''
+ # get product info from category id
+ product_id = db.query(TCGPlayerProduct).filter(TCGPlayerProduct.group_id == group_id).filter(TCGPlayerProduct.name == row['Product Name']).filter(TCGPlayerProduct.ext_number == number).filter(TCGPlayerProduct.ext_rarity == row['Rarity']).first().tcgplayer_product_id
+ # get scryfall id from product id
+ mtgjson_id = db.query(MTGJSONSKU).filter(MTGJSONSKU.tcgplayer_product_id == product_id).first().mtgjson_uuid
+ scryfall_id = db.query(MTGJSONCard).filter(MTGJSONCard.mtgjson_uuid == mtgjson_id).first().scryfall_id
+ # get color identity from scryfall
+ scryfall_service = self.get_service('scryfall')
+ color_identity = await scryfall_service.get_color_identity(scryfall_id)
+ if color_identity is None:
+ return '?'
+ # color identity is str of json array, convert to human readable string of list
+ color_identity = [str(color) for color in color_identity]
+ # if color identity is empty, return C for colorless
+ if not color_identity:
+ return 'C'
+ # ensure order, W > U > B > R > G
+ color_identity = sorted(color_identity, key=lambda x: ['W', 'U', 'B', 'R', 'G'].index(x))
+ color_identity = ''.join(color_identity)
+ return color_identity
+
+ async def _update_row_color_identity(self, db: Session, row: pd.Series) -> pd.Series:
+ """Update color identity from a row.
+
+ Args:
+ row: pandas Series
+ """
+ # get color identity from row
+ color_identity = await self._get_color_identity(db, row)
+ # update row with color identity
+ row['Color Identity'] = color_identity
+ return row
+
- async def _read_and_process_csv(self, csv_path: str) -> List[Dict]:
+ async def _read_and_process_csv(self, db: Session, csv_path: str) -> List[Dict]:
"""Read and process CSV data using pandas.
Args:
@@ -103,6 +147,15 @@ class PullSheetService(BaseService):
# Sort by Set Release Date (descending) and then Product Name (ascending)
df = df.sort_values(['Set Release Date', 'Set', 'Product Name'], ascending=[False, True, True])
+
+ # Process color identities for all rows
+ color_identities = []
+ for _, row in df.iterrows():
+ color_identity = await self._get_color_identity(db, row)
+ color_identities.append(color_identity)
+
+ # Add color identity column to dataframe
+ df['Color Identity'] = color_identities
# Convert to list of dictionaries
items = []
@@ -113,7 +166,8 @@ class PullSheetService(BaseService):
'quantity': str(int(row['Quantity'])), # Convert to string for template
'set': row['Set'],
'rarity': row['Rarity'],
- 'card_number': str(int(row['Number'])) if 'Number' in row and pd.notna(row['Number']) and '/' not in str(row['Number']) else str(row['Number']) if 'Number' in row and pd.notna(row['Number']) and '/' in str(row['Number']) else ''
+ 'card_number': str(int(row['Number'])) if 'Number' in row and pd.notna(row['Number']) and '/' not in str(row['Number']) else str(row['Number']) if 'Number' in row and pd.notna(row['Number']) and '/' in str(row['Number']) else '',
+ 'color_identity': row['Color Identity']
})
return items
\ No newline at end of file
diff --git a/app/services/service_manager.py b/app/services/service_manager.py
index 957a1f5..98ab249 100644
--- a/app/services/service_manager.py
+++ b/app/services/service_manager.py
@@ -34,7 +34,8 @@ class ServiceManager:
'inventory': 'app.services.inventory_service.InventoryService',
'box': 'app.services.inventory_service.BoxService',
'case': 'app.services.inventory_service.CaseService',
- 'marketplace_listing': 'app.services.inventory_service.MarketplaceListingService'
+ 'marketplace_listing': 'app.services.inventory_service.MarketplaceListingService',
+ 'scryfall': 'app.services.external_api.scryfall.scryfall_service.ScryfallService'
}
self._service_configs = {