Skip to content

Commit c0d2dd0

Browse files
committed
store apis implemented
1 parent 6e4a0c8 commit c0d2dd0

File tree

9 files changed

+287
-5
lines changed

9 files changed

+287
-5
lines changed

api/helpers/inventory_helper.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
logger = logging.getLogger()
1111

12+
1213
def to_dict(self):
1314
return {
1415
"name": self.name,
@@ -18,6 +19,7 @@ def to_dict(self):
1819
"notes": self.notes,
1920
}
2021

22+
2123
class InventoryHelper(object):
2224
def __init__(self, user: User) -> None:
2325
self.user = user

api/store_api.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from typing import List
2+
from uuid import UUID
3+
from fastapi import APIRouter, Depends, HTTPException, status
4+
from pydantic import BaseModel
5+
6+
from helpers.jwt import auth_required
7+
from models.entity.user_entity import User
8+
from models.service.store_service import StoreService
9+
10+
store_apis = APIRouter(prefix="/stores", tags=["stores"])
11+
12+
13+
class StoreCreate(BaseModel):
14+
name: str
15+
address: str
16+
phone: str
17+
email: str
18+
website: str = None
19+
20+
21+
class StoreUpdate(BaseModel):
22+
name: str = None
23+
address: str = None
24+
phone: str = None
25+
email: str = None
26+
website: str = None
27+
28+
29+
@store_apis.post("/", status_code=status.HTTP_201_CREATED)
30+
async def create_store(
31+
store_data: StoreCreate, current_user: User = Depends(auth_required)
32+
):
33+
store_service = StoreService()
34+
return store_service.create_store(user_id=current_user.id, **store_data.dict())
35+
36+
37+
@store_apis.get("/{store_id}")
38+
async def get_store(store_id: UUID, current_user: User = Depends(auth_required)):
39+
store_service = StoreService()
40+
return store_service.get_store(store_id)
41+
42+
43+
@store_apis.get("/")
44+
async def get_user_stores(current_user: User = Depends(auth_required)):
45+
store_service = StoreService()
46+
return store_service.get_stores_by_user(current_user.id)
47+
48+
49+
@store_apis.put("/{store_id}")
50+
async def update_store(
51+
store_id: UUID, store_data: StoreUpdate, current_user: User = Depends(auth_required)
52+
):
53+
store_service = StoreService()
54+
store = store_service.get_store(store_id)
55+
if store.user_id != current_user.id:
56+
raise HTTPException(
57+
status_code=status.HTTP_403_FORBIDDEN,
58+
detail="Not authorized to update this store",
59+
)
60+
return store_service.update_store(store_id, **store_data.dict(exclude_unset=True))
61+
62+
63+
@store_apis.delete("/{store_id}")
64+
async def delete_store(store_id: UUID, current_user: User = Depends(auth_required)):
65+
store_service = StoreService()
66+
store = store_service.get_store(store_id)
67+
if store.user_id != current_user.id:
68+
raise HTTPException(
69+
status_code=status.HTTP_403_FORBIDDEN,
70+
detail="Not authorized to delete this store",
71+
)
72+
return store_service.delete_store(store_id)
73+
74+
75+
@store_apis.post("/{store_id}/deactivate")
76+
async def deactivate_store(store_id: UUID, current_user: User = Depends(auth_required)):
77+
store_service = StoreService()
78+
store = store_service.get_store(store_id)
79+
if store.user_id != current_user.id:
80+
raise HTTPException(
81+
status_code=status.HTTP_403_FORBIDDEN,
82+
detail="Not authorized to deactivate this store",
83+
)
84+
return store_service.deactivate_store(store_id)
85+
86+
87+
@store_apis.post("/{store_id}/activate")
88+
async def activate_store(store_id: UUID, current_user: User = Depends(auth_required)):
89+
store_service = StoreService()
90+
store = store_service.get_store(store_id)
91+
if store.user_id != current_user.id:
92+
raise HTTPException(
93+
status_code=status.HTTP_403_FORBIDDEN,
94+
detail="Not authorized to activate this store",
95+
)
96+
return store_service.activate_store(store_id)
97+
98+
99+
@store_apis.get("/search/{query}")
100+
async def search_stores(query: str, current_user: User = Depends(auth_required)):
101+
store_service = StoreService()
102+
return store_service.search_stores(query)

engine/inventory/cart.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from models.entity.user_entity import User
2+
from models.entity.store_entity import Store
23

34

45
class Cart(object):
5-
def __init__(self, user: User):
6+
def __init__(self, user: User, store: Store):
67
self.user = user
78
self.items = []
89

main.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import uvicorn
55
from fastapi import FastAPI
66
from fastapi.middleware.cors import CORSMiddleware
7+
from fastapi.openapi.utils import get_openapi
8+
from fastapi.security import OAuth2PasswordBearer
79
from loguru import logger
810

911
from api.google_login import google_login_apis
1012
from api.inventory_api import inventory_apis
13+
from api.store_api import store_apis
1114
from api.user_api import user_apis
1215
from models.db import create_db_and_tables
1316

@@ -49,8 +52,38 @@ async def welcome():
4952
# app.include_router(firebase_api, prefix="/firebase")
5053
app.include_router(google_login_apis, prefix="/google")
5154
app.include_router(inventory_apis, prefix="/inventory")
55+
app.include_router(store_apis, prefix="/store")
5256

5357
create_db_and_tables()
5458

59+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
60+
61+
62+
def custom_openapi():
63+
if app.openapi_schema:
64+
return app.openapi_schema
65+
openapi_schema = get_openapi(
66+
title="Your API Title",
67+
version="1.0.0",
68+
description="Your API Description",
69+
routes=app.routes,
70+
)
71+
openapi_schema["components"]["securitySchemes"] = {
72+
"BearerAuth": {
73+
"type": "http",
74+
"scheme": "bearer",
75+
"bearerFormat": "JWT",
76+
"description": "Enter your JWT token in the format: Bearer <token>",
77+
}
78+
}
79+
for path in openapi_schema["paths"].values():
80+
for method in path.values():
81+
method.setdefault("security", []).append({"BearerAuth": []})
82+
app.openapi_schema = openapi_schema
83+
return app.openapi_schema
84+
85+
86+
app.openapi = custom_openapi
87+
5588
if __name__ == "__main__":
5689
uvicorn.run(app, port=8000)

models/entity/cart_entity.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from models.entity.cart_item_entity import CartItemEntity
66

77

8-
class CartEntity(SQLModel, table=True ):
8+
class CartEntity(SQLModel, table=True):
99
id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True)
1010
user_id: UUID = Field(foreign_key="user.id")
1111
items: List[CartItemEntity] = Field(default=[])
@@ -25,7 +25,6 @@ def remove_item(self, item: CartItemEntity):
2525
self.total_price -= item.price
2626
self.total_quantity -= item.quantity
2727

28-
2928
def clear(self):
3029
self.items = []
3130
self.total_price = 0.0

models/entity/cart_item_entity.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
from uuid import UUID, uuid4
44
from sqlmodel import Field, SQLModel
55

6+
67
class CartItemEntity(SQLModel, table=True):
78
id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True)
89
cart_id: UUID = Field(foreign_key="cartentity.id")
910
inventory_id: UUID = Field(foreign_key="inventory.id")
10-
quantity: int = Field(default=1)
11+
quantity: int = Field(default=1)
1112
price: float = Field(default=0.0)
1213
created_at: datetime = Field(default_factory=datetime.utcnow)
1314
updated_at: datetime = Field(default_factory=datetime.utcnow)
14-
notes: Optional[str] = None
15+
notes: Optional[str] = None

models/entity/store_entity.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from datetime import datetime
2+
from typing import Optional
3+
from uuid import UUID, uuid4
4+
from sqlmodel import Field, Relationship, SQLModel
5+
6+
from models.entity.user_entity import User
7+
8+
9+
class Store(SQLModel, table=True):
10+
id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True)
11+
name: str = Field(index=True)
12+
user_id: UUID = Field(foreign_key="user.id")
13+
# user: User = Relationship(back_populates="stores")
14+
address: str = Field(index=True)
15+
phone: str = Field(index=True)
16+
email: str = Field(index=True)
17+
website: str = Field(index=True)
18+
created_at: datetime = Field(default_factory=datetime.utcnow)
19+
updated_at: datetime = Field(default_factory=datetime.utcnow)
20+
is_active: bool = Field(default=True)
21+
22+
def __repr__(self):
23+
return f"<Store(id={self.id}, name={self.name})>"
24+
25+
def __str__(self):
26+
return self.name
27+
28+
def __hash__(self):
29+
return hash(self.id)
30+
31+
def is_active(self):
32+
return self.is_active
33+
34+
def is_inactive(self):
35+
return not self.is_active
36+
37+
def get_email(self):
38+
return self.email
39+
40+
def get_phone(self):
41+
return self.phone

models/service/cart_service.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from models.entity.cart_entity import CartEntity
22
from models.entity.cart_item_entity import CartItemEntity
33

4+
45
class CartService(object):
56
def __init__(self, cart_entity: CartEntity):
67
self.cart_entity = cart_entity

models/service/store_service.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from typing import List, Optional
2+
from uuid import UUID
3+
from datetime import datetime
4+
from fastapi import HTTPException, status
5+
6+
from models.db import db_session
7+
from models.entity.store_entity import Store
8+
from models.entity.user_entity import User
9+
10+
11+
class StoreService:
12+
def create_store(
13+
self,
14+
name: str,
15+
user_id: UUID,
16+
address: str,
17+
phone: str,
18+
email: str,
19+
website: str = None,
20+
) -> Store:
21+
try:
22+
store = Store(
23+
name=name,
24+
user_id=user_id,
25+
address=address,
26+
phone=phone,
27+
email=email,
28+
website=website,
29+
)
30+
db_session.add(store)
31+
db_session.commit()
32+
db_session.refresh(store)
33+
return store
34+
except Exception as e:
35+
db_session.rollback()
36+
raise HTTPException(
37+
status_code=status.HTTP_400_BAD_REQUEST,
38+
detail=f"Failed to create store: {str(e)}",
39+
)
40+
41+
def get_store(self, store_id: UUID) -> Optional[Store]:
42+
store = db_session.query(Store).filter(Store.id == store_id).first()
43+
if not store:
44+
raise HTTPException(
45+
status_code=status.HTTP_404_NOT_FOUND,
46+
detail=f"Store with id {store_id} not found",
47+
)
48+
return store
49+
50+
def get_stores_by_user(self, user_id: UUID) -> List[Store]:
51+
return db_session.query(Store).filter(Store.user_id == user_id).all()
52+
53+
def get_store_by_email(self, email: str) -> Optional[Store]:
54+
return db_session.query(Store).filter(Store.email == email).first()
55+
56+
def update_store(self, store_id: UUID, **update_data) -> Store:
57+
try:
58+
store = self.get_store(store_id)
59+
for key, value in update_data.items():
60+
if hasattr(store, key):
61+
setattr(store, key, value)
62+
store.updated_at = datetime.utcnow()
63+
db_session.commit()
64+
db_session.refresh(store)
65+
return store
66+
except Exception as e:
67+
db_session.rollback()
68+
raise HTTPException(
69+
status_code=status.HTTP_400_BAD_REQUEST,
70+
detail=f"Failed to update store: {str(e)}",
71+
)
72+
73+
def delete_store(self, store_id: UUID) -> bool:
74+
try:
75+
store = self.get_store(store_id)
76+
db_session.delete(store)
77+
db_session.commit()
78+
return True
79+
except Exception as e:
80+
db_session.rollback()
81+
raise HTTPException(
82+
status_code=status.HTTP_400_BAD_REQUEST,
83+
detail=f"Failed to delete store: {str(e)}",
84+
)
85+
86+
def deactivate_store(self, store_id: UUID) -> Store:
87+
return self.update_store(store_id, is_active=False)
88+
89+
def activate_store(self, store_id: UUID) -> Store:
90+
return self.update_store(store_id, is_active=True)
91+
92+
def search_stores(self, query: str) -> List[Store]:
93+
return (
94+
db_session.query(Store)
95+
.filter(
96+
(Store.name.ilike(f"%{query}%"))
97+
| (Store.email.ilike(f"%{query}%"))
98+
| (Store.phone.ilike(f"%{query}%"))
99+
| (Store.address.ilike(f"%{query}%"))
100+
)
101+
.all()
102+
)

0 commit comments

Comments
 (0)