import uvicorn from fastapi import FastAPI, Depends, HTTPException from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from sqlalchemy.orm import Session from typing import List from datetime import datetime import models, database import dashboard import logging from read_weight import read_cart_weight CART_ITEMS = [] EXPECTED_WEIGHT = 0.0 app = FastAPI() models.Base.metadata.create_all(bind=database.engine) # 대시보드 라우터 등록 app.include_router(dashboard.router) app.mount("/static", StaticFiles(directory="static"), name="static") def get_db(): db = database.SessionLocal() try: yield db finally: db.close() # 무게 검증 로직 def is_movable(expected, real): if expected <= 0: return True diff_ratio = abs(real - expected) / expected return diff_ratio <= 0.2 # 페이지 라우팅 @app.get("/dashboard") async def dashboard_view(): return FileResponse("templates/dashboard.html") @app.get("/inventory") async def inventory_view(): return FileResponse("templates/inventory.html") # 카트 무게 기준값 설정 @app.post("/cart/tare") def tare_cart(): global EXPECTED_WEIGHT EXPECTED_WEIGHT = read_cart_weight() return {"expected_weight": EXPECTED_WEIGHT} @app.get("/items", response_model=List[models.ItemSchema]) def read_all_items(db: Session = Depends(get_db)): return db.query(models.Item).all() # 상품 추가 @app.post("/cart/add/{item_id}") def add_item(item_id: int, db: Session = Depends(get_db)): global EXPECTED_WEIGHT, CART_ITEMS item = db.query(models.Item).filter(models.Item.id == item_id).first() if not item: raise HTTPException(404, "Item not found") CART_ITEMS.append({ "id": item.id, "name": item.name, "price": item.price, "weight": item.weight }) EXPECTED_WEIGHT += item.weight real = read_cart_weight() movable = is_movable(EXPECTED_WEIGHT, real) return { "action": "add", "id": item.id, "item": item.name, "price": item.price, "expected_weight": EXPECTED_WEIGHT, "real_weight": real, "diff": abs(real - EXPECTED_WEIGHT), "movable": movable } # 상품 제거 @app.post("/cart/remove/{item_id}") def remove_item(item_id: int): global EXPECTED_WEIGHT, CART_ITEMS for i, item in enumerate(CART_ITEMS): if item["id"] == item_id: removed = CART_ITEMS.pop(i) EXPECTED_WEIGHT -= removed["weight"] break else: raise HTTPException(404, "Item not in cart") EXPECTED_WEIGHT = max(EXPECTED_WEIGHT, 0) real = read_cart_weight() movable = is_movable(EXPECTED_WEIGHT, real) return { "action": "remove", "id": removed["id"], "item": removed["name"], "price": removed["price"], "expected_weight": EXPECTED_WEIGHT, "real_weight": real, "movable": movable } # 장바구니 조회 @app.get("/cart") def get_cart(): total_price = sum(item["price"] for item in CART_ITEMS) return { "items": CART_ITEMS, "total_count": len(CART_ITEMS), "total_price": total_price, "expected_weight": EXPECTED_WEIGHT } # 무게 체크 @app.get("/cart/check_weight") def check_cart(): real = read_cart_weight() movable = is_movable(EXPECTED_WEIGHT, real) return { "expected_weight": EXPECTED_WEIGHT, "real_weight": real, "diff": abs(real - EXPECTED_WEIGHT), "movable": movable } # 대시보드 상태 조회 @app.get("/cart/status") def get_cart_status_for_dashboard(): global EXPECTED_WEIGHT, CART_ITEMS real = read_cart_weight() movable = is_movable(EXPECTED_WEIGHT, real) system_status = "NORMAL" if movable else "WARNING_WEIGHT_MISMATCH" return { "real_weight": real, "expected_weight": EXPECTED_WEIGHT, "cart_items": CART_ITEMS, "total_price": sum(item["price"] for item in CART_ITEMS), "total_count": len(CART_ITEMS), "system_status": system_status, "movable": movable } # 결제 @app.post("/cart/pay") def pay_cart(db: Session = Depends(get_db)): global CART_ITEMS, EXPECTED_WEIGHT if not CART_ITEMS: raise HTTPException(status_code=400, detail="장바구니가 비어있습니다.") total_price = sum(item["price"] for item in CART_ITEMS) new_pay = models.Pay( total_price=total_price, created_at=datetime.now() ) db.add(new_pay) db.commit() reset_cart() return {"msg": "결제 완료", "amount": total_price} # 결제 내역 조회 @app.get("/payments", response_model=List[models.PaySchema]) def get_payment_history(db: Session = Depends(get_db)): return db.query(models.Pay).order_by(models.Pay.created_at.desc()).all() # 카트 초기화 @app.post("/cart/reset") def reset_cart(): global EXPECTED_WEIGHT, CART_ITEMS EXPECTED_WEIGHT = 0.0 CART_ITEMS.clear() return {"ok": True} # 로그 필터 class EndpointFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: msg = record.getMessage() return all(x not in msg for x in ["/bot/check", "/bot/report", "/cart/status"]) logging.getLogger("uvicorn.access").addFilter(EndpointFilter()) if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)