From 126187a362ea41c09720703182e8e0a1a7f91eb4 Mon Sep 17 00:00:00 2001 From: Sk_Akib_Ahammed Date: Tue, 13 Jan 2026 12:49:40 +0530 Subject: [PATCH] now the staff can check if the order has been paid or not and update the order status when its ready --- app/app.py | 20 ++++++++++++- app/schema.py | 16 ++++++++++ app/staff.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++++- app/user.py | 40 +++++++++++++++++++++---- app/webhook.py | 41 +++++++++----------------- 5 files changed, 163 insertions(+), 34 deletions(-) diff --git a/app/app.py b/app/app.py index aeaef85..94f7a33 100644 --- a/app/app.py +++ b/app/app.py @@ -9,7 +9,8 @@ UpdateStaffEmailSchema, UpdateMenuItemSchema, MenuScanResponse, - CreateOrderSchema + CreateOrderSchema, + UpdateOrderStatusSchema ) from .auth import ( authenticate_student, @@ -22,6 +23,8 @@ update_menu_item, delete_menu_item, add_staff_member, + get_stall_orders, + update_order_status_staff ) from .manager import ( get_my_staff, @@ -151,3 +154,18 @@ async def delete_menu_item_endpoint( item_id, credentials.credentials ) + +@app.get("/staff/orders", tags=["staff", "manager"]) +async def get_staff_orders_endpoint( + status: str = "PAID", + credentials: HTTPAuthorizationCredentials = Security(security) +): + return await get_stall_orders(credentials.credentials, status_filter=status) + +@app.patch("/staff/orders/{order_id}/status", tags=["staff", "manager"]) +async def update_order_status_endpoint( + order_id: str, + status_data: UpdateOrderStatusSchema, + credentials: HTTPAuthorizationCredentials = Security(security) +): + return await update_order_status_staff(order_id, status_data, credentials.credentials) diff --git a/app/schema.py b/app/schema.py index d22d912..b342b90 100644 --- a/app/schema.py +++ b/app/schema.py @@ -50,3 +50,19 @@ class CartItemSchema(BaseModel): class CreateOrderSchema(BaseModel): stall_id: str items: List[CartItemSchema] + +class OrderItemSchema(BaseModel): + name: str + quantity: int + price: float + +class OrderResponseSchema(BaseModel): + order_id: str + user_id: str + amount: float + status: str + items: List[OrderItemSchema] + created_at: str + +class UpdateOrderStatusSchema(BaseModel): + status: str diff --git a/app/staff.py b/app/staff.py index 6cbdacb..b085870 100644 --- a/app/staff.py +++ b/app/staff.py @@ -5,7 +5,7 @@ import json import google.generativeai as genai from fastapi import UploadFile -from .schema import MenuSchema, UpdateMenuItemSchema, AddStaffSchema +from .schema import MenuSchema, UpdateMenuItemSchema, AddStaffSchema, UpdateOrderStatusSchema from fastapi.responses import JSONResponse from starlette import status from .firebase_init import db @@ -454,3 +454,81 @@ async def scan_menu_image(file: UploadFile, id_token: str): status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": f"Internal Server Error: {str(e)}"} ) + +async def get_stall_orders(id_token: str, status_filter: str = "PAID"): + try: + staff_data, _ = await get_staff_details(id_token) + + if not staff_data: + return JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + content={"message": "Invalid or expired token."} + ) + + stall_id = staff_data.get("stall_id") + + orders_ref = ( + db.collection("orders") + .where("stall_id", "==", stall_id) + .where("status", "==", status_filter) + .order_by("created_at", direction=firestore.Query.DESCENDING) + ) + + docs = orders_ref.stream() + + orders_list = [] + for doc in docs: + data = doc.to_dict() + data['order_id'] = doc.id + + data = serialize_firestore_data(data) + + orders_list.append(data) + + return JSONResponse( + status_code=status.HTTP_200_OK, + content={ + "stall_id": stall_id, + "count": len(orders_list), + "orders": orders_list + } + ) + + except Exception as e: + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={"message": str(e)} + ) + +async def update_order_status_staff(order_id: str, status_data: UpdateOrderStatusSchema, id_token: str): + try: + staff_data, _ = await get_staff_details(id_token) + if not staff_data: + return JSONResponse(status_code=status.HTTP_401_UNAUTHORIZED, content={"message": "Unauthorized"}) + + stall_id = staff_data.get("stall_id") + + order_ref = db.collection("orders").document(order_id) + order_doc = order_ref.get() + + if not order_doc.exists: + return JSONResponse(status_code=status.HTTP_404_NOT_FOUND, content={"message": "Order not found"}) + + order_data = order_doc.to_dict() + + if order_data.get("stall_id") != stall_id: + return JSONResponse( + status_code=status.HTTP_403_FORBIDDEN, + content={"message": "You cannot update orders from other stalls."} + ) + + order_ref.update({ + "status": status_data.status, + "updated_at": firestore.SERVER_TIMESTAMP, + "updated_by": staff_data.get("email") + }) + + return JSONResponse(status_code=status.HTTP_200_OK, content={"message": f"Order status updated to {status_data.status}"}) + + except Exception as e: + return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": str(e)}) diff --git a/app/user.py b/app/user.py index b3cef55..b7de66f 100644 --- a/app/user.py +++ b/app/user.py @@ -5,7 +5,7 @@ from fastapi.responses import JSONResponse from starlette import status from firebase_admin import auth -from .firebase_init import db +from .firebase_init import db, firestore from datetime import datetime from .schema import CreateOrderSchema @@ -117,6 +117,7 @@ async def create_payment_order(order_data: CreateOrderSchema, id_token: str): stall_id = order_data.stall_id total_amount = 0 + order_items = [] menu_ref = ( db.collection("colleges") @@ -139,7 +140,16 @@ async def create_payment_order(order_data: CreateOrderSchema, id_token: str): ) price = item_data.get('price', 0) - total_amount += price * cart_item.quantity + quantity = cart_item.quantity + total_amount += price * quantity + + order_items.append({ + "item_id": cart_item.item_id, + "name": item_data.get('name'), + "price": price, + "quantity": quantity + }) + else: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, @@ -149,22 +159,41 @@ async def create_payment_order(order_data: CreateOrderSchema, id_token: str): if total_amount <= 0: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, - content={"message": "Invalid order total (0). Check item availability."} + content={"message": "Invalid order total."} ) + new_order_ref = db.collection('orders').document() + internal_order_id = new_order_ref.id + + firestore_order_data = { + "user_id": user_uid, + "stall_id": stall_id, + "college_id": college_id, + "items": order_items, + "amount": total_amount, + "status": "PENDING", + "created_at": firestore.SERVER_TIMESTAMP, + "updated_at": firestore.SERVER_TIMESTAMP + } + + new_order_ref.set(firestore_order_data) + data = { "amount": int(total_amount * 100), "currency": "INR", - "receipt": f"order_{user_uid[:5]}_{int(datetime.now().timestamp())}", + "receipt": f"rcpt_{internal_order_id[:8]}", "notes": { "stall_id": stall_id, "user_uid": user_uid, - "college_id": college_id + "college_id": college_id, + "internal_order_id": internal_order_id } } order = razorpay_client.order.create(data=data) + new_order_ref.update({"razorpay_order_id": order['id']}) + return JSONResponse( status_code=status.HTTP_200_OK, content={ @@ -172,6 +201,7 @@ async def create_payment_order(order_data: CreateOrderSchema, id_token: str): "amount": order['amount'], "currency": order['currency'], "key_id": os.environ.get("RAZORPAY_KEY_ID"), + "internal_order_id": internal_order_id, "message": "Order created successfully" } ) diff --git a/app/webhook.py b/app/webhook.py index 970c399..457938c 100644 --- a/app/webhook.py +++ b/app/webhook.py @@ -36,32 +36,19 @@ async def razorpay_webhook(request: Request): payment = payload['payload']['payment']['entity'] notes = payment.get('notes', {}) - if isinstance(notes, list): - notes = {} - - stall_id = notes.get('stall_id') - user_id = notes.get('user_uid') - - if not stall_id: - stall_id = "manual_test_stall" - - order_data = { - "order_id": payment['order_id'], - "payment_id": payment['id'], - "amount": payment['amount'] / 100, - "status": "PAID", - "stall_id": stall_id, - "user_id": user_id, - "created_at": firestore.SERVER_TIMESTAMP - } - - try: - db.collection('orders').add(order_data) - except Exception as e: - print(f"Error saving order to Firestore: {e}") - raise HTTPException(status_code=500, detail="Failed to save order") - - else: - print(f"⏭️ Skipping event: {event_type}") + internal_order_id = notes.get('internal_order_id') + payment_id = payment.get('id') + + if internal_order_id: + order_ref = db.collection('orders').document(internal_order_id) + order_ref.update({ + "status": "PAID", + "payment_id": payment_id, + "razorpay_payment_data": payment, + "updated_at": firestore.SERVER_TIMESTAMP + }) + print(f"✅ Order {internal_order_id} marked as PAID") + else: + print(f"⚠️ Payment received without internal_order_id: {payment['id']}") return {"status": "ok"}