from fastapi import APIRouter, Request, Depends, HTTPException from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from fastapi.requests import Request from fastapi.responses import JSONResponse import asyncio router = APIRouter() import asyncio class JWTBearer(HTTPBearer): def __init__(self, auto_error: bool = True): super(JWTBearer, self).__init__(auto_error=auto_error) async def __call__(self, request: Request): credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request) if credentials: if credentials.scheme != "Bearer": raise HTTPException(status_code=401, detail="Invalid authentication scheme.") return credentials.credentials else: raise HTTPException(status_code=401, detail="Invalid authorization code.") import sys,os sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) jwt_bearer = JWTBearer() import decode_token from models.Database_Entity import StopSignal from models.Database_Entity import ChatHistory,PaymentCallbackLog from service.RefundService import * from models.Database_Entity import PaymentCallbackLog from bson import ObjectId from mongoengine import connect from dotenv import load_dotenv load_dotenv() MONGO_URI = os.getenv("MONGO_URI", "") connect("chatbot_hmdrinks", host=MONGO_URI) async def refund_by_type_and_code(type: str, code: str): if type.lower() == "zalopay": log = PaymentCallbackLog.objects(type="zalopay", app_trans_id=code).first() if not log: return {"code": -3, "message": "Không tìm thấy giao dịch ZaloPay"} data = call_zalopay_refund( app_trans_id=code, amount=log.raw_data.get("amount", 0), description="Hoàn tiền ZaloPay" ) return_code = data.get("return_code") if return_code == 3: log.is_refund = True log.save() return {"code": 0 , "message": f"Hoàn tiền thành công", "data": data} else: log.is_refund = False log.save() return {"code": -1 , "message": f"Hoàn tiền thất bại", "data": data} elif type.lower() == "vnpay": log = PaymentCallbackLog.objects(type="vnpay", txn_ref=code).first() if not log: return {"code": -2, "message": "Không tìm thấy giao dịch VNPay"} raw = log.raw_data data = call_vnpay_refund( txn_ref=code, amount=int(raw.get("vnp_Amount", 0)), # VNPAY trả về x100 transaction_date=raw.get("vnp_PayDate"), transaction_no=raw.get("vnp_TransactionNo"), create_by="system_refund", order_info=raw.get("vnp_OrderInfo", "Hoàn tiền VNPay") ) resultCode = data.get("data").get("vnp_ResponseCode") message = data.get("data").get("vnp_Message") if resultCode == "00": log.is_refund = True log.save() return {"code": 0 , "message": f"Hoàn tiền thành công {message}", "data": data} else: log.is_refund = False log.save() return {"code": -1 , "message": f"Hoàn tiền thất bại {message}", "data": data} elif type.lower() == "momo": log = PaymentCallbackLog.objects(type="momo", order_id=code).first() if not log: return {"code": -3, "message": "Không tìm thấy giao dịch MoMo"} if log.raw_data.get("payType", "") != "qr": return {"code": -2 , "message": f"Payment không thể hoàn tiền với ", "data": data} data = call_momo_refund( trans_id=log.raw_data.get("transId", 0), amount=log.raw_data.get("amount", 0), description=f"Hoàn tiền MoMo cho giao dịch {code}" ) resultCode = data.get("resultCode") if resultCode == 0: log.is_refund = True log.save() return {"code": 0 , "message": f"Hoàn tiền thành công", "data": data} else: log.is_refund = False log.save() return {"code": -1 , "message": f"Hoàn tiền thất bại", "data": data} else: return {"code": -4, "message": f"Không hỗ trợ cổng thanh toán '{type}'"} from fastapi import HTTPException from pydantic import BaseModel class Refund(BaseModel): type: str code: str @router.post("/refund") async def refund_endpoint(request: Refund,token: str = Depends(jwt_bearer)): type = request.type code = request.code user_role = decode_token.JwtService.extract_user_role(token) if user_role != "ADMIN": return JSONResponse(content={"message": "Not allow"}, status_code=404) data = asyncio.run(refund_by_type_and_code(type = type,code=code)) if data.get("code") != 0 : return JSONResponse(content={"message": f"Not allow type {type}","status": -1, "data":data}, status_code=404) else: return JSONResponse( content={ "status": 0, "data": data }, status_code=200 ) @router.post("/refund-schedule") async def refund_endpoint_schedule(request: Refund): type = request.type code = request.code data = asyncio.run(refund_by_type_and_code(type = type,code=code)) if data.get("code") != 0 : return JSONResponse(content={"message": f"Not allow type {type}","status": -1, "data":data}, status_code=404) else: return JSONResponse( content={ "status": 0, "data": data }, status_code=200 )