diff --git a/app/main.py b/app/main.py index 9d33722..89ec4cf 100644 --- a/app/main.py +++ b/app/main.py @@ -58,8 +58,8 @@ async def lifespan(app: FastAPI): # Get a database session db = SessionLocal() try: - data_init_service = service_manager.get_service('data_initialization') - #data_init = await data_init_service.initialize_data(db, game_ids=[1], use_cache=False, init_categories=True, init_products=True, init_groups=True, init_archived_prices=True, init_mtgjson=True, archived_prices_start_date="2025-04-27", archived_prices_end_date="2025-04-28") + #data_init_service = service_manager.get_service('data_initialization') + #data_init = await data_init_service.initialize_data(db, game_ids=[1], use_cache=False, init_categories=True, init_products=True, init_groups=True, init_archived_prices=True, init_mtgjson=False, archived_prices_start_date="2025-05-22", archived_prices_end_date="2025-05-23") #logger.info(f"Data initialization results: {data_init}") # Update most recent prices #MostRecentTCGPlayerPrice.update_most_recent_prices(db) @@ -70,7 +70,7 @@ async def lifespan(app: FastAPI): #logger.info(f"Inventory data initialization results: {inv_data_init}") # Start the scheduler scheduler = service_manager.get_service('scheduler') - await scheduler.refresh_tcgplayer_inventory_table(db) + #await scheduler.refresh_tcgplayer_inventory_table(db) await scheduler.start_scheduled_tasks(db) logger.info("Scheduler started successfully") diff --git a/app/routes/inventory_management_routes.py b/app/routes/inventory_management_routes.py index 6e3a762..24d8eb4 100644 --- a/app/routes/inventory_management_routes.py +++ b/app/routes/inventory_management_routes.py @@ -232,7 +232,7 @@ async def get_transactions( limit: int = 100 ): inventory_service = service_manager.get_service("inventory") - total = db.query(func.count(Transaction.id)).scalar() + total = db.query(func.count(Transaction.id)).filter(Transaction.deleted_at == None).scalar() transactions = await inventory_service.get_transactions(db, skip, limit) return GetAllTransactionsResponse( total=total, diff --git a/app/services/file_service.py b/app/services/file_service.py index 3ebe2a4..27052b5 100644 --- a/app/services/file_service.py +++ b/app/services/file_service.py @@ -120,7 +120,7 @@ class FileService: """List files with optional filtering""" query = db.query(File) if file_type: - query = query.filter(File.file_type == file_type).order_by(File.created_at.desc()) + query = query.filter(File.file_type == file_type).filter(File.deleted_at == None).order_by(File.created_at.desc()) files = query.offset(skip).limit(limit).all() return [FileInDB.model_validate(file) for file in files] diff --git a/app/services/inventory_service.py b/app/services/inventory_service.py index 2e7284e..4c38392 100644 --- a/app/services/inventory_service.py +++ b/app/services/inventory_service.py @@ -26,13 +26,13 @@ class InventoryService(BaseService): # Get the IDs of resulting items resulting_item_ids = [item.id for item in open_event.resulting_items] # Query using the IDs - return db.query(InventoryItem).filter(InventoryItem.physical_item_id.in_(resulting_item_ids)).all() + return db.query(InventoryItem).filter(InventoryItem.physical_item_id.in_(resulting_item_ids)).filter(InventoryItem.deleted_at == None).all() async def get_open_event(self, db: Session, inventory_item: InventoryItem, open_event_id: int) -> OpenEvent: - return db.query(OpenEvent).filter(OpenEvent.source_item == inventory_item.physical_item).filter(OpenEvent.id == open_event_id).first() + return db.query(OpenEvent).filter(OpenEvent.source_item == inventory_item.physical_item).filter(OpenEvent.id == open_event_id).filter(OpenEvent.deleted_at == None).first() async def get_open_events_for_inventory_item(self, db: Session, inventory_item: InventoryItem) -> List[OpenEvent]: - return db.query(OpenEvent).filter(OpenEvent.source_item == inventory_item.physical_item).all() + return db.query(OpenEvent).filter(OpenEvent.source_item == inventory_item.physical_item).filter(OpenEvent.deleted_at == None).all() async def get_inventory_item(self, db: Session, inventory_item_id: int) -> InventoryItem: return db.query(InventoryItem)\ @@ -43,11 +43,12 @@ class InventoryService(BaseService): .first() async def get_expected_value(self, db: Session, product_id: int) -> float: - expected_value = db.query(SealedExpectedValue).filter(SealedExpectedValue.tcgplayer_product_id == product_id).first() + expected_value = db.query(SealedExpectedValue).filter(SealedExpectedValue.tcgplayer_product_id == product_id).filter(SealedExpectedValue.deleted_at == None).first() return expected_value.expected_value if expected_value else None async def get_transactions(self, db: Session, skip: int, limit: int) -> List[Transaction]: return db.query(Transaction)\ + .filter(Transaction.deleted_at == None)\ .order_by(Transaction.transaction_date.desc())\ .offset(skip)\ .limit(limit)\ @@ -62,6 +63,7 @@ class InventoryService(BaseService): joinedload(Transaction.marketplaces) )\ .filter(Transaction.id == transaction_id)\ + .filter(Transaction.deleted_at == None)\ .first() async def create_expected_value(self, db: Session, expected_value_data: SealedExpectedValueCreate) -> SealedExpectedValue: diff --git a/app/services/pricing_service.py b/app/services/pricing_service.py index e16eace..565a59d 100644 --- a/app/services/pricing_service.py +++ b/app/services/pricing_service.py @@ -45,7 +45,7 @@ class PricingService(BaseService): tcgplayer_shipping_fee = Decimal('1.31') average_cards_per_order = Decimal('3.0') marketplace_fee_percentage = Decimal('0.20') - target_margin = Decimal('0.10') + target_margin = Decimal('0.20') velocity_multiplier = Decimal('0.0') global_margin_multiplier = Decimal('0.00') min_floor_price = Decimal('0.25') @@ -55,17 +55,17 @@ class PricingService(BaseService): # card cost margin multiplier if market_price > 0 and market_price < 2: - card_cost_margin_multiplier = Decimal('-0.075') + card_cost_margin_multiplier = Decimal('-0.033') elif market_price >= 2 and market_price < 10: - card_cost_margin_multiplier = Decimal('-0.025') + card_cost_margin_multiplier = Decimal('0.0') elif market_price >= 10 and market_price < 30: - card_cost_margin_multiplier = Decimal('0.025') + card_cost_margin_multiplier = Decimal('0.0125') elif market_price >= 30 and market_price < 50: - card_cost_margin_multiplier = Decimal('0.05') + card_cost_margin_multiplier = Decimal('0.025') elif market_price >= 50 and market_price < 100: - card_cost_margin_multiplier = Decimal('0.075') + card_cost_margin_multiplier = Decimal('0.033') elif market_price >= 100 and market_price < 200: - card_cost_margin_multiplier = Decimal('0.10') + card_cost_margin_multiplier = Decimal('0.05') # Fetch current total quantity in stock for SKU quantity_record = db.query(TCGPlayerInventory).filter( @@ -77,11 +77,11 @@ class PricingService(BaseService): if quantity_in_stock < 4: quantity_multiplier = Decimal('0.0') elif quantity_in_stock == 4: - quantity_multiplier = Decimal('0.1') - elif 5 <= quantity_in_stock < 10: quantity_multiplier = Decimal('0.2') - elif quantity_in_stock >= 10: + elif 5 <= quantity_in_stock < 10: quantity_multiplier = Decimal('0.3') + elif quantity_in_stock >= 10: + quantity_multiplier = Decimal('0.4') else: quantity_multiplier = Decimal('0.0') @@ -130,7 +130,7 @@ class PricingService(BaseService): free_shipping_adjustment = False for x in range(1, 5): quantity = Decimal(str(x)) - if Decimal('5.00') <= adjusted_price * quantity <= Decimal('5.05'): + if Decimal('5.00') <= adjusted_price * quantity <= Decimal('5.15'): adjusted_price = Decimal('4.99') / quantity free_shipping_adjustment = True break diff --git a/app/services/pull_sheet_service.py b/app/services/pull_sheet_service.py index 01465bc..d7b828e 100644 --- a/app/services/pull_sheet_service.py +++ b/app/services/pull_sheet_service.py @@ -113,7 +113,7 @@ 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 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 '' }) return items \ No newline at end of file diff --git a/app/services/scheduler/base_scheduler.py b/app/services/scheduler/base_scheduler.py index f4ea920..9255a40 100644 --- a/app/services/scheduler/base_scheduler.py +++ b/app/services/scheduler/base_scheduler.py @@ -22,16 +22,6 @@ class BaseScheduler: *args, **kwargs ) -> None: - """Schedule a task to run at regular intervals or at specific times using APScheduler - - Args: - task_name: Name of the task - func: Function to execute - interval_seconds: Interval in seconds for periodic execution (mutually exclusive with cron_expression) - cron_expression: Cron expression for time-based scheduling (mutually exclusive with interval_seconds) - *args: Additional positional arguments for the function - **kwargs: Additional keyword arguments for the function - """ if task_name in self.jobs: logger.warning(f"Task {task_name} already exists. Removing existing job.") self.jobs[task_name].remove() @@ -47,20 +37,22 @@ class BaseScheduler: trigger = CronTrigger.from_crontab(cron_expression) job = self.scheduler.add_job( - func, + func=func, trigger=trigger, args=args, kwargs=kwargs, id=task_name, replace_existing=True ) - + self.jobs[task_name] = job + if interval_seconds: logger.info(f"Scheduled task {task_name} to run every {interval_seconds} seconds") else: logger.info(f"Scheduled task {task_name} with cron expression: {cron_expression}") + def remove_task(self, task_name: str) -> None: """Remove a scheduled task""" if task_name in self.jobs: diff --git a/app/services/scheduler/scheduler_service.py b/app/services/scheduler/scheduler_service.py index 3df5349..3dda5a9 100644 --- a/app/services/scheduler/scheduler_service.py +++ b/app/services/scheduler/scheduler_service.py @@ -74,20 +74,23 @@ class SchedulerService(BaseService): # Schedule open orders update to run hourly at 00 minutes await self.scheduler.schedule_task( task_name="update_open_orders_hourly", - func=lambda: self.update_open_orders_hourly(db), - cron_expression="0 * * * *" # Run at minute 0 of every hour + func=self.update_open_orders_hourly, + cron_expression="10 * * * *", # Run at minute 10 of every hour + db=db ) # Schedule all orders update to run daily at 3 AM await self.scheduler.schedule_task( task_name="update_all_orders_daily", - func=lambda: self.update_all_orders_daily(db), - cron_expression="0 3 * * *" # Run at 3:00 AM every day + func=self.update_all_orders_daily, + cron_expression="0 3 * * *", # Run at 3:00 AM every day + db=db ) # Schedule TCGPlayer inventory refresh to run every 3 hours await self.scheduler.schedule_task( task_name="refresh_tcgplayer_inventory_table", - func=lambda: self.refresh_tcgplayer_inventory_table(db), - cron_expression="21 */3 * * *" # Run at minute 0 of every 3rd hour + func=self.refresh_tcgplayer_inventory_table, + cron_expression="28 */3 * * *", # Run at minute 28 of every 3rd hour + db=db ) self.scheduler.start() diff --git a/app/static/transactions.js b/app/static/transactions.js index db11f22..4b52043 100644 --- a/app/static/transactions.js +++ b/app/static/transactions.js @@ -777,8 +777,8 @@ async function showOpenBoxModal(inventoryItemId, physicalItemId) {