kltn21110 commited on
Commit
a65f83d
·
verified ·
1 Parent(s): 5b2fc60

Upload 15 files

Browse files
controller/CallbackController.py ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Request,HTTPException
2
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
3
+ from fastapi.requests import Request
4
+ import yaml
5
+ from typing import Dict
6
+ from fastapi.responses import RedirectResponse
7
+ from service import CallBackService
8
+ import json
9
+ from fastapi.responses import JSONResponse
10
+ from models.Database_Entity import PaymentCallbackLog
11
+ with open("config.yaml", "r") as f:
12
+ config = yaml.safe_load(f)
13
+ base_backend_java = config["callback_urls"]
14
+ base_frontend = config["frontend"]
15
+
16
+ router = APIRouter()
17
+
18
+ class JWTBearer(HTTPBearer):
19
+ def __init__(self, auto_error: bool = True):
20
+ super(JWTBearer, self).__init__(auto_error=auto_error)
21
+
22
+ async def __call__(self, request: Request):
23
+ credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
24
+ if credentials:
25
+ if credentials.scheme != "Bearer":
26
+ raise HTTPException(status_code=401, detail="Invalid authentication scheme.")
27
+ return credentials.credentials
28
+ else:
29
+ raise HTTPException(status_code=401, detail="Invalid authorization code.")
30
+
31
+ jwt_bearer = JWTBearer()
32
+
33
+
34
+
35
+ @router.post("/android/zalo")
36
+ async def zalo_callback_post(request: Request):
37
+ try:
38
+ json_data = await request.json()
39
+ data_str =json_data.get("data")
40
+
41
+ if data_str:
42
+ data_dict = json.loads(data_str)
43
+ app_trans_id = data_dict.get("app_trans_id")
44
+ PaymentCallbackLog(
45
+ type="zalopay",
46
+ app_trans_id=data_dict.get("app_trans_id"),
47
+ raw_data=data_dict,
48
+ status="success" if data_dict.get("status") == "1" else "fail",
49
+ is_refund = False
50
+ ).save()
51
+
52
+ print(app_trans_id)
53
+ data = await CallBackService.zalo_callback(str(app_trans_id))
54
+ return data
55
+ except Exception as e:
56
+ print("Lỗi khi gọi callback web zalo:", e)
57
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
58
+
59
+
60
+ @router.post("/android/group/zalo")
61
+ async def zalo_callback_post(request: Request):
62
+ try:
63
+ json_data = await request.json()
64
+ data_str =json_data.get("data")
65
+ if data_str:
66
+ data_dict = json.loads(data_str)
67
+ app_trans_id = data_dict.get("app_trans_id")
68
+ PaymentCallbackLog(
69
+ type="zalopay",
70
+ app_trans_id=data_dict.get("app_trans_id"),
71
+ raw_data=data_dict,
72
+ status="success" if data_dict.get("status") == "1" else "fail",
73
+ is_refund = False
74
+ ).save()
75
+ print(app_trans_id)
76
+ data = await CallBackService.zalo_group_callback(str(app_trans_id))
77
+ return data
78
+ except Exception as e:
79
+ print("Lỗi khi gọi callback group ảndroid zalo:", e)
80
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
81
+
82
+
83
+ @router.get("/android/payOs")
84
+ async def return_url_handler(code: str = None, id: str = None, cancel: bool = None, status: str = None, orderCode: str = None):
85
+ try:
86
+ return await CallBackService.android_payos_callback(status,orderCode)
87
+ except Exception as e:
88
+ print("Lỗi khi gọi callback android payos:", e)
89
+ # Trả về lỗi 500 - Internal Server Error
90
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
91
+
92
+
93
+ @router.get("/android/group/payOs")
94
+ async def return_url_handler1(code: str = None, id: str = None, cancel: bool = None, status: str = None, orderCode: str = None):
95
+ try:
96
+ return await CallBackService.android_group_payOs_callback(status,orderCode)
97
+ except Exception as e:
98
+ print("Lỗi khi gọi callback group payos:", e)
99
+ # Trả về lỗi 500 - Internal Server Error
100
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
101
+
102
+
103
+ @router.get("/web/payOs")
104
+ async def return_url_handler(code: str = None, id: str = None, cancel: bool = None, status: str = None, orderCode: str = None):
105
+ try:
106
+ return await CallBackService.web_payos_callback(code, id, cancel, status, orderCode)
107
+ except Exception as e:
108
+ print("Lỗi khi gọi callback web payos:", e)
109
+ # Trả về lỗi 500 - Internal Server Error
110
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
111
+
112
+
113
+ @router.post("/android/momo")
114
+ async def return_url_handler(request: Request):
115
+ json_data = await request.json()
116
+ print(json_data)
117
+
118
+ data_str =json_data.get("data")
119
+ order_id = json_data.get("orderId")
120
+ result_code = json_data.get("resultCode")
121
+ PaymentCallbackLog(
122
+ type="momo",
123
+ order_id=order_id,
124
+ raw_data=json_data,
125
+ status="success" if result_code == 0 else "fail",
126
+ is_refund = False
127
+ ).save()
128
+ print(data_str)
129
+
130
+ try:
131
+ result = await CallBackService.momo_callback(order_id,result_code)
132
+ print(result)
133
+ except Exception as e:
134
+ print("Lỗi khi gọi call back android momo:", e)
135
+
136
+ if 0 != int(result_code):
137
+ return RedirectResponse(url=f"{base_frontend['android_redirect_base']}?status=-49")
138
+ else :
139
+ return RedirectResponse(url=f"{base_frontend['android_redirect_base']}?status=1")
140
+
141
+
142
+ @router.post("/android/group/momo")
143
+ async def return_url_handler(request: Request):
144
+ json_data = await request.json()
145
+ print(json_data)
146
+
147
+ data_str =json_data.get("data")
148
+ order_id = json_data.get("orderId")
149
+ result_code = json_data.get("resultCode")
150
+ print(data_str)
151
+ PaymentCallbackLog(
152
+ type="momo",
153
+ order_id=order_id,
154
+ raw_data=json_data,
155
+ status="success" if result_code == 0 else "fail",
156
+ is_refund = False
157
+ ).save()
158
+
159
+ try:
160
+ result = await CallBackService.momo_group_callback(order_id,result_code)
161
+ print(result)
162
+ except Exception as e:
163
+ print("Lỗi khi gọi callback android group momo:", e)
164
+ if 0 != int(result_code):
165
+ return RedirectResponse(url=f"""{base_frontend["android_group_redirect_base"]}?status=-49""")
166
+ else :
167
+ return RedirectResponse(url=f"""{base_frontend["android_group_redirect_base"]}?status=1""")
168
+
169
+
170
+ @router.get("/android/vnpay_ipn")
171
+ async def vnpay_ipn(request: Request):
172
+ params: Dict[str, str] = dict(request.query_params)
173
+ # Lưu callback vnpay
174
+ PaymentCallbackLog(
175
+ type="vnpay",
176
+ txn_ref=params.get("vnp_TxnRef"),
177
+ raw_data=params,
178
+ status="success" if params.get("vnp_ResponseCode") == "00" else "fail",
179
+ is_refund = False
180
+ ).save()
181
+
182
+ try:
183
+ return await CallBackService.vnpay_callbackk(params)
184
+ except Exception as e:
185
+ print("Lỗi khi gọi callback vnpay:", e)
186
+ # Trả về lỗi 500 - Internal Server Error
187
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
188
+
189
+
190
+ @router.get("/android/group/vnpay_ipn")
191
+ async def vnpay_ipn(request: Request):
192
+ params: Dict[str, str] = dict(request.query_params)
193
+ # Lưu callback vnpay
194
+ PaymentCallbackLog(
195
+ type="vnpay",
196
+ txn_ref=params.get("vnp_TxnRef"),
197
+ raw_data=params,
198
+ status="success" if params.get("vnp_ResponseCode") == "00" else "fail",
199
+ is_refund = False
200
+ ).save()
201
+
202
+ try:
203
+ return await CallBackService.vnpay_group_callback(params)
204
+ except Exception as e:
205
+ print("Lỗi khi gọi callback group vnpay ipn:", e)
206
+ # Trả về lỗi 500 - Internal Server Error
207
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
controller/ChatController.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Form, Request,Depends,HTTPException,BackgroundTasks
2
+ from service import ChatService
3
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
4
+ from request import RequestChat
5
+ from fastapi.requests import Request
6
+ from fastapi.responses import JSONResponse
7
+ import asyncio
8
+ router = APIRouter()
9
+ import asyncio
10
+ # Lưu task đang chạy theo chat_history_id
11
+ task_registry: dict[str, asyncio.Task] = {}
12
+ # Lưu stop_event để dừng từng task
13
+ stop_events: dict[str, asyncio.Event] = {}
14
+ import decode_token
15
+ from models.Database_Entity import StopSignal
16
+ from models.Database_Entity import ChatHistory, User
17
+ from repository.MySQL import UserRepository
18
+ class JWTBearer(HTTPBearer):
19
+ def __init__(self, auto_error: bool = True):
20
+ super(JWTBearer, self).__init__(auto_error=auto_error)
21
+
22
+ async def __call__(self, request: Request):
23
+ credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
24
+ if credentials:
25
+ if credentials.scheme != "Bearer":
26
+ raise HTTPException(status_code=401, detail="Invalid authentication scheme.")
27
+ return credentials.credentials
28
+ else:
29
+ raise HTTPException(status_code=401, detail="Invalid authorization code.")
30
+
31
+ jwt_bearer = JWTBearer()
32
+
33
+
34
+ @router.get("/chat/user_history")
35
+ async def get_user_chat_history(token: str = Depends(jwt_bearer)):
36
+ try:
37
+ user_id_token = decode_token.JwtService.extract_user_id(token)
38
+ return await ChatService.get_user_chat_history(user_id_token)
39
+ except Exception as e:
40
+ print("Lỗi khi gọi user history chat:", e)
41
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
42
+
43
+
44
+ @router.post("/new_chat/create/")
45
+ async def create_chat(token: str = Depends(jwt_bearer)):
46
+ try:
47
+ user_id_token = decode_token.JwtService.extract_user_id(token)
48
+ new_chat = await ChatService.create_new_chat_history(user_id_token)
49
+ return new_chat
50
+ except Exception as e:
51
+ print("Lỗi khi gọi create new chat:", e)
52
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
53
+
54
+
55
+ from bson import ObjectId
56
+ @router.post("/question")
57
+ async def question(
58
+ request: RequestChat.ChatWithServer,
59
+ background_tasks: BackgroundTasks,
60
+ token: str = Depends(jwt_bearer)
61
+ ):
62
+ try:
63
+ user_id_token = decode_token.JwtService.extract_user_id(token)
64
+ user_role = decode_token.JwtService.extract_user_role(token)
65
+ chat_id = request.chat_history_id
66
+
67
+ stop_event = asyncio.Event()
68
+ stop_events[chat_id] = stop_event
69
+ print(f"[CREATE] stop_event id: {id(stop_event)} for chat_id: {chat_id}")
70
+ chat_history = ChatHistory.objects(pk=ObjectId(chat_id)).first()
71
+
72
+ if chat_history:
73
+ signal = StopSignal.objects(chat_history=chat_history).first()
74
+ if not signal:
75
+ signal = StopSignal(chat_history=chat_history)
76
+ signal.is_stopped = False
77
+ signal.stopped_at = None
78
+ signal.save()
79
+
80
+ async def run_chat():
81
+ try:
82
+ result = await ChatService.chat_with_user(
83
+ request.user_input,
84
+ user_id_token,
85
+ request.language,
86
+ user_role,
87
+ token,
88
+ chat_id,
89
+ stop_event
90
+ )
91
+ return result
92
+ except asyncio.CancelledError:
93
+ print(f"🛑 Task {chat_id} was cancelled by asyncio.")
94
+ return {"status": "cancelled"}
95
+ except Exception as e:
96
+ print(f"❌ Lỗi trong task {chat_id}:", e)
97
+ return {"error": str(e)}
98
+ finally:
99
+ # Dọn dẹp
100
+ stop_events.pop(chat_id, None)
101
+ task_registry.pop(chat_id, None)
102
+
103
+ task = asyncio.create_task(run_chat())
104
+ task_registry[chat_id] = task
105
+ return await task
106
+
107
+ except Exception as e:
108
+ print("Lỗi khi chạy:", e)
109
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
110
+
111
+
112
+ from datetime import datetime
113
+ @router.post("/stop-task/{chat_history_id}")
114
+ async def stop_task(chat_history_id: str, token: str = Depends(jwt_bearer)):
115
+ user_id = int(decode_token.JwtService.extract_user_id(token))
116
+ if not isinstance(user_id, int) or user_id <= 0:
117
+ raise HTTPException(status_code=400, detail="Invalid user_id: must be a positive integer")
118
+ check = UserRepository.getUserByUserId(user_id)
119
+ if check is None:
120
+ raise HTTPException(status_code=400, detail="User not found or has been deleted in MySQL")
121
+
122
+ check_history_id = UserRepository.getChatHistory(user_id,chat_history_id)
123
+ if check_history_id is None:
124
+ raise HTTPException(status_code=400, detail="Chat not found or has been deleted in MySQL")
125
+
126
+ user = User.objects(user_id=user_id).first()
127
+ if not user:
128
+ return {"error": "User not found or has been deleted in MongoDB"}
129
+
130
+ event = stop_events.get(chat_history_id)
131
+ task = task_registry.get(chat_history_id)
132
+
133
+ print(f"🚨 Đã vào stop-task với chat_history_id = {chat_history_id}")
134
+ print(f"🔎 stop_event: {event}, task: {task}")
135
+
136
+ # Set event trong RAM
137
+ if event:
138
+ print(f"🛑 Setting stop_event for {chat_history_id}")
139
+ event.set()
140
+
141
+ # Cancel task
142
+ if task:
143
+ print(f"🔪 Cancelling task for {chat_history_id}")
144
+ task.cancel()
145
+
146
+ # Cập nhật trạng thái stop vào MongoDB
147
+ from bson import ObjectId
148
+
149
+ chat_history = ChatHistory.objects(pk=ObjectId(chat_history_id)).first()
150
+
151
+ if chat_history:
152
+ signal = StopSignal.objects(chat_history=chat_history).first()
153
+ if not signal:
154
+ signal = StopSignal(chat_history=chat_history)
155
+ signal.is_stopped = True
156
+ signal.stopped_at = datetime.utcnow()
157
+ signal.save()
158
+ return {"message": f"Stop signal sent for chat_history_id {chat_history_id}"}
159
+
160
+
161
+ @router.put("/regenerate")
162
+ async def regenerate(request: RequestChat.Regenerate, token: str = Depends(jwt_bearer)):
163
+ try:
164
+ user_id_token = decode_token.JwtService.extract_user_id(token)
165
+ user_role = decode_token.JwtService.extract_user_role(token)
166
+ new_chat = await ChatService.regenerate(request.question_new ,user_id_token,request.languages ,user_role,token,request.chat_id)
167
+ return new_chat
168
+ except Exception as e:
169
+ print("Lỗi khi gọi regenerate:", e)
170
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
171
+
172
+
173
+ @router.put("/update")
174
+ async def update_chat_name(request: RequestChat.UpdateNameChat, token: str = Depends(jwt_bearer)):
175
+ try:
176
+ user_id_token = decode_token.JwtService.extract_user_id(token)
177
+ updated_chat = await ChatService.update_chat_name(request.chat_id, request.name_chat,user_id_token)
178
+ return updated_chat
179
+ except Exception as e:
180
+ print("Lỗi khi gọi update:", e)
181
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
182
+
183
+
184
+ @router.delete("/delete")
185
+ async def delete_chat(request: RequestChat.DeleteChatRequest, token: str = Depends(jwt_bearer)):
186
+ try:
187
+ user_id_token = decode_token.JwtService.extract_user_id(token)
188
+ deleted_chat = await ChatService.soft_delete_chat(request.chat_id,user_id_token)
189
+ return deleted_chat
190
+ except Exception as e:
191
+ print("Lỗi khi gọi deleted:", e)
192
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
193
+
194
+
195
+ @router.get("/list_detail_chat/{chat_id}")
196
+ async def get_chat_details(chat_id: str, token: str = Depends(jwt_bearer)):
197
+ try:
198
+ user_id_token = decode_token.JwtService.extract_user_id(token)
199
+ return await ChatService.get_chat_details(chat_id,user_id_token)
200
+ except Exception as e:
201
+ print("Lỗi khi gọi list_detail_chat:", e)
202
+ return JSONResponse(content={"error": "Internal server error"}, status_code=500)
controller/GroupOrderController.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Form, Request,Depends,HTTPException
2
+ from service import ChatService
3
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
4
+ from request import RequestChat
5
+ from typing import Optional
6
+ from fastapi.requests import Request
7
+ from fastapi.responses import JSONResponse
8
+
9
+ router = APIRouter()
10
+
11
+ class JWTBearer(HTTPBearer):
12
+ def __init__(self, auto_error: bool = True):
13
+ super(JWTBearer, self).__init__(auto_error=auto_error)
14
+
15
+ async def __call__(self, request: Request):
16
+ credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
17
+ if credentials:
18
+ if credentials.scheme != "Bearer":
19
+ raise HTTPException(status_code=401, detail="Invalid authentication scheme.")
20
+ return credentials.credentials
21
+ else:
22
+ raise HTTPException(status_code=401, detail="Invalid authorization code.")
23
+
24
+ jwt_bearer = JWTBearer()
25
+ import decode_token
controller/RecommendController.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Form, Request,Depends,HTTPException
2
+ from service import ChatService
3
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
4
+ from request import RequestChat
5
+ from typing import Optional
6
+ from fastapi.requests import Request
7
+
8
+
9
+ router = APIRouter()
10
+
11
+ class JWTBearer(HTTPBearer):
12
+ def __init__(self, auto_error: bool = True):
13
+ super(JWTBearer, self).__init__(auto_error=auto_error)
14
+
15
+ async def __call__(self, request: Request):
16
+ credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
17
+ if credentials:
18
+ if credentials.scheme != "Bearer":
19
+ raise HTTPException(status_code=401, detail="Invalid authentication scheme.")
20
+ return credentials.credentials
21
+ else:
22
+ raise HTTPException(status_code=401, detail="Invalid authorization code.")
23
+
24
+ jwt_bearer = JWTBearer()
25
+ import decode_token
controller/RedirectController.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Form, Request,Depends,HTTPException
2
+ from service import ChatService
3
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
4
+ from request import RequestChat
5
+ from typing import Optional
6
+ from fastapi.requests import Request
7
+
8
+
9
+ router = APIRouter()
10
+
11
+ class JWTBearer(HTTPBearer):
12
+ def __init__(self, auto_error: bool = True):
13
+ super(JWTBearer, self).__init__(auto_error=auto_error)
14
+
15
+ async def __call__(self, request: Request):
16
+ credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
17
+ if credentials:
18
+ if credentials.scheme != "Bearer":
19
+ raise HTTPException(status_code=401, detail="Invalid authentication scheme.")
20
+ return credentials.credentials
21
+ else:
22
+ raise HTTPException(status_code=401, detail="Invalid authorization code.")
23
+
24
+ jwt_bearer = JWTBearer()
25
+ import decode_token
26
+ from service import RedirectService
27
+ from typing import Optional
28
+ from fastapi import Request, Query
29
+ from fastapi.responses import JSONResponse
30
+ @router.get("/android/zalo")
31
+ async def zalo_callback_get(
32
+ amount: Optional[int] = Query(None),
33
+ appid: Optional[str] = Query(None),
34
+ apptransid: Optional[str] = Query(None),
35
+ bankcode: Optional[str] = Query(None),
36
+ checksum: Optional[str] = Query(None),
37
+ discountamount: Optional[int] = Query(None),
38
+ pmcid: Optional[int] = Query(None),
39
+ status: Optional[int] = Query(None)
40
+ ):
41
+ return await RedirectService.zalo_redirect(status)
42
+
43
+
44
+ @router.get("/android/group/zalo")
45
+ async def zalo_callback_get(
46
+ amount: Optional[int] = Query(None),
47
+ appid: Optional[str] = Query(None),
48
+ apptransid: Optional[str] = Query(None),
49
+ bankcode: Optional[str] = Query(None),
50
+ checksum: Optional[str] = Query(None),
51
+ discountamount: Optional[int] = Query(None),
52
+ pmcid: Optional[int] = Query(None),
53
+ status: Optional[int] = Query(None)
54
+ ):
55
+ return await RedirectService.zalo_group_redirect(status)
56
+
57
+ @router.get("/web/zalo")
58
+ async def zalo_web_callback_get(request: Request):
59
+ return await RedirectService.zalo_web_redirect(request.query_params)
60
+
61
+
62
+ @router.get("/android/momo")
63
+ async def return_url_handler_1(request: Request):
64
+ query_params = request.query_params
65
+ return await RedirectService.android_momo_redirect(query_params)
66
+
67
+ @router.get("/android/group/momo")
68
+ async def return_url_handler_group_momo(request: Request):
69
+ query_params = request.query_params
70
+ return await RedirectService.android_group_momo_redirect(query_params)
71
+
72
+
73
+ from urllib.parse import urlencode
74
+ @router.get("/web/momo")
75
+ async def return_url_handler_web(request: Request):
76
+ query_params = request.query_params
77
+ return await RedirectService.web_momo_redirect(query_params)
78
+
79
+
80
+ from typing import Dict
81
+ @router.get("/android/vnpay")
82
+ async def vnpay_ipn_redirect(request: Request):
83
+ params: Dict[str, str] = dict(request.query_params)
84
+ return await RedirectService.android_vnpay_ipn_redirect(params)
85
+
86
+
87
+ @router.get("/android/group/vnpay")
88
+ async def vnpay_ipn_redirect(request: Request):
89
+ params: Dict[str, str] = dict(request.query_params)
90
+ return await RedirectService.android_vnpay_group_ipn_redirect(params)
91
+
92
+ @router.get("/web/vnpay")
93
+ async def vnpay_ipn_redirect(request: Request):
94
+ query_params = request.query_params
95
+ return await RedirectService.web_vnpay_ipn_redirect(query_params)
controller/RefundController.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Request, Depends, HTTPException
2
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
3
+ from fastapi.requests import Request
4
+ from fastapi.responses import JSONResponse
5
+ import asyncio
6
+ router = APIRouter()
7
+ import asyncio
8
+ class JWTBearer(HTTPBearer):
9
+ def __init__(self, auto_error: bool = True):
10
+ super(JWTBearer, self).__init__(auto_error=auto_error)
11
+
12
+ async def __call__(self, request: Request):
13
+ credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
14
+ if credentials:
15
+ if credentials.scheme != "Bearer":
16
+ raise HTTPException(status_code=401, detail="Invalid authentication scheme.")
17
+ return credentials.credentials
18
+ else:
19
+ raise HTTPException(status_code=401, detail="Invalid authorization code.")
20
+ import sys,os
21
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
22
+ jwt_bearer = JWTBearer()
23
+ import decode_token
24
+
25
+ from models.Database_Entity import StopSignal
26
+ from models.Database_Entity import ChatHistory,PaymentCallbackLog
27
+ from service.RefundService import *
28
+ from models.Database_Entity import PaymentCallbackLog
29
+ from bson import ObjectId
30
+ from mongoengine import connect
31
+ MONGO_URI = "mongodb+srv://kltn20133118:XEYSVzYvEwsp5Cvo@cluster0.nnsw9.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
32
+ connect("chatbot_hmdrinks", host=MONGO_URI)
33
+
34
+
35
+ async def refund_by_type_and_code(type: str, code: str):
36
+ if type.lower() == "zalopay":
37
+ log = PaymentCallbackLog.objects(type="zalopay", app_trans_id=code,is_refund = False).first()
38
+ if not log:
39
+ return {"code": -3, "message": "Không tìm thấy giao dịch ZaloPay"}
40
+ data = call_zalopay_refund(
41
+ app_trans_id=code,
42
+ amount=log.raw_data.get("amount", 0),
43
+ description="Hoàn tiền ZaloPay"
44
+ )
45
+ return_code = data.get("return_code")
46
+ if return_code == 3:
47
+ log.is_refund = True
48
+ log.save()
49
+ return {"code": 0 , "message": f"Hoàn tiền thành công", "data": data}
50
+ else:
51
+ log.is_refund = False
52
+ log.save()
53
+ return {"code": -1 , "message": f"Hoàn tiền thất bại", "data": data}
54
+
55
+
56
+ elif type.lower() == "vnpay":
57
+ log = PaymentCallbackLog.objects(type="vnpay", txn_ref=code, is_refund = False).first()
58
+ if not log:
59
+ return {"code": -2, "message": "Không tìm thấy giao dịch VNPay"}
60
+ raw = log.raw_data
61
+ data = call_vnpay_refund(
62
+ txn_ref=code,
63
+ amount=int(raw.get("vnp_Amount", 0)), # VNPAY trả về x100
64
+ transaction_date=raw.get("vnp_PayDate"),
65
+ transaction_no=raw.get("vnp_TransactionNo"),
66
+ create_by="system_refund",
67
+ order_info=raw.get("vnp_OrderInfo", "Hoàn tiền VNPay")
68
+ )
69
+
70
+ resultCode = data.get("data").get("vnp_ResponseCode")
71
+ message = data.get("data").get("vnp_Message")
72
+ if resultCode == "00":
73
+ log.is_refund = True
74
+ log.save()
75
+ return {"code": 0 , "message": f"Hoàn tiền thành công {message}", "data": data}
76
+ else:
77
+ log.is_refund = False
78
+ log.save()
79
+ return {"code": -1 , "message": f"Hoàn tiền thất bại {message}", "data": data}
80
+
81
+ elif type.lower() == "momo":
82
+ log = PaymentCallbackLog.objects(type="momo", order_id=code,is_refund = False).first()
83
+ if not log:
84
+ return {"code": -3, "message": "Không tìm thấy giao dịch MoMo"}
85
+ if log.raw_data.get("payType", "") != "qr":
86
+ return {"code": -2 , "message": f"Payment không thể hoàn tiền với ", "data": data}
87
+ data = call_momo_refund(
88
+ trans_id=log.raw_data.get("transId", 0),
89
+ amount=log.raw_data.get("amount", 0),
90
+ description=f"Hoàn tiền MoMo cho giao dịch {code}"
91
+ )
92
+ resultCode = data.get("resultCode")
93
+ if resultCode == 0:
94
+ log.is_refund = True
95
+ log.save()
96
+ return {"code": 0 , "message": f"Hoàn tiền thành công", "data": data}
97
+ else:
98
+ log.is_refund = False
99
+ log.save()
100
+ return {"code": -1 , "message": f"Hoàn tiền thất bại", "data": data}
101
+ else:
102
+ return {"code": -4, "message": f"Không hỗ trợ cổng thanh toán '{type}'"}
103
+
104
+ from fastapi import HTTPException
105
+ from pydantic import BaseModel
106
+
107
+
108
+ class Refund(BaseModel):
109
+ type: str
110
+ code: str
111
+
112
+
113
+ @router.post("/refund")
114
+ async def refund_endpoint(request: Refund,token: str = Depends(jwt_bearer)):
115
+ type = request.type
116
+ code = request.code
117
+ user_role = decode_token.JwtService.extract_user_role(token)
118
+ if user_role != "ADMIN":
119
+ return JSONResponse(content={"message": "Not allow"}, status_code=404)
120
+
121
+ data = asyncio.run(refund_by_type_and_code(type = type,code=code))
122
+ if data.get("code") != 0 :
123
+ return JSONResponse(content={"message": f"Not allow type {type}","status": -1, "data":data}, status_code=404)
124
+ else:
125
+ return JSONResponse(
126
+ content={
127
+ "status": 0,
128
+ "data": data
129
+ },
130
+ status_code=200
131
+ )
132
+
controller/__init__.py ADDED
File without changes
controller/__pycache__/CallbackController.cpython-311.pyc ADDED
Binary file (12.9 kB). View file
 
controller/__pycache__/ChatController.cpython-311.pyc ADDED
Binary file (14.4 kB). View file
 
controller/__pycache__/GroupOrderController.cpython-311.pyc ADDED
Binary file (2.15 kB). View file
 
controller/__pycache__/RecommendController.cpython-311.pyc ADDED
Binary file (2.08 kB). View file
 
controller/__pycache__/RedirectController.cpython-311.pyc ADDED
Binary file (7 kB). View file
 
controller/__pycache__/RefundController.cpython-311.pyc ADDED
Binary file (8.21 kB). View file
 
controller/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (167 Bytes). View file
 
controller/__pycache__/task_manager.cpython-311.pyc ADDED
Binary file (414 Bytes). View file