hisham-cmd commited on
Commit
d045e6b
·
verified ·
1 Parent(s): d8a7674

Upload app/api/cart.py

Browse files
Files changed (1) hide show
  1. app/api/cart.py +68 -18
app/api/cart.py CHANGED
@@ -1,6 +1,6 @@
1
  from typing import Any, Optional
2
  from fastapi import APIRouter, Depends, HTTPException, status, Header
3
- from sqlalchemy.orm import Session
4
  from datetime import datetime, timezone
5
 
6
  from app.db.base import get_db
@@ -11,6 +11,7 @@ from app.schemas.cart import (
11
  CartResponse, CartItemCreate, CartItemUpdate,
12
  CartItemResponse, CouponApply, CouponResponse
13
  )
 
14
  from app.core.security import get_optional_current_user
15
 
16
  router = APIRouter(tags=["Cart"])
@@ -71,6 +72,15 @@ def get_or_create_cart(db: Session, user_id: Optional[int] = None, session_id: O
71
  else:
72
  raise HTTPException(status_code=400, detail="Either login or provide X-Cart-ID header")
73
 
 
 
 
 
 
 
 
 
 
74
  @router.get("/cart", response_model=dict)
75
  def get_cart(
76
  current_user_id: Optional[int] = Depends(get_optional_current_user),
@@ -79,29 +89,69 @@ def get_cart(
79
  ) -> Any:
80
  """Get the current user's (or guest session's) shopping cart."""
81
  cart = get_or_create_cart(db, user_id=current_user_id, session_id=x_cart_id)
 
 
 
 
 
 
 
 
 
 
 
 
82
  totals = calculate_cart_totals(cart)
83
 
84
- items_response = []
 
85
  for item in cart.items:
86
- item_data = CartItemResponse(
87
- id=item.id,
88
- cart_id=item.cart_id,
89
- product_id=item.product_id,
90
- quantity=item.quantity,
91
- unit_price=item.unit_price,
92
- total_price=item.quantity * item.unit_price,
93
- product=item.product
94
- )
95
- items_response.append(item_data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  return {
98
  "isSuccess": True,
99
- "value": CartResponse(
100
- id=cart.id,
101
- user_id=cart.user_id,
102
- items=items_response,
103
- **totals
104
- ),
105
  "statusCode": 200
106
  }
107
 
 
1
  from typing import Any, Optional
2
  from fastapi import APIRouter, Depends, HTTPException, status, Header
3
+ from sqlalchemy.orm import Session, joinedload
4
  from datetime import datetime, timezone
5
 
6
  from app.db.base import get_db
 
11
  CartResponse, CartItemCreate, CartItemUpdate,
12
  CartItemResponse, CouponApply, CouponResponse
13
  )
14
+ from app.schemas.product import ProductListItem
15
  from app.core.security import get_optional_current_user
16
 
17
  router = APIRouter(tags=["Cart"])
 
72
  else:
73
  raise HTTPException(status_code=400, detail="Either login or provide X-Cart-ID header")
74
 
75
+
76
+ def _get_primary_image(product) -> Optional[str]:
77
+ """Extract the primary image URL from a product's images relationship."""
78
+ if product.images:
79
+ sorted_imgs = sorted(product.images, key=lambda x: x.sort_order)
80
+ return sorted_imgs[0].image_url if sorted_imgs else None
81
+ return None
82
+
83
+
84
  @router.get("/cart", response_model=dict)
85
  def get_cart(
86
  current_user_id: Optional[int] = Depends(get_optional_current_user),
 
89
  ) -> Any:
90
  """Get the current user's (or guest session's) shopping cart."""
91
  cart = get_or_create_cart(db, user_id=current_user_id, session_id=x_cart_id)
92
+
93
+ # Re-query the cart with all needed eager loads for response serialization
94
+ cart = db.query(Cart).options(
95
+ joinedload(Cart.items)
96
+ .joinedload(CartItem.product)
97
+ .joinedload(Product.images),
98
+ joinedload(Cart.items)
99
+ .joinedload(CartItem.product)
100
+ .joinedload(Product.category),
101
+ joinedload(Cart.coupon)
102
+ ).filter(Cart.id == cart.id).first()
103
+
104
  totals = calculate_cart_totals(cart)
105
 
106
+ # Build response manually as plain dicts to guarantee image_url is included
107
+ items_list = []
108
  for item in cart.items:
109
+ primary_image = _get_primary_image(item.product)
110
+
111
+ product_dict = {
112
+ "id": item.product.id,
113
+ "name_ar": item.product.name_ar,
114
+ "name_en": item.product.name_en,
115
+ "price": item.product.price,
116
+ "compare_price": item.product.compare_price,
117
+ "stock": item.product.stock,
118
+ "category_id": item.product.category_id,
119
+ "category": None,
120
+ "rating": item.product.rating,
121
+ "rating_count": item.product.rating_count,
122
+ "is_featured": item.product.is_featured,
123
+ "image_url": primary_image,
124
+ "created_at": item.product.created_at.isoformat() if item.product.created_at else None,
125
+ }
126
+ if item.product.category:
127
+ product_dict["category"] = {
128
+ "id": item.product.category.id,
129
+ "name_ar": item.product.category.name_ar,
130
+ "name_en": item.product.category.name_en,
131
+ "icon": item.product.category.icon,
132
+ "sort_order": item.product.category.sort_order,
133
+ }
134
 
135
+ items_list.append({
136
+ "id": item.id,
137
+ "cart_id": item.cart_id,
138
+ "product_id": item.product_id,
139
+ "quantity": item.quantity,
140
+ "unit_price": item.unit_price,
141
+ "total_price": round(item.quantity * item.unit_price, 2),
142
+ "product": product_dict,
143
+ })
144
+
145
+ response_value = {
146
+ "id": cart.id,
147
+ "user_id": cart.user_id,
148
+ "items": items_list,
149
+ **totals
150
+ }
151
+
152
  return {
153
  "isSuccess": True,
154
+ "value": response_value,
 
 
 
 
 
155
  "statusCode": 200
156
  }
157