From 3ff0faebb99251467928d917c586fdf686beb001 Mon Sep 17 00:00:00 2001 From: doudou201703 <84085676+doudou201703@users.noreply.github.com> Date: Thu, 6 Aug 2026 20:39:45 +0800 Subject: [PATCH] six_002 --- ..._id_str_alter_lucky拼团_idkey_and_more.py | 99 +++++++ django_app/models.py | 4 +- django_app/业务订单接口.py | 44 ++- django_app/发票回调管理接口.py | 45 +++ django_app/实时更新物流数据接口.py | 2 +- django_app/小程序发券接口.py | 3 +- django_routes/企业微信管理端接口列表.py | 15 +- django_routes/小程序服务端接口管理列表.py | 2 + sixGuoDjango/settings.py | 4 +- .../小程序用户的位置接口.py | 5 +- .../小程序用户配送地址接口.py | 9 +- .../小程序码与小程序链接口列表/URLLink接口.py | 6 +- .../物流账号邮政/物流账号接口.py | 2 +- .../企微通讯录管理数据库/企微员工数据.py | 22 -- .../企微通讯录管理/通讯录管理接口.py | 41 --- .../客户管理/客户管理接口.py | 3 - .../六果公司支付类.py | 273 ++++++++++++++++++ .../微信支付公钥.pem | 9 + .../江苏六果科技有限公司支付参数.py | 5 +- .../江苏六果科技有限公司服务商支付参数.py | 6 +- wechat_接口/商品订单模拟接口/商品数据接口.py | 61 ++-- wechat_接口/微信支付接口/微信支付测试接口.py | 233 +++++++-------- wechat_数据库/支付数据库/商家转账数据库.py | 80 ----- wechat_数据库/支付订单数据库/商品订单数据.py | 30 +- wechat_数据库/用户数据库/企微客服数据库.py | 21 ++ wechat_项目工具包/EMS中国邮政/ems邮政.py | 41 ++- .../企业微信工具包/消息推送工具.py | 166 +++++------ .../小程序交易订单管理工具.py | 10 + .../微信支付工具包/微信支付类.py | 52 ++-- .../微信支付工具包/领优惠券工具包.py | 8 +- .../微信支付电子发票/服务商电子发票.py | 42 +++ .../微信支付电子发票/电子发票.py | 135 +++++++++ .../数据库的工具包/更新用户积分.py | 1 + wechat_项目工具包/腾讯地图/腾讯地图工具.py | 90 +++--- wechat_项目授权/企业微信消息服务器授权接口.py | 25 +- wechat_项目授权/小程序授权接口.py | 20 +- 测试数据库.py | 24 -- 第三方工具目录/腾讯云.py | 2 - 38 files changed, 1029 insertions(+), 611 deletions(-) create mode 100644 django_app/migrations/0054_wei客服账号_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py create mode 100644 django_app/发票回调管理接口.py delete mode 100644 wechat_wecom_企业微信管理/企微通讯录管理/企微通讯录管理数据库/企微员工数据.py delete mode 100644 wechat_wecom_企业微信管理/企微通讯录管理/通讯录管理接口.py create mode 100644 wechat_微信支付证书/江苏六果科技有限公司支付证书/六果公司支付类.py create mode 100644 wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem delete mode 100644 wechat_数据库/支付数据库/商家转账数据库.py create mode 100644 wechat_数据库/用户数据库/企微客服数据库.py create mode 100644 wechat_项目工具包/微信支付电子发票/服务商电子发票.py create mode 100644 wechat_项目工具包/微信支付电子发票/电子发票.py diff --git a/django_app/migrations/0054_wei客服账号_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py b/django_app/migrations/0054_wei客服账号_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py new file mode 100644 index 0000000..38286a6 --- /dev/null +++ b/django_app/migrations/0054_wei客服账号_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py @@ -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), + ), + ] diff --git a/django_app/models.py b/django_app/models.py index fc66561..baf2997 100644 --- a/django_app/models.py +++ b/django_app/models.py @@ -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. \ No newline at end of file diff --git a/django_app/业务订单接口.py b/django_app/业务订单接口.py index 1d22246..8d4465f 100644 --- a/django_app/业务订单接口.py +++ b/django_app/业务订单接口.py @@ -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商家侧支付订单号) # 调用方法,生成真实的物流订单号码; diff --git a/django_app/发票回调管理接口.py b/django_app/发票回调管理接口.py new file mode 100644 index 0000000..cc0a5bf --- /dev/null +++ b/django_app/发票回调管理接口.py @@ -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") diff --git a/django_app/实时更新物流数据接口.py b/django_app/实时更新物流数据接口.py index 32421e4..0de260b 100644 --- a/django_app/实时更新物流数据接口.py +++ b/django_app/实时更新物流数据接口.py @@ -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) diff --git a/django_app/小程序发券接口.py b/django_app/小程序发券接口.py index 9560203..db6fc75 100644 --- a/django_app/小程序发券接口.py +++ b/django_app/小程序发券接口.py @@ -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发券数据) diff --git a/django_routes/企业微信管理端接口列表.py b/django_routes/企业微信管理端接口列表.py index 5440045..e25d5c8 100644 --- a/django_routes/企业微信管理端接口列表.py +++ b/django_routes/企业微信管理端接口列表.py @@ -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") diff --git a/django_routes/小程序服务端接口管理列表.py b/django_routes/小程序服务端接口管理列表.py index 8e89c00..d0431d2 100644 --- a/django_routes/小程序服务端接口管理列表.py +++ b/django_routes/小程序服务端接口管理列表.py @@ -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") diff --git a/sixGuoDjango/settings.py b/sixGuoDjango/settings.py index 54163d0..2b63648 100644 --- a/sixGuoDjango/settings.py +++ b/sixGuoDjango/settings.py @@ -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", diff --git a/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户的位置接口.py b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户的位置接口.py index aab4e4a..8e9ddda 100644 --- a/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户的位置接口.py +++ b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户的位置接口.py @@ -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") diff --git a/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户配送地址接口.py b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户配送地址接口.py index 713e952..ffa29eb 100644 --- a/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户配送地址接口.py +++ b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户配送地址接口.py @@ -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): diff --git a/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/URLLink接口.py b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/URLLink接口.py index 153b05e..38d4ee1 100644 --- a/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/URLLink接口.py +++ b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/URLLink接口.py @@ -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 diff --git a/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py b/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py index fe63c70..b019e93 100644 --- a/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py +++ b/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py @@ -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): diff --git a/wechat_wecom_企业微信管理/企微通讯录管理/企微通讯录管理数据库/企微员工数据.py b/wechat_wecom_企业微信管理/企微通讯录管理/企微通讯录管理数据库/企微员工数据.py deleted file mode 100644 index 35546f1..0000000 --- a/wechat_wecom_企业微信管理/企微通讯录管理/企微通讯录管理数据库/企微员工数据.py +++ /dev/null @@ -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" diff --git a/wechat_wecom_企业微信管理/企微通讯录管理/通讯录管理接口.py b/wechat_wecom_企业微信管理/企微通讯录管理/通讯录管理接口.py deleted file mode 100644 index c8fb0fd..0000000 --- a/wechat_wecom_企业微信管理/企微通讯录管理/通讯录管理接口.py +++ /dev/null @@ -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 ) diff --git a/wechat_wecom_企业微信管理/客户管理/客户管理接口.py b/wechat_wecom_企业微信管理/客户管理/客户管理接口.py index 2daa527..0fd782f 100644 --- a/wechat_wecom_企业微信管理/客户管理/客户管理接口.py +++ b/wechat_wecom_企业微信管理/客户管理/客户管理接口.py @@ -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) diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/六果公司支付类.py b/wechat_微信支付证书/江苏六果科技有限公司支付证书/六果公司支付类.py new file mode 100644 index 0000000..030a7f6 --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/六果公司支付类.py @@ -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 diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem b/wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem new file mode 100644 index 0000000..2804d15 --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem @@ -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----- diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/江苏六果科技有限公司支付参数.py b/wechat_微信支付证书/江苏六果科技有限公司支付证书/江苏六果科技有限公司支付参数.py index 52df58d..56c215e 100644 --- a/wechat_微信支付证书/江苏六果科技有限公司支付证书/江苏六果科技有限公司支付参数.py +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/江苏六果科技有限公司支付参数.py @@ -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(私钥证书) diff --git a/wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技有限公司服务商支付参数.py b/wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技有限公司服务商支付参数.py index 50cc3e2..f7b7184 100644 --- a/wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技有限公司服务商支付参数.py +++ b/wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技有限公司服务商支付参数.py @@ -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( diff --git a/wechat_接口/商品订单模拟接口/商品数据接口.py b/wechat_接口/商品订单模拟接口/商品数据接口.py index 4b3643c..93f9d9f 100644 --- a/wechat_接口/商品订单模拟接口/商品数据接口.py +++ b/wechat_接口/商品订单模拟接口/商品数据接口.py @@ -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") diff --git a/wechat_接口/微信支付接口/微信支付测试接口.py b/wechat_接口/微信支付接口/微信支付测试接口.py index 0978264..61aaeb9 100644 --- a/wechat_接口/微信支付接口/微信支付测试接口.py +++ b/wechat_接口/微信支付接口/微信支付测试接口.py @@ -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 ): +class 微信支付ViewSets(ViewSet): + notify_url回调地址 = "https://xiao.sixgou.com/demopay/jsapi_callback/" - - @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="------", ) - 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=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, ) - - - @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" ) - - httpResData = BaseResponse( resData=ResData( listData=[ "" ], dictData={ "demo": "xiaozizi" } ), ).model_dump( ) - return Response( data=httpResData, status=status.HTTP_200_OK ) + 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) - - - @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" } ) - - - - - -微信支付ViewSetsRouter = DefaultRouter( ) -微信支付ViewSetsRouter.register( prefix="", viewset=微信支付ViewSets, basename="" ) + 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={}) diff --git a/wechat_数据库/支付数据库/商家转账数据库.py b/wechat_数据库/支付数据库/商家转账数据库.py deleted file mode 100644 index 702347f..0000000 --- a/wechat_数据库/支付数据库/商家转账数据库.py +++ /dev/null @@ -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 diff --git a/wechat_数据库/支付订单数据库/商品订单数据.py b/wechat_数据库/支付订单数据库/商品订单数据.py index 5dc80d0..c672c0f 100644 --- a/wechat_数据库/支付订单数据库/商品订单数据.py +++ b/wechat_数据库/支付订单数据库/商品订单数据.py @@ -47,33 +47,5 @@ class order订单(models.Model): db_table = "order订单" # 给数据表自定义一个名称;默认的会是在 应用名+类名 app_label = models_app_name 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 diff --git a/wechat_数据库/用户数据库/企微客服数据库.py b/wechat_数据库/用户数据库/企微客服数据库.py new file mode 100644 index 0000000..a6ee72d --- /dev/null +++ b/wechat_数据库/用户数据库/企微客服数据库.py @@ -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 diff --git a/wechat_项目工具包/EMS中国邮政/ems邮政.py b/wechat_项目工具包/EMS中国邮政/ems邮政.py index aa21b1b..909df81 100644 --- a/wechat_项目工具包/EMS中国邮政/ems邮政.py +++ b/wechat_项目工具包/EMS中国邮政/ems邮政.py @@ -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") diff --git a/wechat_项目工具包/企业微信工具包/消息推送工具.py b/wechat_项目工具包/企业微信工具包/消息推送工具.py index d37e18d..b385eb8 100644 --- a/wechat_项目工具包/企业微信工具包/消息推送工具.py +++ b/wechat_项目工具包/企业微信工具包/消息推送工具.py @@ -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上传附件资源.上传临时素材() diff --git a/wechat_项目工具包/小程序交易管理服务/小程序交易订单管理工具.py b/wechat_项目工具包/小程序交易管理服务/小程序交易订单管理工具.py index 3f690c4..87559ea 100644 --- a/wechat_项目工具包/小程序交易管理服务/小程序交易订单管理工具.py +++ b/wechat_项目工具包/小程序交易管理服务/小程序交易订单管理工具.py @@ -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__": diff --git a/wechat_项目工具包/微信支付工具包/微信支付类.py b/wechat_项目工具包/微信支付工具包/微信支付类.py index 0178888..a515abf 100644 --- a/wechat_项目工具包/微信支付工具包/微信支付类.py +++ b/wechat_项目工具包/微信支付工具包/微信支付类.py @@ -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) diff --git a/wechat_项目工具包/微信支付工具包/领优惠券工具包.py b/wechat_项目工具包/微信支付工具包/领优惠券工具包.py index 701a5d6..64f9c31 100644 --- a/wechat_项目工具包/微信支付工具包/领优惠券工具包.py +++ b/wechat_项目工具包/微信支付工具包/领优惠券工具包.py @@ -17,7 +17,7 @@ class stock发送代金券功能(BaseModel): # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") pass stock_id_代金券批次号: str = Field(..., description="发放代金券是创建的批次号") - + def send发券并返回前端需要的数据(self): """前端请求:将这个字典对象返回给前端,前端调用小程序原生插件领取券""" pass @@ -29,13 +29,13 @@ 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, # 发券的商家商户号 "customize_send_time0": rfc3339, # 当前的领券的时间 } - + # iteratee为0是按key iteratee是以value的值来排序 reverse=False(从小到大) reverse=True(从大到小) sorted_dict = dict(pydash.sort_by(collection=params每一张券需要验名的数据格式.items(), iteratee=0, reverse=False)) print(sorted_dict) @@ -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, diff --git a/wechat_项目工具包/微信支付电子发票/服务商电子发票.py b/wechat_项目工具包/微信支付电子发票/服务商电子发票.py new file mode 100644 index 0000000..80e7713 --- /dev/null +++ b/wechat_项目工具包/微信支付电子发票/服务商电子发票.py @@ -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服务商电子发票().获取开通服务商电子发票能力邀请链接() diff --git a/wechat_项目工具包/微信支付电子发票/电子发票.py b/wechat_项目工具包/微信支付电子发票/电子发票.py new file mode 100644 index 0000000..1aaa95e --- /dev/null +++ b/wechat_项目工具包/微信支付电子发票/电子发票.py @@ -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", 用户填写的开票=用户填写的开票) diff --git a/wechat_项目工具包/数据库的工具包/更新用户积分.py b/wechat_项目工具包/数据库的工具包/更新用户积分.py index 2ca42ce..29ca31a 100644 --- a/wechat_项目工具包/数据库的工具包/更新用户积分.py +++ b/wechat_项目工具包/数据库的工具包/更新用户积分.py @@ -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( diff --git a/wechat_项目工具包/腾讯地图/腾讯地图工具.py b/wechat_项目工具包/腾讯地图/腾讯地图工具.py index bc068bd..8424ae2 100644 --- a/wechat_项目工具包/腾讯地图/腾讯地图工具.py +++ b/wechat_项目工具包/腾讯地图/腾讯地图工具.py @@ -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", )) diff --git a/wechat_项目授权/企业微信消息服务器授权接口.py b/wechat_项目授权/企业微信消息服务器授权接口.py index fc014ff..6128572 100644 --- a/wechat_项目授权/企业微信消息服务器授权接口.py +++ b/wechat_项目授权/企业微信消息服务器授权接口.py @@ -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: diff --git a/wechat_项目授权/小程序授权接口.py b/wechat_项目授权/小程序授权接口.py index a0eb007..0f26a0b 100644 --- a/wechat_项目授权/小程序授权接口.py +++ b/wechat_项目授权/小程序授权接口.py @@ -58,7 +58,7 @@ class sixmini(ViewSet): 开发者也可使用云函数或微信云托管免鉴权接收消息推送,立即开通 认证 https://mp.weixin.qq.com/wxamp/devprofile/get_profile?token=2052988734&lang=zh_CN """ - + def sendCustomMessage(self, FromUserName: str, post_data_type): """""" # 回复消息的请求 @@ -102,7 +102,7 @@ class sixmini(ViewSet): url=uri, params={"access_token": mini_token}, data=orjson.dumps(post_data_text).decode("utf-8"), ) - + def uploadTempMedia(self, request: WSGIRequest | Request, *args, **kwargs): """ @@ -120,7 +120,7 @@ class sixmini(ViewSet): file = {"media": open(file=file_path, mode="rb", )} result_data = post(url=uri, params={"access_token": wecom_token, "type": "image", }, files=file) print(result_data.json()) - + def 消息加密方法(self, msg: str, appid: str, encoding_aes_key: str, token: str, timestamp: str, nonce: str, ) -> dict: """""" @@ -146,7 +146,7 @@ class sixmini(ViewSet): signature_str = "".join(params) msg_signature = hashlib.sha1(signature_str.encode("utf-8")).hexdigest() return {"Encrypt": encrypt, "MsgSignature": msg_signature, "TimeStamp": timestamp, "Nonce": nonce, } - + def 消息解密(self, encrypt: str): """ 知识点: 微信请求发送过来的 encrypt 是 b64encode编码后的数据, 是由 iv + 编码数据 组成的 @@ -175,12 +175,12 @@ class sixmini(ViewSet): return orjson.loads(xml_content) except Exception as e: raise ValueError("Decryption failed: " + str(e)) - + 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) 确认收货的方法 = pydash.get(obj=data, path="confirm_receive_method", default=None) @@ -204,14 +204,14 @@ class sixmini(ViewSet): 'confirm_receive_time': 1784839114, # 当前用户确认收货的时间 'settlement_time': 1784839115, # 微信官方 确认的 结算时间 } - + def web_view_auth(self, request: WSGIRequest | Request, ): """""" pass # get请求的方法读取文件并且返回文件 print("认证web_view的请求进来了没有") return HttpResponse(content="8cfc2017094adff8d7c66b94e209456e") - + def api_get(self, request: Request, *args, **kwargs): """ :param request: @@ -232,7 +232,7 @@ class sixmini(ViewSet): return HttpResponse(content=echostr, content_type="text/plan") else: return Response(data="不对", ) - + def api_post(self, request: Request, *args, **kwargs): """ 调用本接口: 就可以向已经订阅消息的用户发送消息,(同时需要注意的是:消息模板需要在小程序的管理后台订阅好) diff --git a/测试数据库.py b/测试数据库.py index 8f5adbd..8178113 100644 --- a/测试数据库.py +++ b/测试数据库.py @@ -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") diff --git a/第三方工具目录/腾讯云.py b/第三方工具目录/腾讯云.py index 43b117c..d88c554 100644 --- a/第三方工具目录/腾讯云.py +++ b/第三方工具目录/腾讯云.py @@ -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上传腾讯云图片.删除图片()