Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions apps/api/backend/api/routes/cart_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
from backend.schemas.cart_item import (
CartItemCreateRequest,
CartItemDeleteResponse,
CartItemQuantityUpdateRequest,
CartItemResponse,
)
from backend.services.cart_item_service import add_item_to_cart, remove_item_from_cart
from backend.services.cart_item_service import (
add_item_to_cart,
remove_item_from_cart,
update_cart_item_quantity,
)

router = APIRouter(prefix="/carts", tags=["carts"])

Expand All @@ -29,4 +34,18 @@ def add_cart_item(cart_id: UUID, payload: CartItemCreateRequest) -> CartItemResp
)
def delete_cart_item(cart_id: UUID, cart_item_id: UUID) -> CartItemDeleteResponse:
result = remove_item_from_cart(cart_id, cart_item_id)
return CartItemDeleteResponse(**result)
return CartItemDeleteResponse(**result)


@router.patch(
"/{cart_id}/items/{cart_item_id}",
response_model=CartItemResponse,
status_code=status.HTTP_200_OK,
)
def patch_cart_item_quantity(
cart_id: UUID,
cart_item_id: UUID,
payload: CartItemQuantityUpdateRequest,
) -> CartItemResponse:
item = update_cart_item_quantity(cart_id, cart_item_id, payload)
return CartItemResponse(**item)
1 change: 1 addition & 0 deletions apps/api/backend/schemas/cart.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class CartItemSummaryResponse(BaseModel):
cart_item_id: UUID
product_id: UUID
product_name: str
brand_name: str | None = None
quantity: int
unit_price: Decimal
currency: str
Expand Down
6 changes: 5 additions & 1 deletion apps/api/backend/schemas/cart_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ class CartItemResponse(BaseModel):
class CartItemDeleteResponse(BaseModel):
cart_item_id: UUID
cart_id: UUID
message: str
message: str


class CartItemQuantityUpdateRequest(BaseModel):
quantity: int = Field(ge=1, le=999)
106 changes: 104 additions & 2 deletions apps/api/backend/services/cart_item_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
from sqlalchemy import text

from backend.db.connection import engine
from backend.schemas.cart_item import CartItemCreateRequest
from backend.schemas.cart_item import (
CartItemCreateRequest,
CartItemQuantityUpdateRequest,
)


def add_item_to_cart(cart_id: UUID, payload: CartItemCreateRequest) -> dict[str, Any]:
Expand Down Expand Up @@ -235,4 +238,103 @@ def remove_item_from_cart(cart_id: UUID, cart_item_id: UUID) -> dict[str, Any]:
"cart_item_id": deleted_item["cart_item_id"],
"cart_id": deleted_item["cart_id"],
"message": "Cart item removed successfully",
}
}

def update_cart_item_quantity(
cart_id: UUID,
cart_item_id: UUID,
payload: CartItemQuantityUpdateRequest,
) -> dict[str, Any]:
cart_query = text("""
SELECT
cart_id,
cart_status
FROM carts
WHERE cart_id = :cart_id
AND cart_status = 'active'
LIMIT 1
""")

item_query = text("""
SELECT
cart_item_id,
cart_id,
product_id,
unit_price,
currency
FROM cart_items
WHERE cart_id = :cart_id
AND cart_item_id = :cart_item_id
LIMIT 1
""")

update_query = text("""
UPDATE cart_items
SET
quantity = :quantity,
updated_at = CURRENT_TIMESTAMP
WHERE cart_id = :cart_id
AND cart_item_id = :cart_item_id
RETURNING
cart_item_id,
cart_id,
product_id,
quantity,
unit_price,
currency,
added_at,
updated_at
""")

with engine.begin() as connection:
cart = connection.execute(
cart_query,
{"cart_id": cart_id},
).mappings().first()

if cart is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Active cart not found",
)

item = connection.execute(
item_query,
{
"cart_id": cart_id,
"cart_item_id": cart_item_id,
},
).mappings().first()

if item is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cart item not found",
)

updated_item = connection.execute(
update_query,
{
"cart_id": cart_id,
"cart_item_id": cart_item_id,
"quantity": payload.quantity,
},
).mappings().first()

if updated_item is None:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to update cart item quantity",
)

return {
"cart_item_id": updated_item["cart_item_id"],
"cart_id": updated_item["cart_id"],
"product_id": updated_item["product_id"],
"quantity": updated_item["quantity"],
"unit_price": updated_item["unit_price"],
"currency": updated_item["currency"],
"added_at": updated_item["added_at"],
"updated_at": updated_item["updated_at"],
"message": "Cart item quantity updated successfully",
}
2 changes: 2 additions & 0 deletions apps/api/backend/services/cart_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def get_cart_detail(cart_id: UUID) -> dict[str, Any]:
ci.cart_item_id,
ci.product_id,
p.product_name,
p.brand_name,
ci.quantity,
ci.unit_price,
ci.currency,
Expand Down Expand Up @@ -154,6 +155,7 @@ def get_cart_detail(cart_id: UUID) -> dict[str, Any]:
"cart_item_id": row["cart_item_id"],
"product_id": row["product_id"],
"product_name": row["product_name"],
"brand_name": row["brand_name"],
"quantity": row["quantity"],
"unit_price": row["unit_price"],
"currency": row["currency"],
Expand Down
Loading
Loading