god help me

This commit is contained in:
zman 2025-04-19 22:54:07 -04:00
parent 6178fdd15d
commit 34eac3d954
2864 changed files with 318 additions and 3207 deletions

View File

@ -0,0 +1,86 @@
"""idk lol
Revision ID: 28cfdbde1796
Revises: d4d3f43ce86a
Create Date: 2025-04-19 16:17:07.109451
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision: str = '28cfdbde1796'
down_revision: Union[str, None] = 'd4d3f43ce86a'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('ix_cost_basis_id', table_name='cost_basis')
op.drop_table('cost_basis')
op.drop_index('ix_cards_id', table_name='cards')
op.drop_index('ix_cards_name', table_name='cards')
op.drop_index('ix_cards_set_name', table_name='cards')
op.drop_index('ix_cards_tcgplayer_sku', table_name='cards')
op.drop_table('cards')
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('cards',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('rarity', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('set_name', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('price', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True),
sa.Column('quantity', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('tcgplayer_sku', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('product_line', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('product_name', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('title', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('number', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('condition', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('tcg_market_price', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True),
sa.Column('tcg_direct_low', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True),
sa.Column('tcg_low_price_with_shipping', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True),
sa.Column('tcg_low_price', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True),
sa.Column('total_quantity', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('add_to_quantity', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('tcg_marketplace_price', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True),
sa.Column('photo_url', sa.VARCHAR(), autoincrement=False, nullable=True),
sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=True),
sa.Column('updated_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='cards_pkey')
)
op.create_index('ix_cards_tcgplayer_sku', 'cards', ['tcgplayer_sku'], unique=True)
op.create_index('ix_cards_set_name', 'cards', ['set_name'], unique=False)
op.create_index('ix_cards_name', 'cards', ['name'], unique=False)
op.create_index('ix_cards_id', 'cards', ['id'], unique=False)
op.create_table('cost_basis',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('transaction_item_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('sealed_case_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('sealed_box_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('open_box_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('open_card_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('quantity', sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('unit_cost', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=False),
sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
sa.Column('updated_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
sa.Column('deleted_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['open_box_id'], ['open_boxes.id'], name='cost_basis_open_box_id_fkey'),
sa.ForeignKeyConstraint(['open_card_id'], ['open_cards.id'], name='cost_basis_open_card_id_fkey'),
sa.ForeignKeyConstraint(['sealed_box_id'], ['sealed_boxes.id'], name='cost_basis_sealed_box_id_fkey'),
sa.ForeignKeyConstraint(['sealed_case_id'], ['sealed_cases.id'], name='cost_basis_sealed_case_id_fkey'),
sa.ForeignKeyConstraint(['transaction_item_id'], ['transaction_items.id'], name='cost_basis_transaction_item_id_fkey'),
sa.PrimaryKeyConstraint('id', name='cost_basis_pkey')
)
op.create_index('ix_cost_basis_id', 'cost_basis', ['id'], unique=False)
# ### end Alembic commands ###

94
app.log
View File

@ -1,28 +1,66 @@
2025-04-19 13:56:40,410 - INFO - app.main - Application starting up... 2025-04-19 21:40:53,869 - INFO - app.main - Application starting up...
2025-04-19 13:56:40,492 - INFO - app.main - Database initialized successfully 2025-04-19 21:40:53,914 - INFO - app.main - Database initialized successfully
2025-04-19 13:56:40,492 - INFO - app.services.service_manager - Service OrderManagementService registered 2025-04-19 21:40:53,914 - INFO - app.services.service_manager - Service OrderManagementService registered
2025-04-19 13:56:40,492 - INFO - app.services.service_manager - Service TCGPlayerInventoryService registered 2025-04-19 21:40:53,914 - INFO - app.services.service_manager - Service TCGPlayerInventoryService registered
2025-04-19 13:56:40,492 - INFO - app.services.service_manager - Service LabelPrinterService registered 2025-04-19 21:40:53,915 - INFO - app.services.service_manager - Service LabelPrinterService registered
2025-04-19 13:56:40,492 - INFO - app.services.service_manager - Service RegularPrinterService registered 2025-04-19 21:40:53,915 - INFO - app.services.service_manager - Service RegularPrinterService registered
2025-04-19 13:56:40,495 - INFO - app.services.service_manager - Service AddressLabelService registered 2025-04-19 21:40:53,918 - INFO - app.services.service_manager - Service AddressLabelService registered
2025-04-19 13:56:40,497 - INFO - app.services.service_manager - Service PullSheetService registered 2025-04-19 21:40:53,920 - INFO - app.services.service_manager - Service PullSheetService registered
2025-04-19 13:56:40,497 - INFO - app.services.service_manager - Service SetLabelService registered 2025-04-19 21:40:53,920 - INFO - app.services.service_manager - Service SetLabelService registered
2025-04-19 13:56:40,497 - INFO - app.services.service_manager - Service DataInitializationService registered 2025-04-19 21:40:53,920 - INFO - app.services.service_manager - Service DataInitializationService registered
2025-04-19 13:56:40,498 - INFO - app.services.service_manager - Service SchedulerService registered 2025-04-19 21:40:53,920 - DEBUG - tzlocal - /etc/localtime found
2025-04-19 13:56:40,498 - INFO - app.services.service_manager - Service FileService registered 2025-04-19 21:40:53,921 - DEBUG - tzlocal - 1 found:
2025-04-19 13:56:40,498 - INFO - app.services.service_manager - Service TCGCSVService registered {'/etc/localtime is a symlink to': 'US/Michigan'}
2025-04-19 13:56:40,498 - INFO - app.services.service_manager - Service MTGJSONService registered 2025-04-19 21:40:53,921 - INFO - app.services.service_manager - Service SchedulerService registered
2025-04-19 13:56:40,499 - INFO - app.services.service_manager - All services initialized successfully 2025-04-19 21:40:53,921 - INFO - app.services.service_manager - Service FileService registered
2025-04-19 13:56:40,499 - INFO - app.services.data_initialization - Starting data initialization process 2025-04-19 21:40:53,921 - INFO - app.services.service_manager - Service TCGCSVService registered
2025-04-19 13:56:40,499 - INFO - app.services.data_initialization - Data initialization completed 2025-04-19 21:40:53,921 - INFO - app.services.service_manager - Service MTGJSONService registered
2025-04-19 13:56:40,499 - INFO - app.main - Data initialization results: {} 2025-04-19 21:40:53,921 - INFO - app.services.service_manager - All services initialized successfully
2025-04-19 13:56:40,499 - INFO - apscheduler.scheduler - Adding job tentatively -- it will be properly scheduled when the scheduler starts 2025-04-19 21:40:53,921 - INFO - app.services.data_initialization - Starting data initialization process
2025-04-19 13:56:40,499 - INFO - app.services.scheduler.base_scheduler - Scheduled task update_open_orders_hourly to run every 3600 seconds 2025-04-19 21:40:53,921 - INFO - app.services.data_initialization - Initializing MTGJSON data...
2025-04-19 13:56:40,499 - INFO - apscheduler.scheduler - Adding job tentatively -- it will be properly scheduled when the scheduler starts 2025-04-19 21:40:53,921 - INFO - app.services.data_initialization - Starting MTGJSON initialization
2025-04-19 13:56:40,499 - INFO - app.services.scheduler.base_scheduler - Scheduled task update_all_orders_daily to run every 86400 seconds 2025-04-19 21:40:53,947 - DEBUG - app.services.external_api.mtgjson.mtgjson_service - Loaded SKUs from cache: app/data/cache/mtgjson/skus/TcgplayerSkus.json
2025-04-19 13:56:40,499 - INFO - apscheduler.scheduler - Added job "SchedulerService.start_scheduled_tasks.<locals>.<lambda>" to job store "default" 2025-04-19 22:38:54,248 - INFO - app.services.data_initialization - Data initialization completed
2025-04-19 13:56:40,500 - INFO - apscheduler.scheduler - Added job "SchedulerService.start_scheduled_tasks.<locals>.<lambda>" to job store "default" 2025-04-19 22:38:54,249 - INFO - app.main - Data initialization results: {'mtgjson': {'identifiers_processed': 0, 'skus_processed': 4764017}}
2025-04-19 13:56:40,500 - INFO - apscheduler.scheduler - Scheduler started 2025-04-19 22:38:54,249 - INFO - apscheduler.scheduler - Adding job tentatively -- it will be properly scheduled when the scheduler starts
2025-04-19 13:56:40,500 - INFO - app.services.scheduler.base_scheduler - Scheduler started 2025-04-19 22:38:54,249 - INFO - app.services.scheduler.base_scheduler - Scheduled task update_open_orders_hourly to run every 3600 seconds
2025-04-19 13:56:40,500 - INFO - app.services.scheduler.scheduler_service - All scheduled tasks started 2025-04-19 22:38:54,249 - INFO - apscheduler.scheduler - Adding job tentatively -- it will be properly scheduled when the scheduler starts
2025-04-19 13:56:40,500 - INFO - app.main - Scheduler started successfully 2025-04-19 22:38:54,249 - INFO - app.services.scheduler.base_scheduler - Scheduled task update_all_orders_daily to run every 86400 seconds
2025-04-19 22:38:54,250 - INFO - apscheduler.scheduler - Added job "SchedulerService.start_scheduled_tasks.<locals>.<lambda>" to job store "default"
2025-04-19 22:38:54,250 - INFO - apscheduler.scheduler - Added job "SchedulerService.start_scheduled_tasks.<locals>.<lambda>" to job store "default"
2025-04-19 22:38:54,250 - INFO - apscheduler.scheduler - Scheduler started
2025-04-19 22:38:54,250 - INFO - app.services.scheduler.base_scheduler - Scheduler started
2025-04-19 22:38:54,250 - INFO - app.services.scheduler.scheduler_service - All scheduled tasks started
2025-04-19 22:38:54,250 - INFO - app.main - Scheduler started successfully
2025-04-19 22:38:54,251 - DEBUG - apscheduler.scheduler - Looking for jobs to run
2025-04-19 22:38:54,251 - DEBUG - apscheduler.scheduler - Next wakeup is due at 2025-04-19 23:38:54.249141-04:00 (in 3599.997778 seconds)
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service MTGJSONService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service mtgjson cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service TCGCSVService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service tcgcsv cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service FileService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service file cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.scheduler.base_scheduler - Scheduler stopped
2025-04-19 22:53:56,053 - INFO - app.services.scheduler.scheduler_service - Scheduler services closed
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service SchedulerService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.scheduler.scheduler_service - Scheduler services closed
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service scheduler cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service DataInitializationService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service data_initialization cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service SetLabelService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service set_label cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service PullSheetService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service pull_sheet cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service AddressLabelService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service address_label cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service RegularPrinterService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service regular_printer cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service LabelPrinterService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service label_printer cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service TCGPlayerInventoryService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service tcgplayer_inventory cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service OrderManagementService cleaned up
2025-04-19 22:53:56,053 - INFO - app.services.service_manager - Service order_management cleaned up
2025-04-19 22:53:56,054 - INFO - app.services.service_manager - All services cleaned up successfully
2025-04-19 22:53:56,054 - INFO - app.main - All services cleaned up successfully
2025-04-19 22:53:56,054 - INFO - apscheduler.scheduler - Scheduler has been shut down

View File

@ -30,7 +30,7 @@ file_handler.setFormatter(formatter)
# Configure root logger # Configure root logger
root_logger = logging.getLogger() root_logger = logging.getLogger()
root_logger.setLevel(logging.INFO) root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(console_handler) root_logger.addHandler(console_handler)
root_logger.addHandler(file_handler) root_logger.addHandler(file_handler)
@ -58,7 +58,7 @@ async def lifespan(app: FastAPI):
db = SessionLocal() db = SessionLocal()
try: try:
data_init_service = service_manager.get_service('data_initialization') data_init_service = service_manager.get_service('data_initialization')
data_init = await data_init_service.initialize_data(db, game_ids=[1, 3], use_cache=False, init_categories=False, init_products=False, init_groups=False, init_archived_prices=False, init_mtgjson=False, archived_prices_start_date="2024-03-05", archived_prices_end_date="2025-04-17") data_init = await data_init_service.initialize_data(db, game_ids=[1, 3], use_cache=True, init_categories=False, init_products=False, init_groups=False, init_archived_prices=False, init_mtgjson=True, archived_prices_start_date="2024-03-05", archived_prices_end_date="2025-04-17")
logger.info(f"Data initialization results: {data_init}") logger.info(f"Data initialization results: {data_init}")
# Start the scheduler # Start the scheduler

View File

@ -6,8 +6,7 @@ from app.models.inventory_management import (
OpenEvent, OpenEvent,
Vendor, Vendor,
Customer, Customer,
Transaction, Transaction
CostBasis
) )
from app.models.mtgjson_card import MTGJSONCard from app.models.mtgjson_card import MTGJSONCard
from app.models.mtgjson_sku import MTGJSONSKU from app.models.mtgjson_sku import MTGJSONSKU
@ -34,7 +33,6 @@ __all__ = [
'Vendor', 'Vendor',
'Customer', 'Customer',
'Transaction', 'Transaction',
'CostBasis',
'MTGJSONCard', 'MTGJSONCard',
'MTGJSONSKU', 'MTGJSONSKU',
'Product', 'Product',

View File

@ -1,8 +1,4 @@
from pydantic import BaseModel, ConfigDict
from typing import List, Optional
from datetime import datetime
from sqlalchemy import Column, Integer, String, DateTime, JSON from sqlalchemy import Column, Integer, String, DateTime, JSON
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func from sqlalchemy.sql import func
from app.db.database import Base from app.db.database import Base

View File

@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, Table from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from app.db.database import Base from app.db.database import Base
@ -32,7 +32,7 @@ class SealedCase(PhysicalItem):
} }
# Relationships # Relationships
boxes = relationship("SealedBox", back_populates="case") boxes = relationship("SealedBox", back_populates="case", foreign_keys="[SealedBox.case_id]")
open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_case") open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_case")
class SealedBox(PhysicalItem): class SealedBox(PhysicalItem):
@ -46,7 +46,7 @@ class SealedBox(PhysicalItem):
} }
# Relationships # Relationships
case = relationship("SealedCase", back_populates="boxes") case = relationship("SealedCase", back_populates="boxes", foreign_keys=[case_id])
open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_box") open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_box")
class OpenBox(PhysicalItem): class OpenBox(PhysicalItem):
@ -62,8 +62,8 @@ class OpenBox(PhysicalItem):
# Relationships # Relationships
open_event = relationship("OpenEvent", back_populates="resulting_boxes") open_event = relationship("OpenEvent", back_populates="resulting_boxes")
sealed_box = relationship("SealedBox") sealed_box = relationship("SealedBox", foreign_keys=[sealed_box_id])
cards = relationship("OpenCard", back_populates="box") cards = relationship("OpenCard", back_populates="box", foreign_keys="[OpenCard.box_id]")
class OpenCard(PhysicalItem): class OpenCard(PhysicalItem):
__tablename__ = "open_cards" __tablename__ = "open_cards"
@ -78,7 +78,7 @@ class OpenCard(PhysicalItem):
# Relationships # Relationships
open_event = relationship("OpenEvent", back_populates="resulting_cards") open_event = relationship("OpenEvent", back_populates="resulting_cards")
box = relationship("OpenBox", back_populates="cards") box = relationship("OpenBox", back_populates="cards", foreign_keys=[box_id])
class InventoryItem(Base): class InventoryItem(Base):
__tablename__ = "inventory_items" __tablename__ = "inventory_items"
@ -93,8 +93,8 @@ class InventoryItem(Base):
# Relationships # Relationships
physical_item = relationship("PhysicalItem", back_populates="inventory_item") physical_item = relationship("PhysicalItem", back_populates="inventory_item")
parent = relationship("InventoryItem", remote_side=[id]) parent = relationship("InventoryItem", remote_side=[id], back_populates="children")
children = relationship("InventoryItem") children = relationship("InventoryItem", back_populates="parent", overlaps="parent")
class TransactionItem(Base): class TransactionItem(Base):
__tablename__ = "transaction_items" __tablename__ = "transaction_items"
@ -161,25 +161,3 @@ class Transaction(Base):
# Relationships # Relationships
transaction_items = relationship("TransactionItem", back_populates="transaction") transaction_items = relationship("TransactionItem", back_populates="transaction")
class CostBasis(Base):
__tablename__ = "cost_basis"
id = Column(Integer, primary_key=True, index=True)
transaction_item_id = Column(Integer, ForeignKey("transaction_items.id"))
sealed_case_id = Column(Integer, ForeignKey("sealed_cases.id"), nullable=True)
sealed_box_id = Column(Integer, ForeignKey("sealed_boxes.id"), nullable=True)
open_box_id = Column(Integer, ForeignKey("open_boxes.id"), nullable=True)
open_card_id = Column(Integer, ForeignKey("open_cards.id"), nullable=True)
quantity = Column(Integer, nullable=False, default=1)
unit_cost = Column(Float, nullable=False)
created_at = Column(DateTime(timezone=True))
updated_at = Column(DateTime(timezone=True))
deleted_at = Column(DateTime(timezone=True), nullable=True)
# Relationships
transaction_item = relationship("TransactionItem")
sealed_case = relationship("SealedCase")
sealed_box = relationship("SealedBox")
open_box = relationship("OpenBox")
open_card = relationship("OpenCard")

View File

@ -1,17 +1,13 @@
from fastapi import APIRouter, HTTPException, Depends, Query, UploadFile, File from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
from typing import List from typing import List
from datetime import datetime
from enum import Enum from enum import Enum
from app.schemas.tcgplayer import TCGPlayerAPIOrderSummary, TCGPlayerAPIOrder from app.schemas.tcgplayer import TCGPlayerAPIOrderSummary, TCGPlayerAPIOrder
from app.schemas.generate import GenerateAddressLabelsRequest, GeneratePackingSlipsRequest, GeneratePullSheetsRequest, GenerateResponse, GenerateReturnLabelsRequest from app.schemas.generate import GenerateAddressLabelsRequest, GeneratePackingSlipsRequest, GeneratePullSheetsRequest, GenerateResponse, GenerateReturnLabelsRequest
from app.schemas.file import FileUpload
from app.services.service_manager import ServiceManager from app.services.service_manager import ServiceManager
from app.services.file_service import FileService
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.db.database import get_db from app.db.database import get_db
import os
import tempfile
import logging import logging
from datetime import datetime
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -223,3 +219,24 @@ async def print_pirate_ship_label(
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to print Pirate Ship label: {str(e)}") raise HTTPException(status_code=500, detail=f"Failed to print Pirate Ship label: {str(e)}")
@router.post("/process-manabox-csv")
async def process_manabox_csv(
file: UploadFile = File(...),
db: Session = Depends(get_db)
) -> GenerateResponse:
try:
# ensure csv
if file.content_type != "text/csv":
raise HTTPException(status_code=400, detail="File must be a CSV")
# read file
content = await file.read()
# save file
file_service = service_manager.get_service('file')
stored_file = await file_service.save_file(db, content, f'manabox_upload_{datetime.now().strftime("%Y%m%d_%H%M%S")}.csv', "manabox_csvs", "csv")
# process csv
manabox_service = service_manager.get_service('manabox')
success = await manabox_service.process_manabox_csv(db, stored_file)
return {"success": success, "message": "Manabox CSV processed successfully"}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to process Manabox CSV: {str(e)}")

View File

@ -1,7 +1,7 @@
import os import os
import json import json
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional, List, Dict, Any, Union, Generator, Callable from typing import Optional, List, Dict, Any, Union, Generator, Callable, AsyncGenerator
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.models.tcgplayer_group import TCGPlayerGroup from app.models.tcgplayer_group import TCGPlayerGroup
from app.models.tcgplayer_product import TCGPlayerProduct from app.models.tcgplayer_product import TCGPlayerProduct
@ -462,111 +462,37 @@ class DataInitializationService(BaseService):
identifiers_count = 0 identifiers_count = 0
skus_count = 0 skus_count = 0
# Process identifiers # Get identifiers data
if use_cache: identifiers_data = await mtgjson_service.get_identifiers(db, use_cache)
cached_file = await self.file_service.get_file_by_filename(db, "mtgjson_identifiers.json") if identifiers_data and "data" in identifiers_data:
if cached_file and os.path.exists(cached_file.path): identifiers_count = await self.sync_mtgjson_identifiers(db, list(identifiers_data["data"].values()))
logger.info("MTGJSON identifiers initialized from cache")
identifiers_count = await self._process_streamed_data(
db,
self._stream_json_file(cached_file.path),
"mtgjson_identifiers.json",
"mtgjson",
self.sync_mtgjson_identifiers
)
else:
logger.info("Downloading MTGJSON identifiers from API")
identifiers_count = await self._process_streamed_data(
db,
await mtgjson_service.get_identifiers(db),
"mtgjson_identifiers.json",
"mtgjson",
self.sync_mtgjson_identifiers
)
else:
logger.info("Downloading MTGJSON identifiers from API")
identifiers_count = await self._process_streamed_data(
db,
await mtgjson_service.get_identifiers(db),
"mtgjson_identifiers.json",
"mtgjson",
self.sync_mtgjson_identifiers
)
# Process SKUs # Get SKUs data
if use_cache: skus_data = await mtgjson_service.get_skus(db, use_cache)
cached_file = await self.file_service.get_file_by_filename(db, "mtgjson_skus.json") if skus_data and "data" in skus_data:
if cached_file and os.path.exists(cached_file.path): skus_count = await self.sync_mtgjson_skus(db, list(skus_data["data"].values()))
logger.info("MTGJSON SKUs initialized from cache")
skus_count = await self._process_streamed_data(
db,
self._stream_json_file(cached_file.path),
"mtgjson_skus.json",
"mtgjson",
self.sync_mtgjson_skus
)
else:
logger.info("Downloading MTGJSON SKUs from API")
skus_count = await self._process_streamed_data(
db,
await mtgjson_service.get_skus(db),
"mtgjson_skus.json",
"mtgjson",
self.sync_mtgjson_skus
)
else:
logger.info("Downloading MTGJSON SKUs from API")
skus_count = await self._process_streamed_data(
db,
await mtgjson_service.get_skus(db),
"mtgjson_skus.json",
"mtgjson",
self.sync_mtgjson_skus
)
return { return {
"identifiers_processed": identifiers_count, "identifiers_processed": identifiers_count,
"skus_processed": skus_count "skus_processed": skus_count
} }
async def _process_streamed_data( async def sync_mtgjson_identifiers(self, db: Session, identifiers_data: List[dict]) -> int:
self,
db: Session,
data_stream: Generator[Dict[str, Any], None, None],
filename: str,
subdir: str,
sync_func: Callable
) -> int:
"""Process streamed data and sync to database"""
count = 0
items = []
batch_size = 1000
for item in data_stream:
if item["type"] == "meta":
# Handle meta data separately
continue
count += 1
items.append(item["data"])
# Process in batches
if len(items) >= batch_size:
await sync_func(db, items)
items = []
# Process any remaining items
if items:
await sync_func(db, items)
return count
async def sync_mtgjson_identifiers(self, db: Session, identifiers_data: dict):
"""Sync MTGJSON identifiers data to the database""" """Sync MTGJSON identifiers data to the database"""
from app.models.mtgjson_card import MTGJSONCard from app.models.mtgjson_card import MTGJSONCard
count = 0
with transaction(db): with transaction(db):
for card_id, card_data in identifiers_data.items(): for card_data in identifiers_data:
if not isinstance(card_data, dict):
logger.debug(f"Skipping non-dict item: {card_data}")
continue
card_id = card_data.get("uuid")
if not card_id:
logger.debug(f"Skipping item without UUID: {card_data}")
continue
existing_card = db.query(MTGJSONCard).filter(MTGJSONCard.card_id == card_id).first() existing_card = db.query(MTGJSONCard).filter(MTGJSONCard.card_id == card_id).first()
if existing_card: if existing_card:
# Update existing card # Update existing card
@ -636,53 +562,47 @@ class DataInitializationService(BaseService):
tnt_id=card_data.get("identifiers", {}).get("tntId") tnt_id=card_data.get("identifiers", {}).get("tntId")
) )
db.add(new_card) db.add(new_card)
count += 1
async def sync_mtgjson_skus(self, db: Session, skus_data: dict): return count
async def sync_mtgjson_skus(self, db: Session, skus_data: List[List[dict]]) -> int:
"""Sync MTGJSON SKUs data to the database""" """Sync MTGJSON SKUs data to the database"""
from app.models.mtgjson_sku import MTGJSONSKU from app.models.mtgjson_sku import MTGJSONSKU
count = 0
with transaction(db): with transaction(db):
for card_uuid, sku_list in skus_data.items(): for product_data in skus_data:
for sku in sku_list: for sku_data in product_data:
# Handle case where sku is a string (skuId) sku_id = sku_data.get("skuId")
if isinstance(sku, str): if not sku_id:
sku_id = sku logger.debug(f"Skipping item without SKU ID: {sku_data}")
existing_sku = db.query(MTGJSONSKU).filter(MTGJSONSKU.sku_id == sku_id).first() continue
if existing_sku:
# Update existing SKU existing_sku = db.query(MTGJSONSKU).filter(MTGJSONSKU.sku_id == str(sku_id)).first()
existing_sku.card_id = card_uuid if existing_sku:
else: # Update existing SKU
new_sku = MTGJSONSKU( for key, value in {
sku_id=sku_id, "product_id": sku_data.get("productId"),
card_id=card_uuid "condition": sku_data.get("condition"),
) "finish": sku_data.get("finish"),
db.add(new_sku) "language": sku_data.get("language"),
# Handle case where sku is a dictionary "printing": sku_data.get("printing"),
}.items():
setattr(existing_sku, key, value)
else: else:
sku_id = str(sku.get("skuId")) new_sku = MTGJSONSKU(
existing_sku = db.query(MTGJSONSKU).filter(MTGJSONSKU.sku_id == sku_id).first() sku_id=sku_id,
if existing_sku: product_id=sku_data.get("productId"),
# Update existing SKU condition=sku_data.get("condition"),
for key, value in { finish=sku_data.get("finish"),
"product_id": str(sku.get("productId")), language=sku_data.get("language"),
"condition": sku.get("condition"), printing=sku_data.get("printing"),
"finish": sku.get("finish"), )
"language": sku.get("language"), db.add(new_sku)
"printing": sku.get("printing"), count += 1
"card_id": card_uuid
}.items(): return count
setattr(existing_sku, key, value)
else:
new_sku = MTGJSONSKU(
sku_id=sku_id,
product_id=str(sku.get("productId")),
condition=sku.get("condition"),
finish=sku.get("finish"),
language=sku.get("language"),
printing=sku.get("printing"),
card_id=card_uuid
)
db.add(new_sku)
async def initialize_data( async def initialize_data(
self, self,

View File

@ -2,7 +2,8 @@ import os
import json import json
import zipfile import zipfile
import time import time
from typing import Dict, Any, Optional, Generator import shutil
from typing import Dict, Any, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.services.external_api.base_external_service import BaseExternalService from app.services.external_api.base_external_service import BaseExternalService
from app.schemas.file import FileInDB from app.schemas.file import FileInDB
@ -11,32 +12,10 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class MTGJSONService(BaseExternalService): class MTGJSONService(BaseExternalService):
def __init__(self, cache_dir: str = "app/data/cache/mtgjson"): def __init__(self):
super().__init__(base_url="https://mtgjson.com/api/v5/") super().__init__(base_url="https://mtgjson.com/api/v5/")
# Ensure the cache directory exists
os.makedirs(cache_dir, exist_ok=True)
self.cache_dir = cache_dir
self.identifiers_dir = os.path.join(cache_dir, "identifiers")
self.skus_dir = os.path.join(cache_dir, "skus")
# Ensure subdirectories exist
os.makedirs(self.identifiers_dir, exist_ok=True)
os.makedirs(self.skus_dir, exist_ok=True)
def _format_progress(self, current: int, total: int, start_time: float) -> str: async def _download_and_unzip_file(self, db: Session, url: str, filename: str, subdir: str) -> FileInDB:
"""Format a progress message with percentage and timing information"""
elapsed = time.time() - start_time
if total > 0:
percent = (current / total) * 100
items_per_second = current / elapsed if elapsed > 0 else 0
eta = (total - current) / items_per_second if items_per_second > 0 else 0
return f"[{current}/{total} ({percent:.1f}%)] {items_per_second:.1f} items/sec, ETA: {eta:.1f}s"
return f"[{current} items] {current/elapsed:.1f} items/sec"
def _print_progress(self, message: str, end: str = "\n") -> None:
"""Print progress message with flush"""
print(message, end=end, flush=True)
async def _download_file(self, db: Session, url: str, filename: str, subdir: str) -> FileInDB:
"""Download a file from the given URL and save it using FileService""" """Download a file from the given URL and save it using FileService"""
print(f"Downloading {url}...") print(f"Downloading {url}...")
start_time = time.time() start_time = time.time()
@ -49,7 +28,7 @@ class MTGJSONService(BaseExternalService):
) )
# Save the file using the file service # Save the file using the file service
return await self.file_service.save_file( file_record = await self.file_service.save_file(
db=db, db=db,
file_data=file_data, file_data=file_data,
filename=filename, filename=filename,
@ -58,17 +37,23 @@ class MTGJSONService(BaseExternalService):
content_type="application/zip" content_type="application/zip"
) )
async def _unzip_file(self, file_record: FileInDB, subdir: str, db: Session) -> str: # Unzip the file
await self._unzip_file(file_record, subdir, db)
return file_record
async def _unzip_file(self, file_record: FileInDB, subdir: str, db: Session) -> FileInDB:
"""Unzip a file to the specified subdirectory and return the path to the extracted JSON file""" """Unzip a file to the specified subdirectory and return the path to the extracted JSON file"""
try: try:
# Use the appropriate subdirectory based on the type file_service = self.get_service('file')
extract_path = self.identifiers_dir if subdir == "identifiers" else self.skus_dir cache_dir = file_service.base_cache_dir
os.makedirs(extract_path, exist_ok=True) temp_dir = os.path.join(cache_dir,'mtgjson', subdir, 'temp')
os.makedirs(temp_dir, exist_ok=True)
with zipfile.ZipFile(file_record.path, 'r') as zip_ref: with zipfile.ZipFile(file_record.path, 'r') as zip_ref:
json_filename = zip_ref.namelist()[0] json_filename = zip_ref.namelist()[0]
zip_ref.extractall(extract_path) zip_ref.extractall(temp_dir)
json_path = os.path.join(extract_path, json_filename) json_path = os.path.join(temp_dir, json_filename)
# Create a file record for the extracted JSON file # Create a file record for the extracted JSON file
with open(json_path, 'r') as f: with open(json_path, 'r') as f:
@ -82,127 +67,57 @@ class MTGJSONService(BaseExternalService):
content_type="application/json" content_type="application/json"
) )
return str(json_file_record.path) # remove the temp directory
shutil.rmtree(temp_dir)
return json_file_record
except Exception as e: except Exception as e:
logger.error(f"Error unzipping file: {e}") logger.error(f"Error unzipping file: {e}")
raise raise
def _stream_json_file(self, file_path: str) -> Generator[Dict[str, Any], None, None]: async def get_identifiers(self, db: Session, use_cache: bool = True) -> Dict[str, Any]:
"""Stream a JSON file and yield items one at a time using a streaming parser"""
logger.info(f"Starting to stream JSON file: {file_path}")
try:
with open(file_path, 'r') as f:
# First, we need to find the start of the data section
data_started = False
current_key = None
current_value = []
brace_count = 0
for line in f:
line = line.strip()
if not line:
continue
if not data_started:
if '"data":' in line:
data_started = True
# Skip the opening brace of the data object
line = line[line.find('"data":') + 7:].strip()
if line.startswith('{'):
line = line[1:].strip()
else:
# Yield meta data if found
if '"meta":' in line:
meta_start = line.find('"meta":') + 7
meta_end = line.rfind('}')
if meta_end > meta_start:
meta_json = line[meta_start:meta_end + 1]
try:
meta_data = json.loads(meta_json)
yield {"type": "meta", "data": meta_data}
except json.JSONDecodeError as e:
logger.warning(f"Failed to parse meta data: {e}")
continue
# Process the data section
if data_started:
if not current_key:
# Look for a new key
if '"' in line:
key_start = line.find('"') + 1
key_end = line.find('"', key_start)
if key_end > key_start:
current_key = line[key_start:key_end]
# Get the rest of the line after the key
line = line[key_end + 1:].strip()
if ':' in line:
line = line[line.find(':') + 1:].strip()
if current_key:
# Accumulate the value
current_value.append(line)
brace_count += line.count('{') - line.count('}')
if brace_count == 0 and line.endswith(','):
# We have a complete value
value_str = ''.join(current_value).rstrip(',')
try:
value = json.loads(value_str)
yield {"type": "item", "data": {current_key: value}}
except json.JSONDecodeError as e:
logger.warning(f"Failed to parse value for key {current_key}: {e}")
current_key = None
current_value = []
except Exception as e:
logger.error(f"Error streaming JSON file: {e}")
raise
async def get_identifiers(self, db: Session) -> Generator[Dict[str, Any], None, None]:
"""Download and get MTGJSON identifiers data""" """Download and get MTGJSON identifiers data"""
# Check if we have a cached version # Check if we have a cached version
cached_file = await self.file_service.get_file_by_filename(db, "AllIdentifiers.json") cached_file = await self.file_service.get_file_by_filename(db, "AllIdentifiers.json")
if cached_file: if cached_file and os.path.exists(cached_file.path) and use_cache:
# Ensure the file exists at the path with open(cached_file.path, 'r') as f:
if os.path.exists(cached_file.path): logger.debug(f"Loaded identifiers from cache: {cached_file.path}")
return self._stream_json_file(cached_file.path) return json.load(f)
else:
# Download and process the file
logger.debug(f"Downloading identifiers from MTGJSON")
file_record = await self._download_and_unzip_file(
db=db,
url="https://mtgjson.com/api/v5/AllIdentifiers.json.zip",
filename="AllIdentifiers.json.zip",
subdir="identifiers"
)
# Download and process the file with open(file_record.path, 'r') as f:
file_record = await self._download_file( logger.debug(f"Loaded identifiers from MTGJSON: {file_record.path}")
db=db, return json.load(f)
url="https://mtgjson.com/api/v5/AllIdentifiers.json.zip",
filename="AllIdentifiers.json.zip",
subdir="identifiers"
)
# Unzip and process the file async def get_skus(self, db: Session, use_cache: bool = True) -> Dict[str, Any]:
json_path = await self._unzip_file(file_record, "identifiers", db)
# Return a generator that streams the JSON file
return self._stream_json_file(json_path)
async def get_skus(self, db: Session) -> Generator[Dict[str, Any], None, None]:
"""Download and get MTGJSON SKUs data""" """Download and get MTGJSON SKUs data"""
# Check if we have a cached version # Check if we have a cached version
cached_file = await self.file_service.get_file_by_filename(db, "TcgplayerSkus.json") cached_file = await self.file_service.get_file_by_filename(db, "TcgplayerSkus.json")
if cached_file: if cached_file and os.path.exists(cached_file.path) and use_cache:
# Ensure the file exists at the path with open(cached_file.path, 'r') as f:
if os.path.exists(cached_file.path): logger.debug(f"Loaded SKUs from cache: {cached_file.path}")
return self._stream_json_file(cached_file.path) return json.load(f)
else:
# Download and process the file
logger.debug(f"Downloading SKUs from MTGJSON")
file_record = await self._download_and_unzip_file(
db=db,
url="https://mtgjson.com/api/v5/TcgplayerSkus.json.zip",
filename="TcgplayerSkus.json.zip",
subdir="skus"
)
# Download and process the file with open(file_record.path, 'r') as f:
file_record = await self._download_file( logger.debug(f"Loaded SKUs from MTGJSON: {file_record.path}")
db=db, return json.load(f)
url="https://mtgjson.com/api/v5/TcgplayerSkus.json.zip",
filename="TcgplayerSkus.json.zip",
subdir="skus"
)
# Unzip and process the file
json_path = await self._unzip_file(file_record, "skus", db)
# Return a generator that streams the JSON file
return self._stream_json_file(json_path)
async def clear_cache(self, db: Session) -> None: async def clear_cache(self, db: Session) -> None:
"""Clear all cached data""" """Clear all cached data"""

View File

@ -153,7 +153,8 @@ class FileService:
async def get_file_by_filename(self, db: Session, filename: str) -> Optional[FileInDB]: async def get_file_by_filename(self, db: Session, filename: str) -> Optional[FileInDB]:
"""Get a file record from the database by filename""" """Get a file record from the database by filename"""
file_record = db.query(File).filter(File.name == filename).first() # get most recent file by filename
file_record = db.query(File).filter(File.name == filename).order_by(File.created_at.desc()).first()
if file_record: if file_record:
return FileInDB.model_validate(file_record) return FileInDB.model_validate(file_record)
return None return None

View File

@ -0,0 +1,15 @@
from app.services.base_service import BaseService
from sqlalchemy.orm import Session
from app.schemas.file import FileInDB
from typing import Dict, Any
import csv
class ManaboxService(BaseService):
def __init__(self):
super().__init__(None)
async def process_manabox_csv(self, db: Session, csv_file: FileInDB) -> bool:
return True
# Name,Set code,Set name,Collector number,Foil,Rarity,Quantity,ManaBox ID,Scryfall ID,Purchase price,Misprint,Altered,Condition,Language,Purchase price currency

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 38444, "lowPrice": 154.95, "midPrice": 223.55, "highPrice": 275.98, "marketPrice": 218.59, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 38445, "lowPrice": 349.49, "midPrice": 374.75, "highPrice": 400.0, "marketPrice": 385.0, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 38446, "lowPrice": 97.71, "midPrice": 120.99, "highPrice": 255.61, "marketPrice": 258.98, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 38447, "lowPrice": 80.0, "midPrice": 109.99, "highPrice": 214.45, "marketPrice": 99.92, "directLowPrice": 94.98, "subTypeName": "Foil"}, {"productId": 57653, "lowPrice": 71.99, "midPrice": 75.99, "highPrice": 100.0, "marketPrice": 69.44, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 67401, "lowPrice": 28.01, "midPrice": 78.72, "highPrice": 119.99, "marketPrice": 33.73, "directLowPrice": 114.99, "subTypeName": "Foil"}, {"productId": 71898, "lowPrice": 167.25, "midPrice": 183.34, "highPrice": 223.35, "marketPrice": 167.25, "directLowPrice": 168.28, "subTypeName": "Foil"}, {"productId": 78237, "lowPrice": 36.0, "midPrice": 89.24, "highPrice": 159.91, "marketPrice": 47.42, "directLowPrice": 59.99, "subTypeName": "Foil"}, {"productId": 95046, "lowPrice": 43.0, "midPrice": 62.92, "highPrice": 97.57, "marketPrice": 64.98, "directLowPrice": 44.0, "subTypeName": "Foil"}, {"productId": 110267, "lowPrice": 23.75, "midPrice": 31.21, "highPrice": 48.4, "marketPrice": 27.89, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 125324, "lowPrice": 18.0, "midPrice": 25.99, "highPrice": 53.45, "marketPrice": 25.86, "directLowPrice": 28.58, "subTypeName": "Foil"}, {"productId": 154792, "lowPrice": 16.73, "midPrice": 25.43, "highPrice": 49.0, "marketPrice": 17.47, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 181788, "lowPrice": 23.57, "midPrice": 27.83, "highPrice": 51.0, "marketPrice": 23.83, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 205180, "lowPrice": 16.99, "midPrice": 29.99, "highPrice": 70.2, "marketPrice": 18.3, "directLowPrice": 70.58, "subTypeName": "Foil"}, {"productId": 228752, "lowPrice": 24.99, "midPrice": 29.98, "highPrice": 224.99, "marketPrice": 29.43, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 257182, "lowPrice": 30.6, "midPrice": 75.0, "highPrice": 141.0, "marketPrice": 30.6, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 455848, "lowPrice": 15.0, "midPrice": 27.98, "highPrice": 134.0, "marketPrice": 20.73, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 527738, "lowPrice": 14.69, "midPrice": 19.31, "highPrice": 80.0, "marketPrice": 16.28, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 600517, "lowPrice": 47.97, "midPrice": 61.22, "highPrice": 75.0, "marketPrice": 61.22, "directLowPrice": null, "subTypeName": "Foil"}]}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 21705, "lowPrice": 0.18, "midPrice": 0.57, "highPrice": 29.99, "marketPrice": 0.56, "directLowPrice": 0.43, "subTypeName": "Foil"}, {"productId": 37765, "lowPrice": 0.1, "midPrice": 0.25, "highPrice": 1.6, "marketPrice": 0.14, "directLowPrice": 0.18, "subTypeName": "Normal"}, {"productId": 37767, "lowPrice": 0.18, "midPrice": 0.41, "highPrice": 4.99, "marketPrice": 0.25, "directLowPrice": 0.6, "subTypeName": "Normal"}, {"productId": 37772, "lowPrice": 0.14, "midPrice": 0.39, "highPrice": 4.99, "marketPrice": 0.15, "directLowPrice": 0.17, "subTypeName": "Normal"}, {"productId": 37773, "lowPrice": 0.05, "midPrice": 0.24, "highPrice": 3.99, "marketPrice": 0.12, "directLowPrice": 0.07, "subTypeName": "Normal"}, {"productId": 37778, "lowPrice": 0.09, "midPrice": 0.25, "highPrice": 3.13, "marketPrice": 0.22, "directLowPrice": 0.18, "subTypeName": "Normal"}, {"productId": 37780, "lowPrice": 0.04, "midPrice": 0.37, "highPrice": 4.99, "marketPrice": 0.13, "directLowPrice": 0.19, "subTypeName": "Normal"}, {"productId": 37784, "lowPrice": 0.15, "midPrice": 0.3, "highPrice": 4.99, "marketPrice": 0.22, "directLowPrice": 0.2, "subTypeName": "Normal"}, {"productId": 37785, "lowPrice": 0.15, "midPrice": 0.37, "highPrice": 3.99, "marketPrice": 0.19, "directLowPrice": 0.09, "subTypeName": "Normal"}, {"productId": 37788, "lowPrice": 0.14, "midPrice": 0.3, "highPrice": 3.0, "marketPrice": 0.31, "directLowPrice": 0.2, "subTypeName": "Normal"}, {"productId": 37789, "lowPrice": 0.15, "midPrice": 0.35, "highPrice": 4.99, "marketPrice": 0.31, "directLowPrice": 0.15, "subTypeName": "Normal"}, {"productId": 37790, "lowPrice": 0.14, "midPrice": 0.39, "highPrice": 3.99, "marketPrice": 0.22, "directLowPrice": 0.14, "subTypeName": "Normal"}, {"productId": 37793, "lowPrice": 0.05, "midPrice": 0.25, "highPrice": 3.99, "marketPrice": 0.08, "directLowPrice": 0.08, "subTypeName": "Normal"}, {"productId": 37799, "lowPrice": 0.1, "midPrice": 0.25, "highPrice": 3.0, "marketPrice": 0.2, "directLowPrice": 0.19, "subTypeName": "Normal"}, {"productId": 37802, "lowPrice": 0.1, "midPrice": 0.25, "highPrice": 5.0, "marketPrice": 0.17, "directLowPrice": 0.1, "subTypeName": "Normal"}, {"productId": 37809, "lowPrice": 0.1, "midPrice": 0.25, "highPrice": 1.67, "marketPrice": 0.19, "directLowPrice": 0.07, "subTypeName": "Normal"}, {"productId": 37810, "lowPrice": 0.09, "midPrice": 0.35, "highPrice": 5.25, "marketPrice": 0.28, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 37812, "lowPrice": 0.18, "midPrice": 0.51, "highPrice": 4.99, "marketPrice": 0.83, "directLowPrice": 0.18, "subTypeName": "Normal"}, {"productId": 37813, "lowPrice": 0.15, "midPrice": 0.25, "highPrice": 2.99, "marketPrice": 0.22, "directLowPrice": 0.14, "subTypeName": "Normal"}, {"productId": 37814, "lowPrice": 0.14, "midPrice": 0.28, "highPrice": 1.76, "marketPrice": 0.18, "directLowPrice": null, "subTypeName": "Normal"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 70757, "lowPrice": 0.8, "midPrice": 2.48, "highPrice": 54.0, "marketPrice": 2.61, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70758, "lowPrice": 1.14, "midPrice": 1.74, "highPrice": 12.88, "marketPrice": 1.37, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70759, "lowPrice": 0.75, "midPrice": 2.05, "highPrice": 8.99, "marketPrice": 2.51, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70760, "lowPrice": 0.79, "midPrice": 1.61, "highPrice": 6.0, "marketPrice": 1.17, "directLowPrice": 1.6, "subTypeName": "Foil"}, {"productId": 70761, "lowPrice": 8.0, "midPrice": 11.12, "highPrice": 49.95, "marketPrice": 11.01, "directLowPrice": 11.96, "subTypeName": "Foil"}, {"productId": 70762, "lowPrice": 0.66, "midPrice": 1.34, "highPrice": 3.99, "marketPrice": 1.22, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70763, "lowPrice": 4.1, "midPrice": 6.0, "highPrice": 19.99, "marketPrice": 5.09, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70764, "lowPrice": 15.53, "midPrice": 19.96, "highPrice": 159.99, "marketPrice": 19.05, "directLowPrice": 21.69, "subTypeName": "Foil"}, {"productId": 70765, "lowPrice": 100.0, "midPrice": 119.99, "highPrice": 400.0, "marketPrice": 85.88, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 70782, "lowPrice": 7.26, "midPrice": 13.24, "highPrice": 20.57, "marketPrice": 13.16, "directLowPrice": 17.05, "subTypeName": "Foil"}, {"productId": 70783, "lowPrice": 4.0, "midPrice": 6.15, "highPrice": 11.84, "marketPrice": 5.69, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70784, "lowPrice": 3.86, "midPrice": 5.41, "highPrice": 19.55, "marketPrice": 4.66, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70785, "lowPrice": 1.25, "midPrice": 1.9, "highPrice": 7.4, "marketPrice": 1.6, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70786, "lowPrice": 3.0, "midPrice": 4.4, "highPrice": 10.0, "marketPrice": 3.42, "directLowPrice": 4.39, "subTypeName": "Foil"}, {"productId": 70787, "lowPrice": 9.25, "midPrice": 11.47, "highPrice": 49.88, "marketPrice": 11.19, "directLowPrice": 19.37, "subTypeName": "Foil"}, {"productId": 70789, "lowPrice": 0.5, "midPrice": 1.04, "highPrice": 16.99, "marketPrice": 0.8, "directLowPrice": 1.07, "subTypeName": "Foil"}, {"productId": 70790, "lowPrice": 0.39, "midPrice": 0.99, "highPrice": 16.45, "marketPrice": 0.68, "directLowPrice": 0.6, "subTypeName": "Foil"}, {"productId": 70791, "lowPrice": 0.23, "midPrice": 0.59, "highPrice": 3.99, "marketPrice": 0.45, "directLowPrice": 0.49, "subTypeName": "Foil"}, {"productId": 70792, "lowPrice": 1.5, "midPrice": 2.49, "highPrice": 9.99, "marketPrice": 2.26, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 70793, "lowPrice": 49.0, "midPrice": 59.02, "highPrice": 200.0, "marketPrice": 59.02, "directLowPrice": 51.49, "subTypeName": "Foil"}, {"productId": 70794, "lowPrice": 1.8, "midPrice": 3.91, "highPrice": 88.0, "marketPrice": 3.69, "directLowPrice": 2.94, "subTypeName": "Foil"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 21603, "lowPrice": 11.0, "midPrice": 16.55, "highPrice": 97.99, "marketPrice": 17.1, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21604, "lowPrice": 4.95, "midPrice": 10.97, "highPrice": 14.97, "marketPrice": 6.99, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21605, "lowPrice": 10.0, "midPrice": 13.95, "highPrice": 79.45, "marketPrice": 14.97, "directLowPrice": 5.01, "subTypeName": "Normal"}, {"productId": 21606, "lowPrice": 18.95, "midPrice": 21.88, "highPrice": 86.37, "marketPrice": 17.0, "directLowPrice": 43.94, "subTypeName": "Normal"}, {"productId": 21607, "lowPrice": 0.38, "midPrice": 2.46, "highPrice": 5.7, "marketPrice": 1.5, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21608, "lowPrice": 1.55, "midPrice": 2.47, "highPrice": 4.95, "marketPrice": 2.0, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21609, "lowPrice": 98.95, "midPrice": 103.94, "highPrice": 108.93, "marketPrice": 57.85, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21610, "lowPrice": 4.73, "midPrice": 7.87, "highPrice": 11.0, "marketPrice": 7.61, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21611, "lowPrice": 9.0, "midPrice": 16.58, "highPrice": 22.17, "marketPrice": 14.16, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21612, "lowPrice": 5.99, "midPrice": 6.91, "highPrice": 15.74, "marketPrice": 6.29, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21613, "lowPrice": 9.55, "midPrice": 14.61, "highPrice": 18.95, "marketPrice": 13.98, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21614, "lowPrice": 1.7, "midPrice": 2.5, "highPrice": 4.95, "marketPrice": 1.4, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21615, "lowPrice": 3.86, "midPrice": 5.5, "highPrice": 8.0, "marketPrice": 6.07, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21616, "lowPrice": 8.84, "midPrice": 19.97, "highPrice": 24.95, "marketPrice": 8.5, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21617, "lowPrice": 6.92, "midPrice": 8.0, "highPrice": 13.99, "marketPrice": 7.23, "directLowPrice": 5.23, "subTypeName": "Normal"}, {"productId": 21618, "lowPrice": 25.0, "midPrice": 29.91, "highPrice": 50.0, "marketPrice": 27.0, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21619, "lowPrice": 8.0, "midPrice": 11.41, "highPrice": 18.61, "marketPrice": 9.89, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21620, "lowPrice": 15.0, "midPrice": 18.95, "highPrice": 20.59, "marketPrice": 8.76, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21621, "lowPrice": 18.5, "midPrice": 22.49, "highPrice": 49.95, "marketPrice": 25.0, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21622, "lowPrice": 7.99, "midPrice": 16.72, "highPrice": 19.95, "marketPrice": 11.91, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21623, "lowPrice": 12.0, "midPrice": 15.0, "highPrice": 16.99, "marketPrice": 15.95, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21624, "lowPrice": 0.59, "midPrice": 1.87, "highPrice": 9.95, "marketPrice": 2.5, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21625, "lowPrice": 49.95, "midPrice": 71.67, "highPrice": 99.95, "marketPrice": 66.45, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21626, "lowPrice": 3.99, "midPrice": 4.87, "highPrice": 8.12, "marketPrice": 5.5, "directLowPrice": 3.0, "subTypeName": "Normal"}, {"productId": 21627, "lowPrice": 6.77, "midPrice": 9.03, "highPrice": 24.99, "marketPrice": 5.16, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21628, "lowPrice": 1.1, "midPrice": 2.25, "highPrice": 4.23, "marketPrice": 1.5, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21629, "lowPrice": 5.0, "midPrice": 5.22, "highPrice": 13.97, "marketPrice": 5.0, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21630, "lowPrice": 16.8, "midPrice": 27.54, "highPrice": 45.0, "marketPrice": 15.95, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21631, "lowPrice": 114.95, "midPrice": 150.0, "highPrice": 154.97, "marketPrice": 42.5, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21632, "lowPrice": 16.99, "midPrice": 55.98, "highPrice": 150.0, "marketPrice": 14.79, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 21633, "lowPrice": 10.99, "midPrice": 13.84, "highPrice": 23.95, "marketPrice": 15.49, "directLowPrice": 19.88, "subTypeName": "Normal"}, {"productId": 21634, "lowPrice": 49.97, "midPrice": 74.36, "highPrice": 98.75, "marketPrice": 49.97, "directLowPrice": null, "subTypeName": "Normal"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 82198, "lowPrice": 79.26, "midPrice": 94.13, "highPrice": 249.99, "marketPrice": 89.08, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82732, "lowPrice": 0.74, "midPrice": 1.03, "highPrice": 3.01, "marketPrice": 0.98, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82733, "lowPrice": 13.4, "midPrice": 18.14, "highPrice": 38.5, "marketPrice": 14.09, "directLowPrice": 35.1, "subTypeName": "Normal"}, {"productId": 82734, "lowPrice": 0.99, "midPrice": 1.62, "highPrice": 9.9, "marketPrice": 1.36, "directLowPrice": 1.58, "subTypeName": "Normal"}, {"productId": 82735, "lowPrice": 0.46, "midPrice": 0.85, "highPrice": 4.91, "marketPrice": 0.69, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82736, "lowPrice": 0.54, "midPrice": 0.82, "highPrice": 3.88, "marketPrice": 0.83, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82737, "lowPrice": 0.99, "midPrice": 2.25, "highPrice": 19.99, "marketPrice": 2.15, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82738, "lowPrice": 0.15, "midPrice": 0.5, "highPrice": 2.0, "marketPrice": 0.39, "directLowPrice": 0.25, "subTypeName": "Normal"}, {"productId": 82739, "lowPrice": 1.5, "midPrice": 2.96, "highPrice": 8.87, "marketPrice": 2.32, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82740, "lowPrice": 0.15, "midPrice": 0.47, "highPrice": 2.99, "marketPrice": 0.34, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82741, "lowPrice": 0.45, "midPrice": 0.9, "highPrice": 8.53, "marketPrice": 0.56, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82742, "lowPrice": 0.25, "midPrice": 0.75, "highPrice": 27.99, "marketPrice": 0.5, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82743, "lowPrice": 0.09, "midPrice": 0.33, "highPrice": 1.99, "marketPrice": 0.21, "directLowPrice": 0.25, "subTypeName": "Normal"}, {"productId": 82744, "lowPrice": 0.18, "midPrice": 0.48, "highPrice": 1.83, "marketPrice": 0.45, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82745, "lowPrice": 0.77, "midPrice": 1.25, "highPrice": 18.99, "marketPrice": 0.95, "directLowPrice": 1.71, "subTypeName": "Normal"}, {"productId": 82746, "lowPrice": 0.03, "midPrice": 0.25, "highPrice": 1.5, "marketPrice": 0.11, "directLowPrice": 0.1, "subTypeName": "Normal"}, {"productId": 82747, "lowPrice": 0.2, "midPrice": 0.38, "highPrice": 1.99, "marketPrice": 0.26, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82748, "lowPrice": 0.22, "midPrice": 0.39, "highPrice": 1.52, "marketPrice": 0.29, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82749, "lowPrice": 20.14, "midPrice": 27.69, "highPrice": 79.99, "marketPrice": 22.14, "directLowPrice": 25.63, "subTypeName": "Normal"}, {"productId": 82750, "lowPrice": 0.06, "midPrice": 0.3, "highPrice": 2.99, "marketPrice": 0.07, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82751, "lowPrice": 4.97, "midPrice": 7.93, "highPrice": 17.38, "marketPrice": 7.63, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82752, "lowPrice": 0.12, "midPrice": 0.4, "highPrice": 2.99, "marketPrice": 0.16, "directLowPrice": 0.15, "subTypeName": "Normal"}, {"productId": 82753, "lowPrice": 2.09, "midPrice": 3.5, "highPrice": 11.99, "marketPrice": 2.76, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82754, "lowPrice": 0.05, "midPrice": 0.26, "highPrice": 1.5, "marketPrice": 0.17, "directLowPrice": 0.14, "subTypeName": "Normal"}, {"productId": 82755, "lowPrice": 0.25, "midPrice": 0.75, "highPrice": 3.59, "marketPrice": 0.58, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 82756, "lowPrice": 0.9, "midPrice": 1.75, "highPrice": 11.97, "marketPrice": 1.36, "directLowPrice": 1.5, "subTypeName": "Normal"}, {"productId": 82757, "lowPrice": 3.97, "midPrice": 6.25, "highPrice": 13.5, "marketPrice": 3.97, "directLowPrice": 7.99, "subTypeName": "Normal"}, {"productId": 83374, "lowPrice": 8.96, "midPrice": 13.5, "highPrice": 19.99, "marketPrice": 11.77, "directLowPrice": 19.97, "subTypeName": "Normal"}, {"productId": 83376, "lowPrice": 0.19, "midPrice": 0.5, "highPrice": 5.0, "marketPrice": 0.7, "directLowPrice": 0.49, "subTypeName": "Normal"}, {"productId": 83377, "lowPrice": 0.05, "midPrice": 0.25, "highPrice": 1.5, "marketPrice": 0.17, "directLowPrice": 0.5, "subTypeName": "Normal"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": []}

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 91636, "lowPrice": 29.85, "midPrice": 45.99, "highPrice": 495.95, "marketPrice": 30.89, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 91637, "lowPrice": 14.19, "midPrice": 14.94, "highPrice": 34.8, "marketPrice": 14.73, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 91638, "lowPrice": 3.29, "midPrice": 4.86, "highPrice": 16.78, "marketPrice": 4.65, "directLowPrice": 4.0, "subTypeName": "Foil"}, {"productId": 91639, "lowPrice": 3.67, "midPrice": 5.55, "highPrice": 15.99, "marketPrice": 5.57, "directLowPrice": 5.99, "subTypeName": "Foil"}, {"productId": 91640, "lowPrice": 2.92, "midPrice": 4.0, "highPrice": 19.99, "marketPrice": 3.4, "directLowPrice": 3.99, "subTypeName": "Foil"}, {"productId": 91641, "lowPrice": 2.04, "midPrice": 3.0, "highPrice": 9.99, "marketPrice": 2.47, "directLowPrice": 2.64, "subTypeName": "Foil"}, {"productId": 92296, "lowPrice": 0.4, "midPrice": 0.94, "highPrice": 4.78, "marketPrice": 0.53, "directLowPrice": 0.69, "subTypeName": "Foil"}, {"productId": 92297, "lowPrice": 0.82, "midPrice": 1.43, "highPrice": 29.98, "marketPrice": 1.19, "directLowPrice": 1.29, "subTypeName": "Foil"}, {"productId": 92298, "lowPrice": 1.63, "midPrice": 4.48, "highPrice": 15.0, "marketPrice": 5.31, "directLowPrice": 3.29, "subTypeName": "Foil"}, {"productId": 92299, "lowPrice": 0.63, "midPrice": 1.0, "highPrice": 3.99, "marketPrice": 0.83, "directLowPrice": 0.96, "subTypeName": "Foil"}, {"productId": 92300, "lowPrice": 0.72, "midPrice": 2.06, "highPrice": 19.99, "marketPrice": 2.5, "directLowPrice": 2.5, "subTypeName": "Foil"}, {"productId": 92301, "lowPrice": 0.96, "midPrice": 1.65, "highPrice": 19.99, "marketPrice": 1.16, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 92302, "lowPrice": 2.85, "midPrice": 4.29, "highPrice": 39.99, "marketPrice": 4.29, "directLowPrice": 3.99, "subTypeName": "Foil"}, {"productId": 92303, "lowPrice": 2.49, "midPrice": 3.61, "highPrice": 16.99, "marketPrice": 2.86, "directLowPrice": 3.08, "subTypeName": "Foil"}, {"productId": 92304, "lowPrice": 0.25, "midPrice": 0.93, "highPrice": 19.99, "marketPrice": 0.74, "directLowPrice": 1.53, "subTypeName": "Foil"}, {"productId": 92305, "lowPrice": 0.38, "midPrice": 0.81, "highPrice": 6.85, "marketPrice": 0.63, "directLowPrice": null, "subTypeName": "Foil"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 95578, "lowPrice": 40.0, "midPrice": 48.63, "highPrice": 150.0, "marketPrice": 40.66, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95579, "lowPrice": 23.58, "midPrice": 31.72, "highPrice": 55.21, "marketPrice": 31.84, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95580, "lowPrice": 0.69, "midPrice": 1.38, "highPrice": 6.0, "marketPrice": 1.06, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95581, "lowPrice": 1.0, "midPrice": 2.79, "highPrice": 6.95, "marketPrice": 1.91, "directLowPrice": 2.35, "subTypeName": "Normal"}, {"productId": 95582, "lowPrice": 7.59, "midPrice": 12.19, "highPrice": 24.66, "marketPrice": 10.49, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95583, "lowPrice": 0.25, "midPrice": 1.16, "highPrice": 4.0, "marketPrice": 0.84, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95584, "lowPrice": 0.45, "midPrice": 1.5, "highPrice": 6.31, "marketPrice": 0.8, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95585, "lowPrice": 0.8, "midPrice": 1.55, "highPrice": 4.79, "marketPrice": 0.85, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95586, "lowPrice": 0.1, "midPrice": 0.44, "highPrice": 1.5, "marketPrice": 0.23, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95587, "lowPrice": 0.15, "midPrice": 0.5, "highPrice": 1.5, "marketPrice": 0.49, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95588, "lowPrice": 0.25, "midPrice": 0.54, "highPrice": 2.43, "marketPrice": 0.3, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95589, "lowPrice": 0.25, "midPrice": 0.75, "highPrice": 4.25, "marketPrice": 0.82, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95590, "lowPrice": 0.1, "midPrice": 0.37, "highPrice": 11.5, "marketPrice": 0.25, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95591, "lowPrice": 0.18, "midPrice": 0.39, "highPrice": 2.0, "marketPrice": 0.19, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95592, "lowPrice": 0.14, "midPrice": 0.49, "highPrice": 1.77, "marketPrice": 0.22, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95593, "lowPrice": 0.15, "midPrice": 0.4, "highPrice": 7.0, "marketPrice": 0.23, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95594, "lowPrice": 0.07, "midPrice": 0.39, "highPrice": 3.0, "marketPrice": 0.22, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95595, "lowPrice": 0.2, "midPrice": 0.48, "highPrice": 2.0, "marketPrice": 0.22, "directLowPrice": 0.25, "subTypeName": "Normal"}, {"productId": 95596, "lowPrice": 1.18, "midPrice": 2.62, "highPrice": 10.49, "marketPrice": 2.36, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95597, "lowPrice": 1.93, "midPrice": 2.96, "highPrice": 6.0, "marketPrice": 2.96, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95598, "lowPrice": 0.19, "midPrice": 0.44, "highPrice": 2.91, "marketPrice": 0.21, "directLowPrice": 0.42, "subTypeName": "Normal"}, {"productId": 95599, "lowPrice": 0.15, "midPrice": 0.5, "highPrice": 2.0, "marketPrice": 0.23, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95600, "lowPrice": 0.24, "midPrice": 0.89, "highPrice": 3.0, "marketPrice": 0.65, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95601, "lowPrice": 0.14, "midPrice": 0.5, "highPrice": 2.91, "marketPrice": 0.2, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 95602, "lowPrice": 0.14, "midPrice": 0.5, "highPrice": 2.5, "marketPrice": 0.21, "directLowPrice": 0.35, "subTypeName": "Normal"}, {"productId": 95603, "lowPrice": 0.15, "midPrice": 0.49, "highPrice": 3.0, "marketPrice": 0.43, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 99943, "lowPrice": 14.32, "midPrice": 20.0, "highPrice": 39.99, "marketPrice": 13.81, "directLowPrice": null, "subTypeName": "Normal"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 96436, "lowPrice": 0.41, "midPrice": 0.93, "highPrice": 20.0, "marketPrice": 0.84, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 96437, "lowPrice": 0.39, "midPrice": 0.62, "highPrice": 5.0, "marketPrice": 0.57, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 96438, "lowPrice": 0.1, "midPrice": 0.33, "highPrice": 3.0, "marketPrice": 0.34, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 96439, "lowPrice": 0.05, "midPrice": 0.26, "highPrice": 5.0, "marketPrice": 0.26, "directLowPrice": null, "subTypeName": "Normal"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 100611, "lowPrice": 4.33, "midPrice": 6.37, "highPrice": 123.0, "marketPrice": 4.76, "directLowPrice": 6.4, "subTypeName": "Foil"}, {"productId": 100612, "lowPrice": 3.0, "midPrice": 4.17, "highPrice": 15.99, "marketPrice": 3.88, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 100667, "lowPrice": 119.99, "midPrice": 142.49, "highPrice": 999.95, "marketPrice": 124.0, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 101468, "lowPrice": 35.0, "midPrice": 41.65, "highPrice": 75.68, "marketPrice": 43.6, "directLowPrice": 37.15, "subTypeName": "Foil"}, {"productId": 101469, "lowPrice": 5.0, "midPrice": 7.25, "highPrice": 19.99, "marketPrice": 7.0, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 102777, "lowPrice": 0.51, "midPrice": 1.73, "highPrice": 20.03, "marketPrice": 1.7, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 102778, "lowPrice": 7.51, "midPrice": 10.11, "highPrice": 22.72, "marketPrice": 9.96, "directLowPrice": 14.28, "subTypeName": "Foil"}, {"productId": 102779, "lowPrice": 2.54, "midPrice": 3.43, "highPrice": 8.25, "marketPrice": 2.94, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 102780, "lowPrice": 1.99, "midPrice": 3.42, "highPrice": 14.99, "marketPrice": 3.28, "directLowPrice": 2.0, "subTypeName": "Foil"}, {"productId": 102781, "lowPrice": 1.03, "midPrice": 2.0, "highPrice": 8.0, "marketPrice": 1.75, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 102782, "lowPrice": 0.7, "midPrice": 1.07, "highPrice": 3.41, "marketPrice": 0.99, "directLowPrice": 1.02, "subTypeName": "Foil"}, {"productId": 102783, "lowPrice": 0.26, "midPrice": 0.99, "highPrice": 5.0, "marketPrice": 0.82, "directLowPrice": null, "subTypeName": "Foil"}, {"productId": 102784, "lowPrice": 0.21, "midPrice": 0.82, "highPrice": 2.59, "marketPrice": 0.66, "directLowPrice": 0.44, "subTypeName": "Foil"}, {"productId": 102785, "lowPrice": 6.02, "midPrice": 7.52, "highPrice": 19.0, "marketPrice": 7.17, "directLowPrice": 9.99, "subTypeName": "Foil"}, {"productId": 102786, "lowPrice": 0.74, "midPrice": 2.74, "highPrice": 49.99, "marketPrice": 2.61, "directLowPrice": 2.48, "subTypeName": "Foil"}, {"productId": 102787, "lowPrice": 0.98, "midPrice": 2.49, "highPrice": 12.01, "marketPrice": 2.58, "directLowPrice": null, "subTypeName": "Foil"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": []}

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": []}

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": []}

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": []}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"success": true, "errors": [], "results": [{"productId": 116780, "lowPrice": 0.25, "midPrice": 0.5, "highPrice": 6.99, "marketPrice": 0.29, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 116781, "lowPrice": 0.01, "midPrice": 0.19, "highPrice": 1.32, "marketPrice": 0.07, "directLowPrice": 0.03, "subTypeName": "Normal"}, {"productId": 116782, "lowPrice": 0.01, "midPrice": 0.15, "highPrice": 5.0, "marketPrice": 0.02, "directLowPrice": 0.02, "subTypeName": "Normal"}, {"productId": 116783, "lowPrice": 0.01, "midPrice": 0.2, "highPrice": 16.0, "marketPrice": 0.04, "directLowPrice": 0.14, "subTypeName": "Normal"}, {"productId": 116784, "lowPrice": 0.01, "midPrice": 0.19, "highPrice": 1.32, "marketPrice": 0.04, "directLowPrice": 0.1, "subTypeName": "Normal"}, {"productId": 116785, "lowPrice": 0.01, "midPrice": 0.2, "highPrice": 1.32, "marketPrice": 0.08, "directLowPrice": 0.1, "subTypeName": "Normal"}, {"productId": 116786, "lowPrice": 0.01, "midPrice": 0.2, "highPrice": 1.32, "marketPrice": 0.04, "directLowPrice": 0.25, "subTypeName": "Normal"}, {"productId": 116787, "lowPrice": 0.01, "midPrice": 0.18, "highPrice": 5.0, "marketPrice": 0.13, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 116788, "lowPrice": 0.04, "midPrice": 0.25, "highPrice": 4.99, "marketPrice": 0.13, "directLowPrice": 0.13, "subTypeName": "Normal"}, {"productId": 116789, "lowPrice": 0.01, "midPrice": 0.15, "highPrice": 2.0, "marketPrice": 0.03, "directLowPrice": 0.16, "subTypeName": "Normal"}, {"productId": 116790, "lowPrice": 0.01, "midPrice": 0.2, "highPrice": 1.35, "marketPrice": 0.1, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 116791, "lowPrice": 0.03, "midPrice": 0.2, "highPrice": 1.53, "marketPrice": 0.12, "directLowPrice": 0.1, "subTypeName": "Normal"}, {"productId": 116792, "lowPrice": 0.02, "midPrice": 0.25, "highPrice": 5.06, "marketPrice": 0.12, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 116793, "lowPrice": 0.98, "midPrice": 1.2, "highPrice": 4.99, "marketPrice": 1.03, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 116794, "lowPrice": 0.01, "midPrice": 0.25, "highPrice": 4.99, "marketPrice": 0.16, "directLowPrice": null, "subTypeName": "Normal"}, {"productId": 116795, "lowPrice": 0.01, "midPrice": 0.15, "highPrice": 5.0, "marketPrice": 0.02, "directLowPrice": 0.06, "subTypeName": "Normal"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More