2026-08-02 14:07:04 +08:00
|
|
|
|
import secrets
|
|
|
|
|
|
|
|
|
|
|
|
import jmespath
|
|
|
|
|
|
from django.core.handlers.wsgi import WSGIRequest
|
|
|
|
|
|
from rest_framework import status
|
|
|
|
|
|
from rest_framework.decorators import action
|
|
|
|
|
|
from rest_framework.request import Request
|
|
|
|
|
|
from rest_framework.response import Response
|
2026-08-10 19:33:59 +08:00
|
|
|
|
from rest_framework.routers import DefaultRouter
|
2026-08-02 14:07:04 +08:00
|
|
|
|
from rest_framework.viewsets import ViewSet
|
2026-08-06 20:39:45 +08:00
|
|
|
|
from ulid import ULID
|
2026-08-02 14:07:04 +08:00
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
from sixGuoDjango import BaseResponse, ResData
|
|
|
|
|
|
from wechat_微信支付证书.江苏六果科技有限公司支付证书.六果公司支付类 import sixWechatPay六果泡泡支付
|
2026-08-02 14:07:04 +08:00
|
|
|
|
from wechat_数据库.雪花算法.雪花算法工具 import generator
|
|
|
|
|
|
from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
class 微信支付ViewSets(ViewSet):
|
|
|
|
|
|
notify_url回调地址 = "https://xiao.sixgou.com/demopay/jsapi_callback/"
|
2026-08-02 14:07:04 +08:00
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
@action(detail=False, methods=["post"], url_path="jsapi")
|
|
|
|
|
|
def 小程序支付jsapi(self, request: Request) -> Response:
|
2026-08-02 14:07:04 +08:00
|
|
|
|
""""""
|
|
|
|
|
|
url_pay = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi" # 发起请求的链接
|
2026-08-06 20:39:45 +08:00
|
|
|
|
self_mini_openid = request.data.get("self_mini_openid", False) #
|
|
|
|
|
|
out_trade_no = f"{ULID()}"
|
|
|
|
|
|
body_支付数据 = {
|
|
|
|
|
|
"mchid": sixWechatPay六果泡泡支付().mchid, # 【直连商户号】 直连商户号
|
2026-08-02 14:07:04 +08:00
|
|
|
|
"out_trade_no": out_trade_no, # 【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
|
2026-08-06 20:39:45 +08:00
|
|
|
|
"appid": sixWechatPay六果泡泡支付().appid, # 【公众号 或者 小程序ID】
|
2026-08-02 14:07:04 +08:00
|
|
|
|
"description": "测试支付接口", # 【商品描述】 商品描述要
|
|
|
|
|
|
"notify_url": "https://xiao.sixgou.com/demopay/jsapi_callback/", # 回调地址要
|
|
|
|
|
|
"amount": {
|
|
|
|
|
|
"total": 1, # 【总金额】 订单总金额,单位为分。
|
|
|
|
|
|
"currency": "CNY", # 【货币类型】 CNY:人民币,境内商户号仅支持人民币。
|
|
|
|
|
|
}, # 【支付者】 支付者信息。
|
|
|
|
|
|
"payer": {
|
|
|
|
|
|
# "openid": "ohQkD7A-N93kljcFmkCyG6e_D9vg", # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取
|
|
|
|
|
|
"openid": self_mini_openid, # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取
|
|
|
|
|
|
},
|
|
|
|
|
|
} # 请求的数据
|
2026-08-06 20:39:45 +08:00
|
|
|
|
wechat_pay_data = sixWechatPay六果泡泡支付(pay_methon方法="POST", pay_请求体=body_支付数据, pay_uri=url_pay).getpay_jsapi发起支付()
|
|
|
|
|
|
print(wechat_pay_data)
|
|
|
|
|
|
|
|
|
|
|
|
httpResData = BaseResponse(resData=ResData(listData=[""], dictData=wechat_pay_data), ).model_dump()
|
|
|
|
|
|
return Response(data=httpResData, status=status.HTTP_200_OK)
|
2026-08-02 14:07:04 +08:00
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
@action(detail=False, methods=["post"], url_path="navite")
|
|
|
|
|
|
def 二维码支付(self, request: WSGIRequest | Request) -> Response:
|
2026-08-02 14:07:04 +08:00
|
|
|
|
"""
|
|
|
|
|
|
生成收款的二维码链接,可以让用户来扫码支付
|
|
|
|
|
|
:param request:
|
|
|
|
|
|
:return:
|
|
|
|
|
|
"""
|
2026-08-06 20:39:45 +08:00
|
|
|
|
out_trade_no商家侧订单号 = f"{ULID()}"
|
|
|
|
|
|
native_url = "https://api.mch.weixin.qq.com/v3/pay/transactions/native"
|
2026-08-02 14:07:04 +08:00
|
|
|
|
native_body = {
|
2026-08-06 20:39:45 +08:00
|
|
|
|
"mchid": sixWechatPay六果泡泡支付().mchid, # 服务商户号
|
|
|
|
|
|
"out_trade_no": out_trade_no商家侧订单号, # 商户系统内部订单号
|
|
|
|
|
|
"appid": sixWechatPay六果泡泡支付().appid, # 服务商应用ID
|
2026-08-02 14:07:04 +08:00
|
|
|
|
"description": "测试", # 商品的描述信息
|
2026-08-06 20:39:45 +08:00
|
|
|
|
"notify_url": "https://xiao.sixgou.com/demopay/callback_navite/", # 回调地址
|
|
|
|
|
|
"amount": {"total": 1, "currency": "CNY"},
|
2026-08-02 14:07:04 +08:00
|
|
|
|
}
|
2026-08-06 20:39:45 +08:00
|
|
|
|
wechat_pay_data = sixWechatPay六果泡泡支付(pay_methon方法="POST", pay_请求体=native_body, pay_uri=native_url).getpay_navite发起二维码支付()
|
|
|
|
|
|
print(wechat_pay_data)
|
|
|
|
|
|
# res_data = wechatPay(payment=paymentCategory).getpay_navite(navite_body=native_body)
|
|
|
|
|
|
# print(res_data)
|
|
|
|
|
|
code_url = jmespath.search(data=wechat_pay_data, expression="code_url")
|
|
|
|
|
|
# print(code_url)
|
2026-08-02 14:07:04 +08:00
|
|
|
|
import segno
|
|
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
qr = segno.make_qr(content=code_url, )
|
|
|
|
|
|
data = qr.png_data_uri(scale=5)
|
|
|
|
|
|
qr.save(out="myqr.png")
|
|
|
|
|
|
httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": data}), ).model_dump()
|
|
|
|
|
|
return Response(data=httpResData, status=status.HTTP_200_OK, )
|
2026-08-02 14:07:04 +08:00
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
@action(detail=False, methods=["post"], url_path="qrCode")
|
|
|
|
|
|
def 付款码支付(self, request: Request):
|
2026-08-02 14:07:04 +08:00
|
|
|
|
"""
|
|
|
|
|
|
扫用户付款码的测试接口
|
|
|
|
|
|
:param request:
|
|
|
|
|
|
"""
|
2026-08-06 20:39:45 +08:00
|
|
|
|
nonce_str = secrets.token_hex(10) # 随机字符串
|
|
|
|
|
|
order_random = f"{generator.generate_id()}"
|
|
|
|
|
|
auth_code = request.data.get("auth_code", False) # 前端扫码读取的付款码的数据信息
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# auth_code = "123497182327333282" # TODO 扫码支付付款码,设备读取用户微信中的条码或者二维码信息(这个值需要小程序端,扫码,将数据传递进来)
|
|
|
|
|
|
# fu_kuan_data 是微信官方要求组装的数据类型
|
|
|
|
|
|
fu_kuan_data = {
|
|
|
|
|
|
"appid": paymentCategory.appid, # 小程序的appid
|
|
|
|
|
|
"mch_id": paymentCategory.mchid, # 微信支付分配的商户号
|
|
|
|
|
|
"nonce_str": nonce_str, # 随机字符串
|
|
|
|
|
|
"out_trade_no": order_random, # 商户订单号
|
|
|
|
|
|
"body": "test",
|
|
|
|
|
|
"auth_code": auth_code,
|
|
|
|
|
|
"total_fee": 1, # 订单总金额,单位为分,只能为整数,详见支付金额(必填)
|
|
|
|
|
|
}
|
2026-08-06 20:39:45 +08:00
|
|
|
|
wechat_data = wechatPay(payment=paymentCategory).getpay_code扫用户付款码(body_data=fu_kuan_data)
|
|
|
|
|
|
print(wechat_data)
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# return_code 通信返回码:'SUCCESS' 表示与微信服务器通信成功,'FAIL' 表示通信失败(如网络或参数错误)
|
2026-08-06 20:39:45 +08:00
|
|
|
|
return_code = jmespath.search(data=wechat_data, expression="xml.return_code")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# return_msg 通信返回信息:当 return_code 为 'FAIL' 时,此字段包含错误描述;成功时通常为 'OK'
|
2026-08-06 20:39:45 +08:00
|
|
|
|
return_msg = jmespath.search(data=wechat_data, expression="xml.return_msg")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# result_code 业务结果码:'SUCCESS' 表示支付成功,'FAIL' 表示支付失败(需结合 err_code 分析,但此处未提取)
|
2026-08-06 20:39:45 +08:00
|
|
|
|
result_code = jmespath.search(data=wechat_data, expression="xml.result_code")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# mch_id 商户号(MCH ID):微信支付分配给商户的唯一标识
|
2026-08-06 20:39:45 +08:00
|
|
|
|
mch_id = jmespath.search(data=wechat_data, expression="xml.mch_id")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# appid 公众号或小程序的 AppID:发起支付的应用身份标识
|
2026-08-06 20:39:45 +08:00
|
|
|
|
appid = jmespath.search(data=wechat_data, expression="xml.appid")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# nonce_str 随机字符串:用于防止重放攻击,由商户生成并随请求发送,微信原样返回
|
2026-08-06 20:39:45 +08:00
|
|
|
|
nonce_str = jmespath.search(data=wechat_data, expression="xml.nonce_str")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# openid 用户在当前 AppID 下的唯一标识(OpenID):可用于关联用户账户
|
2026-08-06 20:39:45 +08:00
|
|
|
|
openid = jmespath.search(data=wechat_data, expression="xml.openid")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# total_fee 订单总金额(单位:分):例如 '1' 表示 0.01 元
|
2026-08-06 20:39:45 +08:00
|
|
|
|
total_fee = jmespath.search(data=wechat_data, expression="xml.total_fee")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# cash_fee_type 现金支付币种:目前微信支付仅支持 'CNY'(人民币)
|
2026-08-06 20:39:45 +08:00
|
|
|
|
cash_fee_type = jmespath.search(data=wechat_data, expression="xml.cash_fee_type")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# transaction_id 微信支付系统生成的唯一交易单号:用于对账、退款、查询等操作
|
2026-08-06 20:39:45 +08:00
|
|
|
|
transaction_id = jmespath.search(data=wechat_data, expression="xml.transaction_id")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# 商户系统内部订单号:由商户在调用支付接口时传入,用于关联自身业务订单
|
2026-08-06 20:39:45 +08:00
|
|
|
|
out_trade_no = jmespath.search(data=wechat_data, expression="xml.out_trade_no")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# 附加数据:商户在支付请求中可自定义传入,微信原样返回(常用于传递门店ID、商品类型等)
|
2026-08-06 20:39:45 +08:00
|
|
|
|
attach = jmespath.search(data=wechat_data, expression="xml.attach")
|
2026-08-02 14:07:04 +08:00
|
|
|
|
# time_end 支付完成时间:格式为 yyyyMMddHHmmss,例如 '20260304233708' 表示 2026年03月04日 23:37:08
|
2026-08-06 20:39:45 +08:00
|
|
|
|
time_end = jmespath.search(data=wechat_data, expression="xml.time_end")
|
|
|
|
|
|
httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump()
|
|
|
|
|
|
return Response(data=httpResData, status=status.HTTP_200_OK)
|
2026-08-02 14:07:04 +08:00
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
@action(detail=False, methods=["post"], url_path="jsapi_callback")
|
|
|
|
|
|
def jsapi支付回调测试接口(self, request: Request) -> Response:
|
2026-08-02 14:07:04 +08:00
|
|
|
|
""" 微信支付成功后的回调接口 """
|
2026-08-06 20:39:45 +08:00
|
|
|
|
wechat_data支付回调数据 = sixWechatPay六果泡泡支付(pay_uri="", pay_请求体={}, pay_methon方法="POST").callBack回调解密(headers=request.headers, response_body=request.data)
|
|
|
|
|
|
print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", wechat_data支付回调数据, "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n")
|
|
|
|
|
|
|
|
|
|
|
|
httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump()
|
|
|
|
|
|
return Response(data=httpResData, status=status.HTTP_200_OK)
|
2026-08-02 14:07:04 +08:00
|
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
|
@action(detail=False, methods=["post"], url_path="callback_navite")
|
|
|
|
|
|
def 二维码支付回调(self, request: Request):
|
2026-08-02 14:07:04 +08:00
|
|
|
|
"""注释"""
|
2026-08-06 20:39:45 +08:00
|
|
|
|
wechat_data支付回调数据 = sixWechatPay六果泡泡支付(pay_uri="", pay_请求体={}, pay_methon方法="POST").callBack回调解密(headers=request.headers, response_body=request.data)
|
|
|
|
|
|
print("二维码支付回调二维码支付回调二维码支付回调二维码支付回调二维码支付回调")
|
|
|
|
|
|
return Response(data={"msg": "success"})
|
|
|
|
|
|
|
|
|
|
|
|
@action(detail=False, methods=["get", "post", "put", "delete"], url_path="xml_code")
|
|
|
|
|
|
def 扫用户的付款码收钱(self, request: Request):
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
auth_code = request.data.get("auth_code", None)
|
|
|
|
|
|
data_扫用户付款码数据 = {
|
|
|
|
|
|
"appid": sixWechatPay六果泡泡支付().appid, # 微信分配的公众账号ID(企业号corpid即为此appId)
|
|
|
|
|
|
"attach": "订单额外描述", # 附加数据,在查询API和支付通知中原样返回,可作为自定义参数
|
|
|
|
|
|
"auth_code": "143893528965089", # 授权码,扫码支付时的付款码(条形码/二维码)
|
|
|
|
|
|
"body": "付款码支付测试", # 商品描述,商品简单描述(如:腾讯充值中心-QQ会员充值)
|
|
|
|
|
|
"device_info": "1000", # 设备号,终端设备号(门店号或收银设备ID),自定义参数
|
|
|
|
|
|
"goods_tag": "", # 商品标记,代金券或立减优惠功能的参数,可为空
|
|
|
|
|
|
"mch_id": "10000100", # 商户号,微信支付分配的商户号
|
|
|
|
|
|
"nonce_str": f"{ULID()}", # 随机字符串,长度不超过32位,保证签名不可预测
|
|
|
|
|
|
"out_trade_no": f"{ULID()}", # 商户订单号,商户系统内部订单号,要求32个字符内,且在同一个商户号下唯一
|
|
|
|
|
|
"total_fee": "1", # 订单总金额,单位为分,只能为整数(此处为1分钱)
|
|
|
|
|
|
}
|
|
|
|
|
|
wechat_pay_data = sixWechatPay六果泡泡支付(pay_methon方法="POST", pay_请求体=data_扫用户付款码数据, pay_uri="https://api.mch.weixin.qq.com/pay/micropay").v2签名返回XML()
|
|
|
|
|
|
print(wechat_pay_data)
|
|
|
|
|
|
return Response(data={})
|
|
|
|
|
|
|
|
|
|
|
|
@action(detail=False, methods=["get", "post", "put", "delete"], url_path="add")
|
|
|
|
|
|
def 添加商品数据(self, request: Request):
|
|
|
|
|
|
pass
|
|
|
|
|
|
out_refund_no商家侧生成的退款订单号 = f"{ULID()}"
|
|
|
|
|
|
refund_request = {
|
|
|
|
|
|
"transaction_id": "1217752501201407033233368018", # 微信支付订单号(与 out_trade_no 二选一)
|
|
|
|
|
|
# "out_trade_no": "1217752501201407033233368018", # 商户订单号(与 transaction_id 二选一)
|
|
|
|
|
|
"out_refund_no": out_refund_no商家侧生成的退款订单号, # 商户退款单号,唯一
|
|
|
|
|
|
"reason": "商品已售完", # 退款原因(选填)
|
|
|
|
|
|
"notify_url": "https://xiao.sixgou.com/demopay/退款/", # 异步接收微信支付退款结果通知的回调地址
|
|
|
|
|
|
"funds_account": "AVAILABLE", # 退款资金来源:AVAILABLE-可用余额,UNSETTLED-未结算资金
|
|
|
|
|
|
"amount": {
|
|
|
|
|
|
"refund": 1, # 退款金额,单位:分
|
|
|
|
|
|
"from": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"account": "AVAILABLE", # 出资账户类型
|
|
|
|
|
|
"amount": 444 # 出资金额
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"total": 1, # 原订单金额
|
|
|
|
|
|
"currency": "CNY" # 货币类型
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
return Response(data={})
|
2026-08-10 19:33:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
微信支付ViewSetsRouter = DefaultRouter()
|
|
|
|
|
|
微信支付ViewSetsRouter.register(prefix="", viewset=微信支付ViewSets, basename="微信支付ViewSets")
|