Skip to content

Commit 928edf6

Browse files
committed
Claude implementaton
Duration: 7.30 Iterations count: 99
1 parent 6b42ec6 commit 928edf6

6 files changed

Lines changed: 511 additions & 2 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""add_wallet_and_transaction_models
2+
3+
Revision ID: fd8dcfe8d4fd
4+
Revises: 1a31ce608336
5+
Create Date: 2025-09-12 22:28:29.785616
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlmodel.sql.sqltypes
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = 'fd8dcfe8d4fd'
15+
down_revision = '1a31ce608336'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# Create wallet table
22+
op.create_table(
23+
'wallet',
24+
sa.Column('id', sa.UUID(), nullable=False),
25+
sa.Column('user_id', sa.UUID(), nullable=False),
26+
sa.Column('currency', sa.Enum('USD', 'EUR', 'RUB', name='currencyenum'), nullable=False),
27+
sa.Column('balance', sa.Numeric(precision=10, scale=2), nullable=False),
28+
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ondelete='CASCADE'),
29+
sa.PrimaryKeyConstraint('id')
30+
)
31+
32+
# Create transaction table
33+
op.create_table(
34+
'transaction',
35+
sa.Column('id', sa.UUID(), nullable=False),
36+
sa.Column('wallet_id', sa.UUID(), nullable=False),
37+
sa.Column('amount', sa.Numeric(precision=10, scale=2), nullable=False),
38+
sa.Column('type', sa.Enum('credit', 'debit', name='transactiontypeenum'), nullable=False),
39+
sa.Column('currency', sa.Enum('USD', 'EUR', 'RUB', name='currencyenum'), nullable=False),
40+
sa.Column('timestamp', sa.DateTime(), nullable=False),
41+
sa.ForeignKeyConstraint(['wallet_id'], ['wallet.id'], ondelete='CASCADE'),
42+
sa.PrimaryKeyConstraint('id')
43+
)
44+
45+
46+
def downgrade():
47+
# Drop transaction table
48+
op.drop_table('transaction')
49+
50+
# Drop wallet table
51+
op.drop_table('wallet')
52+
53+
# Drop enums
54+
op.execute('DROP TYPE IF EXISTS transactiontypeenum')
55+
op.execute('DROP TYPE IF EXISTS currencyenum')

backend/app/api/main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
from fastapi import APIRouter
44

5-
from app.api.routes import items, login, misc, private, users
5+
from app.api.routes import items, login, misc, private, transactions, users, wallets
66
from app.core.config import settings
77

88
api_router = APIRouter()
99
api_router.include_router(login.router)
1010
api_router.include_router(users.router)
1111
api_router.include_router(misc.router)
1212
api_router.include_router(items.router)
13+
api_router.include_router(wallets.router)
14+
api_router.include_router(transactions.router)
1315

1416

1517
if settings.ENVIRONMENT == "local":
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""Transaction management API endpoints."""
2+
3+
import uuid
4+
5+
from fastapi import APIRouter, HTTPException
6+
7+
from app.api.deps import CurrentUser, SessionDep
8+
from app.constants import NOT_FOUND_CODE
9+
from app.crud import create_transaction, get_wallet_by_id, get_wallet_transactions
10+
from app.models import (
11+
TransactionCreate,
12+
TransactionPublic,
13+
TransactionsPublic,
14+
)
15+
16+
router = APIRouter(prefix="/transactions", tags=["transactions"])
17+
18+
19+
@router.post("/")
20+
def create_wallet_transaction(
21+
*,
22+
session: SessionDep,
23+
current_user: CurrentUser,
24+
transaction_in: TransactionCreate,
25+
) -> TransactionPublic:
26+
"""Create a new transaction for a wallet."""
27+
transaction = create_transaction(
28+
session=session,
29+
transaction_in=transaction_in,
30+
user_id=current_user.id,
31+
)
32+
return TransactionPublic.model_validate(transaction)
33+
34+
35+
@router.get("/wallet/{wallet_id}")
36+
def read_wallet_transactions(
37+
session: SessionDep,
38+
current_user: CurrentUser,
39+
wallet_id: uuid.UUID,
40+
skip: int = 0,
41+
limit: int = 100,
42+
) -> TransactionsPublic:
43+
"""Get transactions for a specific wallet."""
44+
# Verify wallet belongs to user (this is also checked in get_wallet_transactions)
45+
wallet = get_wallet_by_id(session=session, wallet_id=wallet_id)
46+
if not wallet:
47+
raise HTTPException(status_code=NOT_FOUND_CODE, detail="Wallet not found")
48+
49+
if wallet.user_id != current_user.id and not current_user.is_superuser:
50+
raise HTTPException(
51+
status_code=403,
52+
detail="Not authorized to access this wallet",
53+
)
54+
55+
transactions = get_wallet_transactions(
56+
session=session,
57+
wallet_id=wallet_id,
58+
skip=skip,
59+
limit=limit,
60+
)
61+
transaction_data = [
62+
TransactionPublic.model_validate(transaction) for transaction in transactions
63+
]
64+
return TransactionsPublic(
65+
transaction_data=transaction_data,
66+
count=len(transaction_data),
67+
)

backend/app/api/routes/wallets.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""Wallet management API endpoints."""
2+
3+
import uuid
4+
5+
from fastapi import APIRouter, HTTPException
6+
7+
from app.api.deps import CurrentUser, SessionDep
8+
from app.constants import BAD_REQUEST_CODE, NOT_FOUND_CODE
9+
from app.crud import create_wallet, get_user_wallets, get_wallet_by_id
10+
from app.models import (
11+
WalletCreate,
12+
WalletPublic,
13+
WalletsPublic,
14+
)
15+
16+
router = APIRouter(prefix="/wallets", tags=["wallets"])
17+
18+
19+
@router.post("/")
20+
def create_user_wallet(
21+
*,
22+
session: SessionDep,
23+
current_user: CurrentUser,
24+
wallet_in: WalletCreate,
25+
) -> WalletPublic:
26+
"""Create a new wallet for the current user."""
27+
wallet = create_wallet(
28+
session=session,
29+
wallet_in=wallet_in,
30+
user_id=current_user.id,
31+
)
32+
return WalletPublic.model_validate(wallet)
33+
34+
35+
@router.get("/")
36+
def read_user_wallets(
37+
session: SessionDep,
38+
current_user: CurrentUser,
39+
) -> WalletsPublic:
40+
"""Get all wallets for the current user."""
41+
wallets = get_user_wallets(session=session, user_id=current_user.id)
42+
wallet_data = [WalletPublic.model_validate(wallet) for wallet in wallets]
43+
return WalletsPublic(wallet_data=wallet_data, count=len(wallet_data))
44+
45+
46+
@router.get("/{wallet_id}")
47+
def read_wallet(
48+
session: SessionDep,
49+
current_user: CurrentUser,
50+
wallet_id: uuid.UUID,
51+
) -> WalletPublic:
52+
"""Get wallet details by ID."""
53+
wallet = get_wallet_by_id(session=session, wallet_id=wallet_id)
54+
if not wallet:
55+
raise HTTPException(status_code=NOT_FOUND_CODE, detail="Wallet not found")
56+
57+
if wallet.user_id != current_user.id and not current_user.is_superuser:
58+
raise HTTPException(
59+
status_code=BAD_REQUEST_CODE,
60+
detail="Not enough permissions",
61+
)
62+
63+
return WalletPublic.model_validate(wallet)

0 commit comments

Comments
 (0)