This commit is contained in:
doudou201703
2026-08-06 20:39:45 +08:00
parent 046fac6dc1
commit 3ff0faebb9
38 changed files with 1029 additions and 611 deletions
@@ -0,0 +1,99 @@
# Generated by Django 6.0.2 on 2026-08-04 01:28
import ulid
import wechat_数据库.雪花算法.雪花算法工具
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_app', '0053_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more'),
]
operations = [
migrations.CreateModel(
name='wei客服账号',
fields=[
('kefu_id', models.UUIDField(default=ulid.ULID, primary_key=True, serialize=False)),
('extInfo_推广员账号链接', models.CharField(db_comment='企微客服账号链接', max_length=128)),
('extInfo_企微员工绑定的UNIONID', models.CharField(db_comment='企微客服绑定的小程序unionid', max_length=128)),
('extInfo_企微员工的名称', models.CharField(blank=True, max_length=128, null=True)),
('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')),
('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')),
],
options={
'db_table': 'wei客服账号',
},
),
migrations.AlterField(
model_name='goods商品',
name='id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='lucky拼团',
name='idKey',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='lucky拼团订单',
name='idKey',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='map地图ip转地址',
name='id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='minisub订阅消息模板',
name='idKey',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='order订单',
name='id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='order订单商品数据',
name='order_id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='order订单商品数据',
name='order_id商品',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='wechattransferorder',
name='id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='wecom企微用户',
name='idKeyWecom企微用户',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='wecom企微群',
name='idKeyWecom企微群',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='wecom推广码',
name='id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='weiuser地图定位',
name='id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
migrations.AlterField(
model_name='weiuser微信用户地址',
name='id_str',
field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128),
),
]
+1 -3
View File
@@ -1,14 +1,12 @@
from django.db import models
from django_定时器 import 幸运拼团数据库
from wechat_wecom_企业微信管理.企微通讯录管理.企微通讯录管理数据库 import 企微员工数据
from wechat_数据库.企业微信数据库 import 推广二维码数据表, 企微用户表, 企微群数据库
from wechat_token import token数据库
from wechat_数据库.地图定位 import 用户定位数据库, 腾讯地图解析数据库
from wechat_数据库.小程序后端数据库 import 订阅消息
from wechat_数据库.支付数据库 import 商家转账数据库
from wechat_数据库.支付订单数据库 import 商品订单数据
from wechat_数据库.洗衣液商品数据库 import 六果洗衣液商品
from wechat_数据库.测试数据库 import 测试数据表
from wechat_数据库.用户数据库 import 小程序登陆用户, 小程序用户地址, 小程序积分数据库
from wechat_数据库.用户数据库 import 小程序登陆用户, 小程序用户地址, 小程序积分数据库,企微客服数据库
# Create your models here.
+40 -4
View File
@@ -1,3 +1,6 @@
import threading
from functools import wraps
import emoji
import orjson
import pydash
@@ -18,7 +21,20 @@ from wechat_项目工具包.微信支付工具包.微信支付类 import payment
from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser用户角色, miniUser积分
def sync_lock_接口线程锁(lock):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
with lock:
return fn(*args, **kwargs)
return wrapper
return decorator
class 业务订单接口ViewSets(ViewSet):
lock_接口线程锁 = threading.Lock() # 所有请求 共享这一个 lock对象
def 处理积分方法(self, 商家订单号):
pass
@@ -30,7 +46,6 @@ class 业务订单接口ViewSets(ViewSet):
def 首单自动注册成为推广员(self, out_trade_no):
pass
order对象 = order订单.objects.get(order支付商家侧订单号=out_trade_no)
user用户对象 = weiuser.objects.get(unionid=order对象.order支付者unionid)
six绑定的企微员工对象, sixBool = weiuser.objects.get_or_create(unionid=user用户对象.user_绑定企微UNIONID)
# 判断用户成为推广员的标准 成为的条件,当前用户绑定的企微员工账号, 必须是同一个区县的
@@ -40,6 +55,21 @@ class 业务订单接口ViewSets(ViewSet):
user用户对象.user_角色权限 = miniUser用户角色().推广员
user用户对象.save()
def 生成单品优惠券的数据(self, order购物车商品数据: list[dict]):
pass
准备一个空列表 = []
# 循环传递进来的数据
for item in order购物车商品数据:
# 创建对象
data_dict = {
"merchant_goods_id": "01KYNDT2KKKPZCR5G1TVG9GZ7G",
"goods_name": emoji.replace_emoji(pydash.get(obj=item, path="goods_商品标题")),
"quantity": pydash.get(obj=item, path="单个商品订单数量"),
"unit_price": pydash.get(obj=item, path="单个商品实际支付价格")
}
准备一个空列表.append(data_dict)
return 准备一个空列表
@action(detail=False, methods=["post"], url_path="mall")
def 商城订单支付接口(self, request: Request) -> Response:
"""前端小程序的用户: 发起支付订单的请求接口"""
@@ -53,13 +83,15 @@ class 业务订单接口ViewSets(ViewSet):
share订单分享者ID = request.data.get("share订单分享者ID", "六果") # 当前是否有上级对象
order订单类型 = request.data.get("order订单类型", None)
goods标题 = emoji.replace_emoji(pydash.get(obj=pydash.head(order购物车商品数据), path="goods_商品标题"))
goods_detail_支付优惠券的数据 = self.生成单品优惠券的数据(order购物车商品数据=order购物车商品数据)
print("打印一下哪里出问题了", order购物车商品数据)
out_trade_no商家侧的订单号 = f"OAT{ULID()}" # 生成商家侧的订单号
body = {
"mchid": paymentCategory.mchid, # 【直连商户号】 直连商户号
"out_trade_no": out_trade_no商家侧的订单号, # 【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
"appid": paymentCategory.appid, # 【公众号 或者 小程序ID】
"description": goods标题, # 【商品描述】 商品描述要
"notify_url": "https://six.sixgou.com/six/mall_callbakc/", # 回调地址要
"notify_url": "https://xiao.sixgou.com/six/mall_callbakc/", # 回调地址要
"amount": {
# "total": order购物车商品总价, # 【总金额】 订单总金额,单位为分。
"total": 1, # 【总金额】 订单总金额,单位为分。
@@ -71,6 +103,11 @@ class 业务订单接口ViewSets(ViewSet):
# "openid": "ohQkD7A-N93kljcFmkCyG6e_D9vg", # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取
"openid": self_mini_openid, # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取
},
"detail": {
# 【商品详情】 商品详情描述,该结构去除多余空格换行压缩后,总长度不能超过6144字节。
"goods_detail": goods_detail_支付优惠券的数据
},
"support_fapiao": True, # 【电子发票入口开放标识】 传入true时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效。
} # 请求的数据
wechat_data = wechatPay(payment=sixpay六果科技公司).getpay_jsapi(uri=url_pay, body_data=body, method="POST")
payData = pydash.get(obj=wechat_data, path="response")
@@ -88,13 +125,13 @@ class 业务订单接口ViewSets(ViewSet):
# httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump()
return Response(data=httpResData, status=status.HTTP_200_OK)
@sync_lock_接口线程锁(lock=lock_接口线程锁) # 锁住这个接口所有并发请求,
@action(detail=False, methods=["post"], url_path="mall_callbakc")
def jsapi支付回调测试接口(self, request: Request) -> Response:
""" 微信支付成功后的回调接口 """
dict_body = request.data
wechat_data支付回调数据 = wechatPay(payment=paymentCategory).callBack回调解密(headers=request.headers,
response_body=dict_body, )
print("\n 🍎 🍏 🍊 🍎 🍏 \n", wechat_data支付回调数据, )
out_trade_no商家侧支付订单号 = pydash.get(obj=wechat_data支付回调数据, path="out_trade_no") # 商家侧的订单号
trade_state_desc = pydash.get(obj=wechat_data支付回调数据, path="trade_state_desc") # 支付回调的支付状态
transaction_id = pydash.get(obj=wechat_data支付回调数据, path="transaction_id")
@@ -106,7 +143,6 @@ class 业务订单接口ViewSets(ViewSet):
order物流订单号=生成商家侧物流的订单号,
order支付微信官方订单号=transaction_id,
)
print("打印一下商家的订单号", out_trade_no商家侧支付订单号, transaction_id)
(miniUser积分(share分享者unionidID="", click点击者unionidID="")
.add添加好友助力下单返利积分(order支付商家侧订单号=out_trade_no商家侧支付订单号, share积分类型="好友下单"))
ems邮政物流工具().生成运单(out_trade_no商家侧支付订单号=out_trade_no商家侧支付订单号) # 调用方法,生成真实的物流订单号码;
+45
View File
@@ -0,0 +1,45 @@
from typing import cast
import pydash
from channels.layers import BaseChannelLayer, get_channel_layer
from django.http.response import HttpResponse
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.viewsets import ViewSet
from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司
from wechat_项目工具包.微信支付工具包.微信支付类 import wechatPay
default_channel_layer = cast(BaseChannelLayer, get_channel_layer(alias="default"))
from functools import wraps
import threading
def sync_lock(lock):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
with lock:
return fn(*args, **kwargs)
return wrapper
return decorator
class 电子发票管理接口ViewSets(ViewSet):
lock = threading.Lock() # 所有请求 共享这一个 lock对象
@sync_lock(lock=lock) # 锁住这个接口所有并发请求,
@action(detail=False, methods=["get", "post", "put", "delete"], url_path="callback")
def 电子发票回调接口(self, request: Request):
""""""
print("电子发票请求进来了没有")
print(request.data)
print(request.query_params)
电子发票回调解密后的数据 = wechatPay(payment=sixpay六果科技公司).callBack回调解密(headers=request.headers, response_body=request.data)
print(电子发票回调解密后的数据, "=======================")
fapiao_apply_id = pydash.get(obj=电子发票回调解密后的数据, path="fapiao_apply_id")
return HttpResponse(content="OK")
+1 -1
View File
@@ -38,6 +38,6 @@ class 实时更新物流数据ViewSets(ViewSet):
order物流公司订单编号 = request.data.get("order物流公司订单编号", None)
order物流订单号 = request.data.get("order物流订单号", None)
print("实时更新数据请求进来了吗")
ems邮政物流工具().更新物流快递数据(order物流公司订单编号=order物流公司订单编号, order物流订单号=order物流订单号)
ems邮政物流工具().更新物流快递数据(order物流公司订单编号=order物流公司订单编号, )
httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump()
return Response(data=httpResData, status=status.HTTP_200_OK)
+2 -1
View File
@@ -32,7 +32,8 @@ class 小程序发优惠券到钱包接口ViewSets(ViewSet):
@action(detail=False, methods=["get", "post", "put", "delete"], url_path="生成优惠券")
def 生成优惠券(self, request: Request):
""""""
stock发券数据 = stock发送代金券功能(stock_id_代金券批次号="22512292").send发券并返回前端需要的数据()
# stock发券数据 = stock发送代金券功能(stock_id_代金券批次号="22512292").send发券并返回前端需要的数据()
stock发券数据 = stock发送代金券功能(stock_id_代金券批次号="22625737").send发券并返回前端需要的数据()
# 4. 生成签名
return Response(data=stock发券数据)
@@ -1,17 +1,14 @@
from rest_framework.routers import DefaultRouter
from wechat_wecom_企业微信管理.企微通讯录管理.通讯录管理接口 import 企微员工通讯录管理接口ViewSets
from wechat_wecom_企业微信管理.客户管理.客户管理接口 import 客户管理接口ViewSets
from wechat_wecom_企业微信管理.客服账号管理.客服账号管理接口 import 客服账号管理接口ViewSets
from wechat_wecom_企业微信管理.素材管理.素材管理接口 import 素材管理接口列表ViewSets
from wechat_wecom_企业微信管理.联系我与客户群管理.加入群聊管理接口 import 加入群聊管理ViewSets
from wechat_wecom_企业微信管理.联系我与客户群管理.联系我管理接口 import 联系我管理ViewSets
企业微信管理端接口列表Router = DefaultRouter( )
企业微信管理端接口列表Router.register( prefix="企微客户好友管理", viewset=客户管理接口ViewSets, basename="客户管理接口ViewSets" )
企业微信管理端接口列表Router.register( prefix="chat", viewset=加入群聊管理ViewSets, basename="加入群聊管理ViewSets" )
企业微信管理端接口列表Router.register( prefix="素材管理接口", viewset=素材管理接口列表ViewSets, basename="素材管理接口列表ViewSets" )
企业微信管理端接口列表Router.register( prefix="contact", viewset=联系我管理ViewSets, basename="联系我管理ViewSets" )
企业微信管理端接口列表Router.register( prefix="kefu", viewset=客服账号管理接口ViewSets, basename="客服账号管理接口ViewSets" )
企业微信管理端接口列表Router.register( prefix="员工", viewset=企微员工通讯录管理接口ViewSets, basename="企微员工通讯录管理接口ViewSets" )
企业微信管理端接口列表Router = DefaultRouter()
企业微信管理端接口列表Router.register(prefix="企微客户好友管理", viewset=客户管理接口ViewSets, basename="客户管理接口ViewSets")
企业微信管理端接口列表Router.register(prefix="chat", viewset=加入群聊管理ViewSets, basename="加入群聊管理ViewSets")
企业微信管理端接口列表Router.register(prefix="素材管理接口", viewset=素材管理接口列表ViewSets, basename="素材管理接口列表ViewSets")
企业微信管理端接口列表Router.register(prefix="contact", viewset=联系我管理ViewSets, basename="联系我管理ViewSets")
企业微信管理端接口列表Router.register(prefix="kefu", viewset=客服账号管理接口ViewSets, basename="客服账号管理接口ViewSets")
@@ -1,5 +1,6 @@
from rest_framework.routers import DefaultRouter
from django_app.发票回调管理接口 import 电子发票管理接口ViewSets
from django_app.实时更新物流数据接口 import 实时更新物流数据ViewSets
from django_app.小程序发券接口 import 小程序发优惠券到钱包接口ViewSets
from django_app.添加各类型积分接口 import 添加积分接口ViewSets
@@ -41,3 +42,4 @@ from wechat_mini_服务端接口目录.附近小程序.附近小程序接口 imp
小程序服务端管理接口列表ViewSetsRouter.register(prefix="积分查询", viewset=积分查询接口ViewSets, basename="积分查询接口ViewSets")
小程序服务端管理接口列表ViewSetsRouter.register(prefix="积分提现", viewset=积分提现ViewSets, basename="积分提现ViewSets")
小程序服务端管理接口列表ViewSetsRouter.register(prefix="项目初始化接口", viewset=项目初始化功能接口ViewSets, basename="项目初始化接口")
小程序服务端管理接口列表ViewSetsRouter.register(prefix="invoice", viewset=电子发票管理接口ViewSets, basename="电子发票管理接口ViewSets")
+2 -2
View File
@@ -27,7 +27,7 @@ base_dir_name = "sixGuoDjango"
# DEBUG = SECRET_KEY_DJANGO
DEBUG = True
ALLOWED_HOSTS = ["xiao.sixgou.com", "127.0.0.1"]
ALLOWED_HOSTS = ["xiao.sixgou.com", "127.0.0.1", "wechat.sixgou.com"]
# Application definition
@@ -53,7 +53,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
'corsheaders.middleware.CorsMiddleware', # 👈 添加这一行
# 'corsheaders.middleware.CorsMiddleware', # 👈 添加这一行
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
@@ -22,12 +22,14 @@ class 小程序用户的位置接口ViewSets(ViewSet):
# 判断 当前用户,是否已经拿有位置的信息数据了
if six六果对象.user_区县:
# 当这里为true的时候就可以直接返回了
print("判断当前的用户区县不为None")
return Response()
else:
纬度 = pydash.get(obj=result, path="latitude")
经度 = pydash.get(obj=result, path="longitude")
print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 用户的定位的数据", result)
地图解析结果 = wei地图工具.经纬度转换为地址(location=f"{纬度},{经度}")
print(地图解析结果, "=============")
省 = pydash.get(obj=地图解析结果, path="result.address_component.province")
市 = pydash.get(obj=地图解析结果, path="result.address_component.city")
区 = pydash.get(obj=地图解析结果, path="result.address_component.district")
@@ -38,6 +40,7 @@ class 小程序用户的位置接口ViewSets(ViewSet):
six六果对象.user_省份 = 省
six六果对象.user_城市 = 市
six六果对象.user_街道信息 = 街道
six六果对象.save()
httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump()
return Response(data=httpResData, status=status.HTTP_200_OK)
@@ -49,7 +52,7 @@ class 小程序用户的位置接口ViewSets(ViewSet):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', False)
ip = pydash.head(x_forwarded_for.split(','))
mini_unionid_user = weiuser.objects.get(unionid=self_mini_unionid, )
if mini_unionid_user.user_省份 is None or mini_unionid_user.user_区县 is None or mini_unionid_user.user_城市 is None:
if mini_unionid_user.user_省份 is None or mini_unionid_user.user_城市 is None:
weiData = wei地图工具.ip地址转为地址(x_forwarded_for=ip, )
province_省份 = pydash.get(obj=weiData, path="result.ad_info.province")
city_城市 = pydash.get(obj=weiData, path="result.ad_info.city")
@@ -43,9 +43,14 @@ class 用户配送地址ViewSets(ViewSet):
用户所在街道 = pydash.get(obj=address, path="detailInfo")
weiuser.objects.filter(unionid=self_user_unionid).update(
uesr_手机号码=用户手机号码, user_昵称=用户昵称,
user_省份=用户所在省, user_城市=用户所在市, user_区县=用户所在区县,
user_街道信息=用户所在街道
)
six_user六果对象 = weiuser.objects.get(unionid=self_user_unionid)
if not six_user六果对象.user_区县 or not six_user六果对象.user_城市 or not six_user六果对象.user_省份:
six_user六果对象.user_省份 = 用户所在省
six_user六果对象.user_城市 = 用户所在市
six_user六果对象.user_区县 = 用户所在区县,
six_user六果对象.user_街道信息 = 用户所在街道
six_user六果对象.save()
@action(detail=False, methods=["post"], url_path="first_add")
def 首次添加用户收件地址(self, request: Request):
@@ -1,15 +1,11 @@
import requests
from django.core.files.storage import default_storage
from django.core.files.uploadedfile import InMemoryUploadedFile
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
from rest_framework.routers import SimpleRouter, DefaultRouter
from rest_framework.viewsets import ViewSet
from sixGuoDjango import ResData, BaseResponse
from sixGuoDjango import BaseResponse, ResData
from wechat_token.token工具包 import sixToken
@@ -19,7 +19,7 @@ from ulid import ULID
from sixGuoDjango import BaseResponse, ResData
from wechat_token.token工具包 import sixToken
from wechat_数据库.支付订单数据库.商品订单数据 import order订单, order订单商品数据
from wechat_数据库.支付订单数据库.商品订单数据 import order订单
class ems物流状态更新模型(BaseModel):
@@ -1,22 +0,0 @@
from django.db import models
from uuid6 import uuid8
class wecom企微员工( models.Model ):
"""城市信息表"""
objects = models.Manager( ) #
wecom企微员工_id = models.UUIDField( primary_key=True, default=uuid8 )
# id_str = models.CharField(max_length=128, default=generator.generate_str)
wecom_userid = models.CharField( max_length=128, )
wecom_department = models.CharField( max_length=128, null=True, blank=True )
dateAndTime = models.DateTimeField( auto_now_add=True, db_comment="创建时间" ) # 数据创建时间
updateTime = models.DateTimeField( auto_now=True, db_comment="更新时间" ) # 更新时间(需要用 save() )
class Meta:
db_table = "wecom企微员工" # 给数据表自定义一个名称;默认的会是在 应用名+类名
app_label = "django_app"
@@ -1,41 +0,0 @@
import threading
import pydash
import requests
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from sixGuoDjango import BaseResponse, ResData
from wechat_token.token工具包 import sixToken
from wechat_wecom_企业微信管理.企微通讯录管理.企微通讯录管理数据库.企微员工数据 import wecom企微员工
class 企微员工通讯录管理接口ViewSets( ViewSet ):
lock = threading.Lock( )
@action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="获取成员ID列表" )
def 获取成员ID列表( self, request: Request ):
pass
wecom_phone_token = sixToken.get_weom_phone_token( )
uri = f"https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token={wecom_phone_token}"
postData = requests.post( url=uri, json={
"limit": 10000
} )
企微员工列表数据 = pydash.get( obj=postData.json( ), path="dept_user" )
print( 企微员工列表数据 )
for 员工 in 企微员工列表数据:
print( 员工 )
userid = pydash.get( obj=员工, path="userid" )
department = pydash.get( obj=员工, path="department" )
wecom企微员工.objects.get_or_create( wecom_userid=userid, wecom_department=department )
httpResData = BaseResponse( resData=ResData( listData=[ ], dictData={ } ), ).model_dump( )
return Response( data=httpResData, status=status.HTTP_200_OK )
@@ -38,9 +38,6 @@ class 客户管理接口ViewSets(ViewSet):
@action(detail=False, methods=["post"], url_path="批量获取客户详情并存储到数据库")
def 批量获取客户详情并存储到数据库(self, request: Request):
""""""
self_user_unionid = request.data.get("self_user_unionid", None)
self_mini_openid = request.data.get("self_mini_openid", None)
userid = request.data.get("userid", "YuanBao1975")
state企微员工创建时添加的唯一值 = request.data.get("state企微员工创建时添加的唯一值", None)
userid企微员工账号ID = request.data.get("userid企微员工账号ID", None)
@@ -0,0 +1,273 @@
import base64
import hashlib
import json
import os
import re
import secrets
from datetime import datetime
from pathlib import Path
from typing import Literal, Optional
from zoneinfo import ZoneInfo
import django
import orjson
import pydash
import requests
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.PublicKey.RSA import RsaKey
from Crypto.Signature import pkcs1_15
from Crypto.Util.Padding import unpad
from dicttoxml import dicttoxml
from django.conf import settings
from pydantic import BaseModel, Field, SecretStr
from requests import Response
from sixGuoDjango.settings import base_dir_name
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings")
django.setup()
class sixWechatPay六果泡泡支付(BaseModel):
mchid: str = Field("1700383419", alias="商户号", description="微信支付商户号")
appid: str = Field("wxf612e825377328f0", alias="商户号", description="微信支付商户号")
api_v3_key: str = Field("YWMGAIPTJTWZN4YB3YUTHWK34K9U9M1W", alias="APIv3密钥", description="用于回调解密")
api_v2_key: Optional[SecretStr] = Field("OXRNKGGUYHGNJSSIHKFGVMAAOHRPXJAT", alias="APIv2密钥", description="仅老接口需要")
serial_no商户证书的序列号: str = Field("530160D54E8F56726F506DEE40D7FA49A558E8E0", description="商户证书的序列号")
# ---------- 小程序密钥 ----------
mini_program_app_secret: SecretStr = Field("8691f774e3c0c5a876b21a3e84109ef0", alias="小程序AppSecret")
# ---------- 商户API密钥对(用于签名请求) ----------
merchant_private_key_pem: str = Field(Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_key.pem").read_text(), alias="商户私钥PEM", description="apiclient_key.pem 内容")
merchant_public_key_pem: str = Field(Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem").read_text(), alias="商户公钥PEM", description="apiclient_cert.pem 内容(很少用到)")
# ---------- 微信支付公钥(用于验签和加密敏感字段) ----------
wechatpay_public_key_id: str = Field("PUB_KEY_ID_0117003834192026080500181856002000", alias="微信支付公钥ID")
wechatpay_public_key_pem: str = Field(Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem").read_text(), alias="微信支付公钥PEM", description="pub_key.pem 内容")
# ---------- 平台证书(灰度过渡期备用) ----------
platform_cert_pem: Optional[
str] = Field(Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem").read_text(), alias="平台证书PEM", description="wechatpay.pem 内容")
pay_uri: str | None = Field(None, )
pay_请求体: dict | bytes | str | None = Field(None, description="发请求签名时需要的请求体")
pay_methon方法: Literal["GET", "POST", "PATCH"] = Field("POST", description="发请求签名时需要的请求体")
def model_post_init(self, __context):
print("初始化完成,自动调用 model_post_init")
def 验证签名串(self, response_headers, response_data: dict, ):
"""
@param response_headers:
@type response_headers:
@param response_data:
@type response_data:
@return:
@rtype:
"""
public_key = RSA.import_key(self.platform_cert_pem)
Wechatpay_Timestamp = pydash.get(response_headers, "Wechatpay-Timestamp")
Wechatpay_Nonce = pydash.get(response_headers, "Wechatpay-Nonce")
Wechatpay_Signa = pydash.get(response_headers, "Wechatpay-Signature")
response_data_str = orjson.dumps(response_data, ).decode(encoding="utf-8")
string_to_verify = f"{Wechatpay_Timestamp}\n{Wechatpay_Nonce}\n{response_data_str}\n" # 构造验签名串
print("最终验证的请求字符串", string_to_verify)
hash_obj = SHA256.new(string_to_verify.encode())
# 6. 验证签名
try:
pkcs1_15.new(public_key).verify(msg_hash=hash_obj, signature=base64.b64decode(Wechatpay_Signa))
return True # 签名验证成功
except (ValueError, TypeError) as e:
raise e # 签名验证失败
def gouzhao构造签名串(self, ):
"""
"""
url_data = re.search(r'/v3.*', string=self.pay_uri).group()
utc_unix_timestamp = int(datetime.now(tz=ZoneInfo("utc")).timestamp())
random_str = secrets.token_hex(nbytes=16) # 随机字符串
pay_signaturestring创建成功的签名串 = ""
# 创建签名请求参数
if isinstance(self.pay_请求体, str):
pay_signaturestring创建成功的签名串 = f"{self.pay_methon方法}\n{url_data}\n{utc_unix_timestamp}\n{random_str}\n{self.pay_请求体}\n"
if isinstance(self.pay_请求体, dict):
body_inner = json.dumps(obj=self.pay_请求体)
pay_signaturestring创建成功的签名串 = f"{self.pay_methon方法}\n{url_data}\n{utc_unix_timestamp}\n{random_str}\n{body_inner}\n"
if self.pay_请求体 is None:
body_inner = ""
pay_signaturestring创建成功的签名串 = f"{self.pay_methon方法}\n{url_data}\n{utc_unix_timestamp}\n{random_str}\n{body_inner}\n"
if isinstance(self.pay_请求体, bytes):
body_inner = self.pay_请求体.decode()
pay_signaturestring创建成功的签名串 = f"{self.pay_methon方法}\n{url_data}\n{utc_unix_timestamp}\n{random_str}\n{body_inner}\n"
# 构造一个哈希对象
hash_obj = SHA256.new(pay_signaturestring创建成功的签名串.encode(encoding="utf-8"))
# 加载商户私钥
# 调用了 RSA.import_key() 方法,它会从字符串或文件中导入一个 PEM 格式的 RSA 私钥,并返回一个 RsaKey 类型的对象
private_key: RsaKey = RSA.import_key(self.merchant_private_key_pem) # 用私钥来加密
# 生成签名 使用商户的 私钥进行签名
signature = pkcs1_15.new(rsa_key=private_key).sign(msg_hash=hash_obj)
# 对签名进行Base64编码,符合微信支付API要求
encoded_signature = base64.b64encode(s=signature).decode(encoding="utf-8")
# 组装成微信官方需要的数据;
data = {
"mchid": self.mchid,
"nonce_str": random_str,
"serial_no": self.serial_no商户证书的序列号,
"timestamp": utc_unix_timestamp,
"signature": encoded_signature,
} # 组装好的字典数据;
ftr = "WECHATPAY2-SHA256-RSA2048"
s_with_space = ftr.ljust(len(ftr) + 1) # 将字符串长度 +1(填充空格)
str_list = pydash.join(array=[f'{key}="{value}"' for key, value in data.items()], separator=",")
# 生成请求头
Authorization = f"{s_with_space}{str_list}"
headers = {"Content-Type": "application/json", "Authorization": Authorization, }
# headers.update({"Wechatpay-Serial": self.payment.微信支付公钥ID})
return headers
def 返回前端支付数据(self, prepay_id: str, wechat_appid: str):
"""
小程序调起支付
通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付。
@param prepay_ids
@type prepay_id:
@return:
@rtype:
"""
utc_unix_timestamp = int(datetime.now(tz=ZoneInfo("utc")).timestamp())
random_string = secrets.token_hex(nbytes=30) # 随机字符串
# 组装微信官方要求的格式;
qian_mian_chuan = f"{wechat_appid}\n{utc_unix_timestamp}\n{random_string}\n{prepay_id}\n"
# # 使用组装好地签名串,进行sha256 哈希生成哈希对象
hash_obj = SHA256.new(qian_mian_chuan.encode())
# 生成商户私钥对象
# private_key = RSA.import_key( wechat_config.wechat私钥 )
private_key = RSA.import_key(self.merchant_private_key_pem)
# 生成签名
signature = pkcs1_15.new(private_key).sign(hash_obj)
# 将生成的签名串,转换为base格式
encoded_signature = base64.b64encode(signature).decode()
return {
"appId": self.appid,
"timeStamp": str(utc_unix_timestamp),
"nonceStr": random_string,
"package": prepay_id,
"signType": "RSA",
"paySign": encoded_signature,
}
def getpay_jsapi发起支付(self, ):
headers = self.gouzhao构造签名串()
# 发送请求
response: Response = requests.post(url=self.pay_uri, json=self.pay_请求体, headers=headers)
prepay_id = pydash.get(obj=response.json(), path="prepay_id", default=None)
# 验证请求后返回的数据是否为微信官方所发送;
验证签名结果 = self.验证签名串(response_data=response.json(), response_headers=response.headers)
if 验证签名结果:
prepay_id = f"prepay_id={prepay_id}"
# 调用方法生成返回给前端的对象
return self.返回前端支付数据(prepay_id=prepay_id, wechat_appid=self.appid, ) # 调用 返回前端支付数据()方法生成返回前端的支付字典
else:
raise "验证不通过"
def modegmc解密(self, nonce: str, ciphertext: str, associated_data: str, ) -> dict:
"""
支付成功或者退款回调时需要解密参数,微信返回的响应体.解密后可以获取支付成功或者退款的详细的数据;
@param nonce: // 加密使用的随机串初始化向量
@type nonce:
@param ciphertext: // Base64编码后的密文(需要解密)
@type ciphertext: (需要解密)
@param associated_data: // 附加数据包(可能为空)
@type associated_data:
@return:
@rtype:
"""
nonce_bytes = nonce.encode(encoding="utf-8")
ad_bytes = associated_data.encode(encoding="utf-8")
encrypted_data = base64.b64decode(ciphertext)
cipher = AES.new(key=self.api_v3_key.encode(), mode=AES.MODE_GCM, nonce=nonce_bytes)
# 处理附加关联数据(AAD) - 微信支付中通常是"transaction"
# 这部分数据在加密过程中被验证但未被加密
# 必须与加密时使用的附加数据完全一致
cipher.update(assoc_data=ad_bytes)
auth_tag = encrypted_data[-16:] # 提取认证标签(最后16 字节)
# 提取实际加密内容
ciphertext_bytes = encrypted_data[:-16] # 提取实际加密内容
decrypted_data = cipher.decrypt_and_verify(ciphertext=ciphertext_bytes, received_mac_tag=auth_tag)
# 回调解密数据: dict = json.loads(decrypted_data.decode())
回调解密数据: dict = orjson.loads(decrypted_data.decode(encoding="utf-8"))
return 回调解密数据
def callBack回调解密(self, headers, response_body: dict) -> dict:
"""
执行微信支付回调方法(获取返回的参数数据)
@param request:
@type request:
"""
self.验证签名串(response_headers=headers, response_data=response_body)
ciphertext = pydash.get(obj=response_body, path="resource.ciphertext", default=None)
associated_data = pydash.get(obj=response_body, path="resource.associated_data", default=None)
nonce = pydash.get(obj=response_body, path="resource.nonce", default=None)
wei_xin_zhi_fu_hui_diao_data = self.modegmc解密(
nonce=nonce, ciphertext=ciphertext,
associated_data=associated_data,
)
return wei_xin_zhi_fu_hui_diao_data
def getpay_navite发起二维码支付(self, ):
""" 二维码支付,可以适用于 网站 的用户扫码支付 """
headers = self.gouzhao构造签名串()
response = requests.post(url=self.pay_uri, headers=headers, json=self.pay_请求体)
生成的支付链接 = response.json()
return 生成的支付链接
def v2签名返回XML(self, ):
"""v2版本的签名:将扫码支付的body转换为微信支付所要求的数据类型"""
sorted_dict = dict(pydash.sort_by(collection=self.pay_请求体.items(), iteratee=0))
# 拼接字符串: (将密钥添加到最末尾)
params_list_str = pydash.join(array=[f"{k}={v}" for k, v in sorted_dict.items()], separator="&") + "&key=" + self.api_v2_key
# 得到params_str就是需要 参与 签名的字符串
signature = hashlib.md5(string=params_list_str.encode()).hexdigest().upper() # 使用MD5加密模式
update后的数据 = pydash.set_(obj=self.pay_请求体, path="sign", value=signature)
xml = dicttoxml(obj=update后的数据, custom_root="xml", xml_declaration=False, attr_type=False, cdata=True)
print(type(xml))
headers = self.gouzhao构造签名串()
response = requests.post(url=self.pay_uri, data=xml, headers=headers)
print(response.text)
print(response.json())
return
def 解密群号(self, encryptedData, iv, sessionKey):
"""
"""
try:
session_key_bytes = base64.b64decode(sessionKey)
encrypted_data_bytes = base64.b64decode(encryptedData)
iv_bytes = base64.b64decode(iv)
cipher = AES.new(key=session_key_bytes, mode=AES.MODE_CBC, iv=iv_bytes)
# 解密并去除填充
decrypted_data = unpad(cipher.decrypt(encrypted_data_bytes), AES.block_size).decode()
data_dict = orjson.loads(decrypted_data)
openGId = pydash.get(obj=data_dict, path="openGId")
timestamp = pydash.get(obj=data_dict, path="watermark.timestamp")
appid = pydash.get(obj=data_dict, path="watermark.appid")
return openGId, timestamp, appid
except Exception as e:
raise Exception(f"解密失败: {str(e)}")
def 发起退款(self, ):
pass
uri = f"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"
heardes = self.gouzhao构造签名串()
print(heardes)
response_data = requests.post(url=self.pay_uri, json=self.pay_请求体, headers=heardes)
print(response_data.json())
if __name__ == "__main__":
pass
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsWs1Fz9kzTOal/tazXiD
7TZ33lFJ9bq+AW7LXVO5gXJY68DtvAv2LTFBjEMOQCyGmzNE9v2nEJJ/ZGVERrfo
MC5nVnzQBs+mL6QNOu90/g7TFzls/0+wNxf0usbbzXmU6hLKxWMnr2CPHcNnJIHJ
rA4opkv0AwW125Ap60UChV7ocJeZ25yqJuEg1so/7dp/h1ivTjGF5AJvfFbIFwzK
uQe+qCKi3GsCW5aWv4q9CpKyA3oy3hUjlgWiUMUEfVUia3gfrTDJeggJYi7MjBeZ
zfu2b90JUzryko3vi9L8GWhKI1qMSFNcy24Lf7XVreryt+LwBqvy9F9nx1U90CXY
bQIDAQAB
-----END PUBLIC KEY-----
@@ -17,12 +17,15 @@ from django.conf import settings
平台证书 = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem").read_text()
微信支付公钥 = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem").read_text()
class sixpay六果科技公司:
"""微信支付参数:江苏六果科技有限公司 信息"""
public_key = 公钥证书 # 公钥
private_key = 私钥证书 # 钥私
wechat_certificate = 平台证书 # 平台证书
pem微信支付公钥 = 微信支付公钥
mchid = "1700383419" # 江苏六果科技有限公司商户号(微信支付商户号)
serial_no = "530160D54E8F56726F506DEE40D7FA49A558E8E0" # 江苏六果科技有限公司 商户证书序列号
appsecret = "8691f774e3c0c5a876b21a3e84109ef0" # 未生成 微信支付=>小程序密钥(小程序注册)
@@ -31,6 +34,7 @@ class sixpay六果科技公司:
appid = "wxf612e825377328f0"
get_method = "GET" # 请求方法常量
post_method = "POST" # 请求方法常量 wechatPay
微信支付公钥ID = "PUB_KEY_ID_0117003834192026080500181856002000"
class sixWeCom企业微信:
@@ -43,4 +47,3 @@ class sixWeCom企业微信:
if __name__ == "__main__":
pass
print(私钥证书)
@@ -4,18 +4,14 @@ import django
from sixGuoDjango.settings import 项目名称
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{项目名称}.settings")
django.setup()
from pathlib import Path
from django.conf import settings
六果服务商平台证书 = Path(settings.BASE_DIR).joinpath(
"wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技服务商平台证书.pem").read_text()
"wechat_微信支付证书/江苏六果科技服务商支付证书/六果服务商平台证书.pem").read_text()
六果服务商商户公钥证书 = Path(settings.BASE_DIR).joinpath(
"wechat_微信支付证书/江苏六果科技服务商支付证书/商户公钥.pem").read_text()
六果服务商商户私钥证书 = Path(settings.BASE_DIR).joinpath(
@@ -22,11 +22,12 @@ class 商品接口ViewSets(ViewSet):
httpResData = BaseResponse(resData=ResData(listData=goodsDataList, dictData={}), ).model_dump()
return Response(data=httpResData, status=status.HTTP_200_OK)
@action(detail=False, methods=["get", "post", "put", "delete"], url_path="赢免单商品")
def 添加商品数据(self, request: Request):
@action(detail=False, methods=["post", ], url_path="赢免单商品")
def 赢免单商品(self, request: Request):
pass
赢免单商品数据 = Goods.objects.filter(goods_商品销售场景=goods商品Choices.赢免单.value).first()
data = model_to_dict(instance=赢免单商品数据, fields=None, exclude=None)
print("赢免单,商品查询没有结果了吗", data)
return Response(data=data)
@action(detail=False, methods=["post"], url_path="query")
@@ -50,9 +51,6 @@ class 商品接口ViewSets(ViewSet):
@action(detail=False, methods=["post"], url_path="add_goods")
def 添加商品接口(self, request: Request):
""""""
return
self_user_unionid = request.data.get("self_user_unionid", None)
self_mini_openid = request.data.get("self_mini_openid", None)
Goods.objects.update_or_create(
goods_商品品牌="六果泡泡",
goods_商品信息={
@@ -67,37 +65,36 @@ class 商品接口ViewSets(ViewSet):
# goods_商品销售场景=goods商品Choices.商城商品.value,
goods_商品销售场景=goods商品Choices.赢免单.value,
goods_商品搜索标签=["20"],
goods_商品销售规格=[
{
"goods_商品标题": "六果泡泡 (超划算) 源自天然酵素迅速渗入衣物,99%除菌🦠一洗即净,守护健康",
"零售价格": 15200, "会员价": 14200, "销售规格": "20斤装/桶",
"单个商品订单数量": 1, "单个商品订单总金额": 14200, "商品条码": "", "单个商品实际支付价格": 14200,
"成本价": 12000, "净利润": 12200, "可选参数": ["苹果香", "熏衣草"], "商品ID": f"GOOD{ULID()}",
"推荐积分": {"企微员工": 200, "推广员": 1000},
"goods_商品详情图片": {
"主图": ["https://hudie.xiao.band/icon/six.png"],
"详情图": ["https://hudie.xiao.band/icon/six.png", "https://hudie.xiao.band/icon/six.png"],
},
"goods_sku": [
goods_商品销售规格={
"goods_商品标题": "六果泡泡 (超划算) 源自天然酵素迅速渗入衣物,99%除菌🦠一洗即净,守护健康",
"零售价格": 8000, "会员价": 7000, "销售规格": "20斤装/桶",
"单个商品订单数量": 1, "单个商品订单总金额": 14200, "商品条码": "", "单个商品实际支付价格": 7000,
"成本价": 12000, "净利润": 12200, "可选参数": ["苹果香", "熏衣草"], "商品ID": f"GOOD{ULID()}",
"推荐积分": {"企微员工": 1000, "推广员": 5000},
"goods_商品详情图片": {
"主图": ["https://hudie.xiao.band/icon/six.png"],
"详情图": ["https://hudie.xiao.band/icon/six.png", "https://hudie.xiao.band/icon/six.png"],
},
"goods_sku": {
"goods_select_title": "开启衣物芬芳之旅",
"goods_sku_list": [
{
"goods_sku_id": f"{ULID()}",
"goods_select_title": "开启衣物芬芳之旅",
"goods_sku_list": [
{
"goods_sku_name": "西瓜", "goods_是否默认选择": True,
"goods_sku_主图": ["https://hudie.xiao.band/icon/six.png"],
"goods_sku_详情图": ["https://hudie.xiao.band/icon/six.png", "https://hudie.xiao.band/icon/six.png"],
},
{
"goods_sku_name": "桔子", "goods_是否默认选择": False,
"goods_sku_主图": ["https://hudie.xiao.band/icon/six.png"],
"goods_sku_详情图": ["https://hudie.xiao.band/icon/six.png", "https://hudie.xiao.band/icon/six.png"],
},
],
"goods_sku_条形码": f"",
"goods_sku_name": "苹果香型", "goods_是否默认选择": True,
"goods_sku_主图": ["https://hudie.xiao.band/icon/six.png"],
"goods_sku_详情图": ["https://hudie.xiao.band/icon/six.png", "https://hudie.xiao.band/icon/six.png"],
},
{
"goods_sku_id": f"{ULID()}",
"goods_sku_条形码": f"",
"goods_sku_name": "桔子香型", "goods_是否默认选择": False,
"goods_sku_主图": ["https://hudie.sixgou.com/%E5%85%AD%E6%9E%9C%E6%B3%A1%E6%B3%A1%E4%BA%A7%E5%93%81%E5%9B%BE.png"],
"goods_sku_详情图": ["https://hudie.xiao.band/icon/six.png", "https://hudie.xiao.band/icon/six.png"],
},
],
},
],
},
goods_商家推荐标签=["厂家直销", "独家配方", "自产自销", "量大实惠", "品质保证"],
)
httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump()
@@ -105,4 +102,4 @@ class 商品接口ViewSets(ViewSet):
商品接口ViewSetsRouter = DefaultRouter()
商品接口ViewSetsRouter.register(prefix="", viewset=商品接口ViewSets, basename="")
商品接口ViewSetsRouter.register(prefix="", viewset=商品接口ViewSets, basename="商品接口ViewSets")
@@ -1,112 +1,90 @@
import secrets
import jmespath
import orjson
import pydash
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
from rest_framework.routers import DefaultRouter
from rest_framework.viewsets import ViewSet
from ulid import ULID
from sixGuoDjango import ResData, BaseResponse
from wechat_数据库.支付订单数据库.商品订单数据 import order订单
from sixGuoDjango import BaseResponse, ResData
from wechat_微信支付证书.江苏六果科技有限公司支付证书.六果公司支付类 import sixWechatPay六果泡泡支付
from wechat_数据库.雪花算法.雪花算法工具 import generator
from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay
class 微信支付ViewSets(ViewSet):
notify_url回调地址 = "https://xiao.sixgou.com/demopay/jsapi_callback/"
class 微信支付ViewSets( ViewSet ):
@action( detail=False, methods=[ "post" ], url_path="jsapi" )
def 小程序支付jsapi( self, request: Request ) -> Response:
@action(detail=False, methods=["post"], url_path="jsapi")
def 小程序支付jsapi(self, request: Request) -> Response:
""""""
url_pay = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi" # 发起请求的链接
self_mini_openid = request.data.get( "self_mini_openid", False ) #
order商品数据 = request.data.get( "order商品数据", None )
order用户配送地址 = request.data.get( "order用户配送地址", None )
order商品数量 = request.data.get( "order商品数量", None )
order商品总价 = request.data.get( "order商品总价", None )
order商品ID = request.data.get( "order商品ID", None )
share订单分享者ID = request.data.get( "share订单分享者ID", None ) # 当前是否有上级对象
order订单类型 = request.data.get( "order订单类型", None )
superior_unionid = request.data.get( "superior_unionid", None ) # 当前是否有上级对象
out_trade_no = f"{generator.generate_id( )}"
print( self_mini_openid, "我的id拿不到了吗", order商品数据 )
body = {
"mchid": paymentCategory.mchid, # 【直连商户号】 直连商户号
self_mini_openid = request.data.get("self_mini_openid", False) #
out_trade_no = f"{ULID()}"
body_支付数据 = {
"mchid": sixWechatPay六果泡泡支付().mchid, # 【直连商户号】 直连商户号
"out_trade_no": out_trade_no, # 【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
"appid": paymentCategory.appid, # 【公众号 或者 小程序ID】
"appid": sixWechatPay六果泡泡支付().appid, # 【公众号 或者 小程序ID】
"description": "测试支付接口", # 【商品描述】 商品描述要
"notify_url": "https://xiao.sixgou.com/demopay/jsapi_callback/", # 回调地址要
"amount": {
"total": 1, # 【总金额】 订单总金额,单位为分。
"currency": "CNY", # 【货币类型】 CNY:人民币,境内商户号仅支持人民币。
}, # 【支付者】 支付者信息。
"attach": orjson.dumps( { "share订单分享者ID": share订单分享者ID }, option=orjson.OPT_SORT_KEYS, ).decode( encoding="utf-8" ),
"payer": {
# "openid": "ohQkD7A-N93kljcFmkCyG6e_D9vg", # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取
"openid": self_mini_openid, # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取
},
} # 请求的数据
wechat_data = wechatPay( payment=paymentCategory ).getpay_jsapi( uri=url_pay, body_data=body, method="POST" )
print( wechat_data )
payData = jmespath.search( data=wechat_data, expression="response" )
order订单.objects.create( order支付商家侧订单号=out_trade_no,
order商品总价=order商品总价, order商品数据=order商品数据, order商品数量=order商品数量,
order商品ID=order商品ID, order支付数据=body, order支付状态="支付中", order订单类型=order订单类型,
order支付都ID=self_mini_openid, order用户配送地址=order用户配送地址,
)
httpResData = BaseResponse( resData=ResData( listData=[ "" ], dictData=payData ), ).model_dump( )
return Response( data=httpResData, status=status.HTTP_200_OK )
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)
@action( detail=False, methods=[ "post" ], url_path="navite" )
def 二维码支付( self, request: WSGIRequest | Request ) -> Response:
@action(detail=False, methods=["post"], url_path="navite")
def 二维码支付(self, request: WSGIRequest | Request) -> Response:
"""
生成收款的二维码链接,可以让用户来扫码支付
:param request:
:return:
"""
out_trade_no = f"{generator.generate_id( )}"
out_trade_no商家侧订单号 = f"{ULID()}"
native_url = "https://api.mch.weixin.qq.com/v3/pay/transactions/native"
native_body = {
"mchid": paymentCategory.mchid, # 服务商户号
"out_trade_no": out_trade_no, # 商户系统内部订单号
"appid": paymentCategory.appid, # 服务商应用ID
"mchid": sixWechatPay六果泡泡支付().mchid, # 服务商户号
"out_trade_no": out_trade_no商家侧订单号, # 商户系统内部订单号
"appid": sixWechatPay六果泡泡支付().appid, # 服务商应用ID
"description": "测试", # 商品的描述信息
"notify_url": "https://server.xiao.band/demopay/callback_navite/", # 回调地址
"amount": { "total": 1, "currency": "CNY" },
"notify_url": "https://xiao.sixgou.com/demopay/callback_navite/", # 回调地址
"amount": {"total": 1, "currency": "CNY"},
}
res_data = wechatPay( payment=paymentCategory ).getpay_navite( navite_body=native_body )
print( res_data )
code_url = jmespath.search( data=res_data, expression="code_url" )
print( code_url )
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)
import segno
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, )
qr = segno.make_qr( content="------", )
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, )
@action( detail=False, methods=[ "post" ], url_path="qrCode" )
def 付款码支付( self, request: Request ):
@action(detail=False, methods=["post"], url_path="qrCode")
def 付款码支付(self, request: Request):
"""
扫用户付款码的测试接口
:param request:
"""
nonce_str = secrets.token_hex( 10 ) # 随机字符串
order_random = f"{generator.generate_id( )}"
auth_code = request.data.get( "auth_code", False ) # 前端扫码读取的付款码的数据信息
nonce_str = secrets.token_hex(10) # 随机字符串
order_random = f"{generator.generate_id()}"
auth_code = request.data.get("auth_code", False) # 前端扫码读取的付款码的数据信息
# auth_code = "123497182327333282" # TODO 扫码支付付款码,设备读取用户微信中的条码或者二维码信息(这个值需要小程序端,扫码,将数据传递进来)
# fu_kuan_data 是微信官方要求组装的数据类型
fu_kuan_data = {
@@ -118,72 +96,95 @@ class 微信支付ViewSets( ViewSet ):
"auth_code": auth_code,
"total_fee": 1, # 订单总金额,单位为分,只能为整数,详见支付金额(必填)
}
wechat_data = wechatPay( payment=paymentCategory ).getpay_code扫用户付款码( body_data=fu_kuan_data )
print( wechat_data )
wechat_data = wechatPay(payment=paymentCategory).getpay_code扫用户付款码(body_data=fu_kuan_data)
print(wechat_data)
# return_code 通信返回码:'SUCCESS' 表示与微信服务器通信成功,'FAIL' 表示通信失败(如网络或参数错误)
return_code = jmespath.search( data=wechat_data, expression="xml.return_code" )
return_code = jmespath.search(data=wechat_data, expression="xml.return_code")
# return_msg 通信返回信息:当 return_code 为 'FAIL' 时,此字段包含错误描述;成功时通常为 'OK'
return_msg = jmespath.search( data=wechat_data, expression="xml.return_msg" )
return_msg = jmespath.search(data=wechat_data, expression="xml.return_msg")
# result_code 业务结果码:'SUCCESS' 表示支付成功,'FAIL' 表示支付失败(需结合 err_code 分析,但此处未提取)
result_code = jmespath.search( data=wechat_data, expression="xml.result_code" )
result_code = jmespath.search(data=wechat_data, expression="xml.result_code")
# mch_id 商户号(MCH ID):微信支付分配给商户的唯一标识
mch_id = jmespath.search( data=wechat_data, expression="xml.mch_id" )
mch_id = jmespath.search(data=wechat_data, expression="xml.mch_id")
# appid 公众号或小程序的 AppID:发起支付的应用身份标识
appid = jmespath.search( data=wechat_data, expression="xml.appid" )
appid = jmespath.search(data=wechat_data, expression="xml.appid")
# nonce_str 随机字符串:用于防止重放攻击,由商户生成并随请求发送,微信原样返回
nonce_str = jmespath.search( data=wechat_data, expression="xml.nonce_str" )
nonce_str = jmespath.search(data=wechat_data, expression="xml.nonce_str")
# openid 用户在当前 AppID 下的唯一标识(OpenID):可用于关联用户账户
openid = jmespath.search( data=wechat_data, expression="xml.openid" )
openid = jmespath.search(data=wechat_data, expression="xml.openid")
# total_fee 订单总金额(单位:分):例如 '1' 表示 0.01 元
total_fee = jmespath.search( data=wechat_data, expression="xml.total_fee" )
total_fee = jmespath.search(data=wechat_data, expression="xml.total_fee")
# cash_fee_type 现金支付币种:目前微信支付仅支持 'CNY'(人民币)
cash_fee_type = jmespath.search( data=wechat_data, expression="xml.cash_fee_type" )
cash_fee_type = jmespath.search(data=wechat_data, expression="xml.cash_fee_type")
# transaction_id 微信支付系统生成的唯一交易单号:用于对账、退款、查询等操作
transaction_id = jmespath.search( data=wechat_data, expression="xml.transaction_id" )
transaction_id = jmespath.search(data=wechat_data, expression="xml.transaction_id")
# 商户系统内部订单号:由商户在调用支付接口时传入,用于关联自身业务订单
out_trade_no = jmespath.search( data=wechat_data, expression="xml.out_trade_no" )
out_trade_no = jmespath.search(data=wechat_data, expression="xml.out_trade_no")
# 附加数据:商户在支付请求中可自定义传入,微信原样返回(常用于传递门店ID、商品类型等)
attach = jmespath.search( data=wechat_data, expression="xml.attach" )
attach = jmespath.search(data=wechat_data, expression="xml.attach")
# time_end 支付完成时间:格式为 yyyyMMddHHmmss,例如 '20260304233708' 表示 2026年03月04日 23:37:08
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 )
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)
@action( detail=False, methods=[ "post" ], url_path="jsapi_callback" )
def jsapi支付回调测试接口( self, request: Request ) -> Response:
@action(detail=False, methods=["post"], url_path="jsapi_callback")
def jsapi支付回调测试接口(self, request: Request) -> Response:
""" 微信支付成功后的回调接口 """
dict_body = request.data
wechat_data支付回调数据 = wechatPay( payment=paymentCategory ).callBack回调解密( headers=request.headers, response_body=dict_body, )
print( "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", wechat_data支付回调数据, "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n" )
out_trade_no = jmespath.search( data=wechat_data支付回调数据, expression="out_trade_no" )
trade_state_desc = pydash.get( obj=wechat_data支付回调数据, path="trade_state_desc" )
self_mini_openid = pydash.get( obj=wechat_data支付回调数据, path="payer.openid" )
# 调用异步方法 : 作用 (发起订单录入接口调用)
# 更新 拼团订单的 支付状态
生成物流的订单号 = generator.generate_str( )
order订单.objects.filter( order支付商家侧订单号=out_trade_no ).update( order支付数据=wechat_data支付回调数据, order支付状态=trade_state_desc,
order物流状态=order订单.order订单choosies物流状态.待发货.value, order物流订单号=生成物流的订单号
)
# 在这里还需要处理是否给上级添加积分
share订单分享者ID = pydash.get( obj=orjson.loads( pydash.get( obj=wechat_data支付回调数据, path="attach" ) ), path="share订单分享者ID" )
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 )
httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump()
return Response(data=httpResData, status=status.HTTP_200_OK)
@action( detail=False, methods=[ "post" ], url_path="callback_navite" )
def 二维码支付回调( self, request: WSGIRequest | Request ):
@action(detail=False, methods=["post"], url_path="callback_navite")
def 二维码支付回调(self, request: Request):
"""注释"""
二维码支付回调数据 = wechatPay( payment=paymentCategory ).callBack回调解密( headers=request.headers, response_body=request.body, )
print( "二维码支付回调数据=>::", 二维码支付回调数据 )
return Response( data={ "msg": "success" } )
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={})
微信支付ViewSetsRouter = DefaultRouter( )
微信支付ViewSetsRouter.register( prefix="", viewset=微信支付ViewSets, basename="" )
@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={})
@@ -1,80 +0,0 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from uuid6 import uuid8
from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name
from wechat_数据库.雪花算法.雪花算法工具 import generator
class WechatTransferOrder(models.Model):
"""
微信商家转账订单记录表
用于存储发起请求参数、微信返回的中间状态以及最终回调结果
"""
# === 核心业务字段 ===
# 商户单据号 (发起时生成,全局唯一)
class TransferOrderState(models.TextChoices):
"""
商家转账订单状态枚举
涵盖发起时的中间状态和回调时的终态
"""
# --- 中间状态 (非终态) ---
ACCEPTED = "ACCEPTED", _("已受理 (可原单重试)")
PROCESSING = "PROCESSING", _("资金锁定中")
WAIT_USER_CONFIRM = "WAIT_USER_CONFIRM", _("待用户确认")
TRANSFERING = "TRANSFERING", _("转账中")
CANCELING = "CANCELING", _("撤销中")
# --- 终态 ---
SUCCESS = "SUCCESS", _("转账成功")
FAIL = "FAIL", _("转账失败")
CANCELLED = "CANCELLED", _("已撤销")
id_主键_转账 = models.UUIDField(primary_key=True, default=uuid8, editable=True, )
id_str = models.CharField(max_length=128, default=generator.generate_str)
out_bill_no = models.CharField(max_length=120)
# 微信转账单号 (回调时返回,发起时可能为空或为预生成值)
transfer_bill_no = models.CharField(max_length=64, db_comment="微信转账单号", blank=True, null=True, )
# 订单状态
state = models.CharField(max_length=32, choices=TransferOrderState, )
# 转账金额 (单位:分)
transfer_amount = models.IntegerField(db_comment="转账金额(分)", )
# 收款用户 OpenID
openid = models.CharField(max_length=64, db_comment="收款用户OpenID", blank=True, null=True, )
# 商户号
mch_id = models.CharField(max_length=32, db_comment="商户号", blank=True, null=True, )
# === 异常与扩展字段 ===
# 失败原因 (仅在 state=FAIL 时有值)
fail_reason = models.CharField(max_length=128, db_comment="失败原因代码", blank=True, null=True, )
# 失败详细描述 (可选,如果需要存储更详细的错误信息)
fail_message = models.TextField(db_comment="失败详细描述", blank=True, null=True)
# 加密包信息 (发起时返回,用于特定场景下的重试或解密)
package_info = models.TextField(db_comment="加密包信息", blank=True, null=True, )
# === 时间字段 ===
# 微信返回的创建时间 (发起接口返回的 create_time)
wx_create_time = models.DateTimeField(db_comment="微信单据创建时间", null=True, blank=True)
# 微信返回的更新时间 (回调接口返回的 update_time)
wx_update_time = models.DateTimeField(db_comment="微信单据更新时间", null=True, blank=True)
# 业务创建时间 (本地记录创建时间)
created_at = models.DateTimeField(auto_now_add=True, db_comment="本地创建时间")
# 本地最后更新时间 (每次状态变更自动更新)
updated_at = models.DateTimeField(auto_now=True, db_comment="本地最后更新时间")
class Meta:
db_table = "WechatTransferOrder" # 给数据表自定义一个名称;默认的会是在 应用名+类名
# 联合索引优化查询:常按状态和创建时间查询
app_label = models_app_name
@@ -49,31 +49,3 @@ class order订单(models.Model):
ordering = ["-id_主键_order订单"]
class order订单商品数据(models.Model):
"""城市信息表"""
objects = models.Manager() #
order订单商品数_id = models.UUIDField(primary_key=True, default=uuid8)
order_id_str = models.CharField(max_length=128, default=generator.generate_str)
order_id商品 = models.CharField(max_length=128, default=generator.generate_str)
order_订单数量 = models.IntegerField(null=True, blank=True)
order订单总金额 = models.IntegerField(null=True, blank=True)
order_商品品牌 = models.CharField(max_length=128, )
order_商品标题 = models.CharField(max_length=128, )
order_商品信息 = models.JSONField(null=True, blank=True)
order_商品标签 = models.JSONField(null=True, blank=True)
order_商品详情图片 = models.JSONField(null=True, blank=True)
order_商品销售规格 = models.JSONField(null=True, blank=True, )
order_商品销售场景 = models.CharField(max_length=128, choices=goods商品Choices, null=True, blank=True,
default=goods商品Choices.商城商品.value)
order_分享积分 = models.JSONField(null=True, blank=True, )
order_商品搜索标签 = models.JSONField(null=True, blank=True, )
order_商家推荐标签 = models.JSONField(null=True, blank=True, )
order_其它参数 = models.JSONField(null=True, blank=True)
wai_订单 = models.ForeignKey(to=order订单, on_delete=models.CASCADE, null=True, blank=True)
dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间
updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() )
class Meta:
db_table = "order订单商品数据" # 给数据表自定义一个名称;默认的会是在 应用名+类名
app_label = models_app_name
@@ -0,0 +1,21 @@
from django.db import models
from ulid import ULID
from uuid6 import uuid8
from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name
class wei客服账号(models.Model):
"""城市信息表"""
objects = models.Manager() #
kefu_id = models.UUIDField(primary_key=True, default=uuid8)
extInfo_推广员账号链接 = models.CharField(max_length=128, db_comment="企微客服账号链接")
extInfo_企微员工绑定的UNIONID = models.CharField(max_length=128, db_comment="企微客服绑定的小程序unionid")
extInfo_企微员工的名称 = models.CharField(max_length=128, null=True, blank=True, )
dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间
updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() )
class Meta:
db_table = "wei客服账号" # 给数据表自定义一个名称;默认的会是在 应用名+类名
app_label = models_app_name
@@ -1,4 +1,7 @@
import time
from datetime import datetime
from typing import Literal, Optional
from zoneinfo import ZoneInfo
import emoji
import orjson
@@ -6,7 +9,6 @@ import pydash
import requests
from django.forms import model_to_dict
from pydantic import BaseModel, Field
from ulid import ULID
from django_celery.message.tasks import mini调用微信小程序交易管理服务录入订单接口
from wechat_token.token工具包 import sixToken
@@ -192,43 +194,43 @@ class ems邮政物流工具(BaseModel):
order当前订单对象.order物流订单号 = order订单对象.order物流订单号
order当前订单对象.order物流公司订单编号 = waybill_id
order当前订单对象.save()
print(data.json())
print("生成运单成功时的打印", data.json())
# 这里的作用是, 当订单生成了 就调用 小程序交易管理的发货管理接口, 自动录入订单号
mini调用微信小程序交易管理服务录入订单接口.apply_async(kwargs={"order支付商家侧订单号": order当前订单对象.order支付商家侧订单号}, countdown=30)
def 模拟更新订单状态(self, order物流商家侧订单号):
def 模拟更新订单状态(self, order物流公司订单编号, action_type, action_msg):
""""""
order物流对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号)
mini_token = sixToken.get_mini_token()
milliseconds_int = ULID().milliseconds
模拟更新物流状态 = f"https://api.weixin.qq.com/cgi-bin/express/business/test_update_order?access_token={mini_token}"
utc_unix_timestamp = int(datetime.now(tz=ZoneInfo("utc")).timestamp())
模拟数据 = {
"biz_id": self.ems_biz_id,
"order_id": order物流商家侧订单号, # 商家生成的订单号
"order_id": order物流对象.order物流订单号, # 商家生成的订单号
"delivery_id": self.ems_delivery_id, #
"waybill_id": "", # 物流订单号
"action_time": milliseconds_int, # 这里是更新发的时间戳
"action_type": 100001,
"action_msg": "揽件成功",
"waybill_id": order物流公司订单编号, # 物流订单号
"action_time": utc_unix_timestamp, # 这里是更新发的时间戳
"action_type": action_type,
"action_msg": action_msg,
}
print("打印 一下模拟的数据,主要就是看一下时间戳的问题", 模拟数据)
data = requests.post(url=模拟更新物流状态,
data=orjson.dumps(模拟数据, option=orjson.OPT_SORT_KEYS, ).decode(encoding="utf-8"))
print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json())
def 查询运单轨迹(self, order物流商家侧订单号):
""""""
查询对象 = order订单.objects.get(order物流订单号=order物流商家侧订单号, )
print(查询对象)
mini_token = sixToken.get_mini_token()
def 更新物流快递数据(self, order物流公司订单编号, order物流订单号):
def 更新物流快递数据(self, order物流公司订单编号, ):
""""""
查询对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号, order物流订单号=order物流订单号)
查询对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号, )
mini_token = sixToken.get_mini_token()
emsGetPathData = requests.post(url="https://api.weixin.qq.com/cgi-bin/express/business/path/get",
params={"access_token": mini_token, },
json={
"openid": 查询对象.order支付者openid,
"delivery_id": self.ems_delivery_id, "waybill_id": 查询对象.order物流公司订单编号,
"delivery_id": self.ems_delivery_id, "waybill_id": order物流公司订单编号,
},
)
resData = orjson.loads(emsGetPathData.content.decode(encoding="utf-8"))
@@ -299,4 +301,11 @@ class ems邮政物流工具(BaseModel):
if __name__ == "__main__":
# 当脚本直接运行时执行的代码
ems邮政物流工具().生成运单(out_trade_no商家侧支付订单号="")
# ems邮政物流工具().生成运单(out_trade_no商家侧支付订单号="")
ems邮政物流工具().模拟更新订单状态(order物流公司订单编号="EMS01KZAH47JZA3HCY2R5NS0WD3VN_waybill_id", action_type=100001, action_msg="揽件成功")
time.sleep(30)
ems邮政物流工具().模拟更新订单状态(order物流公司订单编号="EMS01KZAH47JZA3HCY2R5NS0WD3VN_waybill_id", action_type=300002, action_msg="开始派送")
time.sleep(30)
ems邮政物流工具().模拟更新订单状态(order物流公司订单编号="EMS01KZAH47JZA3HCY2R5NS0WD3VN_waybill_id", action_type=300003, action_msg="签收成功")
# ems邮政物流工具().更新物流快递数据(order物流公司订单编号="EMS01KZAD94RDQFQBVVX705YNH6SE_waybill_id")
@@ -5,9 +5,8 @@ import django
from sixGuoDjango.settings import BASE_DIR
from wechat_token.token工具包 import sixToken
os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings" )
django.setup( )
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings")
django.setup()
from pathlib import Path
@@ -15,23 +14,18 @@ import pydash
import requests
from django.conf import settings
from requests import post
class wecom消息推送:
pass
@classmethod
def 上传图片文件( cls ):
def 上传图片文件(cls):
uri = ''
filePath = Path( settings.BASE_DIR ).joinpath( "django_static_directory/media/app.png" )
data = requests.post( url=uri, files={ "media": open( file="文件路径", mode="rb", ) } )
filePath = Path(settings.BASE_DIR).joinpath("django_static_directory/media/app.png")
data = requests.post(url=uri, files={"media": open(file="文件路径", mode="rb", )})
@classmethod
def 欢迎语类型IMG( cls ):
def 欢迎语类型IMG(cls):
pass
IMG = {
"msgtype": "link",
@@ -45,7 +39,7 @@ class wecom消息推送:
return IMG
@classmethod
def 欢迎语类型小程序( cls ):
def 欢迎语类型小程序(cls):
pass
miniprogram = {
"msgtype": "miniprogram", # 附件类型,可选image、link、miniprogram或者video
@@ -60,7 +54,7 @@ class wecom消息推送:
return miniprogram
@classmethod
def 欢迎语类型LINK( cls ):
def 欢迎语类型LINK(cls):
"""
欢迎语类型LINK
"""
@@ -73,7 +67,7 @@ class wecom消息推送:
}
@classmethod
def 欢迎语类型VIDEO( cls ):
def 欢迎语类型VIDEO(cls):
pass
VIDEO = {
"msgtype": "video",
@@ -84,9 +78,9 @@ class wecom消息推送:
return VIDEO
@classmethod
def 创建企业群发( cls ):
def 创建企业群发(cls):
pass
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_msg_template"
json_data = {
"chat_type": "single",
@@ -106,30 +100,26 @@ class wecom消息推送:
},
],
}
data = post(
url=url, json=json_data, params={
"access_token": wecom_token,
},
)
print( data.json( ) )
data = requests.post(url=url, json=json_data, params={"access_token": wecom_token, }, )
print(data.json())
@classmethod
def 提醒成员群发( cls ):
def 提醒成员群发(cls):
"""
提醒成员群发
"""
pass
@classmethod
def 停止企业群发( cls ):
def 停止企业群发(cls):
pass
@classmethod
def 发送新客户欢迎语( cls, CALLBACK_CODE: str ):
""""""
wecom_token = sixToken.get_wecom_token( )
def 发送新客户欢迎语(cls, CALLBACK_CODE: str):
"""发送客户添加好友时的 欢迎语 """
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/send_welcome_msg?access_token={wecom_token}"
miniprogram = cls.欢迎语类型小程序( )
miniprogram = cls.欢迎语类型小程序()
json_data = {
"welcome_code": CALLBACK_CODE,
"text": {
@@ -150,15 +140,12 @@ class wecom消息推送:
""",
},
}
data = post( url=url, json=json_data )
print( "客户欢迎语发送成功了:", data.json( ) )
errcode = pydash.get( obj=data.json( ), path="errcode" )
data = requests.post(url=url, json=json_data)
print("客户欢迎语发送成功了:", data.json())
errcode = pydash.get(obj=data.json(), path="errcode")
if errcode == 41051:
pass
return data.json( ).get( "errmsg" )
return data.json().get("errmsg")
class wecom获取企业的全部群发记录:
@@ -174,13 +161,13 @@ class wecom获取企业的全部群发记录:
"""
@classmethod
def 获取群发记录列表( cls ):
def 获取群发记录列表(cls):
"""
企业和第三方应用可通过此接口获取企业与成员的群发记录。
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_list_v2?access_token={wecom_token}"
请求数据示例 = {
"chat_type": "single",
@@ -191,29 +178,28 @@ class wecom获取企业的全部群发记录:
"limit": 50,
"cursor": "CURSOR"
}
data = post( url=url, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=url, json=请求数据示例).json()
print(data)
@classmethod
def 获取群发成员发送任务列表( cls ):
def 获取群发成员发送任务列表(cls):
"""
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_task?access_token={wecom_token}"
请求数据示例 = { "msgid": "msgGCAAAXtWyujaWJHDDGi0mACAAAA", "limit": 50, "cursor": "CURSOR" }
data = post( url=url, json=请求数据示例 ).json( )
print( data )
请求数据示例 = {"msgid": "msgGCAAAXtWyujaWJHDDGi0mACAAAA", "limit": 50, "cursor": "CURSOR"}
data = requests.post(url=url, json=请求数据示例).json()
print(data)
@classmethod
def 获取企业群发成员执行结果( cls ):
def 获取企业群发成员执行结果(cls):
"""
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_send_result?access_token={wecom_token}"
请求数据示例 = {
"msgid": "msgGCAAAXtWyujaWJHDDGi0mACAAAA",
@@ -221,11 +207,8 @@ class wecom获取企业的全部群发记录:
"limit": 50,
"cursor": "CURSOR"
}
data = post( url=url, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=url, json=请求数据示例).json()
print(data)
class wecom入群欢迎语素材管理:
@@ -235,8 +218,8 @@ class wecom入群欢迎语素材管理:
"""
@classmethod
def 添加入群欢迎语素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 添加入群欢迎语素材(cls):
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/add?access_token={wecom_token}"
请求数据示例 = {
"text": {
@@ -267,12 +250,12 @@ class wecom入群欢迎语素材管理:
"agentid": 1000014,
"notify": 1
}
data = post( url=url, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=url, json=请求数据示例).json()
print(data)
@classmethod
def 编辑入群欢迎语素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 编辑入群欢迎语素材(cls):
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/edit?access_token={wecom_token}"
请求数据示例 = {
"template_id": "msgXXXXXXX",
@@ -303,41 +286,38 @@ class wecom入群欢迎语素材管理:
},
"agentid": 1000014
}
data = post( url=uri, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=uri, json=请求数据示例).json()
print(data)
@classmethod
def 获取入群欢迎语素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 获取入群欢迎语素材(cls):
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/get?access_token={wecom_token}"
请求数据示例 = {
"template_id": "msgXXXXXXX"
}
data = post( url=uri, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=uri, json=请求数据示例).json()
print(data)
@classmethod
def 删除入群欢迎语素材( cls ):
def 删除入群欢迎语素材(cls):
"""
删除入群欢迎语素材
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/del?access_token={wecom_token}"
请求数据示例 = {
"template_id": "msgXXXXXXX",
"agentid": 1000014
}
data = post( url=uri, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=uri, json=请求数据示例).json()
print(data)
class uploadTempMedia上传附件资源:
@classmethod
def upload_file( cls ):
def upload_file(cls):
"""
参数 必须 说明
access_token 是 调用接口凭证
@@ -346,35 +326,29 @@ class uploadTempMedia上传附件资源:
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload_attachment?access_token={wecom_token}&media_type=image&attachment_type=1"
params = { "access_token": wecom_token, "media_type": "image", "attachment_type": "1" }
file_path = Path( settings.BASE_DIR ).joinpath( "django_环境/常用类/xiao小程序项目图片/ico运力管理系统.png" )
print( file_path )
file = { "media": open( file=file_path, mode="rb", ) }
params = {"access_token": wecom_token, "media_type": "image", "attachment_type": "1"}
file_path = Path(settings.BASE_DIR).joinpath("django_环境/常用类/xiao小程序项目图片/ico运力管理系统.png")
print(file_path)
file = {"media": open(file=file_path, mode="rb", )}
data = post( url=uri, files=file )
media_id = pydash.get( obj=data.json( ), path="media_id" )
print( media_id )
data = requests.post(url=uri, files=file)
media_id = pydash.get(obj=data.json(), path="media_id")
print(media_id)
@classmethod
def 上传临时素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 上传临时素材(cls):
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={wecom_token}&type=image"
# file_path = Path(settings.BASE_DIR).joinpath("django_环境/常用类/xiao小程序项目图片/ico运力管理系统.png")
file_path = Path( settings.BASE_DIR ).joinpath( "django_环境//常用类/xiao小程序项目图片/莫大帅分享主图.png" )
print( file_path )
file = { "media": open( file=file_path, mode="rb", ) }
data = post( url=uri, files=file )
media_id = pydash.get( obj=data.json( ), path="media_id" )
print( data.json( ) )
print( media_id )
file_path = Path(settings.BASE_DIR).joinpath("django_环境/常用类/xiao小程序项目图片/莫大帅分享主图.png")
file = {"media": open(file=file_path, mode="rb", )}
data = requests.post(url=uri, files=file)
media_id = pydash.get(obj=data.json(), path="media_id")
print(data.json())
print(media_id)
if __name__ == '__main__':
pass
uploadTempMedia上传附件资源.上传临时素材( )
uploadTempMedia上传附件资源.上传临时素材()
@@ -16,6 +16,13 @@ class miniTransaction交易管理服务工具(BaseModel):
# demo_可选: Optional[int] = None # 可选值
# demo_默认值: int = Field(default=100001, description="描述") # 有默认值
# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述")
def 消息跳转路径设置(self, ):
"""如你已经在小程序内接入平台提供的确认收货组件,可以通过该接口设置发货消息及确认收货消息的跳转动作,
用户点击发货消息时会直接进入你的小程序订单列表页面或详情页面进行确认收货,进一步优化用户体验"""
pass
mini_token = sixToken.get_mini_token()
uri = f"https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path?access_token={mini_token}"
def 发货信息录入(self, order支付商家侧订单号, ):
pass
print("开始调用录入订单信息了")
@@ -73,6 +80,7 @@ class miniTransaction交易管理服务工具(BaseModel):
"""这里的调用的时机为: 目前的业务逻辑是,物流的状态更新用户已签收了 , 我会在此时调用户确认接口 用户会收得到一个 确认收货的提示"""
mini_token = sixToken.get_mini_token()
uri = f"https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive?access_token={mini_token}"
print("发起确认交易调用了")
# 快递签收时间设定为 2026-07-24 04:11:24
action_time_签收时间戳 = pydash.get(obj=pydash.head(order物流数据), path="action_time")
data = {
@@ -80,10 +88,12 @@ class miniTransaction交易管理服务工具(BaseModel):
"received_time": action_time_签收时间戳, # 快递签收时间,时间戳形式,必传
}
postData = requests.post(url=uri, json=data)
print(postData.json())
# 当请求发送后, 因为只能发送一次,所以需要直接更新状态,
更新对象 = order订单.objects.get(order支付微信官方订单号=order支付微信官方订单号)
更新对象.order物流状态 = "待用户确认收货"
更新对象.save()
print("发起确认交易调用成功了")
if __name__ == "__main__":
@@ -11,6 +11,7 @@ import os
import django
from sixGuoDjango.settings import base_dir_name
from wechat_微信支付证书.江苏六果科技服务商支付证书.江苏六果科技有限公司服务商支付参数 import six六果服务商支付参数
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings")
django.setup()
@@ -35,8 +36,8 @@ from typing import Optional, Literal
import pydash
import xmltodict
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Hash import SHA1, SHA256
from Crypto.PublicKey import RSA
from Crypto.PublicKey.RSA import RsaKey
from Crypto.Signature import pkcs1_15
@@ -51,21 +52,13 @@ class paymentCategory(sixpay六果科技公司):
class wechatPay(BaseModel):
payment: type[paymentCategory] | type[sixpay六果科技公司]
payment: type[sixpay六果科技公司] | type[six六果服务商支付参数]
def 构造签名串(self, uri: str, body_data: dict | bytes | str | None = None,
method: Optional[Literal["GET", "POST"]] = "POST",
method: Optional[Literal["GET", "POST", "PATCH"]] = "POST",
):
"""
构造签名串
@param url:
@type url:
@param body:
@type body:
@param method:
@type method:
@return: 返回已经加密后并组装好的请求头;
@rtype:
"""
url_data = re.search(r'/v3.*', string=uri).group()
shi_jian_chou = str(int(time.time())) # 时间戳
@@ -91,7 +84,7 @@ class wechatPay(BaseModel):
# 加载商户私钥
# 调用了 RSA.import_key() 方法,它会从字符串或文件中导入一个 PEM 格式的 RSA 私钥,并返回一个 RsaKey 类型的对象
private_key: RsaKey = RSA.import_key(self.payment.private_key)
# 生成签名
# 生成签名 使用商户的 私钥进行签名
signature = pkcs1_15.new(rsa_key=private_key).sign(msg_hash=hash_obj)
# 对签名进行Base64编码,符合微信支付API要求
encoded_signature = base64.b64encode(s=signature).decode()
@@ -111,24 +104,16 @@ class wechatPay(BaseModel):
headers = {
"Content-Type": "application/json", "Authorization": Authorization,
}
# headers.update({"Wechatpay-Serial": self.payment.微信支付公钥ID})
return headers
def getpay_jsapi(self, uri, body_data: dict | bytes | str | None = None, method: Optional[
Literal["GET", "POST"]] = "POST",
):
"""
@param url: 请求支付的微信官方地址
@type url: str
@param pay_body: 小程序下单接口获取到发起支付的必要参数prepay_id
@type pay_body: str
@return:
@rtype:
"""
headers = self.构造签名串(uri=uri, body_data=body_data, method=method)
# 发送请求
response: Response = requests.post(url=uri, json=body_data, headers=headers)
print(response.json())
prepay_id = pydash.get(obj=response.json(), path="prepay_id", default=None)
# 验证请求后返回的数据是否为微信官方所发送;
验证签名结果 = self.验证签名串(response_data=response.json(), response_headers=response.headers)
@@ -170,6 +155,15 @@ class wechatPay(BaseModel):
回调解密数据: dict = orjson.loads(decrypted_data.decode(encoding="utf-8"))
return 回调解密数据
def modegmc解密电子发票邮箱账号(self, ciphertext):
pass
encrypted_bytes = base64.b64decode(ciphertext)
# 3. 构建 OAEP 解密器(SHA-1)
private_key: RsaKey = RSA.import_key(self.payment.private_key)
cipher = PKCS1_OAEP.new(key=private_key, hashAlgo=SHA1)
plaintext_bytes = cipher.decrypt(encrypted_bytes)
return plaintext_bytes.decode("utf-8")
def getpay_navite(self, navite_body: dict, ):
"""
@param navite_body:
@@ -316,6 +310,7 @@ class wechatPay(BaseModel):
@rtype:
"""
public_key = RSA.import_key(self.payment.wechat_certificate)
# public_key = RSA.import_key(self.payment.pem微信支付公钥)
Wechatpay_Timestamp = pydash.get(response_headers, "Wechatpay-Timestamp")
Wechatpay_Nonce = pydash.get(response_headers, "Wechatpay-Nonce")
Wechatpay_Signa = pydash.get(response_headers, "Wechatpay-Signature")
@@ -331,7 +326,6 @@ class wechatPay(BaseModel):
def v2签名返回XML(self, sign_data: dict):
"""v2版本的签名:将扫码支付的body转换为微信支付所要求的数据类型"""
# sorted_dict = dict(sorted(sign_data.items(), key=lambda item: item[0], reverse=False))
sorted_dict = dict(pydash.sort_by(collection=sign_data.items(), iteratee=0))
# 拼接字符串: (将密钥添加到最末尾)
params_str = "&".join(f"{k}={v}" for k, v in sorted_dict.items()) + '&key=' + self.payment.apiv2
@@ -397,14 +391,6 @@ class wechatPay(BaseModel):
def 解密群号(self, encryptedData, iv, sessionKey):
"""
对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
对称解密的目标密文为 Base64_Decode(encryptedData)。
对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
:param sessionKey:
:param encryptedData:
:param iv:
:return:
"""
try:
session_key_bytes = base64.b64decode(sessionKey)
@@ -447,7 +433,7 @@ class wechatPay(BaseModel):
def 发起退款(self, body):
pass
uri = f"https://api.mch.weixin.qq.com//v3/refund/domestic/refunds"
uri = f"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"
heardes = self.构造签名串(body_data=body, uri=uri, method="POST")
print(heardes)
response_data = requests.post(url=uri, json=body, headers=heardes)
@@ -29,7 +29,7 @@ class stock发送代金券功能(BaseModel):
# 第二步: 创建好需要的数据并验名
params每一张券需要验名的数据格式 = {
"out_request_no0": out_request_no, # 商家侧的发券订单号
"stock_id0": "22512292", # 代金券创建的批次号
"stock_id0": self.stock_id_代金券批次号, # 代金券创建的批次号
"send_coupon_merchant": mchid, # 发券的商家商户号
# 如果是支付券,必须包含此项并参与签名;商家券则去掉
"create_coupon_merchant0": mchid, # 发券的商家商户号
@@ -46,7 +46,7 @@ class stock发送代金券功能(BaseModel):
# 3. 拼接参数串
params = {
"out_request_no": out_request_no,
"stock_id": "22512292",
"stock_id": self.stock_id_代金券批次号,
"create_coupon_merchant": sixpay六果科技公司.mchid,
"customize_send_time": rfc3339,
"send_coupon_merchant": sixpay六果科技公司.mchid,
@@ -0,0 +1,42 @@
import requests
from pydantic import BaseModel
from yarl import URL
from wechat_微信支付证书.江苏六果科技服务商支付证书.江苏六果科技有限公司服务商支付参数 import six六果服务商支付参数
from wechat_项目工具包.微信支付工具包.微信支付类 import wechatPay
class weiPay服务商电子发票(BaseModel):
# demo_必填: int = Field(..., description="描述") # 必传属发生
# demo_可选: Optional[int] = None # 可选值
# demo_默认值: int = Field(default=100001, description="描述") # 有默认值
# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述")
def model_post_init(self, __context):
print("初始化完成,自动调用 model_post_init")
def 获取开通服务商电子发票能力邀请链接(self):
pass
uri = URL.build(
scheme='https',
host="api.mch.weixin.qq.com",
path="/v3/new-tax-control-fapiao/fapiaomerchant/getspinviteurl",
query={
"operation_type": "AUTH_BINDING",
"fapiao_mode": ["TENCENT_DIGITAL_TAX"], # 【开票模式】 邀请商户开通服务商电子发票的可选开票模式
"fapiao_ability_type_list": ["BASE_ABILITY"],
"invite_code": "code_20260805_123", # 必填 【服务商邀请code】 服务商邀请的唯一标识,由服务商生成,可根据邀请code查询邀请开通情况
# "sub_mchid": "1700383419"
"taxpayer_id":"91321202MAE608K31Q"
}
)
print(uri)
headers = wechatPay(payment=six六果服务商支付参数).构造签名串(uri=str(uri), method="GET")
headers.update({"Wechatpay-Serial":"1880A972F4400AF653A108F5F0C7A71585A4338E"})
getData = requests.get(url=uri, headers=headers)
print(getData.text)
if __name__ == "__main__":
pass
weiPay服务商电子发票().获取开通服务商电子发票能力邀请链接()
@@ -0,0 +1,135 @@
import emoji
import pydash
import requests
from pydantic import BaseModel
from ulid import ULID
from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司
from wechat_数据库.支付订单数据库.商品订单数据 import order订单
from wechat_项目工具包.微信支付工具包.微信支付类 import wechatPay
class weiPay电子发票(BaseModel):
# demo_可选: Optional[int] = None # 可选值
# demo_默认值: int = Field(default=100001, description="描述") # 有默认值
# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述")
def model_post_init(self, __context):
print("")
def 配置开发选项(self):
"""配置,小程序用户申请开票时的回调请求地址URL"""
pass
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/development-config"
http_uri = "https://xiao.sixgou.com/wechat_mini/invoice/callback/"
请求体 = {
"callback_url": http_uri,
"show_fapiao_cell": True
}
header电子发票请求头 = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, body_data=请求体, method="PATCH")
postData = requests.patch(url=uri, json=请求体, headers=header电子发票请求头)
def 获取商户开票基础信息(self):
pass
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/base-information"
heardes_data = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, method="GET")
getData = requests.get(url=uri, headers=heardes_data)
print(getData)
print(getData.text)
@classmethod
def 查询电子发票的数据(cls, fapiao_apply_id: str):
fapiao_apply_id = "4500000249202608055531280227"
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}"
headers = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, method="GET")
postData = requests.get(url=uri, headers=headers)
print(postData)
print(postData.json())
@classmethod
def 开具电子发票(cls, fapiao_apply_id, 用户填写的开票):
pass
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications"
发起开票的数据 = {
"scene": "WITH_WECHATPAY", # 开票场景,固定值 "WITH_WECHATPAY" 表示该开票申请来源于微信支付订单
"fapiao_apply_id": fapiao_apply_id, # 发票申请单号,从"获取用户填写抬头信息"接口返回的 fapiao_apply_id
"fapiao_information": [ # 发票信息列表(本次只开一张票,故只有一个元素)
{
"fapiao_id": "20200701123456", # 商户侧发票单号,由商户自行生成,保证唯一
"total_amount": 1, # 总价税合计,单位为分(整数)
"need_list": False, # 是否需要发票明细清单,false 表示不需要(即只在票面显示总金额)
"remark": "微信电子发票测试备注", # 发票备注(选填)
"items": [ # 发票行项目列表
{
"tax_code": "3010101020203000000", # 税收分类编码(需从"获取商品和服务税收分类对照表"接口获取)
"goods_category": "洗化用品", # 商品类别(选填,用于辅助分类)
"goods_name": "六果洗衣液", # 商品名称(必填,显示在发票明细上)
"goods_id": 1, # 商品编号(商户自定义,选填
"specification": "A4", # 规格型号(选填)
"unit": "根", # 计量单位(选填,如“次”“个”“件”)
"quantity": 1, # 数量(整数,此处数量极大,实际应根据订单合理设置)
"total_amount": 1, # 该行项目的总价税合计,单位为分(应与 total_amount 逻辑一致)
"tax_rate": 1300, # 税率,单位为万分比(如 13% 填 1300)
"tax_prefer_mark": "NO_FAVORABLE", # 税收优惠政策标识:NO_FAVORABLE 表示不享受优惠
"discount": False, # 是否享受折扣,false 表示不折扣
}
]
}
]
}
发起开票的数据.update({"buyer_information": 用户填写的开票})
商家侧生成的发票单号 = f"{ULID()}"
发票对象 = order订单.objects.get(order支付微信官方订单号=fapiao_apply_id)
print(发票对象.order购物车商品总价)
总价税合计 = 发票对象.order购物车商品总价
goods_name = emoji.replace_emoji(pydash.get(obj=pydash.head(发票对象.order购物车商品数据), path="goods_商品标题"))
销售规格 = pydash.get(obj=pydash.head(发票对象.order购物车商品数据), path="销售规格")
单个商品订单数量 = pydash.get(obj=pydash.head(发票对象.order购物车商品数据), path="单个商品订单数量")
fapiao_information = [
{
"fapiao_id": 商家侧生成的发票单号, # 商户侧发票单号,由商户自行生成,保证唯一
"total_amount": 总价税合计, # 总价税合计,单位为分(整数)
"need_list": False, # 是否需要发票明细清单,false 表示不需要(即只在票面显示总金额)
"remark": "微信电子发票", # 发票备注(选填)
"items": [ # 发票行项目列表
{
"tax_code": "3010101020203000000", # 税收分类编码(需从"获取商品和服务税收分类对照表"接口获取)
"goods_category": "洗化用品", # 商品类别(选填,用于辅助分类)
"goods_name": goods_name, # 商品名称(必填,显示在发票明细上)
"goods_id": 1, # 商品编号(商户自定义,选填)
"specification": 销售规格, # 规格型号(选填)
"unit": "根", # 计量单位(选填,如“次”“个”“件”)
"quantity": 单个商品订单数量, # 数量(整数,此处数量极大,实际应根据订单合理设置)
"total_amount": 总价税合计, # 该行项目的总价税合计,单位为分(应与 total_amount 逻辑一致)
"tax_rate": 1300, # 税率,单位为万分比(如 13% 填 1300)
"tax_prefer_mark": "NO_FAVORABLE", # 税收优惠政策标识:NO_FAVORABLE 表示不享受优惠
"discount": False, # 是否享受折扣,false 表示不折扣
}
]
}
]
发起开票的数据.update({"fapiao_information": fapiao_information})
print(发起开票的数据)
headers = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, body_data=发起开票的数据, method="POST")
headers.update({"Wechatpay-Serial": "11D762828E947104028F2D045DE78FA806D0D4F2"})
print("打印一下请求头", headers)
postData = requests.post(url=uri, json=发起开票的数据, headers=headers)
print(postData.text)
@classmethod
def 获取用户填写的开票(cls, fapiao_apply_id):
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/user-title?fapiao_apply_id={fapiao_apply_id}&scene=WITH_WECHATPAY"
headers = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, method="GET")
postData = requests.get(url=uri, headers=headers)
return postData.json()
if __name__ == "__main__":
pass
用户填写的开票 = weiPay电子发票.获取用户填写的开票(fapiao_apply_id="4500000272202608055614870626")
weiPay电子发票.开具电子发票(fapiao_apply_id="4500000272202608055614870626", 用户填写的开票=用户填写的开票)
@@ -137,6 +137,7 @@ class miniUser积分(BaseModel):
order好友下单企微员工需要添加的积分值 = int(order好友下单商品数量) * int(order购物车商品好友下单助力的企微员工的的积分值)
if share分享者unionidID == click点击者unionidID or share分享者对象.parent == six六果对象:
print("自己点了自己,不需要添加积分了")
return
if share分享者对象.user_角色权限 == miniUser用户角色().推广员:
pass # 如果是推广员则添加
share对象, share布尔值 = share积分表.objects.update_or_create(
@@ -95,14 +95,14 @@ class wei地图工具:
print(res_data.json())
res_json = res_data.json() # type: dict
d = {
'status': 0,
'message': 'Success',
'request_id': '9435209f1ee84219ae7826e65f577331',
'result': {
'rows': [{
'elements': [{
'distance': 3550, # 起点到终点的距离,单位:米
'duration': 651, # 表示从起点到终点的结合路况的时间,秒为单位注:步行/骑行方式(不计算耗时)以及起终点附近没有道路造成无法计算时,不返回本此节点
"status": 0,
"message": "Success",
"request_id": "9435209f1ee84219ae7826e65f577331",
"result": {
"rows": [{
"elements": [{
"distance": 3550, # 起点到终点的距离,单位:米
"duration": 651, # 表示从起点到终点的结合路况的时间,秒为单位注:步行/骑行方式(不计算耗时)以及起终点附近没有道路造成无法计算时,不返回本此节点
}],
}],
},
@@ -116,29 +116,29 @@ class wei地图工具:
url = f"https://apis.map.qq.com/ws/geocoder/v1/?address={address}"
res = requests.get(url=url, params={"key": cls.key}, )
d = {
'status': 0,
'message': 'Success',
'request_id': '9b049a3ff13c4ac3bda3bb5a9fe0c0a8',
'result': {
'title': '泰州海陵万达广场',
'location': { # 解析到的坐标(GCJ02坐标系)
'lng': 119.917068, # 经度
'lat': 32.471578, # 纬度
"status": 0,
"message": "Success",
"request_id": "9b049a3ff13c4ac3bda3bb5a9fe0c0a8",
"result": {
"title": "泰州海陵万达广场",
"location": { # 解析到的坐标(GCJ02坐标系)
"lng": 119.917068, # 经度
"lat": 32.471578, # 纬度
},
'ad_info': { # 行政区划信息 object 是
'adcode': '321202', # string 是 行政区划代码,规则详见:行政区划代码说明
"ad_info": { # 行政区划信息 object 是
"adcode": "321202", # string 是 行政区划代码,规则详见:行政区划代码说明
},
'address_components': {
'province': '江苏省',
'city': '泰州市',
'district': '海陵区',
'street': '济川东路',
'street_number': '',
"address_components": {
"province": "江苏省",
"city": "泰州市",
"district": "海陵区",
"street": "济川东路",
"street_number": "",
},
'similarity': 0.99,
'deviation': 1000,
'reliability': 7, # 可信度参考:值范围 1 <低可信> - 10 <高可信>
'level': 11, # 解析精度级别,分为11个级别,一般>=9即可采用(定位到点,精度较高) 也可根据实际业务需求自行调整,完整取值表见下文。
"similarity": 0.99,
"deviation": 1000,
"reliability": 7, # 可信度参考:值范围 1 <低可信> - 10 <高可信>
"level": 11, # 解析精度级别,分为11个级别,一般>=9即可采用(定位到点,精度较高) 也可根据实际业务需求自行调整,完整取值表见下文。
},
}
@@ -146,7 +146,7 @@ class wei地图工具:
def 经纬度转换为地址(cls, location):
""""""
pass
url = f'https://apis.map.qq.com/ws/geocoder/v1/?location={location}'
url = f"https://apis.map.qq.com/ws/geocoder/v1/?location={location}"
res = requests.get(url=url, params={"key": cls.key}, )
return res.json()
@@ -159,22 +159,22 @@ class wei地图工具:
print(data)
resData = pydash.omit(data, "request_id")
d = {
'status': 0,
'message': 'Success',
'request_id': '8805bff3303f42dd8a1cbcca3701cf63',
'result': {
'ip': '240e:3a3:b201:3f10:185c:efdb:c5b0:b95c',
'location': {
'lat': 32.49098,
'lng': 119.91956,
"status": 0,
"message": "Success",
"request_id": "8805bff3303f42dd8a1cbcca3701cf63",
"result": {
"ip": "240e:3a3:b201:3f10:185c:efdb:c5b0:b95c",
"location": {
"lat": 32.49098,
"lng": 119.91956,
},
'ad_info': {
'nation': '中国',
'province': '江苏省',
'city': '泰州市',
'district': '海陵区',
'adcode': 321202,
'nation_code': 156,
"ad_info": {
"nation": "中国",
"province": "江苏省",
"city": "泰州市",
"district": "海陵区",
"adcode": 321202,
"nation_code": 156,
},
},
}
@@ -190,6 +190,6 @@ class wei地图工具:
return resData
if __name__ == '__main__':
if __name__ == "__main__":
# wei地图工具.腾讯地图计算二点之间的距离(toData终点={"纬度": "30.80377", "经度": "104.151812"}, fromData起点={"纬度": "30.80377", "经度": "104.151812"})
print(wei地图工具.ip地址转为地址(x_forwarded_for="119.84.150.100", ))
@@ -93,6 +93,7 @@ class sixwecom(ViewSet):
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get?access_token={wecom_token}&external_userid={ExternalUserID}"
data = requests.get(url=uri).json()
print("调用了单独添加新用的数据方法调用了单独添加新用的数据方法调用了单独添加新用的数据方法调用了单独添加新用的数据方法", data)
# 创建数据库数据表
unionid = pydash.get(obj=data, path="external_contact.unionid") # 外部联系人在微信开放平台的唯一身份标识(微信unionid)
name = pydash.get(obj=data, path="external_contact.name") # 外部联系人的名称[注1]如果是微信用户,则返回其微信昵称。如果是企业微信联系人,则返回其设置对外展示的别名或实名
@@ -100,6 +101,7 @@ class sixwecom(ViewSet):
avatar = pydash.get(obj=data, path="external_contact.avatar") # 外部联系人头像。第三方应用和代开发应用均不可获取,
gender = pydash.get(obj=data, path="external_contact.gender") # 外部联系人性别 0-未知 1-男性 2-女性。
follow_user = pydash.get(obj=data, path="follow_user")
print("再打印 下结果", follow_user)
for wecom in follow_user:
userid = pydash.get(obj=wecom, path="userid") # 添加了此外部联系人的企业成员userid (企微员工的userid)
userid = pydash.get(obj=wecom, path="userid") # 添加了此外部联系人的企业成员userid (企微员工的userid)
@@ -156,28 +158,6 @@ class sixwecom(ViewSet):
# 数据更新完成后: 需要调用添加积分的方法, 对新添加企微的用户,添加积分;
(miniUser积分(share分享者unionidID=six上级对象.unionid, click点击者unionidID=self自生对象.unionid, bind绑定的企微unionidID=State)
.add添加点击者添加企微员工双向红包积分(share积分类型="新人红包", share分享者二维码state=State))
# if is是否首次创建:
# # 在这里的场景值:当用户直接扫码添加企微二维码的时候就需要在这里进行处理了
# # 怎么判断的逻辑为: 当用户是首次添加的时候,则说明,这个用户以前在数据库中是不存在的;并且可以确定为这个用户一定是新添加的
# print("\n🍎 🍏 🍊 🍎首次创建首次创建首次创建首次创建 🍏 🍊 🍎 🍏 \n", 上级对象.unionid)
# self自生对象.user_头像 = src
# self自生对象.user_昵称 = name
# self自生对象.codeQrCode = 上级对象.codeQrCode
# self自生对象.codeRemark = 上级对象.codeRemark
# self自生对象.codeConfigId = 上级对象.codeConfigId
# self自生对象.external_userid = external_userid
# self自生对象.user_用户当前的等级 = 上级对象.level + 1
# self自生对象.parent = 上级对象
# self自生对象.user_绑定企微UNIONID = 上级对象.user_绑定企微UNIONID
# self自生对象.user_绑定企微usrID账号 = 上级对象.user_绑定企微usrID账号
# self自生对象.save()
#
# else:
# self自生对象.user_头像 = src
# self自生对象.user_昵称 = name
# self自生对象.external_userid = external_userid
# self自生对象.save()
return None
def 企微主动删除好友事件(self, UserID, ChangeType, State, ExternalUserID):
@@ -197,7 +177,6 @@ class sixwecom(ViewSet):
)
print("到底哪里报错了呀为什么啊")
企微用户关系对象, 企微用户是否为首次 = wecom企微用户.objects.get_or_create(wecom企微ID=UserID, wecom好友的ID=ExternalUserID)
print(企微用户关系对象, 企微用户是否为首次, "==========到底哪里报错了呀为什么啊到底哪里报错了呀为什么啊==================")
if 企微用户是否为首次:
pass
else:
+1 -1
View File
@@ -179,7 +179,7 @@ class sixmini(ViewSet):
def 更新物流信息(self, data):
WayBillId = jmespath.search(data=data, expression="WayBillId")
OrderId = jmespath.search(data=data, expression="OrderId")
ems邮政物流工具().更新物流快递数据(order物流公司订单编号=WayBillId, order物流订单号=OrderId)
ems邮政物流工具().更新物流快递数据(order物流公司订单编号=WayBillId, )
def 确认收货(self, data):
print("确认订单请求接口进来了", data)
-24
View File
@@ -6,27 +6,3 @@ from sixGuoDjango.settings import base_dir_name
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings")
django.setup()
from wechat_数据库.支付订单数据库.商品订单数据 import order订单
from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser用户角色
from wechat_数据库.用户数据库.小程序登陆用户 import weiuser
def 首单自动注册成为推广员(out_trade_no):
pass
order对象 = order订单.objects.get(order支付商家侧订单号=out_trade_no)
user用户对象 = weiuser.objects.get(unionid=order对象.order支付者unionid)
six绑定的企微员工对象, sixBool = weiuser.objects.get_or_create(unionid=user用户对象.user_绑定企微UNIONID)
print(six绑定的企微员工对象.user_区县,user用户对象.user_区县,user用户对象.user_角色权限)
# 判断用户成为推广员的标准 成为的条件,当前用户绑定的企微员工账号, 必须是同一个区县的
print(order对象.order订单类型)
if user用户对象.user_角色权限 == miniUser用户角色().普通会员 and six绑定的企微员工对象.user_区县 == user用户对象.user_区县:
# 当前的用户为普通会员 ,这里被调用了说明肯定是下单成功了 , 需要升级为推广员
print("支付测试成功了,并且能成为推广员")
# user用户对象.user_角色权限 = miniUser用户角色().推广员
# user用户对象.save()
if __name__ == "__main__":
pass
首单自动注册成为推广员(out_trade_no="OAT01KYNGN3T0AKTK1C7WCV5Z047C")
-2
View File
@@ -124,6 +124,4 @@ if __name__ == "__main__":
print(fileImg)
print(fileImg.name)
# default_storage.save(name=fileImg.name, content=fileImg.open(mode="rb"))
srcc = oss上传腾讯云图片.上传图片(key=f"/烟花项目/{fileImg.name}", file=fileImg.open(mode="rb"))
print(srcc)
# oss上传腾讯云图片.删除图片()