data model whew
This commit is contained in:
parent
03b43ce3ab
commit
6178fdd15d
28
alembic/versions/cc7dd65bcdd9_changing_db_bigly.py
Normal file
28
alembic/versions/cc7dd65bcdd9_changing_db_bigly.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""changing db bigly
|
||||
|
||||
Revision ID: cc7dd65bcdd9
|
||||
Revises: 9fb73424598c
|
||||
Create Date: 2025-04-19 13:36:41.784661
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'cc7dd65bcdd9'
|
||||
down_revision: Union[str, None] = '9fb73424598c'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
pass
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
pass
|
339
alembic/versions/d4d3f43ce86a_changing_db_bigly.py
Normal file
339
alembic/versions/d4d3f43ce86a_changing_db_bigly.py
Normal file
@ -0,0 +1,339 @@
|
||||
"""changing db bigly
|
||||
|
||||
Revision ID: d4d3f43ce86a
|
||||
Revises: cc7dd65bcdd9
|
||||
Create Date: 2025-04-19 13:46:27.330261
|
||||
|
||||
"""
|
||||
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 = 'd4d3f43ce86a'
|
||||
down_revision: Union[str, None] = 'cc7dd65bcdd9'
|
||||
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.create_table('customers',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_customers_id'), 'customers', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_customers_name'), 'customers', ['name'], unique=True)
|
||||
op.create_table('products',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=True),
|
||||
sa.Column('tcgplayer_id', sa.String(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('tcgplayer_inventory',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('tcgplayer_id', sa.String(), nullable=True),
|
||||
sa.Column('product_line', sa.String(), nullable=True),
|
||||
sa.Column('set_name', sa.String(), nullable=True),
|
||||
sa.Column('product_name', sa.String(), nullable=True),
|
||||
sa.Column('title', sa.String(), nullable=True),
|
||||
sa.Column('number', sa.String(), nullable=True),
|
||||
sa.Column('rarity', sa.String(), nullable=True),
|
||||
sa.Column('condition', sa.String(), nullable=True),
|
||||
sa.Column('tcg_market_price', sa.Float(), nullable=True),
|
||||
sa.Column('tcg_direct_low', sa.Float(), nullable=True),
|
||||
sa.Column('tcg_low_price_with_shipping', sa.Float(), nullable=True),
|
||||
sa.Column('tcg_low_price', sa.Float(), nullable=True),
|
||||
sa.Column('total_quantity', sa.Integer(), nullable=True),
|
||||
sa.Column('add_to_quantity', sa.Integer(), nullable=True),
|
||||
sa.Column('tcg_marketplace_price', sa.Float(), nullable=True),
|
||||
sa.Column('photo_url', sa.String(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_tcgplayer_inventory_id'), 'tcgplayer_inventory', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_tcgplayer_inventory_tcgplayer_id'), 'tcgplayer_inventory', ['tcgplayer_id'], unique=True)
|
||||
op.create_table('vendors',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_vendors_id'), 'vendors', ['id'], unique=False)
|
||||
op.create_index(op.f('ix_vendors_name'), 'vendors', ['name'], unique=True)
|
||||
op.create_table('physical_items',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('item_type', sa.String(), nullable=True),
|
||||
sa.Column('product_id', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['product_id'], ['products.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('transactions',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('vendor_id', sa.Integer(), nullable=True),
|
||||
sa.Column('customer_id', sa.Integer(), nullable=True),
|
||||
sa.Column('transaction_type', sa.String(), nullable=True),
|
||||
sa.Column('transaction_date', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('transaction_total_amount', sa.Float(), nullable=True),
|
||||
sa.Column('transaction_notes', sa.String(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['customer_id'], ['customers.id'], ),
|
||||
sa.ForeignKeyConstraint(['vendor_id'], ['vendors.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_transactions_id'), 'transactions', ['id'], unique=False)
|
||||
op.create_table('inventory_items',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('physical_item_id', sa.Integer(), nullable=True),
|
||||
sa.Column('cost_basis', sa.Float(), nullable=True),
|
||||
sa.Column('parent_id', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['parent_id'], ['inventory_items.id'], ),
|
||||
sa.ForeignKeyConstraint(['physical_item_id'], ['physical_items.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('physical_item_id')
|
||||
)
|
||||
op.create_index(op.f('ix_inventory_items_id'), 'inventory_items', ['id'], unique=False)
|
||||
op.create_table('sealed_cases',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['id'], ['physical_items.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('transaction_items',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('transaction_id', sa.Integer(), nullable=True),
|
||||
sa.Column('physical_item_id', sa.Integer(), nullable=True),
|
||||
sa.Column('unit_price', sa.Float(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['physical_item_id'], ['physical_items.id'], ),
|
||||
sa.ForeignKeyConstraint(['transaction_id'], ['transactions.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_transaction_items_id'), 'transaction_items', ['id'], unique=False)
|
||||
op.create_table('sealed_boxes',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('case_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['case_id'], ['sealed_cases.id'], ),
|
||||
sa.ForeignKeyConstraint(['id'], ['physical_items.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('open_events',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('sealed_case_id', sa.Integer(), nullable=True),
|
||||
sa.Column('sealed_box_id', sa.Integer(), nullable=True),
|
||||
sa.Column('open_date', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['sealed_box_id'], ['sealed_boxes.id'], ),
|
||||
sa.ForeignKeyConstraint(['sealed_case_id'], ['sealed_cases.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_open_events_id'), 'open_events', ['id'], unique=False)
|
||||
op.create_table('open_cards',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('open_event_id', sa.Integer(), nullable=True),
|
||||
sa.Column('box_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['box_id'], ['open_boxes.id'], ),
|
||||
sa.ForeignKeyConstraint(['id'], ['physical_items.id'], ),
|
||||
sa.ForeignKeyConstraint(['open_event_id'], ['open_events.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('cost_basis',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('transaction_item_id', sa.Integer(), nullable=True),
|
||||
sa.Column('sealed_case_id', sa.Integer(), nullable=True),
|
||||
sa.Column('sealed_box_id', sa.Integer(), nullable=True),
|
||||
sa.Column('open_box_id', sa.Integer(), nullable=True),
|
||||
sa.Column('open_card_id', sa.Integer(), nullable=True),
|
||||
sa.Column('quantity', sa.Integer(), nullable=False),
|
||||
sa.Column('unit_cost', sa.Float(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(['open_box_id'], ['open_boxes.id'], ),
|
||||
sa.ForeignKeyConstraint(['open_card_id'], ['open_cards.id'], ),
|
||||
sa.ForeignKeyConstraint(['sealed_box_id'], ['sealed_boxes.id'], ),
|
||||
sa.ForeignKeyConstraint(['sealed_case_id'], ['sealed_cases.id'], ),
|
||||
sa.ForeignKeyConstraint(['transaction_item_id'], ['transaction_items.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_cost_basis_id'), 'cost_basis', ['id'], unique=False)
|
||||
|
||||
# Drop tables in correct dependency order
|
||||
# First drop foreign key constraints
|
||||
op.execute('DROP TABLE IF EXISTS open_cards CASCADE')
|
||||
op.execute('DROP TABLE IF EXISTS cost_basis CASCADE')
|
||||
op.execute('DROP TABLE IF EXISTS open_boxes CASCADE')
|
||||
op.execute('DROP TABLE IF EXISTS boxes CASCADE')
|
||||
op.execute('DROP TABLE IF EXISTS games CASCADE')
|
||||
|
||||
op.drop_index('ix_inventory_id', table_name='inventory')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
# Create tables in correct dependency order
|
||||
op.create_table('games',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('description', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('image_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='games_pkey')
|
||||
)
|
||||
op.create_index('ix_games_id', 'games', ['id'], unique=False)
|
||||
|
||||
op.create_table('boxes',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('product_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.Column('type', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('set_code', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('sku', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.Column('name', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('game_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.Column('expected_number_of_cards', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.Column('description', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('image_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.ForeignKeyConstraint(['game_id'], ['games.id'], name='boxes_game_id_fkey'),
|
||||
sa.PrimaryKeyConstraint('id', name='boxes_pkey')
|
||||
)
|
||||
op.create_index('ix_boxes_id', 'boxes', ['id'], unique=False)
|
||||
|
||||
op.create_table('open_boxes',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('box_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.Column('date_opened', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
|
||||
sa.Column('number_of_cards', sa.INTEGER(), 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.ForeignKeyConstraint(['box_id'], ['boxes.id'], name='open_boxes_box_id_fkey'),
|
||||
sa.PrimaryKeyConstraint('id', name='open_boxes_pkey')
|
||||
)
|
||||
op.create_index('ix_open_boxes_id', 'open_boxes', ['id'], unique=False)
|
||||
|
||||
op.create_table('open_cards',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('box_id', sa.INTEGER(), 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.ForeignKeyConstraint(['box_id'], ['open_boxes.id'], name='open_cards_box_id_fkey'),
|
||||
sa.PrimaryKeyConstraint('id', name='open_cards_pkey')
|
||||
)
|
||||
op.create_index('ix_open_cards_id', 'open_cards', ['id'], unique=False)
|
||||
|
||||
op.create_table('cost_basis',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('open_box_id', sa.INTEGER(), 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.ForeignKeyConstraint(['open_box_id'], ['open_boxes.id'], name='cost_basis_open_box_id_fkey'),
|
||||
sa.PrimaryKeyConstraint('id', name='cost_basis_pkey')
|
||||
)
|
||||
op.create_index('ix_cost_basis_id', 'cost_basis', ['id'], unique=False)
|
||||
|
||||
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('inventory',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('tcgplayer_id', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('product_line', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||
sa.Column('set_name', 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('rarity', 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='inventory_pkey')
|
||||
)
|
||||
op.create_index('ix_inventory_tcgplayer_id', 'inventory', ['tcgplayer_id'], unique=True)
|
||||
op.create_index('ix_inventory_id', 'inventory', ['id'], unique=False)
|
||||
op.drop_index(op.f('ix_cost_basis_id'), table_name='cost_basis')
|
||||
op.drop_table('cost_basis')
|
||||
op.drop_table('open_cards')
|
||||
op.drop_index(op.f('ix_open_events_id'), table_name='open_events')
|
||||
op.drop_table('open_events')
|
||||
op.drop_table('sealed_boxes')
|
||||
op.drop_index(op.f('ix_transaction_items_id'), table_name='transaction_items')
|
||||
op.drop_table('transaction_items')
|
||||
op.drop_table('sealed_cases')
|
||||
op.drop_index(op.f('ix_inventory_items_id'), table_name='inventory_items')
|
||||
op.drop_table('inventory_items')
|
||||
op.drop_index(op.f('ix_transactions_id'), table_name='transactions')
|
||||
op.drop_table('transactions')
|
||||
op.drop_table('physical_items')
|
||||
op.drop_index(op.f('ix_vendors_name'), table_name='vendors')
|
||||
op.drop_index(op.f('ix_vendors_id'), table_name='vendors')
|
||||
op.drop_table('vendors')
|
||||
op.drop_index(op.f('ix_tcgplayer_inventory_tcgplayer_id'), table_name='tcgplayer_inventory')
|
||||
op.drop_index(op.f('ix_tcgplayer_inventory_id'), table_name='tcgplayer_inventory')
|
||||
op.drop_table('tcgplayer_inventory')
|
||||
op.drop_table('products')
|
||||
op.drop_index(op.f('ix_customers_name'), table_name='customers')
|
||||
op.drop_index(op.f('ix_customers_id'), table_name='customers')
|
||||
op.drop_table('customers')
|
||||
# ### end Alembic commands ###
|
@ -58,7 +58,7 @@ async def lifespan(app: FastAPI):
|
||||
db = SessionLocal()
|
||||
try:
|
||||
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=True, 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=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")
|
||||
logger.info(f"Data initialization results: {data_init}")
|
||||
|
||||
# Start the scheduler
|
||||
|
@ -1,26 +1,50 @@
|
||||
from app.models.box import Box
|
||||
from app.models.card import Card
|
||||
from app.models.file import File
|
||||
from app.models.game import Game
|
||||
from app.models.inventory import Inventory
|
||||
from app.models.inventory_management import (
|
||||
PhysicalItem,
|
||||
InventoryItem,
|
||||
TransactionItem,
|
||||
OpenEvent,
|
||||
Vendor,
|
||||
Customer,
|
||||
Transaction,
|
||||
CostBasis
|
||||
)
|
||||
from app.models.mtgjson_card import MTGJSONCard
|
||||
from app.models.mtgjson_sku import MTGJSONSKU
|
||||
from app.models.product import Product
|
||||
from app.models.tcgplayer_category import TCGPlayerCategory
|
||||
from app.models.tcgplayer_group import TCGPlayerGroup
|
||||
from app.models.tcgplayer_order import TCGPlayerOrder
|
||||
from app.models.tcgplayer_inventory import TCGPlayerInventory
|
||||
from app.models.tcgplayer_order import (
|
||||
TCGPlayerOrder,
|
||||
TCGPlayerOrderTransaction,
|
||||
TCGPlayerOrderProduct,
|
||||
TCGPlayerOrderRefund
|
||||
)
|
||||
from app.models.tcgplayer_price_history import TCGPlayerPriceHistory
|
||||
from app.models.tcgplayer_product import TCGPlayerProduct
|
||||
|
||||
# This makes all models available for Alembic to discover
|
||||
__all__ = [
|
||||
'Box',
|
||||
'Card',
|
||||
'File',
|
||||
'Game',
|
||||
'Inventory',
|
||||
'PhysicalItem',
|
||||
'InventoryItem',
|
||||
'TransactionItem',
|
||||
'OpenEvent',
|
||||
'Vendor',
|
||||
'Customer',
|
||||
'Transaction',
|
||||
'CostBasis',
|
||||
'MTGJSONCard',
|
||||
'MTGJSONSKU',
|
||||
'Product',
|
||||
'TCGPlayerCategory',
|
||||
'TCGPlayerGroup',
|
||||
'TCGPlayerInventory',
|
||||
'TCGPlayerOrder',
|
||||
'TCGPlayerOrderTransaction',
|
||||
'TCGPlayerOrderProduct',
|
||||
'TCGPlayerOrderRefund',
|
||||
'TCGPlayerPriceHistory',
|
||||
'TCGPlayerProduct'
|
||||
]
|
@ -1,30 +0,0 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.database import Base
|
||||
|
||||
class Box(Base):
|
||||
__tablename__ = "boxes"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
product_id = Column(Integer)
|
||||
type = Column(String)
|
||||
set_code = Column(String)
|
||||
sku = Column(Integer)
|
||||
name = Column(String)
|
||||
game_id = Column(Integer, ForeignKey("games.id"))
|
||||
expected_number_of_cards = Column(Integer)
|
||||
description = Column(String)
|
||||
image_url = Column(String)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
class OpenBox(Base):
|
||||
__tablename__ = "open_boxes"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
box_id = Column(Integer, ForeignKey("boxes.id"))
|
||||
number_of_cards = Column(Integer)
|
||||
date_opened = Column(DateTime(timezone=True))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
@ -1,37 +0,0 @@
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, Integer, String, Float, ForeignKey, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.database import Base
|
||||
|
||||
|
||||
class Card(Base):
|
||||
__tablename__ = "cards"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, index=True)
|
||||
rarity = Column(String)
|
||||
set_name = Column(String, index=True)
|
||||
price = Column(Float)
|
||||
quantity = Column(Integer, default=0)
|
||||
|
||||
# TCGPlayer specific fields
|
||||
tcgplayer_sku = Column(String, unique=True, index=True)
|
||||
product_line = Column(String)
|
||||
product_name = Column(String)
|
||||
title = Column(String)
|
||||
number = Column(String)
|
||||
condition = Column(String)
|
||||
tcg_market_price = Column(Float)
|
||||
tcg_direct_low = Column(Float)
|
||||
tcg_low_price_with_shipping = Column(Float)
|
||||
tcg_low_price = Column(Float)
|
||||
total_quantity = Column(Integer)
|
||||
add_to_quantity = Column(Integer)
|
||||
tcg_marketplace_price = Column(Float)
|
||||
photo_url = Column(String)
|
||||
|
||||
# Timestamps
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
@ -1,14 +0,0 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.database import Base
|
||||
|
||||
class Game(Base):
|
||||
__tablename__ = "games"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String)
|
||||
description = Column(String)
|
||||
image_url = Column(String)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
185
app/models/inventory_management.py
Normal file
185
app/models/inventory_management.py
Normal file
@ -0,0 +1,185 @@
|
||||
from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, Table
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.database import Base
|
||||
|
||||
class PhysicalItem(Base):
|
||||
__tablename__ = "physical_items"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
item_type = Column(String)
|
||||
product_id = Column(Integer, ForeignKey("products.id"), nullable=False)
|
||||
created_at = Column(DateTime(timezone=True))
|
||||
updated_at = Column(DateTime(timezone=True))
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_on': item_type,
|
||||
'polymorphic_identity': 'physical_item'
|
||||
}
|
||||
|
||||
# Relationships
|
||||
product = relationship("Product")
|
||||
inventory_item = relationship("InventoryItem", uselist=False, back_populates="physical_item")
|
||||
transaction_items = relationship("TransactionItem", back_populates="physical_item")
|
||||
|
||||
class SealedCase(PhysicalItem):
|
||||
__tablename__ = "sealed_cases"
|
||||
|
||||
id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True)
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': 'sealed_case'
|
||||
}
|
||||
|
||||
# Relationships
|
||||
boxes = relationship("SealedBox", back_populates="case")
|
||||
open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_case")
|
||||
|
||||
class SealedBox(PhysicalItem):
|
||||
__tablename__ = "sealed_boxes"
|
||||
|
||||
id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True)
|
||||
case_id = Column(Integer, ForeignKey("sealed_cases.id"), nullable=True)
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': 'sealed_box'
|
||||
}
|
||||
|
||||
# Relationships
|
||||
case = relationship("SealedCase", back_populates="boxes")
|
||||
open_event = relationship("OpenEvent", uselist=False, back_populates="sealed_box")
|
||||
|
||||
class OpenBox(PhysicalItem):
|
||||
__tablename__ = "open_boxes"
|
||||
|
||||
id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True)
|
||||
open_event_id = Column(Integer, ForeignKey("open_events.id"))
|
||||
sealed_box_id = Column(Integer, ForeignKey("sealed_boxes.id"))
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': 'open_box'
|
||||
}
|
||||
|
||||
# Relationships
|
||||
open_event = relationship("OpenEvent", back_populates="resulting_boxes")
|
||||
sealed_box = relationship("SealedBox")
|
||||
cards = relationship("OpenCard", back_populates="box")
|
||||
|
||||
class OpenCard(PhysicalItem):
|
||||
__tablename__ = "open_cards"
|
||||
|
||||
id = Column(Integer, ForeignKey('physical_items.id'), primary_key=True)
|
||||
open_event_id = Column(Integer, ForeignKey("open_events.id"))
|
||||
box_id = Column(Integer, ForeignKey("open_boxes.id"), nullable=True)
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': 'open_card'
|
||||
}
|
||||
|
||||
# Relationships
|
||||
open_event = relationship("OpenEvent", back_populates="resulting_cards")
|
||||
box = relationship("OpenBox", back_populates="cards")
|
||||
|
||||
class InventoryItem(Base):
|
||||
__tablename__ = "inventory_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
physical_item_id = Column(Integer, ForeignKey("physical_items.id"), unique=True)
|
||||
cost_basis = Column(Float) # Current cost basis for this item
|
||||
parent_id = Column(Integer, ForeignKey("inventory_items.id"), nullable=True) # For tracking hierarchy
|
||||
created_at = Column(DateTime(timezone=True))
|
||||
updated_at = Column(DateTime(timezone=True))
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# Relationships
|
||||
physical_item = relationship("PhysicalItem", back_populates="inventory_item")
|
||||
parent = relationship("InventoryItem", remote_side=[id])
|
||||
children = relationship("InventoryItem")
|
||||
|
||||
class TransactionItem(Base):
|
||||
__tablename__ = "transaction_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
transaction_id = Column(Integer, ForeignKey("transactions.id"))
|
||||
physical_item_id = Column(Integer, ForeignKey("physical_items.id"))
|
||||
unit_price = 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 = relationship("Transaction", back_populates="transaction_items")
|
||||
physical_item = relationship("PhysicalItem", back_populates="transaction_items")
|
||||
|
||||
class OpenEvent(Base):
|
||||
__tablename__ = "open_events"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
sealed_case_id = Column(Integer, ForeignKey("sealed_cases.id"), nullable=True)
|
||||
sealed_box_id = Column(Integer, ForeignKey("sealed_boxes.id"), nullable=True)
|
||||
open_date = Column(DateTime(timezone=True))
|
||||
created_at = Column(DateTime(timezone=True))
|
||||
updated_at = Column(DateTime(timezone=True))
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# Relationships
|
||||
sealed_case = relationship("SealedCase", back_populates="open_event")
|
||||
sealed_box = relationship("SealedBox", back_populates="open_event")
|
||||
resulting_boxes = relationship("OpenBox", back_populates="open_event")
|
||||
resulting_cards = relationship("OpenCard", back_populates="open_event")
|
||||
|
||||
class Vendor(Base):
|
||||
__tablename__ = "vendors"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, unique=True, index=True)
|
||||
created_at = Column(DateTime(timezone=True))
|
||||
updated_at = Column(DateTime(timezone=True))
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
class Customer(Base):
|
||||
__tablename__ = "customers"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, unique=True, index=True)
|
||||
created_at = Column(DateTime(timezone=True))
|
||||
updated_at = Column(DateTime(timezone=True))
|
||||
|
||||
class Transaction(Base):
|
||||
__tablename__ = "transactions"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=True)
|
||||
customer_id = Column(Integer, ForeignKey("customers.id"), nullable=True)
|
||||
transaction_type = Column(String) # 'purchase' or 'sale'
|
||||
transaction_date = Column(DateTime(timezone=True))
|
||||
transaction_total_amount = Column(Float)
|
||||
transaction_notes = Column(String)
|
||||
created_at = Column(DateTime(timezone=True))
|
||||
updated_at = Column(DateTime(timezone=True))
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# Relationships
|
||||
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")
|
12
app/models/product.py
Normal file
12
app/models/product.py
Normal file
@ -0,0 +1,12 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime
|
||||
from app.db.database import Base
|
||||
|
||||
class Product(Base):
|
||||
__tablename__ = "products"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String)
|
||||
tcgplayer_id = Column(String)
|
||||
created_at = Column(DateTime(timezone=True))
|
||||
updated_at = Column(DateTime(timezone=True))
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
@ -2,8 +2,8 @@ from sqlalchemy import Column, Integer, String, Float, DateTime
|
||||
from sqlalchemy.sql import func
|
||||
from app.db.database import Base
|
||||
|
||||
class Inventory(Base):
|
||||
__tablename__ = "inventory"
|
||||
class TCGPlayerInventory(Base):
|
||||
__tablename__ = "tcgplayer_inventory"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
tcgplayer_id = Column(String, unique=True, index=True)
|
||||
@ -22,7 +22,6 @@ class Inventory(Base):
|
||||
add_to_quantity = Column(Integer)
|
||||
tcg_marketplace_price = Column(Float)
|
||||
photo_url = Column(String)
|
||||
|
||||
# Timestamps
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.current_timestamp())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.current_timestamp())
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
@ -3,11 +3,6 @@ from sqlalchemy.orm import Session
|
||||
from app.db.database import get_db
|
||||
from app.models.file import File as FileModel
|
||||
from app.schemas.file import FileCreate, FileUpdate, FileDelete, FileList, FileInDB
|
||||
from app.models.box import Box as BoxModel, OpenBox as OpenBoxModel
|
||||
from app.schemas.box import BoxCreate, BoxUpdate, BoxDelete, BoxList, OpenBoxCreate, OpenBoxUpdate, OpenBoxDelete, OpenBoxList, BoxInDB, OpenBoxInDB
|
||||
from app.models.game import Game as GameModel
|
||||
from app.schemas.game import GameCreate, GameUpdate, GameDelete, GameList, GameInDB
|
||||
from app.models.card import Card as CardModel
|
||||
from app.routes.set_label_routes import router as set_label_router
|
||||
from app.routes.order_routes import router as order_router
|
||||
|
||||
@ -48,61 +43,3 @@ async def update_file(file_id: int, file: FileUpdate):
|
||||
@router.delete("/files/{file_id}", response_model=FileDelete)
|
||||
async def delete_file(file_id: int):
|
||||
return {"message": "File deleted successfully"}
|
||||
|
||||
# ============================================================================
|
||||
# Box Management Endpoints
|
||||
# ============================================================================
|
||||
@router.get("/boxes", response_model=BoxList)
|
||||
async def get_boxes(page: int = 1, limit: int = 10, type: str = None, id: int = None):
|
||||
return {"boxes": [], "total": 0, "page": page, "limit": limit}
|
||||
|
||||
@router.post("/boxes", response_model=BoxInDB)
|
||||
async def create_box(box: BoxCreate):
|
||||
return {"message": "Box created successfully"}
|
||||
|
||||
@router.put("/boxes/{box_id}", response_model=BoxInDB)
|
||||
async def update_box(box_id: int, box: BoxUpdate):
|
||||
return {"message": "Box updated successfully"}
|
||||
|
||||
@router.delete("/boxes/{box_id}", response_model=BoxDelete)
|
||||
async def delete_box(box_id: int):
|
||||
return {"message": "Box deleted successfully"}
|
||||
|
||||
# ============================================================================
|
||||
# Open Box Management Endpoints
|
||||
# ============================================================================
|
||||
@router.get("/open_boxes", response_model=OpenBoxList)
|
||||
async def get_open_boxes(page: int = 1, limit: int = 10, type: str = None, id: int = None):
|
||||
return {"open_boxes": [], "total": 0, "page": page, "limit": limit}
|
||||
|
||||
@router.post("/open_boxes", response_model=OpenBoxInDB)
|
||||
async def create_open_box(open_box: OpenBoxCreate):
|
||||
return {"message": "Open box created successfully"}
|
||||
|
||||
@router.put("/open_boxes/{open_box_id}", response_model=OpenBoxInDB)
|
||||
async def update_open_box(open_box_id: int, open_box: OpenBoxUpdate):
|
||||
return {"message": "Open box updated successfully"}
|
||||
|
||||
@router.delete("/open_boxes/{open_box_id}", response_model=OpenBoxDelete)
|
||||
async def delete_open_box(open_box_id: int):
|
||||
return {"message": "Open box deleted successfully"}
|
||||
|
||||
# ============================================================================
|
||||
# Game Management Endpoints
|
||||
# ============================================================================
|
||||
@router.get("/games", response_model=GameList)
|
||||
async def get_games(page: int = 1, limit: int = 10, type: str = None, id: int = None):
|
||||
return {"games": [], "total": 0, "page": page, "limit": limit}
|
||||
|
||||
@router.post("/games", response_model=GameInDB)
|
||||
async def create_game(game: GameCreate):
|
||||
return {"message": "Game created successfully"}
|
||||
|
||||
@router.put("/games/{game_id}", response_model=GameInDB)
|
||||
async def update_game(game_id: int, game: GameUpdate):
|
||||
return {"message": "Game updated successfully"}
|
||||
|
||||
@router.delete("/games/{game_id}", response_model=GameDelete)
|
||||
async def delete_game(game_id: int):
|
||||
return {"message": "Game deleted successfully"}
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Base schema with common attributes
|
||||
class BoxBase(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
game_id: int
|
||||
set_id: Optional[int] = None
|
||||
price: Optional[float] = None
|
||||
quantity: Optional[int] = 0
|
||||
status: Optional[str] = "available" # available, sold, reserved
|
||||
|
||||
# Schema for creating a new box
|
||||
class BoxCreate(BoxBase):
|
||||
pass
|
||||
|
||||
# Schema for updating a box
|
||||
class BoxUpdate(BoxBase):
|
||||
pass
|
||||
|
||||
# Schema for reading a box
|
||||
class BoxInDB(BoxBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# Schema for deleting a box
|
||||
class BoxDelete(BaseModel):
|
||||
message: str
|
||||
|
||||
# Schema for listing boxes
|
||||
class BoxList(BaseModel):
|
||||
boxes: List[BoxInDB]
|
||||
total: int
|
||||
page: int
|
||||
limit: int
|
||||
|
||||
# OpenBox schemas
|
||||
class OpenBoxBase(BaseModel):
|
||||
box_id: int
|
||||
opened_at: Optional[datetime] = None
|
||||
opened_by: Optional[str] = None
|
||||
contents: Optional[List[dict]] = None
|
||||
status: Optional[str] = "pending" # pending, opened, verified, listed
|
||||
|
||||
class OpenBoxCreate(OpenBoxBase):
|
||||
pass
|
||||
|
||||
class OpenBoxUpdate(OpenBoxBase):
|
||||
pass
|
||||
|
||||
class OpenBoxInDB(OpenBoxBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
class OpenBoxDelete(BaseModel):
|
||||
message: str
|
||||
|
||||
class OpenBoxList(BaseModel):
|
||||
open_boxes: List[OpenBoxInDB]
|
||||
total: int
|
||||
page: int
|
||||
limit: int
|
@ -1,55 +0,0 @@
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Base schema with common attributes
|
||||
class CardBase(BaseModel):
|
||||
name: str
|
||||
rarity: Optional[str] = None
|
||||
set_name: Optional[str] = None
|
||||
price: Optional[float] = None
|
||||
quantity: Optional[int] = 0
|
||||
|
||||
# TCGPlayer specific fields
|
||||
tcgplayer_sku: Optional[str] = None
|
||||
product_line: Optional[str] = None
|
||||
product_name: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
number: Optional[str] = None
|
||||
condition: Optional[str] = None
|
||||
tcg_market_price: Optional[float] = None
|
||||
tcg_direct_low: Optional[float] = None
|
||||
tcg_low_price_with_shipping: Optional[float] = None
|
||||
tcg_low_price: Optional[float] = None
|
||||
total_quantity: Optional[int] = None
|
||||
add_to_quantity: Optional[int] = None
|
||||
tcg_marketplace_price: Optional[float] = None
|
||||
photo_url: Optional[str] = None
|
||||
|
||||
# Schema for creating a new card
|
||||
class CardCreate(CardBase):
|
||||
pass
|
||||
|
||||
# Schema for updating a card
|
||||
class CardUpdate(CardBase):
|
||||
pass
|
||||
|
||||
# Schema for reading a card (includes id and relationships)
|
||||
class CardInDB(CardBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# Schema for listing cards
|
||||
class CardList(BaseModel):
|
||||
cards: List[CardInDB]
|
||||
total: int
|
||||
page: int
|
||||
limit: int
|
||||
|
||||
# Schema for deleting a card
|
||||
class CardDelete(BaseModel):
|
||||
message: str
|
@ -1,41 +0,0 @@
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Base schema with common attributes
|
||||
class GameBase(BaseModel):
|
||||
name: str
|
||||
publisher: Optional[str] = None
|
||||
release_date: Optional[datetime] = None
|
||||
description: Optional[str] = None
|
||||
website: Optional[str] = None
|
||||
logo_url: Optional[str] = None
|
||||
status: Optional[str] = "active" # active, inactive, discontinued
|
||||
|
||||
# Schema for creating a new game
|
||||
class GameCreate(GameBase):
|
||||
pass
|
||||
|
||||
# Schema for updating a game
|
||||
class GameUpdate(GameBase):
|
||||
pass
|
||||
|
||||
# Schema for reading a game
|
||||
class GameInDB(GameBase):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
# Schema for deleting a game
|
||||
class GameDelete(BaseModel):
|
||||
message: str
|
||||
|
||||
# Schema for listing games
|
||||
class GameList(BaseModel):
|
||||
games: List[GameInDB]
|
||||
total: int
|
||||
page: int
|
||||
limit: int
|
@ -6,7 +6,7 @@ import json
|
||||
from datetime import datetime
|
||||
from sqlalchemy.orm import Session
|
||||
from app.db.database import transaction
|
||||
from app.models.inventory import Inventory
|
||||
from app.models.tcgplayer_inventory import TCGPlayerInventory
|
||||
from app.models.tcgplayer_product import TCGPlayerProduct
|
||||
from app.services.inventory_service import InventoryService
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
from typing import List, Optional, Dict
|
||||
from sqlalchemy.orm import Session
|
||||
from app.models.inventory import Inventory
|
||||
from app.models.tcgplayer_inventory import TCGPlayerInventory
|
||||
from app.services.base_service import BaseService
|
||||
|
||||
class InventoryService(BaseService[Inventory]):
|
||||
class InventoryService(BaseService[TCGPlayerInventory]):
|
||||
def __init__(self):
|
||||
super().__init__(Inventory)
|
||||
super().__init__(TCGPlayerInventory)
|
||||
|
||||
def create(self, db: Session, obj_in: Dict) -> Inventory:
|
||||
def create(self, db: Session, obj_in: Dict) -> TCGPlayerInventory:
|
||||
"""
|
||||
Create a new inventory item in the database.
|
||||
|
||||
@ -20,7 +20,7 @@ class InventoryService(BaseService[Inventory]):
|
||||
"""
|
||||
return super().create(db, obj_in)
|
||||
|
||||
def update(self, db: Session, db_obj: Inventory, obj_in: Dict) -> Inventory:
|
||||
def update(self, db: Session, db_obj: TCGPlayerInventory, obj_in: Dict) -> TCGPlayerInventory:
|
||||
"""
|
||||
Update an existing inventory item in the database.
|
||||
|
||||
@ -34,7 +34,7 @@ class InventoryService(BaseService[Inventory]):
|
||||
"""
|
||||
return super().update(db, db_obj, obj_in)
|
||||
|
||||
def get_by_tcgplayer_id(self, db: Session, tcgplayer_id: str) -> Optional[Inventory]:
|
||||
def get_by_tcgplayer_id(self, db: Session, tcgplayer_id: str) -> Optional[TCGPlayerInventory]:
|
||||
"""
|
||||
Get an inventory item by its TCGPlayer ID.
|
||||
|
||||
@ -43,11 +43,11 @@ class InventoryService(BaseService[Inventory]):
|
||||
tcgplayer_id: The TCGPlayer ID to find
|
||||
|
||||
Returns:
|
||||
Optional[Inventory]: The inventory item if found, None otherwise
|
||||
Optional[TCGPlayerInventory]: The inventory item if found, None otherwise
|
||||
"""
|
||||
return db.query(self.model).filter(self.model.tcgplayer_id == tcgplayer_id).first()
|
||||
|
||||
def get_by_set(self, db: Session, set_name: str, skip: int = 0, limit: int = 100) -> List[Inventory]:
|
||||
def get_by_set(self, db: Session, set_name: str, skip: int = 0, limit: int = 100) -> List[TCGPlayerInventory]:
|
||||
"""
|
||||
Get all inventory items from a specific set.
|
||||
|
||||
@ -58,6 +58,6 @@ class InventoryService(BaseService[Inventory]):
|
||||
limit: Maximum number of records to return
|
||||
|
||||
Returns:
|
||||
List[Inventory]: List of inventory items from the specified set
|
||||
List[TCGPlayerInventory]: List of inventory items from the specified set
|
||||
"""
|
||||
return db.query(self.model).filter(self.model.set_name == set_name).offset(skip).limit(limit).all()
|
@ -336,6 +336,125 @@ async function submitPirateShipLabel() {
|
||||
}
|
||||
}
|
||||
|
||||
// Show set labels modal
|
||||
function showSetLabelsModal() {
|
||||
const modal = document.getElementById('setLabelsModal');
|
||||
modal.classList.remove('hidden');
|
||||
modal.classList.add('flex');
|
||||
fetchAvailableSets();
|
||||
|
||||
// Add event listener for search input
|
||||
const searchInput = document.getElementById('setSearch');
|
||||
searchInput.addEventListener('input', filterSets);
|
||||
}
|
||||
|
||||
// Close set labels modal
|
||||
function closeSetLabelsModal() {
|
||||
const modal = document.getElementById('setLabelsModal');
|
||||
modal.classList.remove('flex');
|
||||
modal.classList.add('hidden');
|
||||
|
||||
// Clear search input
|
||||
document.getElementById('setSearch').value = '';
|
||||
}
|
||||
|
||||
// Filter sets based on search input
|
||||
function filterSets() {
|
||||
const searchTerm = document.getElementById('setSearch').value.toLowerCase();
|
||||
const setItems = document.querySelectorAll('#setLabelsList > div');
|
||||
|
||||
setItems.forEach(item => {
|
||||
const label = item.querySelector('label');
|
||||
const text = label.textContent.toLowerCase();
|
||||
if (text.includes(searchTerm)) {
|
||||
item.style.display = 'flex';
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch available sets from the API
|
||||
async function fetchAvailableSets() {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch(`${API_BASE_URL}/set-labels/available-sets`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch available sets');
|
||||
}
|
||||
|
||||
const sets = await response.json();
|
||||
displayAvailableSets(sets);
|
||||
} catch (error) {
|
||||
showToast('Error fetching available sets: ' + error.message, 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Display available sets in the modal
|
||||
function displayAvailableSets(sets) {
|
||||
const setList = document.getElementById('setLabelsList');
|
||||
setList.innerHTML = '';
|
||||
|
||||
if (!sets || sets.length === 0) {
|
||||
setList.innerHTML = '<div class="text-center text-gray-400 py-4">No sets available</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort sets alphabetically by name
|
||||
sets.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
sets.forEach(set => {
|
||||
const setItem = document.createElement('div');
|
||||
setItem.className = 'flex items-center p-2 hover:bg-gray-600 rounded-lg cursor-pointer';
|
||||
setItem.innerHTML = `
|
||||
<input type="checkbox" id="set-${set.code}" class="rounded border-gray-600 bg-gray-800 text-teal-600 focus:ring-teal-500">
|
||||
<label for="set-${set.code}" class="ml-2 text-gray-300">${set.name} (${set.code})</label>
|
||||
`;
|
||||
setList.appendChild(setItem);
|
||||
});
|
||||
|
||||
// Trigger initial filter in case there's text in the search box
|
||||
filterSets();
|
||||
}
|
||||
|
||||
// Submit set labels request
|
||||
async function submitSetLabels() {
|
||||
try {
|
||||
const selectedSets = Array.from(document.querySelectorAll('#setLabelsList input[type="checkbox"]:checked'))
|
||||
.map(checkbox => checkbox.id.replace('set-', ''));
|
||||
|
||||
if (selectedSets.length === 0) {
|
||||
showToast('Please select at least one set', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
const response = await fetch(`${API_BASE_URL}/set-labels/generate`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
sets: selectedSets
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.detail || 'Failed to generate set labels');
|
||||
}
|
||||
|
||||
showToast('Set labels generated successfully');
|
||||
closeSetLabelsModal();
|
||||
} catch (error) {
|
||||
showToast('Error generating set labels: ' + error.message, 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Load orders when page loads
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetchOrders();
|
||||
|
@ -45,6 +45,9 @@
|
||||
<button onclick="showPirateShipModal()" class="px-4 py-2 bg-yellow-600 text-white rounded-lg hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-offset-2 transition-colors">
|
||||
Upload Pirate Ship Label
|
||||
</button>
|
||||
<button onclick="showSetLabelsModal()" class="px-4 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 transition-colors">
|
||||
Generate Set Labels
|
||||
</button>
|
||||
</div>
|
||||
<div id="labelOptions" class="bg-gray-700 rounded-lg p-4">
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Label Type</label>
|
||||
@ -93,6 +96,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Set Labels Modal -->
|
||||
<div id="setLabelsModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center">
|
||||
<div class="bg-gray-800 rounded-lg p-6 max-w-md w-full mx-4">
|
||||
<h3 class="text-xl font-semibold text-gray-100 mb-4">Generate Set Labels</h3>
|
||||
<div class="mb-4">
|
||||
<div class="mb-2">
|
||||
<label for="setSearch" class="block text-sm font-medium text-gray-300 mb-2">Search Sets</label>
|
||||
<input type="text" id="setSearch" placeholder="Search sets..." class="w-full rounded-lg border-gray-600 bg-gray-700 text-gray-100 focus:ring-blue-500 focus:border-blue-500">
|
||||
</div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Select Sets</label>
|
||||
<div id="setLabelsList" class="max-h-60 overflow-y-auto bg-gray-700 rounded-lg p-2">
|
||||
<!-- Sets will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end space-x-3">
|
||||
<button onclick="closeSetLabelsModal()" class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-colors">
|
||||
Cancel
|
||||
</button>
|
||||
<button onclick="submitSetLabels()" class="px-4 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 transition-colors">
|
||||
Generate
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order List Section -->
|
||||
<div class="bg-gray-800 rounded-xl shadow-sm p-6">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
|
Loading…
x
Reference in New Issue
Block a user