from pydantic import BaseModel import uuid, hmac, hashlib, requests # --- Thông tin định danh --- PARTNER_CODE = "MOMO" ACCESS_KEY = "F8BBA842ECF85" SECRET_KEY = "K951B6PE1waDMi640xX08PD3vg6EkVlz" # --- Model yêu cầu hoàn tiền --- class RefundRequest(BaseModel): partnerCode: str orderId: str requestId: str amount: int transId: int description: str lang: str = "vi" # --- Tạo chữ ký --- def generate_refund_signature(data: dict) -> str: raw_data = ( f"accessKey={ACCESS_KEY}&amount={data['amount']}&description={data['description']}" f"&orderId={data['orderId']}&partnerCode={PARTNER_CODE}" f"&requestId={data['requestId']}&transId={data['transId']}" ) return hmac.new(SECRET_KEY.encode(), raw_data.encode(), hashlib.sha256).hexdigest() def call_momo_refund(amount: int, trans_id: int, description: str = "Hoàn tiền giao dịch"): order_id = str(uuid.uuid4()) request_id = str(uuid.uuid4()) refund = RefundRequest( partnerCode=PARTNER_CODE, orderId=order_id, requestId=request_id, amount=amount, transId=trans_id, description=description, ) payload = refund.dict() payload["signature"] = generate_refund_signature(payload) response = requests.post( "https://test-payment.momo.vn/v2/gateway/api/refund", json=payload, headers={"Content-Type": "application/json"}, timeout=90, ) return response.json() # result = call_momo_refund(amount=100000, trans_id=4506777858) # print(result) import hmac import hashlib import requests from datetime import datetime import uuid # ====== CẤU HÌNH MẶC ĐỊNH ====== VNP_URL = "https://sandbox.vnpayment.vn/merchant_webapi/api/transaction" VNP_TMN_CODE = 'MCQ3SXQ1' VNP_SECRET_KEY = '2QS3MSRVQQAFN36I5GA02DWB353KO4FD' IP_ADDR = "127.0.0.1" # ====== HÀM TẠO CHECKSUM HMAC SHA512 ====== def hmac_sha512(key: str, data: str) -> str: return hmac.new(key.encode(), data.encode(), hashlib.sha512).hexdigest() # ====== HÀM HOÀN TIỀN VNPAY ====== def call_vnpay_refund( txn_ref: str, amount: int, transaction_date: str, create_by: str, order_info: str, transaction_no: str = "", # optional transaction_type: str = "02", # "02": full refund, "03": partial vnp_url: str = VNP_URL, vnp_tmn_code: str = VNP_TMN_CODE, vnp_secret_key: str = VNP_SECRET_KEY, ip_addr: str = IP_ADDR, ): # Lấy thời gian hiện tại (vnp_CreateDate) now = datetime.now().strftime("%Y%m%d%H%M%S") # Tạo request body params = { "vnp_RequestId": str(uuid.uuid4().hex[:32]), "vnp_Version": "2.1.0", "vnp_Command": "refund", "vnp_TmnCode": vnp_tmn_code, "vnp_TransactionType": transaction_type, "vnp_TxnRef": txn_ref, "vnp_Amount": str(amount), # nhân 100 nếu VNP yêu cầu "vnp_TransactionNo": transaction_no, "vnp_TransactionDate": transaction_date, "vnp_CreateBy": create_by, "vnp_CreateDate": now, "vnp_IpAddr": ip_addr, "vnp_OrderInfo": order_info } sign_data = "|".join([ params["vnp_RequestId"], params["vnp_Version"], params["vnp_Command"], params["vnp_TmnCode"], params["vnp_TransactionType"], params["vnp_TxnRef"], params["vnp_Amount"], params["vnp_TransactionNo"], params["vnp_TransactionDate"], params["vnp_CreateBy"], params["vnp_CreateDate"], params["vnp_IpAddr"], params["vnp_OrderInfo"] ]) params["vnp_SecureHash"] = hmac_sha512(vnp_secret_key, sign_data) response = requests.post(vnp_url, json=params, headers={"Content-Type": "application/json"}) return { "status_code": response.status_code, "data": response.json() } import hmac import hashlib import requests import time from datetime import datetime import random import string # Cấu hình tài khoản ZaloPay APP_ID = "2553" KEY1 = "PcY4iZIKFCIdgZvA6ueMcMHHUbRLYjPL" QUERY_ENDPOINT = "https://sb-openapi.zalopay.vn/v2/query" REFUND_ENDPOINT = "https://sb-openapi.zalopay.vn/v2/refund" def generate_mac(data: str, key: str) -> str: return hmac.new(key.encode(), data.encode(), hashlib.sha256).hexdigest() def generate_m_refund_id(): date_part = datetime.now().strftime("%y%m%d") random_part = ''.join(random.choices(string.digits, k=10)) return f"{date_part}_{APP_ID}_{random_part}" def call_zalopay_refund(app_trans_id: str, amount: int, description: str, refund_fee_amount: int = None): """ Hàm thực hiện hoàn tiền giao dịch ZaloPay dựa trên app_trans_id. Args: app_trans_id (str): Mã giao dịch của ứng dụng. amount (int): Số tiền hoàn lại (đơn vị: VND). description (str): Mô tả lý do hoàn tiền. refund_fee_amount (int, optional): Số tiền phí hoàn (nếu có). Returns: dict: Kết quả phản hồi từ ZaloPay. """ # Bước 1: Truy vấn để lấy zp_trans_id mac_input = f"{APP_ID}|{app_trans_id}|{KEY1}" mac = generate_mac(mac_input, KEY1) query_payload = { "app_id": APP_ID, "app_trans_id": app_trans_id, "mac": mac } try: query_response = requests.post(QUERY_ENDPOINT, data=query_payload) query_result = query_response.json() zp_trans_id = query_result.get("zp_trans_id") if not zp_trans_id: print("❌ Không tìm thấy zp_trans_id từ app_trans_id.") return {"code": -1, "message": "Không tìm thấy zp_trans_id"} except Exception as e: print("❌ Lỗi khi truy vấn giao dịch:", e) return {"code": -2, "message": "Lỗi truy vấn giao dịch"} timestamp = int(time.time() * 1000) m_refund_id = generate_m_refund_id() if refund_fee_amount is not None: hmac_data = f"{APP_ID}|{zp_trans_id}|{amount}|{refund_fee_amount}|{description}|{timestamp}" else: hmac_data = f"{APP_ID}|{zp_trans_id}|{amount}|{description}|{timestamp}" refund_mac = generate_mac(hmac_data, KEY1) refund_data = { "app_id": APP_ID, "m_refund_id": m_refund_id, "zp_trans_id": zp_trans_id, "amount": amount, "timestamp": timestamp, "description": description, "mac": refund_mac } if refund_fee_amount is not None: refund_data["refund_fee_amount"] = refund_fee_amount try: headers = { "Content-Type": "application/x-www-form-urlencoded" } refund_response = requests.post(REFUND_ENDPOINT, data=refund_data, headers=headers) return refund_response.json() except Exception as e: print("❌ Lỗi khi gửi hoàn tiền:", e) return {"code": -3, "message": "Lỗi hoàn tiền"}