commit 046fac6dc1014c0835bc9ac39b983f69238c5294 Author: doudou201703 <84085676+doudou201703@users.noreply.github.com> Date: Sun Aug 2 14:07:04 2026 +0800 six_001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/demo.md b/demo.md new file mode 100644 index 0000000..dc98b7e --- /dev/null +++ b/demo.md @@ -0,0 +1,76 @@ +你提供的这段内容非常关键,它展示了微信支付API要求的 `multipart/form-data` 请求体的**原始格式**。 + +你看到的 `--boundary`、`Content-Disposition` 和空行,正是 HTTP 协议中 `multipart/form-data` 的标准结构。 + +好消息是,**你完全不需要手动去拼接这些字符串**(比如手动加 `\r\n` 或 `--boundary`)。Python 的 `requests` +库可以自动帮你完成这些繁琐的工作,只要你的参数格式正确。 + +针对你提供的这段结构,核心在于如何处理 `meta` 字段。在 `requests` 的 `files` 参数中,`meta` 被视为一个**内容为 JSON +字符串的“虚拟文件”**。 + +以下是完全对应你提供的 Body 结构的 Python 代码实现: + +### 🎯 核心代码实现 + +```python +import requests +import json + +url = "https://api.mch.weixin.qq.com/v3/..." # 你的接口地址 + +# 1. 准备 meta 的数据(字典) +meta_data = { + "filename": "filea.jpg", + "sha256": "hjkahkjsjkfsjk78687dhjahdajhk" +} + +# 2. 准备文件二进制数据 +# 对应你描述中的 "pic1 //媒体图片的二进制内容" +with open("filea.jpg", "rb") as f: + file_binary = f.read() + +# 3. 构造 files 参数 +# 这里的关键是:meta 也要当作一个“文件”来处理,但它的“内容”是 JSON 字符串 +files = { + # 对应 Body 中的第一部分:name="meta" + # 格式:(文件名, 内容, 内容类型) + # 注意:meta 没有实际文件名,所以第一个参数填 None + 'meta': (None, json.dumps(meta_data), 'application/json'), + + # 对应 Body 中的第二部分:name="file"; filename="filea.jpg" + 'file': ('filea.jpg', file_binary, 'image/jpeg') +} + +# 4. 发送请求 +# 注意:不要设置 Content-Type 头,requests 会自动生成包含 boundary 的正确头 +response = requests.post(url, files=files) + +print(response.text) +``` + +### 🔍 代码与你提供的 Body 的对应关系 + +为了让你更放心,我把 `requests` 库自动生成的请求体和你手写的结构做一个对比: + +| 你的手写结构 (Body) | Python `requests` 的处理逻辑 | +|:------------------------------------|:----------------------------------------------------| +| `--boundary` | **自动生成**:库会随机生成一个 boundary 字符串。 | +| `name="meta"` | **`'meta': ...`**:字典的键对应 `name`。 | +| `Content-Type: application/json` | **`'application/json'`**:元组的第三个参数指定了内容类型。 | +| `{ "filename": ... }` | **`json.dumps(...)`**:这是元组的第二个参数(内容),必须是字符串。 | +| `name="file"; filename="filea.jpg"` | **`'file': ('filea.jpg', ...)`**:元组的第一个参数指定了上传的文件名。 | +| `pic1 (二进制内容)` | **`file_binary`**:元组的第二个参数,即读取到的二进制数据。 | +| `--boundary--` | **自动添加**:请求结束时,库会自动加上结束标记。 | + +### ⚠️ 常见错误提醒 + +1. **不要手动设置 `Content-Type`**: + 如果你手动写 `headers={'Content-Type': 'multipart/form-data'}`,你会丢失 `boundary=...` + 这一关键参数,导致微信服务器无法解析,报错“参数格式错误”。让 `requests` 自己处理这个头。 + +2. **`meta` 必须是字符串**: + 千万不要把 `meta` 放在 `data` 参数里(如 `data={'meta': ...}`),也不要直接传字典。必须放在 `files` 里,并且内容要用 + `json.dumps()` 转成字符串。 + +3. **文件名后缀**: + 微信支付对图片格式有要求(JPG, BMP, PNG),确保你的 `filename` 后缀和实际文件内容一致。 \ No newline at end of file diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..079a513 --- /dev/null +++ b/demo.py @@ -0,0 +1,12 @@ +import os + +import django + +from sixGuoDjango.settings import 项目名称 + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{项目名称}.settings") +django.setup() + +if __name__ == "__main__": + # 这里写你的主程序代码 + pass diff --git a/django_app/__init__.py b/django_app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_app/admin.py b/django_app/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/django_app/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/django_app/apps.py b/django_app/apps.py new file mode 100644 index 0000000..87f919f --- /dev/null +++ b/django_app/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class DjangoAppConfig(AppConfig): + name = "django_app" diff --git a/django_app/migrations/0001_initial.py b/django_app/migrations/0001_initial.py new file mode 100644 index 0000000..9820d8e --- /dev/null +++ b/django_app/migrations/0001_initial.py @@ -0,0 +1,360 @@ +# Generated by Django 6.0.2 on 2026-05-02 23:36 + +import django.db.models.deletion +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='goods商品', + fields=[ + ('id_主键_goods商品', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('goods商品数据', models.JSONField()), + ('goods商品类型', models.CharField(choices=[('幸运拼团', '幸运拼团'), ('商城商品', '商城商品')], default='商城商品', max_length=128)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'goods商品', + 'ordering': ['dateAndTime', 'updateTime'], + }, + ), + migrations.CreateModel( + name='lucky拼团', + fields=[ + ('idKey', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False)), + ('lucky拼团详细', models.JSONField(default=list)), + ('lucky开团状态', models.CharField(choices=[('未开团', '未开团'), ('已开团', '已开团')], default='未开团', max_length=128)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'lucky拼团', + 'ordering': ['dateAndTime', 'updateTime'], + }, + ), + migrations.CreateModel( + name='map地图IP转地址', + fields=[ + ('id_map', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('map用户unionid', models.CharField(max_length=128)), + ('map用户openid', models.CharField(max_length=128)), + ('map解析结果', models.JSONField()), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'map地图IP转地址', + 'ordering': ['-id_map'], + }, + ), + migrations.CreateModel( + name='miniSub订阅消息模板', + fields=[ + ('idKey', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False)), + ('sub订阅用户ID', models.CharField(max_length=128)), + ('sub订阅次数', models.IntegerField(default=0)), + ('sub订阅模板ID', models.CharField(max_length=128)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'miniSub订阅消息模板', + 'ordering': ['dateAndTime', 'updateTime'], + }, + ), + migrations.CreateModel( + name='share分享者积分', + fields=[ + ('id_主键_hare分享者积分', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('share分享者unionid', models.CharField(max_length=128)), + ('share分享者openid', models.CharField(blank=True, max_length=128, null=True)), + ('share分享类型', models.CharField(blank=True, max_length=128, null=True)), + ('share分享昵称', models.CharField(blank=True, max_length=128, null=True)), + ('share分享积分值', models.IntegerField(default=0)), + ('share点击者unionid', models.CharField(blank=True, max_length=128, null=True)), + ('share点击者openid', models.CharField(blank=True, max_length=128, null=True)), + ('share点击者昵称', models.CharField(max_length=128)), + ('share日期', models.DateField(blank=True, null=True)), + ('share日期时间', models.DateTimeField(blank=True, null=True)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'share分享者积分', + 'ordering': ['-id_主键_hare分享者积分'], + }, + ), + migrations.CreateModel( + name='WechatTransferOrder', + fields=[ + ('id_主键_转账', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('out_bill_no', models.CharField(max_length=120)), + ('transfer_bill_no', models.CharField(blank=True, db_comment='微信转账单号', max_length=64, null=True)), + ('state', models.CharField(choices=[('ACCEPTED', '已受理 (可原单重试)'), ('PROCESSING', '资金锁定中'), ('WAIT_USER_CONFIRM', '待用户确认'), ('TRANSFERING', '转账中'), ('CANCELING', '撤销中'), ('SUCCESS', '转账成功'), ('FAIL', '转账失败'), ('CANCELLED', '已撤销')], max_length=32)), + ('transfer_amount', models.IntegerField(db_comment='转账金额(分)')), + ('openid', models.CharField(blank=True, db_comment='收款用户OpenID', max_length=64, null=True)), + ('mch_id', models.CharField(blank=True, db_comment='商户号', max_length=32, null=True)), + ('fail_reason', models.CharField(blank=True, db_comment='失败原因代码', max_length=128, null=True)), + ('fail_message', models.TextField(blank=True, db_comment='失败详细描述', null=True)), + ('package_info', models.TextField(blank=True, db_comment='加密包信息', null=True)), + ('wx_create_time', models.DateTimeField(blank=True, db_comment='微信单据创建时间', null=True)), + ('wx_update_time', models.DateTimeField(blank=True, db_comment='微信单据更新时间', null=True)), + ('created_at', models.DateTimeField(auto_now_add=True, db_comment='本地创建时间')), + ('updated_at', models.DateTimeField(auto_now=True, db_comment='本地最后更新时间')), + ], + options={ + 'db_table': 'WechatTransferOrder', + }, + ), + migrations.CreateModel( + name='wecom企微用户', + fields=[ + ('idKeyWecom企微用户', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False)), + ('wecom企微ID', models.CharField(max_length=128)), + ('wecom企微状态State', models.CharField(default='', max_length=128, null=True)), + ('wecom对好友打的标签', models.JSONField(blank=True, default=list, null=True)), + ('wecom对好友的备注名称', models.CharField(max_length=128)), + ('wecom对好友的添加时间', models.BigIntegerField(blank=True, null=True)), + ('wecom对好友的备注信息', models.CharField(default='', max_length=128)), + ('wecom企微对好友添加的手机号码', models.JSONField(blank=True, default=list, null=True)), + ('wecom企微好友添加方式', models.CharField(max_length=128)), + ('wecom好友UNIONID', models.CharField(max_length=128)), + ('wecom好友昵称', models.CharField(max_length=128)), + ('wecom好友头像', models.TextField(default='https://hudie.xiao.band/default_avacitve.jpeg')), + ('wecom好友性别', models.CharField(max_length=128)), + ('wecom好友的ID', models.CharField(max_length=128)), + ('wecom好友关系状态', 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': 'wecom企微用户', + 'ordering': ['-dateAndTime', '-updateTime'], + }, + ), + migrations.CreateModel( + name='wecom企微群', + fields=[ + ('idKeyWecom企微群', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False)), + ('chat_id群', models.CharField(max_length=128)), + ('chat群名称', models.CharField(blank=True, max_length=128, null=True)), + ('chat群主ID', models.CharField(blank=True, max_length=128, null=True)), + ('chat群成员外部好友external_userid', models.CharField(blank=True, max_length=128, null=True)), + ('chat群成员外部好友unionid', models.CharField(blank=True, max_length=128, null=True)), + ('chat群成员外部好友名称', models.CharField(blank=True, max_length=128, null=True)), + ('chat群成员外部好友群名称', models.CharField(blank=True, max_length=128, null=True)), + ('chat群成员外部好友类型', models.IntegerField(blank=True, null=True)), + ('chat群成员外部好友加入方式', models.IntegerField(blank=True, null=True)), + ('chat群成员外部好友邀请者', models.CharField(blank=True, max_length=128, null=True)), + ('chat群管理员列表', models.JSONField(default=list)), + ('chat群创建时间', models.IntegerField(blank=True, null=True)), + ('chat群成员加入时间', models.IntegerField(blank=True, null=True)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'wecom企微群', + 'ordering': ['-dateAndTime', '-updateTime'], + }, + ), + migrations.CreateModel( + name='weitoken', + fields=[ + ('token_name', models.CharField(max_length=120, primary_key=True, serialize=False)), + ('token_value', models.TextField(blank=True, null=True)), + ('tick_value', models.TextField(blank=True, null=True)), + ('phone_token_value', models.TextField(blank=True, null=True)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'weitoken', + 'ordering': ['dateAndTime', 'updateTime'], + }, + ), + migrations.CreateModel( + name='weiuser地图定位', + fields=[ + ('idKey', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('map用户uniond', models.CharField(max_length=128)), + ('map用户openid', models.CharField(max_length=128)), + ('map经度longitude', models.DecimalField(blank=True, decimal_places=6, max_digits=10, null=True)), + ('map纬度latitude', models.DecimalField(blank=True, decimal_places=6, max_digits=10, null=True)), + ('map省', models.CharField(blank=True, max_length=128, null=True)), + ('map市', models.CharField(blank=True, max_length=128, null=True)), + ('map区', models.CharField(blank=True, max_length=128, null=True)), + ('map街道', models.CharField(blank=True, max_length=128, null=True)), + ('map街道号码', 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': 'weiuser地图定位', + 'ordering': ['dateAndTime', 'updateTime'], + }, + ), + migrations.CreateModel( + name='weiuser用户角色表', + fields=[ + ('idKeyweiuser用户角色表', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('user用户角色名称', models.CharField(choices=[('推广员', '推广员'), ('企微员工', '企微员工'), ('无状态', '无状态'), ('普通会员', '普通会员'), ('六果科技有限公司', '六果科技有限公司'), ('群好友', '群好友')], default='普通会员', max_length=128)), + ('user用户的unionid', models.CharField(max_length=128)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'weiuser用户角色表', + 'ordering': ['-dateAndTime', '-updateTime'], + }, + ), + migrations.CreateModel( + name='xiaozizi', + fields=[ + ('idKey', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('xiao_name', models.CharField(max_length=128)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'xiaozizi', + 'ordering': ['-idKey'], + }, + ), + migrations.CreateModel( + name='lucky拼团订单', + fields=[ + ('idKey', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, primary_key=True, serialize=False)), + ('order拼团支付订单号', models.CharField(max_length=128)), + ('order支付都ID', models.CharField(max_length=128)), + ('order商品ID', models.CharField(max_length=128)), + ('order商品数据', models.JSONField()), + ('order商品总价', models.IntegerField()), + ('order商品数量', models.IntegerField()), + ('order支付数据', models.JSONField(default=dict)), + ('order支付状态', models.CharField(default='支付中', max_length=128)), + ('order用户配送地址', models.JSONField(default=dict)), + ('order物流状态', models.CharField(blank=True, max_length=128, null=True)), + ('order物流订单号', models.CharField(blank=True, max_length=128, null=True)), + ('order物流数据', models.JSONField(default=dict)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ('wai外键lucky拼团表', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='django_app.lucky拼团')), + ], + options={ + 'db_table': 'lucky拼团订单', + 'ordering': ['dateAndTime', 'updateTime'], + }, + ), + migrations.CreateModel( + name='order订单', + fields=[ + ('id_主键_order订单', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('order支付订单号', models.CharField(max_length=128)), + ('order支付者openid', models.CharField(max_length=128)), + ('order支付者unionid', models.CharField(max_length=128)), + ('order分享者unionid', models.CharField(default='六果', max_length=128)), + ('order商品ID', models.CharField(max_length=128)), + ('order商品数据', models.JSONField()), + ('order商品总价', models.IntegerField()), + ('order商品数量', models.IntegerField()), + ('order支付数据', models.JSONField(default=dict)), + ('order支付状态', models.CharField(default='支付中', max_length=128)), + ('order用户配送地址', models.JSONField(default=dict)), + ('order物流状态', models.CharField(blank=True, max_length=128, null=True)), + ('order物流订单号', models.CharField(blank=True, max_length=128, null=True)), + ('order物流数据', models.JSONField(default=dict)), + ('order订单类型', models.CharField(blank=True, max_length=128, null=True)), + ('order物流公司订单编号', 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='更新时间')), + ('wai外键lucky拼团表', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_app.lucky拼团')), + ], + options={ + 'db_table': 'order订单', + 'ordering': ['-id_主键_order订单'], + }, + ), + migrations.CreateModel( + name='weiuser', + fields=[ + ('unionid', models.CharField(editable=False, max_length=120, primary_key=True, serialize=False)), + ('mini_openid', models.CharField(blank=True, db_comment='自身id', max_length=100, null=True, unique=True)), + ('wechat_openid', models.CharField(blank=True, db_comment='服务号自身id', max_length=100, null=True, unique=True)), + ('wecom_openid', models.CharField(blank=True, db_comment='企微自身id', max_length=100, null=True, unique=True)), + ('external_userid', models.CharField(blank=True, db_comment='外部联系人ID', max_length=100, null=True)), + ('nickName', models.CharField(db_comment='用户的昵称', default='匿名用户', max_length=120)), + ('avatar', models.CharField(db_comment='用户头像', default='https://hudie.xiao.band/default_avacitve.jpeg', max_length=245)), + ('level', models.IntegerField(default=1)), + ('isShowImg', models.BooleanField(db_comment='是否显示图片,这个图片就是企微二维码', default=False)), + ('isWorkers', models.CharField(choices=[('推广员', '推广员'), ('企微员工', '企微员工'), ('无状态', '无状态')], db_comment='推广员状态', default='无状态')), + ('codeConfigId', models.TextField(blank=True, null=True)), + ('codeQrCode', models.TextField(blank=True, null=True)), + ('codeRemark', models.TextField(blank=True, null=True)), + ('add_time', models.DateTimeField(blank=True, db_comment='用户添加好友的时间', null=True)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='django_app.weiuser')), + ], + options={ + 'db_table': 'weiuser', + 'ordering': ['-dateAndTime', '-updateTime'], + }, + ), + migrations.CreateModel( + name='wecom推广码', + fields=[ + ('idKey', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('codeConfigId', models.CharField(max_length=128)), + ('codeType', models.IntegerField(blank=True, null=True)), + ('codeQrCode', models.CharField(blank=True, max_length=256, null=True)), + ('codeRemark', models.CharField(blank=True, max_length=128, null=True)), + ('codeState', models.CharField(blank=True, max_length=128, null=True)), + ('codeUser', models.JSONField(blank=True, null=True)), + ('code省', models.CharField(blank=True, max_length=128, null=True)), + ('code市', models.CharField(blank=True, max_length=128, null=True)), + ('code区', 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='更新时间')), + ('wai外键weiuser表', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='django_app.weiuser')), + ], + options={ + 'db_table': 'wecom推广码', + 'ordering': ['-dateAndTime', '-updateTime'], + }, + ), + migrations.CreateModel( + name='weiuser微信用户地址', + fields=[ + ('id_主键_配送地址', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('address', models.JSONField()), + ('isDefaultAddress', models.CharField(choices=[('是默认地址', '是默认地址'), ('不是默认地址', '不是默认地址')], max_length=120)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ('key_weiuser', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_app.weiuser')), + ], + options={ + 'db_table': 'weiuser微信用户地址', + 'ordering': ['-id_主键_配送地址'], + }, + ), + ] diff --git a/django_app/migrations/0002_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py b/django_app/migrations/0002_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py new file mode 100644 index 0000000..f318428 --- /dev/null +++ b/django_app/migrations/0002_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py @@ -0,0 +1,89 @@ +# Generated by Django 6.0.2 on 2026-05-03 04:26 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0001_initial'), + ] + + operations = [ + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0003_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py b/django_app/migrations/0003_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py new file mode 100644 index 0000000..442a9ca --- /dev/null +++ b/django_app/migrations/0003_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py @@ -0,0 +1,89 @@ +# Generated by Django 6.0.2 on 2026-05-03 04:45 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0002_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more'), + ] + + operations = [ + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0004_goods_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py b/django_app/migrations/0004_goods_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py new file mode 100644 index 0000000..75c5174 --- /dev/null +++ b/django_app/migrations/0004_goods_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py @@ -0,0 +1,111 @@ +# Generated by Django 6.0.2 on 2026-05-25 16:10 + +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0003_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Goods', + fields=[ + ('idKey', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('goods_id商品', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('goods_商品品牌', models.CharField(max_length=128)), + ('goods_商品标题', models.CharField(max_length=128)), + ('goods_商品信息', models.JSONField(blank=True, default=dict, null=True)), + ('goods_商品详情图片', models.JSONField(blank=True, default=dict, null=True)), + ('goods_商品销售规格', models.JSONField(blank=True, default=list, null=True)), + ('goods_商品销售场景', models.CharField(blank=True, choices=[('幸运拼团', '幸运拼团'), ('商城商品', '商城商品')], max_length=128, null=True)), + ('goods_商品搜索标签', models.JSONField(blank=True, default=list, null=True)), + ('goods_商家推荐标签', models.JSONField(blank=True, default=list, null=True)), + ('goods_其它参数', models.JSONField(blank=True, null=True)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'Goods', + }, + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0005_goods_goods_商品标签_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0005_goods_goods_商品标签_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..ca21bb1 --- /dev/null +++ b/django_app/migrations/0005_goods_goods_商品标签_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-05-25 16:17 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0004_goods_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='goods', + name='goods_商品标签', + field=models.JSONField(blank=True, default=list, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0006_goods_goods_分享积分_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0006_goods_goods_分享积分_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..14440c8 --- /dev/null +++ b/django_app/migrations/0006_goods_goods_分享积分_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-05-25 16:25 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0005_goods_goods_商品标签_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='goods', + name='goods_分享积分', + field=models.JSONField(blank=True, default=dict, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0007_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0007_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..50668df --- /dev/null +++ b/django_app/migrations/0007_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-05-27 06:07 + +import django.db.models.deletion +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0006_goods_goods_分享积分_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.CreateModel( + name='zizi', + fields=[ + ('zizi_id', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('zizi_name', models.CharField(max_length=128)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ('wai键', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_app.xiaozizi')), + ], + options={ + 'db_table': 'xiao', + }, + ), + ] diff --git a/django_app/migrations/0008_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0008_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..1a4a1d3 --- /dev/null +++ b/django_app/migrations/0008_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,121 @@ +# Generated by Django 6.0.2 on 2026-05-27 06:42 + +import django.db.models.deletion +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0007_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.CreateModel( + name='order订单商品数据', + fields=[ + ('order订单商品数_id', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('order_id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('order_id商品', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('order_商品品牌', models.CharField(max_length=128)), + ('order_商品标题', models.CharField(max_length=128)), + ('order_商品信息', models.JSONField(blank=True, null=True)), + ('order_商品标签', models.JSONField(blank=True, null=True)), + ('order_商品详情图片', models.JSONField(blank=True, null=True)), + ('order_商品销售规格', models.JSONField(blank=True, null=True)), + ('order_商品销售场景', models.CharField(blank=True, choices=[('幸运拼团', '幸运拼团'), ('商城商品', '商城商品')], default='商城商品', max_length=128, null=True)), + ('order_分享积分', models.JSONField(blank=True, null=True)), + ('order_商品搜索标签', models.JSONField(blank=True, null=True)), + ('order_商家推荐标签', models.JSONField(blank=True, null=True)), + ('order_其它参数', models.JSONField(blank=True, null=True)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ('wai_订单', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_app.order订单')), + ], + options={ + 'db_table': 'order订单商品数据', + }, + ), + ] diff --git a/django_app/migrations/0009_order订单商品数据_order_订单数量_order订单商品数据_order订单总金额_and_more.py b/django_app/migrations/0009_order订单商品数据_order_订单数量_order订单商品数据_order订单总金额_and_more.py new file mode 100644 index 0000000..a7dcca0 --- /dev/null +++ b/django_app/migrations/0009_order订单商品数据_order_订单数量_order订单商品数据_order订单总金额_and_more.py @@ -0,0 +1,114 @@ +# Generated by Django 6.0.2 on 2026-05-27 07:35 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0008_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='order订单商品数据', + name='order_订单数量', + field=models.IntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name='order订单商品数据', + name='order订单总金额', + field=models.IntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0010_rename_order商品总价_order订单_order购物车商品总价_and_more.py b/django_app/migrations/0010_rename_order商品总价_order订单_order购物车商品总价_and_more.py new file mode 100644 index 0000000..fd03397 --- /dev/null +++ b/django_app/migrations/0010_rename_order商品总价_order订单_order购物车商品总价_and_more.py @@ -0,0 +1,127 @@ +# Generated by Django 6.0.2 on 2026-05-27 08:02 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0009_order订单商品数据_order_订单数量_order订单商品数据_order订单总金额_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='order订单', + old_name='order商品总价', + new_name='order购物车商品总价', + ), + migrations.RenameField( + model_name='order订单', + old_name='order商品数量', + new_name='order购物车商品数量', + ), + migrations.RemoveField( + model_name='order订单', + name='order商品ID', + ), + migrations.RemoveField( + model_name='order订单', + name='order商品数据', + ), + migrations.AddField( + model_name='order订单', + name='order购物车商品数据', + field=models.JSONField(blank=True, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0011_mini用户角色表_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0011_mini用户角色表_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..4aeb162 --- /dev/null +++ b/django_app/migrations/0011_mini用户角色表_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,125 @@ +# Generated by Django 6.0.2 on 2026-05-29 17:24 + +import django.db.models.deletion +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0010_rename_order商品总价_order订单_order购物车商品总价_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='mini用户角色表', + fields=[ + ('mini用户角色表_id', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('mini用户角色表_id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('mini_角色名称', models.CharField(choices=[('推广员', '推广员'), ('企微员工', '企微员工'), ('无状态', '无状态'), ('普通会员', '普通会员'), ('六果科技有限公司', '六果科技有限公司'), ('群好友', '群好友')], default='普通会员', max_length=20)), + ('mini_等级权重', models.IntegerField(default=1, verbose_name='等级权重')), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'mini用户角色表', + }, + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AddField( + model_name='weiuser', + name='mini_wai键_用户角色', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_app.mini用户角色表'), + ), + ] diff --git a/django_app/migrations/0012_order订单_order支付微信官方订单号_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0012_order订单_order支付微信官方订单号_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..782c29d --- /dev/null +++ b/django_app/migrations/0012_order订单_order支付微信官方订单号_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,114 @@ +# Generated by Django 6.0.2 on 2026-05-30 09:06 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0011_mini用户角色表_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='order订单', + name='order支付微信官方订单号', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0013_xiaozizi_xiao_age_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0013_xiaozizi_xiao_age_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..eef5213 --- /dev/null +++ b/django_app/migrations/0013_xiaozizi_xiao_age_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,114 @@ +# Generated by Django 6.0.2 on 2026-05-31 13:22 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0012_order订单_order支付微信官方订单号_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='xiaozizi', + name='xiao_age', + field=models.IntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0014_wecom企微员工_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0014_wecom企微员工_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..4004bae --- /dev/null +++ b/django_app/migrations/0014_wecom企微员工_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,123 @@ +# Generated by Django 6.0.2 on 2026-06-01 06:58 + +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0013_xiaozizi_xiao_age_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='wecom企微员工', + fields=[ + ('wecom企微员工_id', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('wecom_userid', models.CharField(max_length=128)), + ('wecom_department', 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': 'wecom企微员工', + }, + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0015_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0015_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..60487ee --- /dev/null +++ b/django_app/migrations/0015_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-06-07 16:06 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0014_wecom企微员工_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0016_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0016_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..3768aa9 --- /dev/null +++ b/django_app/migrations/0016_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-06-17 13:55 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0015_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0017_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0017_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..e7456b7 --- /dev/null +++ b/django_app/migrations/0017_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-06-19 23:20 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0016_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0018_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0018_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..c15ba3e --- /dev/null +++ b/django_app/migrations/0018_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-06-22 12:43 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0017_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0019_remove_weiuser_mini_wai键_用户角色_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0019_remove_weiuser_mini_wai键_用户角色_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..aeec260 --- /dev/null +++ b/django_app/migrations/0019_remove_weiuser_mini_wai键_用户角色_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,113 @@ +# Generated by Django 6.0.2 on 2026-07-14 17:43 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0018_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='weiuser', + name='mini_wai键_用户角色', + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='mini用户角色表', + name='mini用户角色表_id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0020_delete_mini用户角色表_remove_weiuser_isworkers_and_more.py b/django_app/migrations/0020_delete_mini用户角色表_remove_weiuser_isworkers_and_more.py new file mode 100644 index 0000000..fc97343 --- /dev/null +++ b/django_app/migrations/0020_delete_mini用户角色表_remove_weiuser_isworkers_and_more.py @@ -0,0 +1,121 @@ +# Generated by Django 6.0.2 on 2026-07-14 17:51 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0019_remove_weiuser_mini_wai键_用户角色_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.DeleteModel( + name='mini用户角色表', + ), + migrations.RemoveField( + model_name='weiuser', + name='isWorkers', + ), + migrations.AddField( + model_name='weiuser', + name='user_roles', + field=models.CharField(choices=[('推广员', '推广员'), ('企微员工', '企微员工'), ('无状态', '无状态'), ('普通会员', '普通会员'), ('六果科技有限公司', '六果科技有限公司'), ('群好友', '群好友')], default='普通会员'), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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='avatar', + field=models.CharField(db_comment='用户头像', default='https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png', max_length=245), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0021_weiuser微信用户地址_mini_openid_weiuser微信用户地址_mini_unionid_and_more.py b/django_app/migrations/0021_weiuser微信用户地址_mini_openid_weiuser微信用户地址_mini_unionid_and_more.py new file mode 100644 index 0000000..fe6b1fe --- /dev/null +++ b/django_app/migrations/0021_weiuser微信用户地址_mini_openid_weiuser微信用户地址_mini_unionid_and_more.py @@ -0,0 +1,116 @@ +# Generated by Django 6.0.2 on 2026-07-14 18:11 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0020_delete_mini用户角色表_remove_weiuser_isworkers_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='weiuser微信用户地址', + name='mini_openid', + field=models.CharField(default=' '), + preserve_default=False, + ), + migrations.AddField( + model_name='weiuser微信用户地址', + name='mini_unionid', + field=models.CharField(default=' '), + preserve_default=False, + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0022_remove_weiuser微信用户地址_key_weiuser_and_more.py b/django_app/migrations/0022_remove_weiuser微信用户地址_key_weiuser_and_more.py new file mode 100644 index 0000000..c22e789 --- /dev/null +++ b/django_app/migrations/0022_remove_weiuser微信用户地址_key_weiuser_and_more.py @@ -0,0 +1,108 @@ +# Generated by Django 6.0.2 on 2026-07-14 18:46 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0021_weiuser微信用户地址_mini_openid_weiuser微信用户地址_mini_unionid_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='weiuser微信用户地址', + name='key_weiuser', + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0023_rename_avatar_weiuser_user_头像_and_more.py b/django_app/migrations/0023_rename_avatar_weiuser_user_头像_and_more.py new file mode 100644 index 0000000..2f01bf6 --- /dev/null +++ b/django_app/migrations/0023_rename_avatar_weiuser_user_头像_and_more.py @@ -0,0 +1,124 @@ +# Generated by Django 6.0.2 on 2026-07-14 19:30 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0022_remove_weiuser微信用户地址_key_weiuser_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='weiuser', + old_name='avatar', + new_name='user_头像', + ), + migrations.RenameField( + model_name='weiuser', + old_name='nickName', + new_name='user_昵称', + ), + migrations.RenameField( + model_name='weiuser', + old_name='level', + new_name='user_用户当前的等级', + ), + migrations.AddField( + model_name='weiuser', + name='uesr_手机号码', + field=models.CharField(blank=True, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0024_rename_user_roles_weiuser_user_角色权限_and_more.py b/django_app/migrations/0024_rename_user_roles_weiuser_user_角色权限_and_more.py new file mode 100644 index 0000000..35363ea --- /dev/null +++ b/django_app/migrations/0024_rename_user_roles_weiuser_user_角色权限_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-07-14 19:33 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0023_rename_avatar_weiuser_user_头像_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='weiuser', + old_name='user_roles', + new_name='user_角色权限', + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0025_remove_weiuser_isshowimg_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0025_remove_weiuser_isshowimg_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..b52a131 --- /dev/null +++ b/django_app/migrations/0025_remove_weiuser_isshowimg_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,108 @@ +# Generated by Django 6.0.2 on 2026-07-14 19:34 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0024_rename_user_roles_weiuser_user_角色权限_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='weiuser', + name='isShowImg', + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0026_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0026_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..f213b9f --- /dev/null +++ b/django_app/migrations/0026_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-07-14 20:09 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0025_remove_weiuser_isshowimg_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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='unionid', + field=models.CharField(max_length=120, primary_key=True, serialize=False), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0027_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0027_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..be33b83 --- /dev/null +++ b/django_app/migrations/0027_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,110 @@ +# Generated by Django 6.0.2 on 2026-07-16 20:07 + +import sixGuoDjango +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0026_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='idKey', + field=models.UUIDField(default=sixGuoDjango.uuid_hex, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0028_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0028_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..fac5d10 --- /dev/null +++ b/django_app/migrations/0028_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,110 @@ +# Generated by Django 6.0.2 on 2026-07-16 20:12 + +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0027_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='idKey', + field=models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0029_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0029_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..300da39 --- /dev/null +++ b/django_app/migrations/0029_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,104 @@ +# Generated by Django 6.0.2 on 2026-07-16 20:24 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0028_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.AlterField( + model_name='xiaozizi', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0030_remove_zizi_wai键_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0030_remove_zizi_wai键_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..60e629f --- /dev/null +++ b/django_app/migrations/0030_remove_zizi_wai键_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-07-16 20:28 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0029_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='zizi', + name='wai键', + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share分享者积分', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + migrations.DeleteModel( + name='xiaozizi', + ), + migrations.DeleteModel( + name='zizi', + ), + ] diff --git a/django_app/migrations/0031_share积分表_delete_share分享者积分_alter_goods_goods_id商品_and_more.py b/django_app/migrations/0031_share积分表_delete_share分享者积分_alter_goods_goods_id商品_and_more.py new file mode 100644 index 0000000..2aec72e --- /dev/null +++ b/django_app/migrations/0031_share积分表_delete_share分享者积分_alter_goods_goods_id商品_and_more.py @@ -0,0 +1,120 @@ +# Generated by Django 6.0.2 on 2026-07-17 10:45 + +import uuid6 +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0030_remove_zizi_wai键_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='share积分表', + fields=[ + ('id_主键', models.UUIDField(default=uuid6.uuid8, primary_key=True, serialize=False)), + ('id_str', models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128)), + ('share分享者unionid', models.CharField(max_length=128)), + ('share分享者openid', models.CharField(blank=True, max_length=128, null=True)), + ('share分享类型', models.CharField(blank=True, max_length=128, null=True)), + ('share分享者昵称', models.CharField(blank=True, max_length=128, null=True)), + ('share分享者积分值', models.IntegerField(default=0)), + ('share点击者unionid', models.CharField(blank=True, max_length=128, null=True)), + ('share点击者openid', models.CharField(blank=True, max_length=128, null=True)), + ('share点击者昵称', models.CharField(max_length=128)), + ('share日期', models.DateField(blank=True, null=True)), + ('share日期时间', models.DateTimeField(blank=True, null=True)), + ('dateAndTime', models.DateTimeField(auto_now_add=True, db_comment='创建时间')), + ('updateTime', models.DateTimeField(auto_now=True, db_comment='更新时间')), + ], + options={ + 'db_table': 'share积分表', + }, + ), + migrations.DeleteModel( + name='share分享者积分', + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0032_share积分表_share分享者头像_share积分表_share点击者头像_and_more.py b/django_app/migrations/0032_share积分表_share分享者头像_share积分表_share点击者头像_and_more.py new file mode 100644 index 0000000..624940d --- /dev/null +++ b/django_app/migrations/0032_share积分表_share分享者头像_share积分表_share点击者头像_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-07-18 19:30 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0031_share积分表_delete_share分享者积分_alter_goods_goods_id商品_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='share积分表', + name='share分享者头像', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='share积分表', + name='share点击者头像', + field=models.TextField(blank=True, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0033_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0033_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..d3f75be --- /dev/null +++ b/django_app/migrations/0033_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-18 22:19 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0032_share积分表_share分享者头像_share积分表_share点击者头像_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0034_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0034_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..ce36189 --- /dev/null +++ b/django_app/migrations/0034_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-18 22:22 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0033_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0035_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0035_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..da40f53 --- /dev/null +++ b/django_app/migrations/0035_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-18 23:21 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0034_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0036_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0036_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..359b89e --- /dev/null +++ b/django_app/migrations/0036_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-19 16:50 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0035_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0037_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0037_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..58722fb --- /dev/null +++ b/django_app/migrations/0037_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-19 16:55 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0036_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0038_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py b/django_app/migrations/0038_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..fc58803 --- /dev/null +++ b/django_app/migrations/0038_alter_goods_goods_id商品_alter_goods商品_id_str_and_more.py @@ -0,0 +1,104 @@ +# Generated by Django 6.0.2 on 2026-07-20 17:32 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0037_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + 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购物车商品数据', + field=models.JSONField(blank=True, default=list, null=True), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0039_remove_goods_goods_分享积分_remove_goods_goods_商品详情图片_and_more.py b/django_app/migrations/0039_remove_goods_goods_分享积分_remove_goods_goods_商品详情图片_and_more.py new file mode 100644 index 0000000..fe10c5f --- /dev/null +++ b/django_app/migrations/0039_remove_goods_goods_分享积分_remove_goods_goods_商品详情图片_and_more.py @@ -0,0 +1,108 @@ +# Generated by Django 6.0.2 on 2026-07-20 23:04 + +import ulid +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0038_alter_goods_goods_id商品_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='goods', + name='goods_分享积分', + ), + migrations.RemoveField( + model_name='goods', + name='goods_商品详情图片', + ), + migrations.AlterField( + model_name='goods', + name='goods_id商品', + field=models.CharField(default=ulid.ULID, max_length=128), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0040_share积分表_share分享的商品id_alter_goods商品_id_str_and_more.py b/django_app/migrations/0040_share积分表_share分享的商品id_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..de874d7 --- /dev/null +++ b/django_app/migrations/0040_share积分表_share分享的商品id_alter_goods商品_id_str_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-21 16:54 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0039_remove_goods_goods_分享积分_remove_goods_goods_商品详情图片_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='share积分表', + name='share分享的商品ID', + field=models.CharField(blank=True, null=True), + ), + 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='share积分表', + name='id_str', + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0041_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py b/django_app/migrations/0041_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py new file mode 100644 index 0000000..bd1eb98 --- /dev/null +++ b/django_app/migrations/0041_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py @@ -0,0 +1,95 @@ +# Generated by Django 6.0.2 on 2026-07-23 20:37 + +import ulid +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0040_share积分表_share分享的商品id_alter_goods商品_id_str_and_more'), + ] + + operations = [ + 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='share积分表', + name='id_str', + field=models.CharField(default=ulid.ULID, 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0042_rename_order支付订单号_order订单_order支付商家侧订单号_and_more.py b/django_app/migrations/0042_rename_order支付订单号_order订单_order支付商家侧订单号_and_more.py new file mode 100644 index 0000000..70914ed --- /dev/null +++ b/django_app/migrations/0042_rename_order支付订单号_order订单_order支付商家侧订单号_and_more.py @@ -0,0 +1,94 @@ +# Generated by Django 6.0.2 on 2026-07-24 03:32 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0041_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='order订单', + old_name='order支付订单号', + new_name='order支付商家侧订单号', + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0043_weiuser_user_ip地址_weiuser_user_区县_weiuser_user_城市_and_more.py b/django_app/migrations/0043_weiuser_user_ip地址_weiuser_user_区县_weiuser_user_城市_and_more.py new file mode 100644 index 0000000..a63c9c6 --- /dev/null +++ b/django_app/migrations/0043_weiuser_user_ip地址_weiuser_user_区县_weiuser_user_城市_and_more.py @@ -0,0 +1,114 @@ +# Generated by Django 6.0.2 on 2026-07-25 21:32 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0042_rename_order支付订单号_order订单_order支付商家侧订单号_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='weiuser', + name='user_IP地址', + field=models.GenericIPAddressField(blank=True, null=True), + ), + migrations.AddField( + model_name='weiuser', + name='user_区县', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AddField( + model_name='weiuser', + name='user_城市', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AddField( + model_name='weiuser', + name='user_省份', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AddField( + model_name='weiuser', + name='user_街道信息', + field=models.CharField(blank=True, max_length=128, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0044_share积分表_share支付订单商家侧的订单号_alter_goods商品_id_str_and_more.py b/django_app/migrations/0044_share积分表_share支付订单商家侧的订单号_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..b45a4a5 --- /dev/null +++ b/django_app/migrations/0044_share积分表_share支付订单商家侧的订单号_alter_goods商品_id_str_and_more.py @@ -0,0 +1,94 @@ +# Generated by Django 6.0.2 on 2026-07-25 23:51 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0043_weiuser_user_ip地址_weiuser_user_区县_weiuser_user_城市_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='share积分表', + name='share支付订单商家侧的订单号', + field=models.CharField(blank=True, max_length=128, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0045_share积分表_share积分是否可以提现的状态_alter_goods商品_id_str_and_more.py b/django_app/migrations/0045_share积分表_share积分是否可以提现的状态_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..9cd48eb --- /dev/null +++ b/django_app/migrations/0045_share积分表_share积分是否可以提现的状态_alter_goods商品_id_str_and_more.py @@ -0,0 +1,94 @@ +# Generated by Django 6.0.2 on 2026-07-26 01:30 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0044_share积分表_share支付订单商家侧的订单号_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='share积分表', + name='share积分是否可以提现的状态', + field=models.CharField(blank=True, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0046_weiuser_user_绑定企微usrid账号_alter_goods商品_id_str_and_more.py b/django_app/migrations/0046_weiuser_user_绑定企微usrid账号_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..8321c0c --- /dev/null +++ b/django_app/migrations/0046_weiuser_user_绑定企微usrid账号_alter_goods商品_id_str_and_more.py @@ -0,0 +1,94 @@ +# Generated by Django 6.0.2 on 2026-07-26 16:49 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0045_share积分表_share积分是否可以提现的状态_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='weiuser', + name='user_绑定企微usrID账号', + field=models.CharField(blank=True, max_length=128, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0047_weiuser_user_企微角色权限_alter_goods商品_id_str_and_more.py b/django_app/migrations/0047_weiuser_user_企微角色权限_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..5a6fbbe --- /dev/null +++ b/django_app/migrations/0047_weiuser_user_企微角色权限_alter_goods商品_id_str_and_more.py @@ -0,0 +1,94 @@ +# Generated by Django 6.0.2 on 2026-07-26 23:35 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0046_weiuser_user_绑定企微usrid账号_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='weiuser', + name='user_企微角色权限', + field=models.CharField(blank=True, max_length=128, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0048_share积分表_share支付提现微信公司生成的转账数据_share积分表_share支付用户提现状态_and_more.py b/django_app/migrations/0048_share积分表_share支付提现微信公司生成的转账数据_share积分表_share支付用户提现状态_and_more.py new file mode 100644 index 0000000..f859191 --- /dev/null +++ b/django_app/migrations/0048_share积分表_share支付提现微信公司生成的转账数据_share积分表_share支付用户提现状态_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-28 01:39 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0047_weiuser_user_企微角色权限_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='share积分表', + name='share支付提现微信公司生成的转账数据', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='share积分表', + name='share支付用户提现状态', + field=models.CharField(blank=True, max_length=128, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0049_share积分表_share支付微信侧返回的提现状态_alter_goods商品_id_str_and_more.py b/django_app/migrations/0049_share积分表_share支付微信侧返回的提现状态_alter_goods商品_id_str_and_more.py new file mode 100644 index 0000000..bbf9ea7 --- /dev/null +++ b/django_app/migrations/0049_share积分表_share支付微信侧返回的提现状态_alter_goods商品_id_str_and_more.py @@ -0,0 +1,99 @@ +# Generated by Django 6.0.2 on 2026-07-28 03:01 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0048_share积分表_share支付提现微信公司生成的转账数据_share积分表_share支付用户提现状态_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='share积分表', + name='share支付微信侧返回的提现状态', + field=models.CharField(blank=True, max_length=128, null=True), + ), + 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='share积分表', + name='share支付提现微信公司生成的转账数据', + field=models.JSONField(blank=True, default=dict, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0050_weiuser_user_绑定企微unionid_alter_goods_goods_商品销售场景_and_more.py b/django_app/migrations/0050_weiuser_user_绑定企微unionid_alter_goods_goods_商品销售场景_and_more.py new file mode 100644 index 0000000..c6013d4 --- /dev/null +++ b/django_app/migrations/0050_weiuser_user_绑定企微unionid_alter_goods_goods_商品销售场景_and_more.py @@ -0,0 +1,109 @@ +# Generated by Django 6.0.2 on 2026-07-29 02:52 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0049_share积分表_share支付微信侧返回的提现状态_alter_goods商品_id_str_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='weiuser', + name='user_绑定企微UNIONID', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AlterField( + model_name='goods', + name='goods_商品销售场景', + field=models.CharField(blank=True, choices=[('幸运拼团', '幸运拼团'), ('商城商品', '商城商品'), ('赢免单', '赢免单')], max_length=128, null=True), + ), + migrations.AlterField( + model_name='goods商品', + name='goods商品类型', + field=models.CharField(choices=[('幸运拼团', '幸运拼团'), ('商城商品', '商城商品'), ('赢免单', '赢免单')], default='商城商品', max_length=128), + ), + 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='order订单商品数据', + name='order_商品销售场景', + field=models.CharField(blank=True, choices=[('幸运拼团', '幸运拼团'), ('商城商品', '商城商品'), ('赢免单', '赢免单')], default='商城商品', max_length=128, null=True), + ), + 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), + ), + migrations.AlterField( + model_name='weiuser用户角色表', + name='id_str', + field=models.CharField(default=wechat_数据库.雪花算法.雪花算法工具.SnowflakeIDGenerator.generate_str, max_length=128), + ), + ] diff --git a/django_app/migrations/0051_delete_weiuser用户角色表_weiuser_user_绑定用工关系_and_more.py b/django_app/migrations/0051_delete_weiuser用户角色表_weiuser_user_绑定用工关系_and_more.py new file mode 100644 index 0000000..8c9ab80 --- /dev/null +++ b/django_app/migrations/0051_delete_weiuser用户角色表_weiuser_user_绑定用工关系_and_more.py @@ -0,0 +1,92 @@ +# Generated by Django 6.0.2 on 2026-07-30 18:45 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0050_weiuser_user_绑定企微unionid_alter_goods_goods_商品销售场景_and_more'), + ] + + operations = [ + migrations.DeleteModel( + name='weiuser用户角色表', + ), + migrations.AddField( + model_name='weiuser', + name='user_绑定用工关系', + field=models.CharField(blank=True, max_length=128, null=True), + ), + 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/migrations/0052_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py b/django_app/migrations/0052_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py new file mode 100644 index 0000000..106e385 --- /dev/null +++ b/django_app/migrations/0052_alter_goods商品_id_str_alter_lucky拼团_idkey_and_more.py @@ -0,0 +1,84 @@ +# Generated by Django 6.0.2 on 2026-08-01 03:25 + +import wechat_数据库.雪花算法.雪花算法工具 +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_app', '0051_delete_weiuser用户角色表_weiuser_user_绑定用工关系_and_more'), + ] + + operations = [ + 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/migrations/__init__.py b/django_app/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_app/models.py b/django_app/models.py new file mode 100644 index 0000000..fc66561 --- /dev/null +++ b/django_app/models.py @@ -0,0 +1,14 @@ +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 小程序登陆用户, 小程序用户地址, 小程序积分数据库 +# Create your models here. \ No newline at end of file diff --git a/django_app/tests.py b/django_app/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/django_app/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/django_app/views.py b/django_app/views.py new file mode 100644 index 0000000..555c9ac --- /dev/null +++ b/django_app/views.py @@ -0,0 +1,111 @@ +from typing import cast + +import orjson +import pydash +from asgiref.sync import async_to_sync +from channels.layers import BaseChannelLayer, get_channel_layer +from django.core.files.storage import default_storage +from django.core.files.uploadedfile import InMemoryUploadedFile +from django.http import HttpResponseRedirect +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 django_jwt_token.jwt认证接口 import Jwt身份认证 +from sixGuoDjango import BaseResponse, ResData, redis_5 + +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 DemoXiaoViewSets(ViewSet): + lock = threading.Lock() # 所有请求 共享这一个 lock对象 + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="zizi") + def 只用于初始化项目测试接口(self, request: Request): + """""" + print("测试接口") + # 可以对用户添加某一类型的积分 + + # with ThreadPoolExecutor( max_workers=3 ) as executor: + # 返回值 = executor.map( 请求企微, [ 1, 2, 3 ] ) + # print( 返回值 ) + # for item in 返回值: + # print( item ) + xiao = request.data.get("xiao", None) + print(xiao) + + 商品数据 = request.data.get("商品数据", "") + data = orjson.loads(商品数据) + 列表 = pydash.get(obj=data, path="列表") + print(列表, 商品数据) + fileDataList: list[InMemoryUploadedFile] = request.FILES.getlist("fileDataList", None) # 接收多个图片或者文件 + + for file in fileDataList: + default_storage.save(name=file.name, content=file) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="xiao") + def xiao(self, request: Request): + """""" + openid = "oy4Jw6A1T3WkKOOhMxcbQTDSM8rs" + channels_name = redis_5.get(name="xiaozizi") + async_to_sync(awaitable=default_channel_layer.send)(channel=channels_name, + message={"type": "chat_msg", + "data": {"xiao": "zizi"}, + }) + + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="eventSource") + def sse请求处理接口(self, request: Request): + """""" + print( + "sse请求处理接口sse请求处理接口sse请求处理接口sse请求处理接口sse请求处理接口sse请求处理接口sse请求处理接口sse请求处理接口sse请求处理接口sse请求处理接口") + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="xiaozizi", + authentication_classes=[Jwt身份认证]) + # @sync_lock_线程锁( lock=lock ) + def xiaozizi(self, request: Request): + pass + return Response(data={"xiao": "111111111111111111"}) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="redirect") + # @sync_lock_线程锁( lock=lock ) + def redirect(self, request: Request): + # 接口是用来测试重定向 + pass + return HttpResponseRedirect(redirect_to="https://six.sixgou.com/") + + # @sync_lock(lock=lock) + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="中文", ) + def 中文(self, request: Request): + print("卡异步的请求") + xiaozizi = request.data.get("xiaozizi", None) + print(xiaozizi) + return Response(data={"msg": xiaozizi}) + + +DemoXiaoViewSetsDemoRouter = DefaultRouter() +DemoXiaoViewSetsDemoRouter.register(prefix="", viewset=DemoXiaoViewSets, basename="DemoXiaoViewSets") diff --git a/django_app/业务订单接口.py b/django_app/业务订单接口.py new file mode 100644 index 0000000..1d22246 --- /dev/null +++ b/django_app/业务订单接口.py @@ -0,0 +1,118 @@ +import emoji +import orjson +import pydash +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 BaseResponse, ResData +from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司 +from wechat_数据库.支付订单数据库.商品订单数据 import order订单 +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.EMS中国邮政.ems邮政 import ems邮政物流工具 +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser用户角色, miniUser积分 + + +class 业务订单接口ViewSets(ViewSet): + + def 处理积分方法(self, 商家订单号): + pass + # 将字符串转为换字典 + order对象 = order订单.objects.get(order支付商家侧订单号=商家订单号) # 拿到当前订单的对象数据 + # 通过订单号,拿到 第一个值: + order购物车商品列表数据 = pydash.get(obj=pydash.head(order对象.order购物车商品数据), path="推荐积分.商品详情页面分享") + + 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) + # 判断用户成为推广员的标准 成为的条件,当前用户绑定的企微员工账号, 必须是同一个区县的 + if user用户对象.user_角色权限 == miniUser用户角色().普通会员 and six绑定的企微员工对象.user_区县 == user用户对象.user_区县: + # 当前的用户为普通会员 ,这里被调用了说明肯定是下单成功了 , 需要升级为推广员 + print("支付测试成功了,并且能成为推广员") + user用户对象.user_角色权限 = miniUser用户角色().推广员 + user用户对象.save() + + @action(detail=False, methods=["post"], url_path="mall") + def 商城订单支付接口(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", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + order购物车商品数据 = request.data.get("order购物车商品数据", None) + order购物车商品数量 = request.data.get("order购物车商品数量", None) + order购物车商品总价 = request.data.get("order购物车商品总价", None) + order用户配送地址 = request.data.get("order用户配送地址", None) + 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_商品标题")) + 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/", # 回调地址要 + "amount": { + # "total": order购物车商品总价, # 【总金额】 订单总金额,单位为分。 + "total": 1, # 【总金额】 订单总金额,单位为分。 + "currency": "CNY", # 【货币类型】 CNY:人民币,境内商户号仅支持人民币。 + }, # 【支付者】 支付者信息。 + "attach": orjson.dumps({"share订单分享者ID": share订单分享者ID, "out_trade_no": out_trade_no商家侧的订单号, }).decode( + encoding="utf-8"), + "payer": { + # "openid": "ohQkD7A-N93kljcFmkCyG6e_D9vg", # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取 + "openid": self_mini_openid, # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取 + }, + } # 请求的数据 + wechat_data = wechatPay(payment=sixpay六果科技公司).getpay_jsapi(uri=url_pay, body_data=body, method="POST") + payData = pydash.get(obj=wechat_data, path="response") + order订单对象 = order订单.objects.create(order支付商家侧订单号=out_trade_no商家侧的订单号, + order购物车商品总价=order购物车商品总价, order购物车商品数据=order购物车商品数据, + order购物车商品数量=order购物车商品数量, + order支付数据=body, order支付状态="支付中", + order订单类型=order订单类型, + order用户配送地址=order用户配送地址, + order分享者unionid=share订单分享者ID, + order支付者openid=self_mini_openid, + order支付者unionid=self_mini_unionid, + ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=payData), ).model_dump() + # httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @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") + self.首单自动注册成为推广员(out_trade_no=out_trade_no商家侧支付订单号) + 生成商家侧物流的订单号 = f"EMS{ULID()}" + order订单.objects.filter(order支付商家侧订单号=out_trade_no商家侧支付订单号).update(order支付数据=wechat_data支付回调数据, + order支付状态=trade_state_desc, + order物流状态=order订单.order订单choosies物流状态.待揽件.value, + 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商家侧支付订单号) # 调用方法,生成真实的物流订单号码; + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +业务订单接口ViewSetsViewSetsRouter: DefaultRouter = DefaultRouter() +业务订单接口ViewSetsViewSetsRouter.register(prefix="", viewset=业务订单接口ViewSets, basename="业务订单接口ViewSets") diff --git a/django_app/实时更新物流数据接口.py b/django_app/实时更新物流数据接口.py new file mode 100644 index 0000000..32421e4 --- /dev/null +++ b/django_app/实时更新物流数据接口.py @@ -0,0 +1,43 @@ +from typing import cast + +from channels.layers import BaseChannelLayer, get_channel_layer +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_项目工具包.EMS中国邮政.ems邮政 import ems邮政物流工具 + +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="实时更新物流数据") + def 实时更新物流数据(self, request: Request): + """前端小程序, 物流追踪页面, 左上角 刷新按钮 返回的数据""" + order物流公司订单编号 = request.data.get("order物流公司订单编号", None) + order物流订单号 = request.data.get("order物流订单号", None) + print("实时更新数据请求进来了吗") + ems邮政物流工具().更新物流快递数据(order物流公司订单编号=order物流公司订单编号, 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 new file mode 100644 index 0000000..9560203 --- /dev/null +++ b/django_app/小程序发券接口.py @@ -0,0 +1,42 @@ +from typing import cast + +from channels.layers import BaseChannelLayer, get_channel_layer +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 wechat_项目工具包.微信支付工具包.领优惠券工具包 import stock发送代金券功能 + +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对象 + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="生成优惠券") + def 生成优惠券(self, request: Request): + """""" + stock发券数据 = stock发送代金券功能(stock_id_代金券批次号="22512292").send发券并返回前端需要的数据() + # 4. 生成签名 + return Response(data=stock发券数据) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="返回当前券的状态") + def 返回当前券的状态(self, request: Request): + pass + return Response(data={}) diff --git a/django_app/添加各类型积分接口.py b/django_app/添加各类型积分接口.py new file mode 100644 index 0000000..ddbc556 --- /dev/null +++ b/django_app/添加各类型积分接口.py @@ -0,0 +1,82 @@ +from typing import cast + +from channels.layers import BaseChannelLayer, get_channel_layer +from django.forms import model_to_dict +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_数据库.洗衣液商品数据库.六果洗衣液商品 import Goods +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser积分 + +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="添加每日签到奖励") + def 添加每日签到奖励(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + print('每日签到接口', self_mini_openid, self_mini_unionid) + miniUser积分(share分享者unionidID=self_mini_unionid, click点击者unionidID=self_mini_unionid).add添加每日积分(share积分类型="每日签到", share分享者积分值=50) + httpResData = BaseResponse(resData=ResData(listData=[""], 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): + pass + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + share分享者_unionid = request.data.get("share分享者_unionid", None) + miniUser积分(share分享者unionidID=share分享者_unionid, click点击者unionidID=self_mini_unionid).add添加通知好友积分(share积分类型="发券奖励", share分享者积分值=10) + return Response(data={}) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="添加好物推荐积分") + def 添加好物推荐积分(self, request: Request): + """这里是前端用,分享了商品详情页面的 商品数据""" + pass + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + share分享者_unionid = request.data.get("share分享者_unionid", None) + share分享的商品ID = request.data.get("share分享的商品ID", None) + miniUser积分(share分享者unionidID=share分享者_unionid, click点击者unionidID=self_mini_unionid).add添加用户分享商品推荐的积分( + share积分类型="好物推荐", share分享者积分值=10, share分享的商品ID=share分享的商品ID, + ) + currend当前商品的数据 = Goods.objects.get(idKey=share分享的商品ID) # 拿到当前分享的商品ID,返回给前端,前端用户点击后,会直接进入分享页面 + data = model_to_dict(instance=currend当前商品的数据, fields=None, exclude=None) + return Response(data=data) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="添加小程序分享积分") + def 添加小程序分享积分(self, request: Request): + pass + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + share分享者_unionid = request.data.get("share分享者_unionid", None) + print(share分享者_unionid, self_mini_unionid, self_mini_openid) + miniUser积分(share分享者unionidID=share分享者_unionid, click点击者unionidID=self_mini_unionid).add添加小程序推荐积分( + share分享者积分值=10, share积分类型="小程序推荐", + ) + return Response(data={}) diff --git a/django_app/用户评价接口.py b/django_app/用户评价接口.py new file mode 100644 index 0000000..56d101a --- /dev/null +++ b/django_app/用户评价接口.py @@ -0,0 +1,47 @@ +from typing import cast + +from channels.layers import BaseChannelLayer, get_channel_layer +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_数据库.支付订单数据库.商品订单数据 import order订单 + +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="用户发起评价") + def 用户发起评价(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + order物流订单号 = request.data.get("order物流订单号", None) + order物流公司订单编号 = request.data.get("order物流公司订单编号", None) + order订单.objects.filter(order物流订单号=order物流订单号, order物流公司订单编号=order物流公司订单编号).update( + order物流状态="已评价", + ) + 订单查询列表 = order订单.objects.filter(order支付者openid=self_mini_openid, order支付状态="支付成功").values() + 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 new file mode 100644 index 0000000..3d4059a --- /dev/null +++ b/django_app/积分提现接口.py @@ -0,0 +1,102 @@ +from typing import cast + +import pydash +from channels.layers import BaseChannelLayer, get_channel_layer +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 ulid import ULID + +from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司 +from wechat_数据库.用户数据库.小程序积分数据库 import share积分表 +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser提现状态 + +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="发起提现") + def 前端用户发起可提现积分事件(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + print("用户发起了积分提现在的功能了", self_mini_unionid) + # 通地 self_mini_unionid 查询 这个就是分享者的ID + share支付订单商家侧的订单号 = f"{ULID()}" + 可提现在的数据 = share积分表.objects.filter(share分享者unionid=self_mini_unionid, share积分是否可以提现的状态=miniUser提现状态().可提现) + print(len(可提现在的数据)) + transferAccountsBody = { + "appid": sixpay六果科技公司.appid, "out_bill_no": share支付订单商家侧的订单号, # 必填 integer【商户单号】 + # 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 + "transfer_scene_id": "1000", + # 必填 integer【转账场景ID】 该笔转账使用的转账场景,可前往“商户平台-产品中心-商家转账”中申请。如:1000(现金营销),1006(企业报销)等 + # "openid":"ohQkD7A-N93kljcFmkCyG6e_D9vg", + "openid": self_mini_openid, # 必填 integer【收款用户OpenID】 用户在商户appid下的唯一标识。发起转账前需获取到用户的OpenID,获取方式详见参数说明。 + # "user_name":"757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45", # 【收款用户姓名】 + # 收款方真实姓名。需要加密传入,支持标准RSA算法和国密算法,公钥由微信侧提供。 + "transfer_amount": 10, # 必填 integer【转账金额】 转账金额单位为“分”。 + "transfer_remark": "新会员开通有礼", # 必填 string(32)【转账备注】 转账备注,用户收款时可见该备注信息,UTF8编码,最多允许32个字符 + "notify_url": "https://six.sixgou.com/wechat_mini/积分提现/积分提现回调/", # 选填【通知地址】 异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数。 + "user_recv_perception": "现金奖励", # 选填 【用户收款感知】 用户收款时感知到的收款原因将根据转账场景自动展示默认内容。如有其他展示需求, + # 必填 array[TransferSceneReportInfo] 【转账场景报备信息】 各转账场景下需报备的内容,商户需要按照所属转账场景规则传参,详见转账场景报备信息字段说明。 + "transfer_scene_report_infos": [ + { + "info_type": "活动名称", # 必填 string(15)【信息类型】 不能超过15个字符,商户所属转账场景下的信息类型,此字段内容为固定值 + "info_content": "新人红包", # 必填 【信息内容】 不能超过32个字符,商户所属转账场景下的信息内容,商户可按实际业务场景自定义传参 + }, + { + "info_type": "奖励说明", "info_content": "新人红包", + }, + ], + } + wechat_data提现返回数据 = wechatPay(payment=paymentCategory).transferAccounts商家转账到零钱(transferAccountsBody=transferAccountsBody) + print(wechat_data提现返回数据) + share支付微信侧返回的提现状态 = pydash.get(obj=wechat_data提现返回数据, path="state") + share支付微信侧提现订单号 = pydash.get(obj=wechat_data提现返回数据, path="transfer_bill_no") + share支付微信侧提现订单号 = pydash.get(obj=wechat_data提现返回数据, path="out_bill_no") + share发起提现的时间 = pydash.get(obj=wechat_data提现返回数据, path="create_time") + share提现的数据package_info = pydash.get(obj=wechat_data提现返回数据, path="package_info") + + arry = [{"age": 100}, {"age": 200}, {"age": 300}, {"age": 400}] + sum_limit = 900 + + result = [] + total = 0 + + for item in arry: + if total + item["age"] <= sum_limit: + result.append(item) + total += item["age"] + else: + break + + print(result) + return Response(data=result) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="积分提现回调") + def 添加商品数据(self, request: Request): + pass + 提现返回数据 = wechatPay(payment=paymentCategory).callBack回调解密(headers=request.headers, response_body=request.data) + + print(提现返回数据) + return Response(data={}) diff --git a/django_app/积分查询管理接口.py b/django_app/积分查询管理接口.py new file mode 100644 index 0000000..12a0504 --- /dev/null +++ b/django_app/积分查询管理接口.py @@ -0,0 +1,92 @@ +from datetime import datetime +from typing import cast + +from channels.layers import BaseChannelLayer, get_channel_layer +from django.db.models import Case, Count, IntegerField, Sum, When +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 wechat_数据库.用户数据库.小程序积分数据库 import share积分表 +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser提现状态 + +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="统计积分查询") + def 统计积分查询(self, request: Request): + """""" + """这里查询的数据,用于在商品详情页面 显示的 点击次数+累计积分总和""" + pass + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None, ) # 这里的查询者,就是积分表中的分享者 + 查询当前用户是否有记录结果 = share积分表.objects.filter(share分享者unionid=self_mini_unionid, ).exists() + if 查询当前用户是否有记录结果 is False: + pass + return Response(data={"share分享者unionid": self_mini_unionid, "share总积分": 0, "share分享点击人数": 0, "share不可提现积分": 0, "share已提现积分": 0}, ) + else: + xiaozizidata = ( + share积分表.objects + .filter(share分享者unionid="oy4Jw6P1FnuTNF-hSoJHNztSAoQ0") + .aggregate( + share总积分=Sum("share分享者积分值"), + share可提现积分=Sum( + Case( + When(share积分是否可以提现的状态=miniUser提现状态().可提现, then="share分享者积分值"), + default=0, + output_field=IntegerField() + ) + ), + + share不可提现积分=Sum( + Case( + When(share积分是否可以提现的状态=miniUser提现状态().不可提现, then="share分享者积分值" + ), + default=0, + output_field=IntegerField() + ) + ), + share已提现积分=Sum( + Case( + When(share积分是否可以提现的状态="已提现", then="share分享者积分值" + ), + default=0, + output_field=IntegerField() + ) + ), + share点击次数=Count("id_主键") + ) + ) + xiaozizidata["unionid"] = self_mini_unionid + print(xiaozizidata) + return Response(data=xiaozizidata) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="查询当前用户积列详情列表数据") + def 查询当前用户积列详情列表数据(self, request: Request): + """本接口处理的: 当用户进入积分详情页面时候, 返回给当前用户所有的积分列表详情""" + pass + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + 当前的月份 = datetime.now().month + shareDaat = share积分表.objects.filter(share分享者unionid=self_mini_unionid, ).order_by("-dateAndTime").values() + return Response(data=shareDaat) diff --git a/django_app/项目初始化的接口.py b/django_app/项目初始化的接口.py new file mode 100644 index 0000000..90ed114 --- /dev/null +++ b/django_app/项目初始化的接口.py @@ -0,0 +1,48 @@ +from typing import cast + +from channels.layers import BaseChannelLayer, get_channel_layer +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_数据库.用户数据库.小程序登陆用户 import weiuser + +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="初始化") + def 只用于初始化项目测试接口(self, request: Request): + """""" + six六果对象xiao, six是否新创建值 = weiuser.objects.update_or_create(unionid="六果", + defaults={ + "user_IP地址": None, "user_昵称": "六果", "user_用户当前的等级": 0, "user_省份": "六果", "user_城市": "六果", "user_区县": "六果", + "user_街道信息": "六果", "user_头像": "https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png", "user_绑定企微usrID账号": "六果", "user_角色权限": "六果", "external_userid": "六果", + "parent_id": "六果", "mini_openid": "wxf612e825377328f0", "wechat_openid": "六果", "wecom_openid": "wwbe6369dc26a9d83a", "codeConfigId": "六果", "codeRemark": "六果", + "codeQrCode": "https://hudie.xiao.band/mini.jpg", + "user_企微角色权限": "六果", "user_绑定企微UNIONID": "六果" + }) + + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/django_celery/__init__.py b/django_celery/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_celery/config.py b/django_celery/config.py new file mode 100644 index 0000000..2044791 --- /dev/null +++ b/django_celery/config.py @@ -0,0 +1,38 @@ +"""配置文件""" +# broker_url = "redis://default:com792282@127.0.0.1:6379/5" +# result_backend = "redis://:com792282@127.0.0.1:6379/6" + +# result_backend = "django-db" # 任务结果存储数据库:这里默认是存储到数据库中 + +CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True +# 用于设置单个任务的最大允许执行时间(单位通常是秒)。当 Celery Worker 执行的任务耗时超过这个设定值时,Celery将会强制终止该任务的执行。这个机制可以防止某个任务无限期地运行下去,从而可能导致Worker阻塞无法处理新的任务。 +CELERY_TASK_TIME_LIMIT = 30 * 60 +timezone = "Asia/Shanghai" # 时区:与 django 使用相同的时区; +# 这个配置项设置了Celery在发布任务和存储任务结果时使用的序列化器。当Celery Worker从Broker接收任务并将任务结果返回到Broker时,都会用到这个序列化器。在您给出的配置中,CELERY_TASK_SERIALIZER = "json" 表明任务将以JSON格式进行序列化。JSON是一种轻量级的数据交换格式,易于阅读和编写,同时也便于不同语言之间的解析。 + +task_serializer = "json" +# 此配置项定义了Celery Worker所接受的任务消息内容类型(MIME类型)。换句话说,只有在这个列表中的内容类型的任务消息,Celery Worker才会接受并尝试去执行。在您给出的配置中,CELERY_ACCEPT_CONTENT = ['json'] +# 表示Worker仅接受以JSON格式序列化的任务消息。这与CELERY_TASK_SERIALIZER配置相呼应,确保系统内部的一致性,即发布的任务消息和接收的任务消息都采用相同的序列化格式。 +accept_content = [ "json" ] +# CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler" + +# 下面的语法是实现 定时作务的; USE_TZ +# DJANGO_CELERY_BEAT_TZ_AWARE = False # 一定要配置,否则会报mysql不支持的时间设置 +# CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler" # 默认配置 +# CELERY_BEAT_SCHEDULE = { +# "add_demo_event_one_hours": { +# "task": "django_celery.scheduledUpdatestoken.tasks.updateToken", +# "schedule": timedelta( seconds=60 ) +# }, +# +# } +""" +django_celery_beat.models.ClockedSchedule # 此模型存放已经关闭的任务 +django_celery_beat.models.CrontabSchedule # cron的时间表 +django_celery_beat.models.IntervalSchedule # 以特定间隔(例如,每5秒)运行的计划。以特定时间间隔(例如每 5 秒)运行的计划。 +django_celery_beat.models.PeriodicTask # 此模型定义要运行的单个周期性任务。 +django_celery_beat.models.PeriodicTasks # 此模型仅用作索引以跟踪计划何时更改 +django_celery_beat.models.SolarSchedule # 定制任务 +from django_celery_beat.models import PeriodicTask, CrontabSchedule 包含 cron 中的条目等字段的计划:分钟、小时、星期几、day_of_month month_of_year。 +import json +""" diff --git a/django_celery/main.py b/django_celery/main.py new file mode 100644 index 0000000..93545c4 --- /dev/null +++ b/django_celery/main.py @@ -0,0 +1,152 @@ +""" +Celery 启动入口文件 - 必须放在最顶层 +""" +import os + +import django + +from sixGuoDjango.settings import BASE_DIR + + + + + +os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings" ) +django.setup( ) + +import orjson +from kombu import Queue, Exchange +from kombu.serialization import register + +from celery import Celery, signals + + + + + +# redis_url = os.environ.get("REDIS_URL") +redis_url = "127.0.0.1:6379" +# redis_url = f"{REDIS_IP}:6379" +# 作用就是:需要加载一个django项目的配置文件# 为"芹菜"程序设置默认的Django设置模块。; + +# app.conf.beat_schedule = { +app = Celery( + main="django_celery", + broker=f"redis://default:com792282@{redis_url}/9", + backend=f"redis://default:com792282@{redis_url}/8", # 存储数据库 + namespace="CELERY", # 作用:配置前缀(如 "CELERY"),用于从 settings 中提取配置。Django 中默认为 "CELERY" + task_queues=[ + Queue( name="xiao_queue", routing_key="xiao_queue", exchange=Exchange( name="xiao_queue", type="direct" ) ), + Queue( name="celery", routing_key="celery", exchange=Exchange( name="celery", type="direct" ) ), # 添加默认队列 + ], + # 作用:预定义队列列表(kombu.Queue对象) + worker_cancel_long_running_tasks_on_connection_loss=True, ## 默认,保持任务完整性 + # task_acks_late=True, # 任务确认延迟 + task_time_limit=60, # 任务硬性时间限制(以秒为单位)。超过此限制后,正在处理该任务的 worker 将被终止并由新的 worker 替换 + # 关键配置:指定xiao_queue队列只使用一个worker+可选:确保每个任务由独立worker处理 + worker_max_tasks_per_child=100, # 每个子进程执行多少任务后自动重启,防止内存泄漏。 + worker_prefetch_multiplier=1, ## 每个 worker 一次只取 1 个任务(避免长任务阻塞) + ) + +app.conf.update( + timezone="Asia/Shanghai", + enable_utc=False, + task_serializer="utf8json", + result_serializer="utf8json", + accept_content=[ "json", "utf8json" ], + ) +json_dumps = lambda obj: orjson.dumps( obj ).decode( ) +json_loads = lambda obj: orjson.loads( obj ) +# 注册自定义 JSON 序列化器 +register( name="utf8json", encoder=json_dumps, decoder=json_loads, content_type="application/json", + content_encoding="utf-8" ) +app.autodiscover_tasks( + packages=[ + "django_celery.message", + "django_celery.xiao_queue队列", + ], + ) +# +import logging + + + + + +logger = logging.getLogger( __name__ ) + +# @task_prerun.connect +# def log_task_queue( sender=None, task_id=None, task=None, args=None, kwargs=None, **kwds ): +# """ +# :param sender: +# :type sender: +# :param task_id: +# :type task_id: +# :param task: +# :type task: +# :param args: +# :type args: +# :param kwargs: +# :type kwargs: +# :param kwds: +# :type kwds: + +# """ +# # 正确方式:从 request.delivery_info 获取实际消费的队列(即 routing_key) +# delivery_info = current_task.request.delivery_info +# queue_name = delivery_info.get( "routing_key", "unknown" ) if delivery_info else "unknown" +# logger.warning( f"[QUEUE DEBUG] Task {task.name}[{task_id}] is running from queue: {queue_name}" ) +# + +""" +# Worker1:只处理 xiao_queue,使用 1 个进程 +celery -A django_celery.main worker -Q xiao_queue --concurrency=10 -n worker_xiao + +# Worker2:处理其他队列,使用 9 个进程 +celery -A django_celery.main worker -Q celery --concurrency=1 -n worker_default + +worker_xiao:指定的线程名称, -Q 指定的队列的名称(--queue) -A指定app(--app) --concurrency=1(指定的数量进程或者线程) -P threads(指定使用线程) -n(--hostname)给进程或者线程取个指定的名称 +celery -A django_celery.main worker -Q xiao_queue --concurrency=100 -P threads -n worker_xiao -E (推荐:最合适的启动线程) +celery -A django_celery.main worker -Q xiao_queue --concurrency=1 -P prefork -n worker_xiao (不推荐配置不够强大进程) +celery -A django_celery.main worker -Q sql_queue --concurrency=1 -P prefork -n worker_sql (不推荐配置不够强大进程) +celery -A django_celery.main worker -Q xiao_queue --concurrency=3000 -P eventlet -n worker_xiao (这里启动的是协程) +celery -A django_celery.main worker -Q xiao_queue --concurrency=3000 -P gevent -n worker_xiao (不推荐,协程,需要猴子协议) + + + +celery --app django_celery.main worker --pool=threads --concurrency=10 + +""" + + + + + +# ========== 使用Celery信号系统 ========== +@signals.worker_shutdown.connect +def on_worker_shutdown( sender=None, **kwargs ): + """Celery worker关闭时的回调""" + print( "\n🚀 Celery Worker正在优雅关闭..." ) + print( "1. 保存任务状态..." ) + print( "2. 关闭数据库连接..." ) + print( "3. 清理临时文件..." ) + + + + + +@signals.worker_ready.connect +def on_worker_ready( sender=None, **kwargs ): + """Worker启动完成时的回调""" + # 打印所有已注册任务 + print( "=== 已注册任务 ===" ) + for name in sender.app.tasks.keys( ): + if not name.startswith( 'celery.' ): + print( f" {name}" ) + + + + + +if __name__ == '__main__': + pass diff --git a/django_celery/message/tasks.py b/django_celery/message/tasks.py new file mode 100644 index 0000000..a3f815e --- /dev/null +++ b/django_celery/message/tasks.py @@ -0,0 +1,60 @@ +"""注释""" +import requests +from celery import Task +from channels.layers import get_channel_layer + +from django_celery.main import app +from wechat_token.token工具包 import sixToken +from wechat_数据库.支付订单数据库.商品订单数据 import order订单 +from wechat_项目工具包.小程序交易管理服务.小程序交易订单管理工具 import miniTransaction交易管理服务工具 + +channel_layer = get_channel_layer() +import logging + +logger = logging.getLogger(__name__) + + +# 这是任务执行成功后的回调监听函数;(使用方法: 只需要在调用任务的时候添加属性 link=函数名.s() ) +@app.task(bind=True) +def on_success_callback(self: Task, result, *args, **kwargs): + """这是任务执行成功后的回调监听函数""" + # 在这里实现你的回调逻辑 + print("成功地回调") + task_name = self.name + # 获取触发回调的任务ID + task_id = self.request.id + print(self.request.parent_id) # 这个参数非常重要,是执行任务的🆔(可以知道是哪个任务的回调) + print(f"任务 {task_name} (ID: {task_id}) 执行成功,回调函数已触发") + + +class MyCustomTask(Task): + """注释""" + + def on_success(self, retval, task_id, args, kwargs): + """ 任务执行成功,回调函数打印返回值 """ + # 在任务成功执行后运行的逻辑 + # logger.info( f"任务 {task_id} 成功: {retval}" ) + pass + + def on_retry(self, exc, task_id, args, kwargs, einfo): + """ 在任务重试后运行的逻辑 """ + + pass + + def on_failure(self, exc, task_id, args, kwargs, einfo): + """参数""" + # 在任务执行失败后运行的逻辑 + pass + + +@app.task(base=MyCustomTask, bind=True) +def mini调用微信小程序交易管理服务录入订单接口(self: Task,order支付商家侧订单号, **kwargs, ): + """执行这个任务,:会自动打印回调""" + # 任务完成后,往前端发消息 print("任务执行了") + # TODO my_task.apply_async( kwargs={ "name": "这里是传递的名称的值" }, queue="xiao_queue", ) + # 根据订单号: 对运单接口发起生成运单的物流信息 + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 到底调用了没有呀", ) + + miniTransaction交易管理服务工具().发货信息录入(order支付商家侧订单号=order支付商家侧订单号) + + diff --git a/django_celery/xiao_queue队列/tasks.py b/django_celery/xiao_queue队列/tasks.py new file mode 100644 index 0000000..24e1aad --- /dev/null +++ b/django_celery/xiao_queue队列/tasks.py @@ -0,0 +1,61 @@ +"""注释""" + +from celery import Task + +from django_celery.main import app + +import logging + +from wechat_数据库.雪花算法.雪花算法工具 import generator + +logger = logging.getLogger(__name__) + + +# 这是任务执行成功后的回调监听函数;(使用方法: 只需要在调用任务的时候添加属性 link=函数名.s() ) +@app.task(bind=True) +def on_success_callback(self: Task, result, *args, **kwargs): + """这是任务执行成功后的回调监听函数""" + # 在这里实现你的回调逻辑 + print("成功地回调") + task_name = self.name + # 获取触发回调的任务ID + task_id = self.request.id + print(self.request.parent_id) # 这个参数非常重要,是执行任务的🆔(可以知道是哪个任务的回调) + print(f"任务 {task_name} (ID: {task_id}) 执行成功,回调函数已触发") + + +class MyCustomTaskMessages(Task): + """注释""" + + def on_success(self, retval, task_id, args, kwargs): + """""" + # 在任务成功执行后运行的逻辑 + # logger.info( f"任务 {task_id} 成功: {retval}" ) + pass + # print( retval ) + + def on_retry(self, exc, task_id, args, kwargs, einfo): + """""" + # 在任务重试后运行的逻辑 + pass + + def on_failure(self, exc, task_id, args, kwargs, einfo): + """""" + pass + # 只记录,不要 raise 非法对象! + print(f"Task failed: {exc}") + # 不要在这里 raise 任何东西,除非是合法异常 + + +@app.task(base=MyCustomTaskMessages, bind=True, queue="xiao_queue", retry_kwargs={'max_retries': 5}, retry_backoff=True, ) +def taskMessages(self, xiaoziziname, **kwargs): + """""" + try: + pass + auto_str = generator.generate_str() + print("成功了", auto_str, xiaoziziname) + return "" + except Exception as e: + pass + print(e) + return e diff --git a/django_celery/测试接口.py b/django_celery/测试接口.py new file mode 100644 index 0000000..66a87d3 --- /dev/null +++ b/django_celery/测试接口.py @@ -0,0 +1,32 @@ +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 django_celery.xiao_queue队列.tasks import taskMessages +from sixGuoDjango import BaseResponse, ResData + + + + + +class Celery测试接口ViewSets( ViewSet ): + + + @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="test" ) + def 测试路由接口( self, request: WSGIRequest | Request ): + """""" + taskMessages.delay( token="alkdsfjal;d" ) + taskMessages.apply_async( kwargs={ 'token': 'your_token' }, ) + httpResData = BaseResponse( resData=ResData( listData=[ "" ], dictData={ "demo": "xiaozizi" } ), ).model_dump( ) + return Response( data=httpResData, status=status.HTTP_200_OK ) + + + + + +Celery测试接口ViewSetsRouter = DefaultRouter( ) +Celery测试接口ViewSetsRouter.register( prefix="", viewset=Celery测试接口ViewSets, basename="" ) diff --git a/django_channels/SSE测试.py b/django_channels/SSE测试.py new file mode 100644 index 0000000..be422fc --- /dev/null +++ b/django_channels/SSE测试.py @@ -0,0 +1,79 @@ +"""注释""" +# consumers.py +# 推荐解决方案:事件驱动架构 +# 修改实现为事件驱动模式: +import asyncio +import json +import time + +from channels.generic.http import AsyncHttpConsumer + +# 全局消息队列 (生产环境用Redis等分布式队列) +MESSAGE_QUEUE = asyncio.Queue() + + +class SSEConsumer(AsyncHttpConsumer): + async def handle(self, body): + # 设置SSE响应头 + await self.send_headers( + headers=[ + (b"Content-Type", b"text/event-stream"), + (b"Cache-Control", b"no-cache"), + (b"Connection", b"keep-alive"), + ] + ) + + # 事件循环监听 + while True: + # 异步等待新消息(挂起状态) + data = await MESSAGE_QUEUE.get() + # 推送消息给客户端 + await self.send_body(f"event: message\ndata: {data}\n\n".encode()) + + async def disconnect(self): + # 客户端断开时清理资源 + print(f"Client {self.scope['client']} disconnected") + + +# 其他Django视图或后台任务中 + +# 生产者触发更新示例 +async def trigger_update(): + """模拟外部事件触发更新""" + # 创建新消息 + message = {"time": time.time(), "event": "DataUpdated"} + + # 将消息推送到全局队列 + await MESSAGE_QUEUE.put(json.dumps(message)) + + +# 测试代码 +async def xiaozizi(): + """从队列中获取消息并打印""" + print("等待消息...") + d = await MESSAGE_QUEUE.get() + print(f"收到消息: {d}") + return d + + +# 在脚本末尾添加(如果需要测试) +async def main(): + """主测试函数""" + print("开始测试...") + + # 启动一个任务来监听消息 + listen_task = asyncio.create_task(xiaozizi()) + + # 稍等一下再发送消息,确保监听任务已经启动 + await asyncio.sleep(0.1) + + # 发送测试消息 + # await trigger_update() + + # 等待监听任务完成 + result = await listen_task + print(f"测试完成,结果: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/django_channels/__init__.py b/django_channels/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_channels/consumers.py b/django_channels/consumers.py new file mode 100644 index 0000000..555f67e --- /dev/null +++ b/django_channels/consumers.py @@ -0,0 +1,43 @@ +"""2""" + +import pydash +from asgiref.sync import async_to_sync + +from sixGuoDjango import RedisClientManager + +redia_socket_5 = RedisClientManager().get_client(db_name="redis_5") +"""consumers""" + +import orjson +from channels.generic.websocket import WebsocketConsumer + + +class ChatConsumer(WebsocketConsumer): + def connect(self): + print("连接请求进来了", self.channel_name) + room_id = pydash.get(obj=self.scope, path="url_route.kwargs.room_id") + self.accept() # 接受连接 + redia_socket_5.set(name=room_id, value=self.channel_name) + # self.channel_layer.group_add(group="demo_name", channel=self.channel_name) + async_to_sync(self.channel_layer.group_add)(group="demo_name", channel=self.channel_name) + async_to_sync(self.channel_layer.group_add)(group="demo_xiaozizi", channel=self.channel_name) + + def receive(self, text_data=None, bytes_data=None): + # text_data 已经是字符串,直接使用 + if text_data == "ping": + self.send(text_data=orjson.dumps({"type": "监听心跳", "text": {"xiao": "xiaozizi"}}, + option=orjson.OPT_SORT_KEYS).decode(encoding="utf-8")) + else: + # 处理其他消息 + # print("判断生成了哟", text_data) + self.send(text_data=orjson.dumps({"type": "chat_msg", "text": {"xiao": "xiaozizi"}}, + option=orjson.OPT_SORT_KEYS).decode(encoding="utf-8")) + + def disconnect(self, code): + room_id = pydash.get(obj=self.scope, path="url_route.kwargs.room_id") # 断开连接后可以拿到参数 + print("连接断开,code:", code, room_id) + async_to_sync(self.channel_layer.group_discard)(group="demo_name", channel=self.channel_name) + async_to_sync(self.channel_layer.group_discard)(group="demo_xiaozizi", channel=self.channel_name) + + def update_更新用户头像(self, event): + self.send(text_data=orjson.dumps(event, option=orjson.OPT_SORT_KEYS).decode(encoding="utf-8")) diff --git a/django_channels/routing.py b/django_channels/routing.py new file mode 100644 index 0000000..7c65cd5 --- /dev/null +++ b/django_channels/routing.py @@ -0,0 +1,37 @@ +# routing.py +""" +ASGI config for django_cat project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" +from sixGuoDjango.settings import BASE_DIR + +"""asgi路由""" +import os + +os.environ.setdefault(key='DJANGO_SETTINGS_MODULE', value=f"{BASE_DIR.name}.settings") +from django.core.asgi import get_asgi_application +from channels.routing import ProtocolTypeRouter, URLRouter +from django_channels import consumers, tableConsumer +from django.urls import path + +application = ProtocolTypeRouter( + { + "http": get_asgi_application(), # 如果处理http请求就走这里 + "websocket": URLRouter( + [ + # re_path(r'room/(?P\w+)/$', consumers.ChatConsumer.as_asgi()), + path(route="room/", view=consumers.ChatConsumer.as_asgi()), # 调用第一个类处理业务 + # path("web//", tableConsumer.TableConsumer.as_asgi()), # 调用第二个类处理业务 + ], + ) + }, +) +# AllowedHostsOriginValidator: +# 这是一个安全中间件,用于验证WebSocket连接请求的Origin头部是否包含在ALLOWED_HOSTS设置中。 +# 这是防止跨站伪造攻击(Cross-Site Request Forgery, CSRF)的一种措施, +# 确保只有来自信任源(通常是应用自己的域名)的WebSocket连接请求才能被接受。 +# 如果请求的Origin不在允许列表中,此中间件会拒绝连接。 diff --git a/django_channels/tableConsumer.py b/django_channels/tableConsumer.py new file mode 100644 index 0000000..55861f9 --- /dev/null +++ b/django_channels/tableConsumer.py @@ -0,0 +1,101 @@ +import pydash +from asgiref.sync import async_to_sync +from channels.exceptions import StopConsumer +from channels.generic.websocket import JsonWebsocketConsumer +from channels.layers import get_channel_layer + +from sixGuoDjango import redis_5 + +# channel_layer: RedisChannelLayer = get_channel_layer("default") +channel_layer = get_channel_layer(alias="default") +default_group_name = "default_group_name" + + +class websocket(JsonWebsocketConsumer): + + def connect(self) -> None: + """ + 首次连拉时触发方法前端请求的语法为 "wss://wecom.fujugongxiang.com/web/room_name_value/" + room_name_value: 就是前端路由配置的room_name的值 path("web//", tableConsumer.websocket.as_asgi()), + 并且最末尾要带有 / 斜杠 + """ + user_openid = self.scope["url_route"]["kwargs"].get("room_name", "") + print("websocket:=>", user_openid, self.channel_name) + if not user_openid: + self.close(code=4001) # 关闭连接(可选) + return + self.accept() + # 将进来的用户保存到redis数据库中 + redis_5.set(value=self.channel_name, name=user_openid) + # 将用户添加到自己的组里面 (只能异步,否则添加不成功的) + self.send_json(content={"channel_name": self.channel_name}) + async_to_sync(awaitable=self.channel_layer.group_add)(group=default_group_name, channel=self.channel_name) + + def disconnect(self, ): + user_openid = self.scope["url_route"]["kwargs"].get("room_name", None) + async_to_sync(self.channel_layer.group_discard)(group=user_openid, channel=self.channel_name, ) # 只能异步的删除; + async_to_sync(self.channel_layer.group_discard)(group=default_group_name, channel=self.channel_name, ) + raise StopConsumer() + + def receive_json(self, content, **kwargs) -> None: + print(content, "是在这里吗") + # self.send() + self.send_json(content={"xiao": "xiaozizi"}) + pass + + def chat_messages(self, event) -> None: + """ + :param event: + """ + data = pydash.get(obj=event, path="message") + self.send_json(content="messagemessagemessagemessage") + + def chat_subMsg(self, event): + """ + + :param event: + :type event: + """ + # 处理消息回调的函数 + print("事件没有调用了吗") + self.send_json(content=event) + + def chat_hongBao(self, event): + """ + :param event: + :type event: + """ + # 处理首次领红包的业务 + user_openid = self.scope["url_route"]["kwargs"].get("room_name", None) + print(user_openid) + print("我得调用一下:chat_hongBao") + channelID = pydash.get(obj=event, path="message.channelID") + self.send_json(content={"chat": "chat_hongBao", }) + + def chat_Lucky拼团(self, event): + print("socked事件调用幸运拼团数据更新: 🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏", event) + self.send_json(content=event) + + def commandsSendStr(self, event): + """ + :param event: + :type event: + """ + self.send_json(content={"commands": "demo这是个测试的数据", "type": "commands"}) + + def chat_demo(self, event): + """ + :param event: + :type event: + """ + print(event, "函数被调用了,") + self.send_json(content={"demo": "demo_test"}) + + def 消息提示(self, event): + """事件""" + print(event) + print("这只是个用来测试的方法") + self.send_json(content="这只是个用来测试的方法") + + def update_更新用户头像(self, event): + print(event) diff --git a/django_channels/异步视图.py b/django_channels/异步视图.py new file mode 100644 index 0000000..32fa0c4 --- /dev/null +++ b/django_channels/异步视图.py @@ -0,0 +1,81 @@ +"""注释""" +import pydash +from channels.generic.websocket import AsyncJsonWebsocketConsumer + + +class websocket(AsyncJsonWebsocketConsumer): + + async def connect(self) -> None: + """ + 前端请求: wss://wecom.fujugongxiang.com/web/room_name_value/ + room_name_value 来自 URL 路径: path("web//", websocket.as_asgi()) + """ + # 获取 URL 参数 + user_openid = self.scope["url_route"]["kwargs"].get("room_name", "") + + if not user_openid: + await self.close(code=4001) # 关闭连接(可选) + return + + # 接受连接 + await self.accept() + + # 将用户加入组(异步直接 await) + await self.channel_layer.group_add(group=user_openid, channel=self.channel_name, ) + + # 返回 channel_name 给前端(可选) + await self.send_json(content={"channel_name": self.channel_name}) + + async def disconnect(self, close_code) -> None: + """ + 断开连接时触发 + """ + + user_openid = self.scope["url_route"]["kwargs"].get("room_name", "") + if user_openid: + # 从组中移除(异步) + await self.channel_layer.group_discard(group=user_openid, channel=self.channel_name, ) # 自动清理,无需 raise StopConsumer() + + async def receive_json(self, content, **kwargs) -> None: + """ + 收到前端发来的 JSON 消息 + """ + print("收到消息:", content) + # 回显 + await self.send_json(content=content) + + # 自定义事件处理器(会被 group_send 触发) + async def chat_messages(self, event) -> None: + """ + 处理 chat_messages 事件 + """ + data = pydash.get(event, "message") + print("chat_messages 收到数据:", data) + await self.send_json(content=data) + + async def chat_subMsg(self, event): + """ + 处理 subMsg 回调 + """ + pass + + async def chat_hongBao(self, event): + """ + 处理红包事件 + """ + print(event, "========== chat_hongBao 被触发 ============") + channel_id = pydash.get(event, "message.channelID") + await self.receive_json(content={"demo": "text"}) + + async def commandsSendStr(self, event): + """ + 发送命令 + """ + await self.send_json(content={"commands": "demo这是个测试的数据", "type": "commands"}) + + async def chat_demo(self, event): + """ + demo 测试事件 + """ + print("chat_demo 被调用:", event) + await self.receive_json(content={"demo": "demo_test"}) diff --git a/django_jwt_token/RSA非对称密钥.py b/django_jwt_token/RSA非对称密钥.py new file mode 100644 index 0000000..d68ca4e --- /dev/null +++ b/django_jwt_token/RSA非对称密钥.py @@ -0,0 +1,45 @@ +import base64 +import os +import django +from Crypto.Cipher import PKCS1_OAEP, PKCS1_v1_5 + +from sixGuoDjango.settings import base_dir_name + + + +os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings" ) +django.setup( ) + +from pathlib import Path + +from Crypto.PublicKey import RSA +from django.conf import settings + + + + + +def jwt_rsa_证书创建( ): + # 生成2048位密钥对 + key = RSA.generate( bits=2048 ) + # + # 导出私钥(PEM格式) + private_key = key.export_key( passphrase=settings.SECRET_KEY ) + # print( "私钥:\n", private_key.decode( ) ) + + # 导出公钥(PEM格式) + public_key = key.publickey( ).export_key( ) + + Path( settings.BASE_DIR ).joinpath( "django_jwt_token/private.pem" ).write_bytes( data=private_key ) + Path( settings.BASE_DIR ).joinpath( "django_jwt_token/public.pem" ).write_bytes( data=public_key ) + + print( "证书创建成功了" ) + + + + + +if __name__ == "__main__": + # 这里写你的主程序代码 + pass + jwt_rsa_证书创建( ) diff --git a/django_jwt_token/demo.py b/django_jwt_token/demo.py new file mode 100644 index 0000000..737930d --- /dev/null +++ b/django_jwt_token/demo.py @@ -0,0 +1,50 @@ +import os + +import django + +from sixGuoDjango.settings import base_dir_name + + + +os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings" ) +django.setup( ) + +from datetime import datetime, timedelta, timezone +from pathlib import Path + +from Crypto.PublicKey import RSA +from django.conf import settings +from jwt import JWT +from jwt.jwk import jwk_from_pem +from jwt.utils import get_int_from_datetime + + + +# 创建 JWT 实例 +instance = JWT( ) + +# 创建 payload +message = { + 'iss': 'my-app', + 'sub': 'user123', + 'name': '张三', + 'role': 'admin', + 'iat': get_int_from_datetime( datetime.now( timezone.utc ) ), + 'exp': get_int_from_datetime( datetime.now( timezone.utc ) + timedelta( hours=1 ) ), + } + +# ✅ 正确:使用私钥进行签名 +private_key_pem_私钥 = Path( "private.pem" ).read_bytes( ) +私钥对象 = RSA.import_key( extern_key=private_key_pem_私钥, passphrase=settings.SECRET_KEY ).export_key( ) +signing_key = jwk_from_pem( pem_content=私钥对象 ) + +token = instance.encode( message, signing_key, alg='RS256' ) # 注意算法名改为 RS256 +print( f"生成的 JWT: {token}" ) + +# ✅ 正确:使用公钥进行验证 +public_key_pem_公钥 = Path( "public.pem" ).read_bytes( ) +verifying_key = jwk_from_pem( pem_content=public_key_pem_公钥 ) + +# 解码验证 JWT +received_message = instance.decode( message=token, key=verifying_key, do_time_check=True ) +print( f"解码后的消息: {received_message}" ) diff --git a/django_jwt_token/jwt认证接口.py b/django_jwt_token/jwt认证接口.py new file mode 100644 index 0000000..34716ad --- /dev/null +++ b/django_jwt_token/jwt认证接口.py @@ -0,0 +1,90 @@ +from pathlib import Path +from zoneinfo import ZoneInfo + +import pydash +from django.conf import settings +from jwt import JWT, jwk_from_pem +from jwt.exceptions import JWTDecodeError +from jwt.utils import get_time_from_int +from rest_framework import exceptions +from rest_framework.authentication import BaseAuthentication +from rest_framework.response import Response + + + +public_key_pem_公钥 = Path( settings.BASE_DIR ).joinpath( "django_jwt_token/public.pem" ).read_bytes( ) + +instance = JWT( ) + +from rest_framework.permissions import BasePermission +from rest_framework.exceptions import AuthenticationFailed + + + + + +class Jwt权限认证( BasePermission ): + """自定义JWT认证权限类""" + + + + def has_permission( self, request, view ): + """ + 必须实现这个方法,返回 True 表示有权限,False 表示无权限 + :param request: 请求对象 + :param view: 视图对象 + :return: bool + """ + # 获取 token(从 Authorization header 或 cookie) + auth_header = request.headers.get( 'Authorization', '' ) + token = request.data.get( "token", None ) + Authorization = pydash.get( obj=request.headers, path="Authorization" ) + print( "有作用了啦" ) + print( "拿到token了吗?", Authorization ) + # ✅ 正确:使用公钥进行验证 + verifying_key = jwk_from_pem( pem_content=public_key_pem_公钥 ) + + # 解码验证 JWT + received_message = instance.decode( message=Authorization, key=verifying_key, do_time_check=True ) + print( f"解码后的消息: {received_message}" ) + + + + def has_object_permission( self, request, view, obj ): + pass + + + + + +class Jwt身份认证( BaseAuthentication ): + + + def authenticate( self, request ): + try: + Authorization = request.headers.get( "Authorization", "" ) + # ✅ 正确:使用公钥进行验证 + verifying_key = jwk_from_pem( pem_content=public_key_pem_公钥 ) + # 解码验证 JWT + received_message = instance.decode( message=Authorization, key=verifying_key, do_time_check=True ) + 过期时间戳 = pydash.get( obj=received_message, path="exp" ) + time_过期日间 = get_time_from_int( 过期时间戳 ).astimezone( tz=ZoneInfo( key="Asia/Shanghai" ) ) + print( "过期的时间为:", time_过期日间, received_message ) + return received_message, time_过期日间, + except exceptions.AuthenticationFailed: + msg = "===============" + raise "认证失败" + except JWTDecodeError as e: + print( '999999999999999999999', str( e ) ) + # 如果你想保留原始异常链 + raise AuthenticationFailed( f"Token无效: {str( e )}" ) + # raise f"Token无效: {str( e )}" + + + + def authenticate_header( self, request ): + pass + """ + 返回 HTTP 401 响应时,告诉客户端应该使用哪种认证方式 + """ + return 'Bearer' diff --git a/django_jwt_token/private.pem b/django_jwt_token/private.pem new file mode 100644 index 0000000..2975b28 --- /dev/null +++ b/django_jwt_token/private.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,FDB397A184DB8297 + +1k9DgnqNjn8QWzEw5AydYPKAAH/a5FQgw5tqNeRxLW7gOqV4ZH1XfY1QsRbHFKXU +i/t0m9gWbI+4VTphdCZPjAp0kHjxCUfsMZqEB6cwGvQ775bLoC002SJACshFOf0R +Aj/QnXPNexZ7gexHGbUnSGa+HMzJRelOBR+MyUiwa5Jq7UAaPlrWnCUIaByUOsHG +ZUqeftabkeV8FagXCy6Izcg+E0eB3TFA/lWxqlKMSVx2bvomS9X/d9f4uxx2Ejv5 +9Oc09IKsu2XoHsQibSXTUDhsYEupAP6U+Bp3Yki8LOMusm/ERwV+UQwsitSxD1Gc +NeQnvZhI3acJvJka3KsZaDLm1ErtruY7xPyLOzttiz2np77MSfb2GvXU4RXPCwq6 +odmc2SRNmY1b8+2+XRq/lOZHzkbdPQrHm6vd+OfjV5V1+4QQ+721qSCYeLx5lAmz +NRJziMBrF5jW4BNCWiPECT8Z1nMhVl/MJAYhn/zssMuxjJ5umFQCQ7UcvCsBRCc8 +2aC2d0Qj/XGhLd92lXv/LcyOgx9YLyw/DdlwORp3H17dW+mMpgJMsRp3BS3Y0nHp +XN4oygsiNpgfDjbttu21A3fWbbFfe63Ef2xcuo4aAC+WpausHRTrK/7xkSRwX2Rm +S5Mc3yCCJ2237zTQi56sHbiFa3fkhP5jx9tJ4/lzFcJ9evlpWL6kjXCKIkzpVr1p +3uPJbw5BvoOZThkEbWmRX1gm+TC1IMWD4sGRN+rpjb9I3nFhvV+2zQBHZRB+lVz/ +OhsffGTLbpzIVDs0EsmcpGmV8fVXJ4Ke1Vdy+ebE+ZBVYeTEJI5KyMzakjG+Fl0J +U5YX4NEVxLiF8Sb/B0Mx9h5VqDZHtltHuF2By0ud8C3JjbzvmapxLIqW4UTK47mU +dPTASM/dvUhPHsfiCkNZ1fbwlNzA3j0YSPIF2pZlz5sVKXCFQ1aLUVdYBbJ5AsyP +YHMVFSIT9vFr56YDxZ9f2zPVGo1sCiu/N6sqJdAO93sTN4sRiDiDBay+2W+et4cP +XEjPoDs4Ohxo0MrS74Y0Kxhf81KmjUTIS7uk1AQcpDQoldbN4UgomuLp1okLFBQl +kqS9PC01hTjv2LeC8TnOfzivl/KQtnl3xhzK8ylaSd/5VWUkOcM/Z4jqTTDqaL27 +A5FRv2mjm7Ziaw2YjOPKxlXcsieOkbfuWbl3pbot7pg1oG4iwlSJCUcMJJUP4Kmm +bsN4X6JQagouaHj6SVqNWc8EBDQKppebmKUlyzrBPRhlAAZB/9fPoc5w0bCtn8Ne +v67OTQRtRJceY/C9jyhp/C3MXiSQkJ7Dltzko7R8ghIrUS4fRSpj35siUlPRpz7f ++nRlT2zD3D0R5fBl/nEBAA4mWryN2auDO9/54VtvfujUgWJkkNYPdw62l/f72a7V +hq7WQSpWBvo1r71lTpLw2EkZz/joF1FKsdi+1k+K/hP76wvOpwnALGrjvfQEgEQg +AgCA4zVTDHXkZz5tBndAaA2N2tDPfQmDdCv0IxCbvGXD3f861ChsNU5F/MeyE2X7 +SHBT1H5mfSU/y4mwf5q9pbBYX/UO0+pnDWlC2TuJiI1fZx25Mjt8Pw== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/django_jwt_token/public.pem b/django_jwt_token/public.pem new file mode 100644 index 0000000..5a964d2 --- /dev/null +++ b/django_jwt_token/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmG+9lzwnpsABxqO00Aqe +it3cOTV2354FmIztL1GOa34odktiiUOJIGY1JhVN3LXt4CaSpCkK6tfSQRXOrF2j +d0QYimN0zIQwJ7GJnzPQynoBJh2O9u6zOMtVkFqG9eafEqaR2lf5Ol1Pu3evUJx0 +a6IiIr+hxKJqP6MO73eeriKYV+4V/+jzrn2WJjp3RnM9P1PQ4fCkIAZOLmb9lB/W +sNMaEJs8nab3KJeILv5kLm1wDMYuLzQ3kGtCrQPK6riw9s02hELSWj3Wy1U8ZM8b +QcIv6WGn1Zyhwpos9CDe+sH2D4EejA7wMZoBg4M39GRikK8VKE1nvN1wjQ7eIAGg +fwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/django_jwt_token/用户登陆身份接口.py b/django_jwt_token/用户登陆身份接口.py new file mode 100644 index 0000000..e9f2a3e --- /dev/null +++ b/django_jwt_token/用户登陆身份接口.py @@ -0,0 +1,64 @@ +import threading +import time +from datetime import datetime, timedelta +from pathlib import Path +from zoneinfo import ZoneInfo + +from Crypto.PublicKey import RSA +from django.conf import settings +from jwt import JWT, jwk_from_pem +from jwt.utils import get_int_from_datetime +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 + + + +private_key_pem_私钥 = Path( settings.BASE_DIR ).joinpath( "django_jwt/private.pem" ).read_bytes( ) + + + + + +class JwtUserViewSets( ViewSet ): + lock = threading.Lock( ) + + instance = JWT( ) # 创建对象 + + + + @action( detail=False, methods=[ "post" ], url_path="login" ) + def login( self, request: Request ): + """""" + + # 创建 payload + message = { + 'iss': 'my-app', + 'sub': 'user123', + 'name': '张三', + 'role': 'admin', + 'iat': get_int_from_datetime( datetime.now( tz=ZoneInfo( key="utc" ) ) ), # 生成jwt-token的时间 + 'exp': get_int_from_datetime( datetime.now( tz=ZoneInfo( key="utc" ) ) + timedelta( hours=1 ) ), # 多长时间过期 + } + + # ✅ 正确:使用私钥进行签名 (目前我使用的是私钥加密的) (生成钥钥的时候就是加密的私钥) + 私钥对象 = RSA.import_key( extern_key=private_key_pem_私钥, passphrase=settings.SECRET_KEY ).export_key( format="PEM" ) + signing_key = jwk_from_pem( pem_content=私钥对象 ) + token = self.instance.encode( payload=message, key=signing_key, alg='RS256' ) # 注意算法名改为 RS256 + print( f"生成的 JWT: {token}" ) + return Response( data=token, status=status.HTTP_200_OK, headers={ "Authorization": token, "Access-Control-Allow-Origin": "*" } ) + + + + + +JwtUserViewSetsRouter = DefaultRouter( ) +JwtUserViewSetsRouter.register( prefix="", viewset=JwtUserViewSets, basename="JwtUserViewSets" ) + + + + + diff --git a/django_routes/企业微信管理端接口列表.py b/django_routes/企业微信管理端接口列表.py new file mode 100644 index 0000000..5440045 --- /dev/null +++ b/django_routes/企业微信管理端接口列表.py @@ -0,0 +1,17 @@ +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" ) diff --git a/django_routes/小程序前端页面分享接口列表.py b/django_routes/小程序前端页面分享接口列表.py new file mode 100644 index 0000000..1cbfed0 --- /dev/null +++ b/django_routes/小程序前端页面分享接口列表.py @@ -0,0 +1,10 @@ +from rest_framework.routers import DefaultRouter + +from wechat_mini_服务端接口目录.小程序前端分享页面.主面分享页面接口 import 主页分享页面接口ViewSets +from wechat_mini_服务端接口目录.小程序前端分享页面.商品详情页面分享接口 import 商品详情页面分享接口ViewSets +from wechat_mini_服务端接口目录.小程序前端分享页面.幸运拼团分享接口 import 幸运拼团分享接口ViewSets + +小程序前端分享页面Router = DefaultRouter() +小程序前端分享页面Router.register(prefix="home_page", viewset=主页分享页面接口ViewSets, basename="主页分享页面接口ViewSets") +小程序前端分享页面Router.register(prefix="goods_page", viewset=商品详情页面分享接口ViewSets, basename="商品详情页面分享接口ViewSets") +小程序前端分享页面Router.register(prefix="lucky_page", viewset=幸运拼团分享接口ViewSets, basename="幸运拼团分享接口ViewSets") diff --git a/django_routes/小程序服务端接口管理列表.py b/django_routes/小程序服务端接口管理列表.py new file mode 100644 index 0000000..8e89c00 --- /dev/null +++ b/django_routes/小程序服务端接口管理列表.py @@ -0,0 +1,43 @@ +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 +from django_app.积分提现接口 import 积分提现ViewSets +from django_app.积分查询管理接口 import 积分查询接口ViewSets +from django_app.项目初始化的接口 import 项目初始化功能接口ViewSets +# from wechat_mini_业务接口目录.用户积分管理业务接口.积分管理业务 import 积分管理ViewSets +from wechat_mini_服务端接口目录.小程序交易管理服务接口列表.发货信息录入 import 发货信息录入ViewSets +from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.ShortLink接口 import ShortLinkViewSets +from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.URLLink接口 import URLLinkViewSets +from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.scheme码接口 import Scheme接口ViewSets +from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.小程序码接口 import 小程序码接口ViewSets +from wechat_mini_服务端接口目录.手机号.获取手机号接口 import 获取手机号ViewSets +from wechat_mini_服务端接口目录.接口调用凭证.获取稳定版接口调用凭据接口 import 获取稳定版接口调用凭据ViewSets +from wechat_mini_服务端接口目录.物流账号邮政.物流账号接口 import EMS物流ViewSets +from wechat_mini_服务端接口目录.用工关系接口列表.用工关系接口 import 用工关系接口ViewSets +from wechat_mini_服务端接口目录.附近小程序.附近小程序接口 import 附近小程序ViewSets + +小程序服务端管理接口列表ViewSetsRouter = DefaultRouter() +小程序服务端管理接口列表ViewSetsRouter.register(prefix="nearby_mini_program", viewset=附近小程序ViewSets, + basename="附近小程序ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="phone", viewset=获取手机号ViewSets, + basename="获取手机号ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="token", viewset=获取稳定版接口调用凭据ViewSets, + basename="获取稳定版接口调用凭据ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="ems", viewset=EMS物流ViewSets, basename="EMS物流ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="shipment_information_management", viewset=发货信息录入ViewSets, + basename="发货信息录入ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="用工关系", viewset=用工关系接口ViewSets, basename="用工关系接口ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="qrcode", viewset=小程序码接口ViewSets, basename="小程序码接口ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="scheme", viewset=Scheme接口ViewSets, basename="Scheme接口ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="link", viewset=URLLinkViewSets, basename="URLLinkViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="short", viewset=ShortLinkViewSets, basename="ShortLinkViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="用户评价", viewset=用户评价ViewSets, basename="用户评价ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="更新物流", viewset=实时更新物流数据ViewSets, basename="实时更新物流数据ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="优惠券", viewset=小程序发优惠券到钱包接口ViewSets, basename="小程序发优惠券到钱包接口ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="添加积分接口", viewset=添加积分接口ViewSets, basename="添加积分接口ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="积分查询", viewset=积分查询接口ViewSets, basename="积分查询接口ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="积分提现", viewset=积分提现ViewSets, basename="积分提现ViewSets") +小程序服务端管理接口列表ViewSetsRouter.register(prefix="项目初始化接口", viewset=项目初始化功能接口ViewSets, basename="项目初始化接口") diff --git a/django_routes/小程序用户地址定位地图路由列表.py b/django_routes/小程序用户地址定位地图路由列表.py new file mode 100644 index 0000000..94e5aa9 --- /dev/null +++ b/django_routes/小程序用户地址定位地图路由列表.py @@ -0,0 +1,9 @@ +from rest_framework.routers import DefaultRouter + +from wechat_mini_服务端接口目录.小程序用户地址定位.小程序用户的位置接口 import 小程序用户的位置接口ViewSets +from wechat_mini_服务端接口目录.小程序用户地址定位.小程序用户配送地址接口 import 用户配送地址ViewSets + +小程序用户地址定位地图Router = DefaultRouter() +小程序用户地址定位地图Router.register(prefix="delivery", viewset=用户配送地址ViewSets, basename="用户配送地址ViewSets") +小程序用户地址定位地图Router.register(prefix="map", viewset=小程序用户的位置接口ViewSets, + basename="小程序用户的位置接口ViewSets") diff --git a/django_routes/小程序码链接接口路由列表.py b/django_routes/小程序码链接接口路由列表.py new file mode 100644 index 0000000..4fa5510 --- /dev/null +++ b/django_routes/小程序码链接接口路由列表.py @@ -0,0 +1,12 @@ +# from rest_framework.routers import DefaultRouter +# +# from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.ShortLink接口 import ShortLinkViewSets +# from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.URLLink接口 import URLLinkViewSets +# from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.scheme码接口 import Scheme接口ViewSets +# from wechat_mini_服务端接口目录.小程序码与小程序链接口列表.小程序码接口 import 小程序码接口ViewSets +# +# 小程序码路由Router = DefaultRouter() +# 小程序码路由Router.register(prefix="qrcode", viewset=小程序码接口ViewSets, basename="小程序码接口ViewSets") +# 小程序码路由Router.register(prefix="scheme", viewset=Scheme接口ViewSets, basename="Scheme接口ViewSets") +# 小程序码路由Router.register(prefix="link", viewset=URLLinkViewSets, basename="URLLinkViewSets") +# 小程序码路由Router.register(prefix="short", viewset=ShortLinkViewSets, basename="ShortLinkViewSets") diff --git a/django_routes/服务号接口列表.py b/django_routes/服务号接口列表.py new file mode 100644 index 0000000..5fe832a --- /dev/null +++ b/django_routes/服务号接口列表.py @@ -0,0 +1,8 @@ +from rest_framework.routers import DefaultRouter + +from django_wechat_服务号.服务号接收微信code网页授权 import 服务号网页授权接口ViewSets + + + +服务号接口列表Router = DefaultRouter( ) +服务号接口列表Router.register( prefix="auth", viewset=服务号网页授权接口ViewSets, basename="服务号网页授权接口ViewSets" ) diff --git a/django_routes/桌面端接口列表.py b/django_routes/桌面端接口列表.py new file mode 100644 index 0000000..e05fb3c --- /dev/null +++ b/django_routes/桌面端接口列表.py @@ -0,0 +1,12 @@ +from rest_framework.routers import DefaultRouter + +from django_web_管理后台接口.企业微信查询管理接口.企微用户接口 import 企业微信接口ViewSets +from django_web_管理后台接口.用户登陆.用户登陆接口 import 用户登陆接口ViewSets +from django_web_微信开放平台应用用户登陆.接收微信的code回调 import 接收微信的code回调ViewSets + + + +桌面端企业微信接口ViewSets列表Router = DefaultRouter( ) +桌面端企业微信接口ViewSets列表Router.register( prefix="企微用户", viewset=企业微信接口ViewSets, basename="企业微信接口ViewSets" ) +桌面端企业微信接口ViewSets列表Router.register( prefix="用户", viewset=用户登陆接口ViewSets, basename="用户登陆接口ViewSets" ) +桌面端企业微信接口ViewSets列表Router.register( prefix="auth", viewset=接收微信的code回调ViewSets, basename="接收微信的code回调ViewSets" ) diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0.png differ diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_7Qas1JF.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_7Qas1JF.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_7Qas1JF.png differ diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_Lxv5Xpz.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_Lxv5Xpz.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_Lxv5Xpz.png differ diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_a09vawh.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_a09vawh.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_a09vawh.png differ diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_d8ts1H2.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_d8ts1H2.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_d8ts1H2.png differ diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_sJYYrWr.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_sJYYrWr.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_sJYYrWr.png differ diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_uQucVEC.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_uQucVEC.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_uQucVEC.png differ diff --git a/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_z0pdu84.png b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_z0pdu84.png new file mode 100644 index 0000000..3108c1d Binary files /dev/null and b/django_static_directory/media/01a109f32aa5d89fb02633029ed19ac0_z0pdu84.png differ diff --git a/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3.jpg b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3.jpg new file mode 100644 index 0000000..c4fb7a3 Binary files /dev/null and b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3.jpg differ diff --git a/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_6nTfpUZ.jpg b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_6nTfpUZ.jpg new file mode 100644 index 0000000..c4fb7a3 Binary files /dev/null and b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_6nTfpUZ.jpg differ diff --git a/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_IQixypw.jpg b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_IQixypw.jpg new file mode 100644 index 0000000..c4fb7a3 Binary files /dev/null and b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_IQixypw.jpg differ diff --git a/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_VDNCqYc.jpg b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_VDNCqYc.jpg new file mode 100644 index 0000000..c4fb7a3 Binary files /dev/null and b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_VDNCqYc.jpg differ diff --git a/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_hWtYdBj.jpg b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_hWtYdBj.jpg new file mode 100644 index 0000000..c4fb7a3 Binary files /dev/null and b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_hWtYdBj.jpg differ diff --git a/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_hpp5gnh.jpg b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_hpp5gnh.jpg new file mode 100644 index 0000000..c4fb7a3 Binary files /dev/null and b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_hpp5gnh.jpg differ diff --git a/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_uNrDVeX.jpg b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_uNrDVeX.jpg new file mode 100644 index 0000000..c4fb7a3 Binary files /dev/null and b/django_static_directory/media/04bb3a80d9e837ec90b5fb03b242cff3_uNrDVeX.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_UiuqEFB.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_UiuqEFB.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_UiuqEFB.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_VpmGVYy.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_VpmGVYy.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_VpmGVYy.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_W2JdnSu.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_W2JdnSu.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_W2JdnSu.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_cUjTIPZ.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_cUjTIPZ.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_cUjTIPZ.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_fqvysSR.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_fqvysSR.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_fqvysSR.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_lgHuWqC.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_lgHuWqC.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_lgHuWqC.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_wjs0qag.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_wjs0qag.jpg new file mode 100644 index 0000000..9c82f83 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec 2_wjs0qag.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec.jpg new file mode 100644 index 0000000..d494a48 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_1PHgPAk.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_1PHgPAk.jpg new file mode 100644 index 0000000..d494a48 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_1PHgPAk.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_1en5YYm.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_1en5YYm.jpg new file mode 100644 index 0000000..d494a48 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_1en5YYm.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_VWxkypd.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_VWxkypd.jpg new file mode 100644 index 0000000..d494a48 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_VWxkypd.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_jeaIOq6.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_jeaIOq6.jpg new file mode 100644 index 0000000..d494a48 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_jeaIOq6.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_lhNMtLm.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_lhNMtLm.jpg new file mode 100644 index 0000000..d494a48 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_lhNMtLm.jpg differ diff --git a/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_p3uNLus.jpg b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_p3uNLus.jpg new file mode 100644 index 0000000..d494a48 Binary files /dev/null and b/django_static_directory/media/1c4c11b3289d630ff7e5b2ed23a5acec_p3uNLus.jpg differ diff --git a/django_static_directory/media/6901028300094.jpg b/django_static_directory/media/6901028300094.jpg new file mode 100644 index 0000000..d3fa3c7 Binary files /dev/null and b/django_static_directory/media/6901028300094.jpg differ diff --git a/django_static_directory/media/6901028300094_AhDBJcQ.jpg b/django_static_directory/media/6901028300094_AhDBJcQ.jpg new file mode 100644 index 0000000..d3fa3c7 Binary files /dev/null and b/django_static_directory/media/6901028300094_AhDBJcQ.jpg differ diff --git a/django_static_directory/media/6901028300094_OhN2jOR.jpg b/django_static_directory/media/6901028300094_OhN2jOR.jpg new file mode 100644 index 0000000..d3fa3c7 Binary files /dev/null and b/django_static_directory/media/6901028300094_OhN2jOR.jpg differ diff --git a/django_static_directory/media/6901028300094_VmJYwRa.jpg b/django_static_directory/media/6901028300094_VmJYwRa.jpg new file mode 100644 index 0000000..d3fa3c7 Binary files /dev/null and b/django_static_directory/media/6901028300094_VmJYwRa.jpg differ diff --git a/django_static_directory/media/6901028300094_YtZ21mu.jpg b/django_static_directory/media/6901028300094_YtZ21mu.jpg new file mode 100644 index 0000000..d3fa3c7 Binary files /dev/null and b/django_static_directory/media/6901028300094_YtZ21mu.jpg differ diff --git a/django_static_directory/media/6901028300094_e8ai8Vi.jpg b/django_static_directory/media/6901028300094_e8ai8Vi.jpg new file mode 100644 index 0000000..d3fa3c7 Binary files /dev/null and b/django_static_directory/media/6901028300094_e8ai8Vi.jpg differ diff --git a/django_static_directory/media/6901028300094_nalElhT.jpg b/django_static_directory/media/6901028300094_nalElhT.jpg new file mode 100644 index 0000000..d3fa3c7 Binary files /dev/null and b/django_static_directory/media/6901028300094_nalElhT.jpg differ diff --git a/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec.jpg b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec.jpg new file mode 100644 index 0000000..9ee21c7 Binary files /dev/null and b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec.jpg differ diff --git a/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_4nzZs66.jpg b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_4nzZs66.jpg new file mode 100644 index 0000000..9ee21c7 Binary files /dev/null and b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_4nzZs66.jpg differ diff --git a/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_AF1avZ2.jpg b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_AF1avZ2.jpg new file mode 100644 index 0000000..9ee21c7 Binary files /dev/null and b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_AF1avZ2.jpg differ diff --git a/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_M6Ej34n.jpg b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_M6Ej34n.jpg new file mode 100644 index 0000000..9ee21c7 Binary files /dev/null and b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_M6Ej34n.jpg differ diff --git a/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_QC0AMux.jpg b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_QC0AMux.jpg new file mode 100644 index 0000000..9ee21c7 Binary files /dev/null and b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_QC0AMux.jpg differ diff --git a/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_gQEdnYi.jpg b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_gQEdnYi.jpg new file mode 100644 index 0000000..9ee21c7 Binary files /dev/null and b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_gQEdnYi.jpg differ diff --git a/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_oaApqbH.jpg b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_oaApqbH.jpg new file mode 100644 index 0000000..9ee21c7 Binary files /dev/null and b/django_static_directory/media/8976890a43038c1031c2cda8dfd414ec_oaApqbH.jpg differ diff --git a/django_static_directory/media/扫描 4.png b/django_static_directory/media/扫描 4.png new file mode 100644 index 0000000..8212915 Binary files /dev/null and b/django_static_directory/media/扫描 4.png differ diff --git a/django_static_directory/media/扫描 4_9wY9sO8.png b/django_static_directory/media/扫描 4_9wY9sO8.png new file mode 100644 index 0000000..8212915 Binary files /dev/null and b/django_static_directory/media/扫描 4_9wY9sO8.png differ diff --git a/django_static_directory/media/扫描 4_BdM2DSo.png b/django_static_directory/media/扫描 4_BdM2DSo.png new file mode 100644 index 0000000..8212915 Binary files /dev/null and b/django_static_directory/media/扫描 4_BdM2DSo.png differ diff --git a/django_static_directory/media/扫描 4_ZyYNucA.png b/django_static_directory/media/扫描 4_ZyYNucA.png new file mode 100644 index 0000000..8212915 Binary files /dev/null and b/django_static_directory/media/扫描 4_ZyYNucA.png differ diff --git a/django_static_directory/media/扫描 4_n8PcQ0Z.png b/django_static_directory/media/扫描 4_n8PcQ0Z.png new file mode 100644 index 0000000..8212915 Binary files /dev/null and b/django_static_directory/media/扫描 4_n8PcQ0Z.png differ diff --git a/django_static_directory/static/favicon.ico b/django_static_directory/static/favicon.ico new file mode 100644 index 0000000..fabbf79 Binary files /dev/null and b/django_static_directory/static/favicon.ico differ diff --git a/django_static_directory/static/six.ico b/django_static_directory/static/six.ico new file mode 100644 index 0000000..fabbf79 Binary files /dev/null and b/django_static_directory/static/six.ico differ diff --git a/django_static_directory/static/xiao.png b/django_static_directory/static/xiao.png new file mode 100644 index 0000000..895c0b0 Binary files /dev/null and b/django_static_directory/static/xiao.png differ diff --git a/django_static_directory/static_test/favicon.ico b/django_static_directory/static_test/favicon.ico new file mode 100644 index 0000000..fabbf79 Binary files /dev/null and b/django_static_directory/static_test/favicon.ico differ diff --git a/django_web_微信开放平台应用用户登陆/0p7rS8xxjR.txt b/django_web_微信开放平台应用用户登陆/0p7rS8xxjR.txt new file mode 100644 index 0000000..6606a85 --- /dev/null +++ b/django_web_微信开放平台应用用户登陆/0p7rS8xxjR.txt @@ -0,0 +1 @@ +6cc4ac5304ad1a914e945ed504414126 \ No newline at end of file diff --git a/django_web_微信开放平台应用用户登陆/接收微信的code回调.py b/django_web_微信开放平台应用用户登陆/接收微信的code回调.py new file mode 100644 index 0000000..6768a6c --- /dev/null +++ b/django_web_微信开放平台应用用户登陆/接收微信的code回调.py @@ -0,0 +1,133 @@ +import threading +from datetime import datetime, timedelta +from functools import wraps +from pathlib import Path +from urllib.parse import urlencode +from zoneinfo import ZoneInfo + +import orjson +import pydash +import requests +from Crypto.PublicKey import RSA +from django.conf import settings +from django.http import HttpResponseRedirect +from jwt import JWT, jwk_from_pem +from jwt.utils import get_int_from_datetime +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.viewsets import ViewSet + +from wechat_token.token数据库 import weitoken + + +def sync_lock_线程锁(lock): + def decorator(fn): + @wraps(fn) + def wrapper(*args, **kwargs): + with lock: + return fn(*args, **kwargs) + + return wrapper + + return decorator + + +class AllowMyAppRedirect(HttpResponseRedirect): + allowed_schemes = ["http", "https", "myapp"] + + +class 接收微信的code回调ViewSets(ViewSet): + lock = threading.Lock() + private_key_pem_私钥 = Path(settings.BASE_DIR).joinpath("django_jwt_token/private.pem").read_bytes() + + def jwt_生成token(self, openid, uniond): + # 读取私钥的 bytes字符串 + + # 创建一个 JWT对象 + jwt对象实例 = JWT() # 创建对象 + # 创建 payload + message = { + "openid": openid, + "uniond": uniond, + 'iat': get_int_from_datetime(datetime.now(tz=ZoneInfo(key="utc"))), # 生成jwt-token的时间 + 'exp': get_int_from_datetime(datetime.now(tz=ZoneInfo(key="utc")) + timedelta(hours=1)), # 多长时间过期 + } + # 获取私钥对象 (并且要私钥的密码) + 私钥对象 = RSA.import_key(extern_key=self.private_key_pem_私钥, passphrase=settings.SECRET_KEY).export_key() + signing_key = jwk_from_pem(pem_content=私钥对象, ) + token = jwt对象实例.encode(payload=message, key=signing_key, alg="RS256") + return token + + def get网站授权access_token(self, code, state): + uri = "https://api.weixin.qq.com/sns/oauth2/access_token" + postData = requests.post(url=uri, params={ + "appid": "wx6c9d4541e0285d02", + "secret": "bb87178b80e23f2fc96b688577dafca4", + "code": code, + "grant_type": "authorization_code" + }).json() + access_token = pydash.get(obj=postData, path="access_token") + expires_in = pydash.get(obj=postData, path="expires_in") + refresh_token = pydash.get(obj=postData, path="refresh_token") + openid = pydash.get(obj=postData, path="openid") + scope = pydash.get(obj=postData, path="scope") + unionid = pydash.get(obj=postData, path="unionid") + return postData + + def get获取用户个人信息(self, code, state): + uri = f"https://api.weixin.qq.com/sns/userinfo" + token, is创建 = weitoken.objects.update_or_create(token_name="web_token") + if is创建: + wx_access_token_dict = self.get网站授权access_token(code=code, state=state) + token.token_value = pydash.get(obj=wx_access_token_dict, path="access_token") + token.save() + access_token = pydash.get(obj=wx_access_token_dict, path="access_token") + openid = pydash.get(obj=wx_access_token_dict, path="openid") + getData = requests.get(url=uri, params={"access_token": access_token, "openid": openid}) + res = orjson.loads(getData.content.decode(encoding="utf-8")) + return res + else: + time创建时间 = token.updateTime.timestamp() # 更新时间的时间戳 + current_时间戳 = get_int_from_datetime(value=datetime.now()) + if current_时间戳 - time创建时间 > 3600: + # 时间过期时,需要重新请求 拿到新的 access_token + wx_access_token_dict = self.get网站授权access_token(code=code, state=state) + # 更新token的值 + token.token_value = pydash.get(obj=wx_access_token_dict, path="access_token") + token.save() + access_token = pydash.get(obj=wx_access_token_dict, path="access_token") + openid = pydash.get(obj=wx_access_token_dict, path="openid") + getData = requests.get(url=uri, params={"access_token": access_token, "openid": openid}) + res = orjson.loads(getData.content.decode(encoding="utf-8")) + return res + else: + wx_access_token_dict = self.get网站授权access_token(code=code, state=state) + # 更新token的值 + token.token_value = pydash.get(obj=wx_access_token_dict, path="access_token") + token.save() + access_token = pydash.get(obj=wx_access_token_dict, path="access_token") + openid = pydash.get(obj=wx_access_token_dict, path="openid") + getData = requests.get(url=uri, params={"access_token": access_token, "openid": openid}) + res = orjson.loads(getData.content.decode(encoding="utf-8")) + return res + + @action(detail=False, methods=["get", ], url_path="get_code", ) + # @sync_lock_线程锁( lock=lock ) + def get_code(self, request: Request): + """ + 前端,带着code的get请求,在这里拿到code,获取登陆用户的信息, + 重点: 通过回调,前端,(处理业务逻辑) 由于我这里使用的是Mac桌面版本. + :param request: + :return: + """ + code = request.query_params.get(key="code", default=None) + state = request.data.get("state", None) + user_info_用户信息 = self.get获取用户个人信息(code=code, state=state) + openid = pydash.get(obj=user_info_用户信息, path="openid") + unionid = pydash.get(obj=user_info_用户信息, path="unionid") + print("为什么没有值了呢", openid, unionid) + token = self.jwt_生成token(openid=openid, uniond=unionid) + setData = pydash.set_(obj=user_info_用户信息, path="token", value=token) + query_string = urlencode(setData, ) + uri = f"myapp://open/home?{query_string}" + return AllowMyAppRedirect(redirect_to=uri) diff --git a/django_web_微信开放平台应用用户登陆/网页端验证文件接口.py b/django_web_微信开放平台应用用户登陆/网页端验证文件接口.py new file mode 100644 index 0000000..0f15834 --- /dev/null +++ b/django_web_微信开放平台应用用户登陆/网页端验证文件接口.py @@ -0,0 +1,46 @@ +import threading +from functools import wraps +from pathlib import Path + +from django.conf import settings +from django.http import HttpResponse +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.viewsets import ViewSet + + + + + +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( ) + + + + # @sync_lock_线程锁( lock=lock ) + def 网页端验证文件接口( self, request: Request ): + pass + print( "=======================" ) + auth_text = Path( settings.BASE_DIR ).joinpath( "django_web_微信开放平台应用用户登陆/0p7rS8xxjR.txt" ).read_text( ) + print( auth_text ) + return HttpResponse( content=auth_text ) diff --git a/django_web_管理后台接口/企业微信查询管理接口/企微用户接口.py b/django_web_管理后台接口/企业微信查询管理接口/企微用户接口.py new file mode 100644 index 0000000..50addd8 --- /dev/null +++ b/django_web_管理后台接口/企业微信查询管理接口/企微用户接口.py @@ -0,0 +1,37 @@ +import threading + +from rest_framework.decorators import action +from rest_framework.pagination import PageNumberPagination +from rest_framework.request import Request +from rest_framework.viewsets import ViewSet + +from sixGuoDjango import BaseResponse, ResData +from wechat_数据库.企业微信数据库.企微用户表 import wecom企微用户 + + + + + +class 企微用户分页( PageNumberPagination ): + page_size = 10 + page_size_query_param = "page_size" + max_page_size = 100 + + + + + +class 企业微信接口ViewSets( ViewSet ): + lock = threading.Lock( ) + + + + @action( detail=False, methods=[ "post" ], url_path="查询添加的企微用户" ) + def 查询添加的企微用户( self, request: Request ): + """""" + wecom_data = wecom企微用户.objects.all( ).values( ) + paginator = 企微用户分页( ) + page_queryset = paginator.paginate_queryset( wecom_data, request ) + print( "🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎" ) + httpResData = BaseResponse( resData=ResData( listData=wecom_data, dictData={ } ), ).model_dump( ) + return paginator.get_paginated_response( page_queryset ) diff --git a/django_web_管理后台接口/用户登陆/用户登陆接口.py b/django_web_管理后台接口/用户登陆/用户登陆接口.py new file mode 100644 index 0000000..254e9b4 --- /dev/null +++ b/django_web_管理后台接口/用户登陆/用户登陆接口.py @@ -0,0 +1,62 @@ +import threading +from datetime import datetime, timedelta +from pathlib import Path +from zoneinfo import ZoneInfo + +from Crypto.PublicKey import RSA +from django.conf import settings +from jwt import JWT, jwk_from_pem +from jwt.utils import get_int_from_datetime +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 django_jwt_token.jwt认证接口 import Jwt身份认证 + + + +private_key_pem_私钥 = Path( settings.BASE_DIR ).joinpath( "django_jwt_token/private.pem" ).read_bytes( ) + + + + + +class 用户登陆接口ViewSets( ViewSet ): + lock = threading.Lock( ) + + instance = JWT( ) # 创建对象 + + + + @action( detail=False, methods=[ "post" ], url_path="登陆" ) + def 登陆( self, request: Request ): + """""" + message = { + 'iss': 'my-app', + 'sub': 'user123', + 'name': '张三', + 'role': 'admin', + 'iat': get_int_from_datetime( datetime.now( tz=ZoneInfo( key="utc" ) ) ), + 'exp': get_int_from_datetime( datetime.now( tz=ZoneInfo( key="utc" ) ) + timedelta( hours=1 ) ), + } + + # ✅ 正确:使用私钥进行签名 + 私钥对象 = RSA.import_key( extern_key=private_key_pem_私钥, passphrase=settings.SECRET_KEY ).export_key( ) + signing_key = jwk_from_pem( pem_content=私钥对象 ) + token = self.instance.encode( payload=message, key=signing_key, alg='RS256' ) # 注意算法名改为 RS256 + print( f"生成的 JWT: {token}" ) + return Response( data=token, status=status.HTTP_200_OK, headers={ "Authorization": token, "Access-Control-Allow-Origin": "*" } ) + + + + @action( detail=False, methods=[ "post" ], url_path="验证用户身份", authentication_classes=[ Jwt身份认证 ] ) + def 验证用户身份( self, request: Request ): + """""" + # 模拟一个可能导致错误的操作 + # ✅ 正确:使用公钥进行验证 + print( "只是打印测试一下" ) + print( request.user ) + print( request.auth ) + return Response( data={ "code": 200, "msg": "Success", "data": "" }, ) diff --git a/django_wechat_服务号/__init__.py b/django_wechat_服务号/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_wechat_服务号/服务号接收微信code网页授权.py b/django_wechat_服务号/服务号接收微信code网页授权.py new file mode 100644 index 0000000..7095c90 --- /dev/null +++ b/django_wechat_服务号/服务号接收微信code网页授权.py @@ -0,0 +1,120 @@ +import hashlib +import threading +from datetime import datetime, timedelta +from functools import wraps +from pathlib import Path +from zoneinfo import ZoneInfo + +from Crypto.PublicKey import RSA +from django.conf import settings +from django.http import HttpResponse, HttpResponseRedirect +from jwt import JWT, jwk_from_pem +from jwt.utils import get_int_from_datetime +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 wechat_token.token工具包 import sixToken +from wechat_数据库.雪花算法.雪花算法工具 import generator + + + + + +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( ) + + def jwt_生成token( self, 有效时间_单位小时: int = 1 ): + # 读取私钥的 bytes字符串 + private_key_pem_私钥 = Path( settings.BASE_DIR ).joinpath( "django_jwt_token/private.pem" ).read_bytes( ) + + # 创建一个 JWT对象 + jwt对象实例 = JWT( ) # 创建对象 + # 创建 payload + message = { + "oenid": "xiaozizi", + "uniond": "kladfj", + 'iat': get_int_from_datetime( datetime.now( tz=ZoneInfo( key="utc" ) ) ), # 生成jwt-token的时间 + 'exp': get_int_from_datetime( datetime.now( tz=ZoneInfo( key="utc" ) ) + timedelta( hours=有效时间_单位小时 ) ), # 多长时间过期 + } + # 获取私钥对象 (并且要私钥的密码) + 私钥对象 = RSA.import_key( extern_key=private_key_pem_私钥, passphrase=settings.SECRET_KEY ).export_key( ) + signing_key = jwk_from_pem( pem_content=私钥对象, ) + token = jwt对象实例.encode( payload=message, key=signing_key, alg="RS256" ) + return token + + @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="get_code" ) + # @sync_lock_线程锁( lock=lock ) + def 获取code接口( self, request: Request ): + pass + code = request.query_params.get( key="code", default=None ) + print( "拿到的code的值是多少了呢?", code ) + six_token = self.jwt_生成token( 有效时间_单位小时=24 ) + uri = f"http://0.0.0.0:3000/home?six_token={six_token}" + # uri = f"https://wechat.sixgou.com?code={code}" + return HttpResponseRedirect( redirect_to=uri ) + + @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="msg" ) + # @sync_lock_线程锁( lock=lock ) + def 响应微信服务器回调Token( self, request: Request ): + pass + print( request.headers ) + signature = request.query_params.get( key="signature", default="" ) + timestamp = request.query_params.get( key="timestamp", default="" ) + nonce = request.query_params.get( key="nonce", default="" ) + echostr = request.query_params.get( key="echostr", default="" ) + print( signature, "===================" ) + token = "xiaozizi" + params = [ token, timestamp, nonce ] + params.sort( ) + tmp_str = "".join( params ) + sig_str = f"{token}{timestamp}{nonce}" + res = hashlib.sha1( data=tmp_str.encode( encoding="utf-8" ) ).hexdigest( ) + if sig_str == res: + print( "判断相等了" ) + return HttpResponse( content=echostr ) + + @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="signature" ) + # @sync_lock_线程锁( lock=lock ) + def signature( self, request: Request ): + """ + 对网页请求使用 的功能进行授权 如:chooiseImage (在微信环境中,调用用户的相机的功能) + 从前端的body,接收到url,然后后端生成随机字符串和时间戳 + 重点: 这个属性的key的字符,大小写要一模一样 + :param request: + :return: + """ + pass + url = request.data.get( "url", None ) + timestamp = get_int_from_datetime( value=datetime.now( ) ) + nonceStr = generator.generate_str( ) + jsapi_ticket = sixToken.get_wechat_tick_token( ) + sig_str = f"jsapi_ticket={jsapi_ticket}&noncestr={nonceStr}×tamp={timestamp}&url={url}" + signature = hashlib.sha1( data=sig_str.encode( encoding="utf-8" ) ).hexdigest( ) + return Response( data={ "nonceStr": nonceStr, "timestamp": timestamp, "signature": signature } ) + + # @action( detail=False, methods=[ "get",], url_path="认证接口文件" ) + # @sync_lock_线程锁( lock=lock ) + def 认证接口文件( self, request: Request ): + pass + return HttpResponse( content="kMmcLX8ZO79apUxA" ) diff --git a/django_定时器/团购任务.py b/django_定时器/团购任务.py new file mode 100644 index 0000000..39906e0 --- /dev/null +++ b/django_定时器/团购任务.py @@ -0,0 +1,141 @@ +import os + +import django + +from sixGuoDjango.settings import BASE_DIR + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() + +# timer_manager.py +import threading +import secrets +from datetime import datetime, timedelta +from zoneinfo import ZoneInfo + +from apscheduler.jobstores.base import JobLookupError +from apscheduler.schedulers.background import BackgroundScheduler +from apscheduler.jobstores.memory import MemoryJobStore +from apscheduler.executors.pool import ThreadPoolExecutor + +from django_定时器.幸运拼团数据库 import lucky拼团 +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class TwoHourWindowManager: + """ + 团购任务 + """ + _instance = None + _lock = threading.Lock() + + def __new__(cls): + if cls._instance is None: + with cls._lock: + if cls._instance is None: + cls._instance = super().__new__(cls) + cls._instance._initialized = False + return cls._instance + + def __init__(self): + if self._initialized: + return + self._initialized = True + self.generate_str_id = None + # 共享状态 + self.items = [] + self.current_cleanup_job_id: str | None = None + self.state_lock = threading.RLock() # 保护 items 和 job_id + # 在这里,需要对数据库的数据进行处理 + self.init初始化数据库() + # 初始化调度器(单例) + jobstores = {'default': MemoryJobStore()} + executors = {'default': ThreadPoolExecutor(max_workers=2)} + self.scheduler = BackgroundScheduler( + jobstores=jobstores, executors=executors, timezone='Asia/Shanghai', # 替换为你的 settings.TIME_ZONE + ) + self.scheduler.start() + # 启动初始清理任务(2小时后) + self._schedule_cleanup() + + def 开团重置(self): + """APScheduler 调用的清理函数""" + with self.state_lock: + print("开团重置任务触发了啦") + + print(f"[{datetime.now()}] ⏰⏰⏰⏰⏰⏰⏰⏰⏰⏰⏰ 定时器到期,清空列表(当前 {len(self.items)} 项)") + self.items.clear() + self.current_cleanup_job_id = None # 任务已执行,ID 失效 + self.init初始化数据库() + self._schedule_cleanup() # 开启新的任务 + print("开启新的任务") + + def init初始化数据库(self): + print("初始化数据库执行中") + generate_str = generator.generate_str() + 创建对象 = lucky拼团.objects.create(idKey=generate_str, lucky拼团详细=[]) + self.generate_str_id = 创建对象.idKey + + def _schedule_cleanup(self): + """安排一个新的 2 小时后清理任务""" + with self.state_lock: + # 取消旧任务(如果存在且未执行) + if self.current_cleanup_job_id is not None: + print("存在旧的任务的吗?") + try: + self.scheduler.remove_job(self.current_cleanup_job_id) + print("存在旧的任务的吗?") + pass + except JobLookupError: + pass # 可能已被执行或不存在 + print("打印报错", JobLookupError) + + # 添加新任务 + job = self.scheduler.add_job( + func=self.开团重置, + trigger='date', + run_date=datetime.now(tz=ZoneInfo("Asia/Shanghai")) + timedelta(seconds=7200), + id=f"cleanup_{secrets.token_hex(8)}", + name="Auto Cleanup", + ) + self.current_cleanup_job_id = job.id + print(f"[{datetime.now()}] 🕒 新建清理任务,2小时后执行,ID: {job.id}") + + def add_item(self, item): + """外部调用:安全地添加元素""" + with self.state_lock: + self.items.append(item) + print(f"[{datetime.now()}] ➕ 添加: {item}, 当前列表: {self.items}") + if len(self.items) >= 4: + print(f"[{datetime.now()}] 🧹 列表已满,立即清空并重置2小时计时器") + self.items.clear() + self._schedule_cleanup() # 重置计时器 + + def get_items(self): + """ + :return: + :rtype: + """ + with self.state_lock: + return self.items.copy() + + def shutdown(self): + """ + """ + self.scheduler.shutdown() + + +if __name__ == '__main__': + pass + # main.py 或 views.py + # from timer_manager import TwoHourWindowManager + + # 获取单例实例 + window = TwoHourWindowManager() + + # 添加元素(可在多线程/Web请求中调用) + window.add_item("user_123") + window.add_item("order_456") + + # 查看当前状态 + print("当前列表:", window.get_items()) diff --git a/django_定时器/定时器语法.py b/django_定时器/定时器语法.py new file mode 100644 index 0000000..bec4757 --- /dev/null +++ b/django_定时器/定时器语法.py @@ -0,0 +1,58 @@ +import logging +import secrets + +from apscheduler.executors.pool import ThreadPoolExecutor +from apscheduler.schedulers.blocking import BlockingScheduler +from apscheduler.triggers.interval import IntervalTrigger +from django.conf import settings + +# 配置日志 +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class DingShiQi: + def __init__(self): + # ✅ 实例属性:每个实例独立 + self.ding_id = secrets.token_hex(12) + # 注册 executors + executors = { + 'my_executor': ThreadPoolExecutor(max_workers=1, ), + 'you_executor': ThreadPoolExecutor(max_workers=1), + } + # 使用 BlockingScheduler(会阻塞) + self.scheduler = BlockingScheduler(timezone=settings.TIME_ZONE, executors=executors) + + def task任务(self): + print("任务执行了啦") # 或 logger.info("任务执行了啦") + + def triggerIntervalTrigger触发器(self) -> IntervalTrigger: + return IntervalTrigger(seconds=3) + + def 添加任务(self): + self.scheduler.add_job( + func=self.task任务, + id=self.ding_id, + trigger=self.triggerIntervalTrigger触发器(), + name="xiaozizi", + max_instances=1, + misfire_grace_time=1, + coalesce=True, + executor="my_executor", # 在这里可以选择线程池的名称 + ) + + def startTask(self): + logger.info("Starting scheduler...") + try: + self.scheduler.start() # ⚠️ 这里会阻塞! + except KeyboardInterrupt: + logger.info("Stopping scheduler...") + self.scheduler.shutdown() + logger.info("Scheduler shut down successfully!") + + +if __name__ == '__main__': + print("TIME_ZONE:", settings.TIME_ZONE) + ding = DingShiQi() + ding.添加任务() + ding.startTask() # ← 会阻塞在这里,每3秒打印一次 "任务执行了啦" diff --git a/django_定时器/幸运拼团业务模型接口.py b/django_定时器/幸运拼团业务模型接口.py new file mode 100644 index 0000000..e5c7baf --- /dev/null +++ b/django_定时器/幸运拼团业务模型接口.py @@ -0,0 +1,192 @@ +import datetime +import threading +from datetime import timedelta +from typing import cast +from zoneinfo import ZoneInfo + +import jmespath +import orjson +import pydash +import requests +from asgiref.sync import async_to_sync +from channels.layers import get_channel_layer, BaseChannelLayer +from django.forms import model_to_dict +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 django_celery.message.tasks import my_task +from django_定时器.团购任务 import TwoHourWindowManager +from django_定时器.幸运拼团数据库 import lucky拼团对象类型, lucky拼团 +from sixGuoDjango import ResData, BaseResponse +from wechat_数据库.支付订单数据库.商品订单数据 import order订单 +from wechat_数据库.洗衣液商品数据库.六果洗衣液商品 import goods商品, goods商品Choices +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_数据库.雪花算法.雪花算法工具 import generator +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay + +# window = 0 +window = TwoHourWindowManager() +default_channel_layer = cast(BaseChannelLayer, get_channel_layer(alias="default")) + +class 拼团业务接口ViewSets(ViewSet): + lock = threading.Lock() + + def 处理积分方法(self, attach): + pass + # 将字符串转为换字典 + attachData = orjson.loads(attach) + # 拿到数据 + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", attachData) + share订单分享者ID = pydash.get(obj=attachData, path="share订单分享者ID") + out_trade_no = pydash.get(obj=attachData, path="out_trade_no") + if share订单分享者ID == "六果": + # 说明没有分享都,啥也不需要干 + pass + else: + print("\n🍎 🍏 🍊 有分享者,需要调用添加积分的接口 \n", ) + uri = "https://xiao.sixgou.com/integral/pay_add/" + requests.post(url=uri, json={"attachData": attachData}) + pass + + @action(detail=False, methods=["post"], url_path="current") + def 查询当前的拼团的数据(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + 拼团商品 = goods商品.objects.filter(goods商品类型=goods商品Choices.幸运拼团.value).values() + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", 拼团商品) + 查询对象 = lucky拼团.objects.get(idKey=window.generate_str_id) + 时间戳 = (查询对象.dateAndTime.astimezone(tz=ZoneInfo("Asia/Shanghai")) + timedelta(seconds=7200)).timestamp() + 最终时间戳 = int(时间戳) * 1000 - int(datetime.datetime.now(tz=ZoneInfo("Asia/Shanghai")).timestamp()) * 1000 + resData = {"idKey": 查询对象.idKey, "lucky拼团详细": 查询对象.lucky拼团详细, "dateAndTime": 最终时间戳} + httpResData = BaseResponse(resData=ResData(listData=拼团商品, dictData=resData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="join") + def 加入拼团支付(self, request: Request): + """""" + url_pay = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi" # 发起请求的链接 + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", 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) # 当前是否有上级对象 + order用户配送地址 = request.data.get("order用户配送地址", None) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", share订单分享者ID, "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n") + out_trade_no = generator.generate_str() + body = { + "mchid": paymentCategory.mchid, # 【直连商户号】 直连商户号 + "out_trade_no": out_trade_no, # 【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。 + "appid": paymentCategory.appid, # 【公众号 或者 小程序ID】 + "description": "幸运拼团", # 【商品描述】 商品描述要 + "notify_url": "https://xiao.sixgou.com/lucky/update/", # 回调地址要 + "amount": { + "total": 1, # 【总金额】 订单总金额,单位为分。 + "currency": "CNY", # 【货币类型】 CNY:人民币,境内商户号仅支持人民币。 + }, # 【支付者】 支付者信息。 + "payer": { + "openid": self_mini_openid, # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取 + # "openid": OPENID测试, # 【用户标识】 用户在普通商户AppID下的唯一标识。 下单前需获取到用户的OpenID,详见OpenID获取 + }, + "attach": orjson.dumps({"share订单分享者ID": share订单分享者ID}, option=orjson.OPT_SORT_KEYS, ).decode( + encoding="utf-8") + } # 请求的数据 + wechat_data = wechatPay(payment=paymentCategory).getpay_jsapi(uri=url_pay, body_data=body, method="POST") + order订单.objects.create(order支付商家侧订单号=out_trade_no, + order商品总价=order商品总价, order商品数据=order商品数据, order商品数量=order商品数量, + order分享者unionid=share订单分享者ID, + order商品ID=order商品ID, order支付数据=body, + wai外键lucky拼团表_id=window.generate_str_id, order支付状态="支付中", + order支付者openid=self_mini_openid, order用户配送地址=order用户配送地址, + order订单类型=order订单类型 + ) + payData = pydash.get(obj=wechat_data, path="response") + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=payData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="update") + def 更新幸运拼团的支付回调接口(self, request: Request): + """ """ + with self.lock: + wechat_data支付回调数据 = wechatPay(payment=paymentCategory).callBack回调解密(headers=request.headers, + response_body=request.data) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", wechat_data支付回调数据, "返回的结果支付返回", + type(wechat_data支付回调数据)) + 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") + attach = pydash.get(obj=wechat_data支付回调数据, path="attach") + self.处理积分方法(attach=attach) + # 调用异步方法 : 作用 (发起订单录入接口调用) + share订单分享者ID = pydash.get(obj=orjson.loads(pydash.get(obj=wechat_data支付回调数据, path="attach")), + path="share订单分享者ID") + my_task.apply_async(kwargs={"self_mini_openid": self_mini_openid, "out_trade_no": out_trade_no, + "share订单分享者ID": share订单分享者ID}, countdown=30) + # 更新 拼团订单的 支付状态 + 生成物流的订单号 = generator.generate_str() + order订单.objects.filter(order支付商家侧订单号=out_trade_no).update(order支付数据=wechat_data支付回调数据, + order支付状态=trade_state_desc, + order物流状态=order订单.order订单choosies物流状态.待发货.value, + order物流订单号=生成物流的订单号 + ) + + 当前用户对象 = weiuser.objects.get(mini_openid=self_mini_openid) + 参与拼团的对象 = lucky拼团对象类型(wei_openid=self_mini_openid, pay订单号=window.generate_str_id, + avatar=当前用户对象.avatar, nickName=当前用户对象.nickName) + # 查询当前的对象,然后进行数据的更新 + 当前拼团的对象 = lucky拼团.objects.get(idKey=window.generate_str_id) + print("🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 长度是多少了呢", len(当前拼团的对象.lucky拼团详细)) + # 需要判断当前列表的长度,如果大于等于5的话,就需要调用清团重开 + if len(当前拼团的对象.lucky拼团详细) >= 4: + # 需要清掉重新 + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 新开团的ID是否变更了", window.generate_str_id) + 当前拼团的对象.lucky拼团详细.append(参与拼团的对象) + 当前拼团的对象.lucky开团状态 = lucky拼团.choosies.已开团.value + 当前拼团的对象.save() + 对象 = model_to_dict(instance=当前拼团的对象, fields=None) + async_to_sync(awaitable=default_channel_layer.group_send)(group="default_group_name", + message={"lucktyData": 对象, + "type": "chat_Lucky拼团"}, ) + window.开团重置() + else: + 当前拼团的对象.lucky拼团详细.append(参与拼团的对象) + 当前拼团的对象.save() + 对象 = model_to_dict(instance=当前拼团的对象, fields=None) + async_to_sync(awaitable=default_channel_layer.group_send)(group="default_group_name", + message={"lucktyData": 对象, + "type": "chat_Lucky拼团"}, ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="group_opening_order") + def 查询当前开团的最后一个团数据(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + 拼团订单号 = window.generate_str_id + # 查询结果 = lucky拼团.objects.filter(lucky开团状态=lucky拼团.choosies.已开团.value, lucky拼团订单__order支付都ID=self_mini_openid, + # lucky拼团订单__order支付状态="支付成功" + # ).order_by("-updateTime") + 查询结果 = lucky拼团.objects.filter(lucky开团状态=lucky拼团.choosies.已开团.value, + lucky拼团详细__contains=[{"wei_openid": self_mini_openid}]).order_by( + "-updateTime").first() + print(查询结果, "🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ") + if 查询结果 is None: + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + else: + 返回结果数据 = model_to_dict(instance=查询结果, fields=None) + print(返回结果数据, "🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ") + httpResData = BaseResponse(resData=ResData(listData=[], dictData=返回结果数据), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + +# 拼团业务接口ViewSetsRouter = DefaultRouter() +# 拼团业务接口ViewSetsRouter.register(prefix="", viewset=拼团业务接口ViewSets, basename="") diff --git a/django_定时器/幸运拼团数据库.py b/django_定时器/幸运拼团数据库.py new file mode 100644 index 0000000..d801d49 --- /dev/null +++ b/django_定时器/幸运拼团数据库.py @@ -0,0 +1,68 @@ +from typing import TypedDict +from django.db import models +from django.utils.translation import gettext_lazy + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +# 定义 一 个字典的类型结构 +class lucky拼团对象类型(TypedDict): + wei_openid: str + pay订单号: str + avatar: str + nickName: str + + +class lucky拼团(models.Model): + """城市信息表""" + + class choosies(models.TextChoices): + 未开团 = "未开团", gettext_lazy("未开团") + 已开团 = "已开团", gettext_lazy("已开团") + + objects = models.Manager() # + idKey = models.CharField(primary_key=True, default=generator.generate_str, ) # 拼团的团订单号 + lucky拼团详细 = models.JSONField(default=list) + lucky开团状态 = models.CharField(max_length=128, choices=choosies, default=choosies.未开团.value) + # lucky创建时间 = models.DateTimeField() + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "lucky拼团" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["dateAndTime", "updateTime"] + + +class lucky拼团订单(models.Model): + """城市信息表""" + objects = models.Manager() # + + class choosies物流状态(models.TextChoices): + 待发货 = "待发货", gettext_lazy("待发货") + 已发货 = "已发货", gettext_lazy("已发货") + 已签收 = "已签收", gettext_lazy("已签收") + 待评价 = "待评价", gettext_lazy("待评价") + + idKey = models.CharField(primary_key=True, default=generator.generate_str, ) + order拼团支付订单号 = models.CharField(max_length=128, ) + order支付都ID = models.CharField(max_length=128, ) + wai外键lucky拼团表 = models.ForeignKey(to=lucky拼团, on_delete=models.CASCADE, ) + order商品ID = models.CharField(max_length=128, ) + order商品数据 = models.JSONField() + order商品总价 = models.IntegerField() + order商品数量 = models.IntegerField() + order支付数据 = models.JSONField(default=dict) + order支付状态 = models.CharField(max_length=128, default="支付中") + order用户配送地址 = models.JSONField(default=dict) + order物流状态 = models.CharField(max_length=128, blank=True, null=True, ) + order物流订单号 = models.CharField(max_length=128, blank=True, null=True, ) + order物流数据 = models.JSONField(default=dict) + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "lucky拼团订单" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["dateAndTime", "updateTime"] diff --git a/django_邮件/邮件发送工具包.py b/django_邮件/邮件发送工具包.py new file mode 100644 index 0000000..acb6ba9 --- /dev/null +++ b/django_邮件/邮件发送工具包.py @@ -0,0 +1,294 @@ +import smtplib +from email.header import Header +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +from email.utils import formataddr + +html = """ + + + + + + 专业微信小程序开发服务 + + + + + + +""" + + +# SMTP服务器: smtp.163.com + +def send_email_bcc_only(emSubject主题, emBody内容, to_emails): + """只有 BCC 收件人,TO 字段为空""" + from_email = "792282@qq.com" + password = "epagsnfwzrkrbgfa" + display_name = "六果科技" + + msg = MIMEMultipart() + msg["From"] = formataddr(pair=("免费小程序已送达", "792282@qq.com"), charset="utf-8") + msg["To"] = "" # 不显示任何收件人(这时达成的效果, 也就是相当于秘密抄送,无需要显示就行了) + msg["Subject"] = Header(s=emSubject主题, charset="utf-8", ) + # msg.attach(MIMEText(emBody内容, "plain", "utf-8")) + msg.attach(MIMEText(_text=html, _subtype="html", _charset="utf-8")) + try: + with smtplib.SMTP_SSL("smtp.qq.com", 465) as emServer: + emServer.login(from_email, password) + # ✅ 所有收件人都在 to_addrs 中,但不会显示在邮件头 + emServer.sendmail(from_email, to_emails, msg.as_string()) + print(f"邮件已密送给 {len(to_emails)} 位收件人") + except Exception as e: + print(f"发送失败: {e}") + + +# 使用 +recipients = ["xiao@xiao.band", "13382551360@163.com"] +send_email_bcc_only(emSubject主题="数字化", emBody内容="邮件的内容", to_emails=["xiao@xiao.band", ]) diff --git a/iconDir/a6c90449-8edc-48b5-bcb5-6fbdae5971f6.png b/iconDir/a6c90449-8edc-48b5-bcb5-6fbdae5971f6.png new file mode 100644 index 0000000..0976398 Binary files /dev/null and b/iconDir/a6c90449-8edc-48b5-bcb5-6fbdae5971f6.png differ diff --git a/iconDir/bg.png b/iconDir/bg.png new file mode 100644 index 0000000..4ccb88b Binary files /dev/null and b/iconDir/bg.png differ diff --git a/iconDir/sketch_sketch.png b/iconDir/sketch_sketch.png new file mode 100644 index 0000000..7fec4b5 Binary files /dev/null and b/iconDir/sketch_sketch.png differ diff --git a/iconDir/优秀_good-one.png b/iconDir/优秀_good-one.png new file mode 100644 index 0000000..0a51903 Binary files /dev/null and b/iconDir/优秀_good-one.png differ diff --git a/iconDir/信息已发送_message-sent.png b/iconDir/信息已发送_message-sent.png new file mode 100644 index 0000000..590f782 Binary files /dev/null and b/iconDir/信息已发送_message-sent.png differ diff --git a/iconDir/储存卡_memory.png b/iconDir/储存卡_memory.png new file mode 100644 index 0000000..d98dafc Binary files /dev/null and b/iconDir/储存卡_memory.png differ diff --git a/iconDir/全部_all-application.png b/iconDir/全部_all-application.png new file mode 100644 index 0000000..195686f Binary files /dev/null and b/iconDir/全部_all-application.png differ diff --git a/iconDir/减少_reduce-one.png b/iconDir/减少_reduce-one.png new file mode 100644 index 0000000..43dc5f3 Binary files /dev/null and b/iconDir/减少_reduce-one.png differ diff --git a/iconDir/减少_reduce.png b/iconDir/减少_reduce.png new file mode 100644 index 0000000..40dc051 Binary files /dev/null and b/iconDir/减少_reduce.png differ diff --git a/iconDir/删除键_delete-key.png b/iconDir/删除键_delete-key.png new file mode 100644 index 0000000..4ff3e83 Binary files /dev/null and b/iconDir/删除键_delete-key.png differ diff --git a/iconDir/加载_loading-three.png b/iconDir/加载_loading-three.png new file mode 100644 index 0000000..d02f9cc Binary files /dev/null and b/iconDir/加载_loading-three.png differ diff --git a/iconDir/台灯_desk-lamp.png b/iconDir/台灯_desk-lamp.png new file mode 100644 index 0000000..7eb2dd2 Binary files /dev/null and b/iconDir/台灯_desk-lamp.png differ diff --git a/iconDir/圆形双上箭头.png b/iconDir/圆形双上箭头.png new file mode 100644 index 0000000..8f94dbb Binary files /dev/null and b/iconDir/圆形双上箭头.png differ diff --git a/iconDir/圆形双下箭头.png b/iconDir/圆形双下箭头.png new file mode 100644 index 0000000..8d935d2 Binary files /dev/null and b/iconDir/圆形双下箭头.png differ diff --git a/iconDir/圆形双右箭头.png b/iconDir/圆形双右箭头.png new file mode 100644 index 0000000..62f3150 Binary files /dev/null and b/iconDir/圆形双右箭头.png differ diff --git a/iconDir/圆形双左箭头.png b/iconDir/圆形双左箭头.png new file mode 100644 index 0000000..ebc0f4b Binary files /dev/null and b/iconDir/圆形双左箭头.png differ diff --git a/iconDir/地图距离_map-distance.png b/iconDir/地图距离_map-distance.png new file mode 100644 index 0000000..2350362 Binary files /dev/null and b/iconDir/地图距离_map-distance.png differ diff --git a/iconDir/太阳1_sun-one.png b/iconDir/太阳1_sun-one.png new file mode 100644 index 0000000..8849380 Binary files /dev/null and b/iconDir/太阳1_sun-one.png differ diff --git a/iconDir/已定位_local.png b/iconDir/已定位_local.png new file mode 100644 index 0000000..8f97728 Binary files /dev/null and b/iconDir/已定位_local.png differ diff --git a/iconDir/帮助_help.png b/iconDir/帮助_help.png new file mode 100644 index 0000000..9e1cebd Binary files /dev/null and b/iconDir/帮助_help.png differ diff --git a/iconDir/广告_ad.png b/iconDir/广告_ad.png new file mode 100644 index 0000000..6769619 Binary files /dev/null and b/iconDir/广告_ad.png differ diff --git a/iconDir/应用菜单_application-menu.png b/iconDir/应用菜单_application-menu.png new file mode 100644 index 0000000..0d65351 Binary files /dev/null and b/iconDir/应用菜单_application-menu.png differ diff --git a/iconDir/微信_wechat.png b/iconDir/微信_wechat.png new file mode 100644 index 0000000..80ee7fe Binary files /dev/null and b/iconDir/微信_wechat.png differ diff --git a/iconDir/成功_success.png b/iconDir/成功_success.png new file mode 100644 index 0000000..be366d5 Binary files /dev/null and b/iconDir/成功_success.png differ diff --git a/iconDir/扫描设置_scan-setting.png b/iconDir/扫描设置_scan-setting.png new file mode 100644 index 0000000..5ebea3b Binary files /dev/null and b/iconDir/扫描设置_scan-setting.png differ diff --git a/iconDir/支付宝_alipay.png b/iconDir/支付宝_alipay.png new file mode 100644 index 0000000..c4eb493 Binary files /dev/null and b/iconDir/支付宝_alipay.png differ diff --git a/iconDir/收藏文件_collection-files.png b/iconDir/收藏文件_collection-files.png new file mode 100644 index 0000000..2334779 Binary files /dev/null and b/iconDir/收藏文件_collection-files.png differ diff --git a/iconDir/数据库搜索_database-search.png b/iconDir/数据库搜索_database-search.png new file mode 100644 index 0000000..3a2b150 Binary files /dev/null and b/iconDir/数据库搜索_database-search.png differ diff --git a/iconDir/数据库网络_database-network.png b/iconDir/数据库网络_database-network.png new file mode 100644 index 0000000..4180fe2 Binary files /dev/null and b/iconDir/数据库网络_database-network.png differ diff --git a/iconDir/日历_calendar-dot.png b/iconDir/日历_calendar-dot.png new file mode 100644 index 0000000..3e262c6 Binary files /dev/null and b/iconDir/日历_calendar-dot.png differ diff --git a/iconDir/时间.png b/iconDir/时间.png new file mode 100644 index 0000000..84af155 Binary files /dev/null and b/iconDir/时间.png differ diff --git a/iconDir/星星_star.png b/iconDir/星星_star.png new file mode 100644 index 0000000..1200ee9 Binary files /dev/null and b/iconDir/星星_star.png differ diff --git a/iconDir/星球_planet.png b/iconDir/星球_planet.png new file mode 100644 index 0000000..26d2151 Binary files /dev/null and b/iconDir/星球_planet.png differ diff --git a/iconDir/更多_more-app.png b/iconDir/更多_more-app.png new file mode 100644 index 0000000..688a9ad Binary files /dev/null and b/iconDir/更多_more-app.png differ diff --git a/iconDir/月亮_moon.png b/iconDir/月亮_moon.png new file mode 100644 index 0000000..8ca3936 Binary files /dev/null and b/iconDir/月亮_moon.png differ diff --git a/iconDir/朋友圈_friends-circle.png b/iconDir/朋友圈_friends-circle.png new file mode 100644 index 0000000..b6646ee Binary files /dev/null and b/iconDir/朋友圈_friends-circle.png differ diff --git a/iconDir/树1_tree-one.png b/iconDir/树1_tree-one.png new file mode 100644 index 0000000..eb09603 Binary files /dev/null and b/iconDir/树1_tree-one.png differ diff --git a/iconDir/树苗_sapling.png b/iconDir/树苗_sapling.png new file mode 100644 index 0000000..a7a8099 Binary files /dev/null and b/iconDir/树苗_sapling.png differ diff --git a/iconDir/校验_check-one.png b/iconDir/校验_check-one.png new file mode 100644 index 0000000..6b5517e Binary files /dev/null and b/iconDir/校验_check-one.png differ diff --git a/iconDir/比特币_bitcoin.png b/iconDir/比特币_bitcoin.png new file mode 100644 index 0000000..f4f8929 Binary files /dev/null and b/iconDir/比特币_bitcoin.png differ diff --git a/iconDir/水资源_water.png b/iconDir/水资源_water.png new file mode 100644 index 0000000..bb6e81d Binary files /dev/null and b/iconDir/水资源_water.png differ diff --git a/iconDir/法案.png b/iconDir/法案.png new file mode 100644 index 0000000..de0d018 Binary files /dev/null and b/iconDir/法案.png differ diff --git a/iconDir/添加_add-one.png b/iconDir/添加_add-one.png new file mode 100644 index 0000000..10383b1 Binary files /dev/null and b/iconDir/添加_add-one.png differ diff --git a/iconDir/添加_add.png b/iconDir/添加_add.png new file mode 100644 index 0000000..9501819 Binary files /dev/null and b/iconDir/添加_add.png differ diff --git a/iconDir/添加购物车_shopping-cart-add.png b/iconDir/添加购物车_shopping-cart-add.png new file mode 100644 index 0000000..672d349 Binary files /dev/null and b/iconDir/添加购物车_shopping-cart-add.png differ diff --git a/iconDir/电池满电_battery-full.png b/iconDir/电池满电_battery-full.png new file mode 100644 index 0000000..4290e96 Binary files /dev/null and b/iconDir/电池满电_battery-full.png differ diff --git a/iconDir/网络摄像头_webcam.png b/iconDir/网络摄像头_webcam.png new file mode 100644 index 0000000..c20a90b Binary files /dev/null and b/iconDir/网络摄像头_webcam.png differ diff --git a/iconDir/表格_table-file.png b/iconDir/表格_table-file.png new file mode 100644 index 0000000..54d6461 Binary files /dev/null and b/iconDir/表格_table-file.png differ diff --git a/iconDir/购物车_shopping-cart.png b/iconDir/购物车_shopping-cart.png new file mode 100644 index 0000000..e967c9b Binary files /dev/null and b/iconDir/购物车_shopping-cart.png differ diff --git a/iconDir/邮件1_maill-one.png b/iconDir/邮件1_maill-one.png new file mode 100644 index 0000000..e7a0e71 Binary files /dev/null and b/iconDir/邮件1_maill-one.png differ diff --git a/iconDir/邮件符号_at-sign.png b/iconDir/邮件符号_at-sign.png new file mode 100644 index 0000000..dd533f7 Binary files /dev/null and b/iconDir/邮件符号_at-sign.png differ diff --git a/iconDir/重新定位_repositioning.png b/iconDir/重新定位_repositioning.png new file mode 100644 index 0000000..161a8fd Binary files /dev/null and b/iconDir/重新定位_repositioning.png differ diff --git a/iconDir/重装_reload.png b/iconDir/重装_reload.png new file mode 100644 index 0000000..c43c646 Binary files /dev/null and b/iconDir/重装_reload.png differ diff --git a/iconDir/键盘_keyboard-one.png b/iconDir/键盘_keyboard-one.png new file mode 100644 index 0000000..d13d95e Binary files /dev/null and b/iconDir/键盘_keyboard-one.png differ diff --git a/iconDir/降落伞_parachute.png b/iconDir/降落伞_parachute.png new file mode 100644 index 0000000..9af6862 Binary files /dev/null and b/iconDir/降落伞_parachute.png differ diff --git a/iconDir/降落伞_parachute.svg b/iconDir/降落伞_parachute.svg new file mode 100644 index 0000000..937858c --- /dev/null +++ b/iconDir/降落伞_parachute.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/iconDir/雷达图_radar-chart.png b/iconDir/雷达图_radar-chart.png new file mode 100644 index 0000000..bc106cb Binary files /dev/null and b/iconDir/雷达图_radar-chart.png differ diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..4f6fac3 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sixGuoDjango.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..407f16d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,99 @@ +amqp==5.3.1 +annotated-types==0.7.0 +APScheduler==3.11.2 +asgiref==3.11.1 +asn1crypto==1.5.1 +attrs==25.4.0 +autobahn==25.12.2 +Automat==25.4.16 +billiard==4.2.4 +boto3==1.42.59 +botocore==1.42.59 +cbor2==5.8.0 +celery==5.6.2 +celery-types==0.26.0 +certifi==2026.1.4 +cffi==2.0.0 +channels==4.3.2 +channels_redis==4.3.0 +charset-normalizer==3.4.4 +click==8.3.1 +click-didyoumean==0.3.1 +click-plugins==1.1.1.2 +click-repl==0.3.0 +constantly==23.10.4 +cos_python_sdk_v5==1.9.41 +crcmod==1.7 +cryptography==46.0.5 +daphne==4.2.1 +dicttoxml==1.7.16 +Django==6.0.2 +django-cors-headers==4.9.0 +django-stubs==5.2.9 +django-stubs-ext==5.2.9 +djangorestframework==3.16.1 +djangorestframework-stubs==3.16.8 +emoji==2.15.0 +filelock==3.25.0 +furl==2.1.4 +hiredis==3.3.0 +hyperlink==21.0.0 +idna==3.11 +Incremental==24.11.0 +jmespath==1.1.0 +jwt==1.4.0 +kombu==5.6.2 +msgpack==1.1.2 +orderedmultidict==1.0.2 +orjson==3.11.8 +packaging==25.0 +pillow==12.2.0 +pip==26.0.1 +platformdirs==4.9.2 +prompt_toolkit==3.0.52 +psycopg-binary==3.3.3 +psycopg2-binary==2.9.11 +py-ubjson==0.16.1 +pyasn1==0.6.2 +pyasn1_modules==0.4.2 +pycparser==3.0 +pycryptodome==3.23.0 +pydantic==2.12.5 +pydantic_core==2.41.5 +pydash==8.0.6 +pyOpenSSL==25.3.0 +python-barcode==0.16.1 +python-dateutil==2.9.0.post0 +python-ulid==3.2.0 +pytz==2026.1.post1 +PyYAML==6.0.3 +redis==7.2.1 +requests==2.32.5 +ruff==0.15.22 +s3transfer==0.16.0 +segno==1.6.6 +service-identity==24.2.0 +setuptools==80.10.2 +six==1.17.0 +sortedcontainers==2.4.0 +SQLAlchemy==2.0.48 +sqlparams==6.2.0 +sqlparse==0.5.5 +tomlkit==0.14.0 +tornado==6.5.4 +Twisted==25.5.0 +txaio==25.12.2 +types-PyYAML==6.0.12.20250915 +typing_extensions==4.15.0 +typing-inspection==0.4.2 +tzdata==2025.3 +tzlocal==5.3.1 +ujson==5.11.0 +urllib3==2.6.3 +uuid6==2025.0.1 +vine==5.1.0 +vtracer==0.6.15 +wcwidth==0.6.0 +wheel==0.46.3 +xmltodict==1.0.3 +zope.interface==8.2 diff --git a/sixGuoDjango.iml b/sixGuoDjango.iml new file mode 100644 index 0000000..01c8157 --- /dev/null +++ b/sixGuoDjango.iml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sixGuoDjango/__init__.py b/sixGuoDjango/__init__.py new file mode 100644 index 0000000..12a6cfd --- /dev/null +++ b/sixGuoDjango/__init__.py @@ -0,0 +1,159 @@ +import threading +from datetime import datetime +from typing import List, Dict, Any, Literal, Optional + +import redis +from pydantic import BaseModel, Field +from redis import Redis +from uuid6 import uuid8 + + +class ResData(BaseModel): + """响应数据体""" + listData: List[Any] = Field(default_factory=list, description="列表数据") + dictData: Dict[str, Any] = Field(default_factory=dict, description="字典数据") + + +class SingletonMetaDefault(type): + """单例类""" + _instances: dict = {} + _lock = threading.RLock() + + def __call__(cls, *args, **kwargs): + # 使用类本身作为 key(因为 RedisClientManager 不需要参数化实例) + # 如果你确实需要参数化单例(比如不同 config),才用 args/kwargs 做 key + # 但此处我们只需要一个全局管理器,所以 key = cls + key = cls + with cls._lock: + if key not in cls._instances: + cls._instances[key] = super().__call__(*args, **kwargs) + return cls._instances[key] + + +class RedisClientManager(metaclass=SingletonMetaDefault): + """ + 单例 Redis 连接客户端管理器,支持按名称获取不同数据库的客户端。 + """ + + _config: Dict[str, str] = { + "redis_0": "redis://:com792282@127.0.0.1:6379/0", + "redis_1": "redis://:com792282@127.0.0.1:6379/1", + "redis_2": "redis://:com792282@127.0.0.1:6379/2", + "redis_3": "redis://:com792282@127.0.0.1:6379/3", + "redis_4": "redis://:com792282@127.0.0.1:6379/4", + "redis_5": "redis://:com792282@127.0.0.1:6379/5", + "redis_6": "redis://:com792282@127.0.0.1:6379/6", + "redis_7": "redis://:com792282@127.0.0.1:6379/7", + "redis_8": "redis://:com792282@127.0.0.1:6379/8", + "redis_9": "redis://:com792282@127.0.0.1:6379/9", + "redis_10": "redis://:com792282@127.0.0.1:6379/10", + "redis_11": "redis://:com792282@127.0.0.1:6379/11", + "redis_12": "redis://:com792282@127.0.0.1:6379/12", + } + + def __init__(self): + if not hasattr(self, '_clients'): + self._clients = {} + self._client_lock = threading.Lock() + + def get_client(self, db_name: Optional[ + Literal[ + "redis_1", "redis_2", "redis_3", "redis_4", "redis_5", "redis_6", "redis_7", "redis_8", "redis_9", "redis_10", "redis_11", "redis_12"]] = "redis_5", + ) -> redis.StrictRedis: + """ + :param db_name: + :type db_name: + :return: + :rtype: + """ + if db_name not in self._clients: + with self._client_lock: + if db_name not in self._clients: # double-check + url = self._config.get(db_name) + if not url: + raise ValueError(f"Redis client config for '{db_name}' not found.") + self._clients[db_name] = redis.StrictRedis.from_url(url, decode_responses=True) + return self._clients[db_name] + + def close_all(self): + """关闭所有已创建的 Redis 连接(可选)""" + for client in self._clients.values(): + client.close() + self._clients.clear() + + +redis_default_current: Redis = RedisClientManager().get_client(db_name="redis_10") +redis_5: Redis = RedisClientManager().get_client(db_name="redis_5") + + +class BaseResponse(BaseModel): + """统一返回数据类型""" + code: int = Field(default=200, description="") + message: str = Field(default="success", description="消息") + describe: str = Field(default="success", description="描述") + total: int = Field(default=0, description="数据总数") + resData: ResData = Field(default_factory=ResData, description="响应数据") + + +class Timestamp: + """时间戳获取工具""" + + def __init__(self): + self._current_time = None + + def get_int(self, format_type: Optional[Literal["milliseconds", "microseconds"]] = "milliseconds") -> int: + """ + 获取当前时间的整型时间戳(秒级) + 返回: int 类型的时间戳 + """ + now = datetime.now() + + if format_type == "seconds": + return int(now.timestamp()) + elif format_type == "milliseconds": + return int(now.timestamp() * 1000) + elif format_type == "microseconds": + return int(now.timestamp() * 1000000) + else: + raise ValueError(f"不支持的格式类型: {format_type},可选值: seconds/milliseconds/microseconds") + + def get_str(self, format_type: Optional[Literal["milliseconds", "microseconds"]] = "milliseconds") -> str: + """ + 获取当前时间的字符串时间戳 + + 参数: + format_type: + - "seconds": 秒级时间戳字符串(如 "1721030400") + - "milliseconds": 毫秒级时间戳字符串(如 "1721030400123") + - "microseconds": 微秒级时间戳字符串(如 "1721030400123456") + + 返回: str 类型的时间戳 + """ + now = datetime.now() + + if format_type == "seconds": + return str(int(now.timestamp())) + elif format_type == "milliseconds": + return str(int(now.timestamp() * 1000)) + elif format_type == "microseconds": + return str(int(now.timestamp() * 1000000)) + else: + raise ValueError(f"不支持的格式类型: {format_type},可选值: seconds/milliseconds/microseconds") + + def get_both(self) -> dict: + """ + 同时获取 int 和 str 格式的时间戳 + 返回: {"int": int, "str_seconds": str, "str_milliseconds": str} + """ + return { + "int": self.get_int(), + "str_seconds": self.get_str("seconds"), + "str_milliseconds": self.get_str("milliseconds"), + } + + +def uuid_hex(): + return uuid8().hex +# 使用示例 +if __name__ == "__main__": + pass diff --git a/sixGuoDjango/asgi.py b/sixGuoDjango/asgi.py new file mode 100644 index 0000000..9fd2121 --- /dev/null +++ b/sixGuoDjango/asgi.py @@ -0,0 +1,32 @@ +""" +ASGI config for sixGuoDjango project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/howto/deployment/asgi/ +""" + +import os + +import django +from django.urls import path + +from django_channels.consumers import ChatConsumer + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sixGuoDjango.settings") +django.setup() +from channels.routing import URLRouter, ProtocolTypeRouter +from django.core.asgi import get_asgi_application +from django_channels import tableConsumer + +# 创建基础的ASGI应用 +django_asgi_app = get_asgi_application() +application = ProtocolTypeRouter({ + "http": django_asgi_app, # 如果处理http请求就走这里 + "websocket": URLRouter(routes=[ # type: ignore[arg-type] + # path(route="web//", view=tableConsumer.websocket.as_asgi()), # type: ignore[arg-type] + path(route="room//", view=ChatConsumer.as_asgi()), # type: ignore[arg-type] + ]) +}, +) diff --git a/sixGuoDjango/settings.py b/sixGuoDjango/settings.py new file mode 100644 index 0000000..54163d0 --- /dev/null +++ b/sixGuoDjango/settings.py @@ -0,0 +1,195 @@ +""" +Django settings for django_six_gou_com project. + +Generated by "django-admin startproject" using Django 5.1.3. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" +import os +from pathlib import Path + +from django.conf import settings + +# Build paths inside the project like this: BASE_DIR / "subdir". +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "aksdfjgqeprihgwkhmntypi-2986-1309468139461-903481349086" +base_dir_name = "sixGuoDjango" +项目名称 = "sixGuoDjango" +# SECURITY WARNING: run with debug turned on in production! +# DEBUG = SECRET_KEY_DJANGO +DEBUG = True + +ALLOWED_HOSTS = ["xiao.sixgou.com", "127.0.0.1"] + +# Application definition + +INSTALLED_APPS = [ + "daphne", # ASGI服务器 + # "django_celery_results", # Celery结果存储 + # "django_celery_beat", # Celery定时任务 + "channels", # WebSocket支持 + # "adrf", # 异步Django REST framework + "corsheaders", + "rest_framework", + # "django_apscheduler", # 高级定时任务 + "django.contrib.admin", # 管理后台 + "django.contrib.auth", # 认证系统 + # "corsheaders", + "django.contrib.contenttypes", # 内容类型框架 + "django.contrib.sessions", # 会话管理 + "django.contrib.messages", # 消息框架 + "django.contrib.staticfiles", + "django_app.apps.DjangoAppConfig", + ] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + 'corsheaders.middleware.CorsMiddleware', # 👈 添加这一行 + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + ] + +ROOT_URLCONF = f"sixGuoDjango.urls" +# ROOT_URLCONF = f"django_routers.url_base" +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(BASE_DIR, "templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, + ] + +WSGI_APPLICATION = f"sixGuoDjango.wsgi.application" + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, + {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, + {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, + {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, + ] + +# ASGI配置(异步服务网关接口) +ASGI_APPLICATION: str = f"sixGuoDjango.asgi.application" +# 国际化配置 +LANGUAGE_CODE = "zh-hans" # 中文语言 +TIME_ZONE = "Asia/Shanghai" # 上海时区 +USE_I18N = False # 启用国际化 +USE_L10N = True # 启用本地化 +USE_TZ = True # 禁用UTC时间,使用本地时间 + +# 静态文件配置 +STATIC_URL = "/django_static_directory/static/" # 静态文件URL前缀 +STATICFILES_DIRS = [os.path.join(BASE_DIR, "django_static_directory/static_test"), ] # 开发者环境 +STATIC_ROOT = os.path.join(BASE_DIR, "django_static_directory/static") # 生产环境静态文件收集目录 + +# 媒体文件配置 +MEDIA_URL = "/media/" # 用户上传文件URL前缀 +MEDIA_ROOT = os.path.join(BASE_DIR, "django_static_directory/media") # 媒体文件存储路径 + +# 模型默认主键字段类型 +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +# *****asgi配置部分*************************************************************************** +# *****mysql数据库的配置部分*********************************************************************** +# +# redis数据库地址 = "django_redis" +redis数据库地址 = "127.0.0.1" +# redis数据库地址 = "django_redis" +post数据库HOST地址 = "django_postgres" # 生产环境,并且是为docker创建的数据库 +DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql", + # 安装异步数据库连接池 pip install "django-db-connection-pool[postgresql]" + "NAME": "six", # 替换为实际的数据库名 + "USER": "xiaozizi", # 替换为实际的数据库用户名 + "PASSWORD": "com792282", # 替换为实际的数据库密 + "HOST": "127.0.0.1", # 若数据库不在本地,改为对应的主机地址 + # "HOST": "106.54.2.188", # 若数据库不在本地,改为对应的主机地址 + # "HOST": post数据库HOST地址, # 若数据库不在本地,改为对应的主机地址 + "PORT": "5433", # 默认PostgreSQL端口,如有变动请修改 + # "PORT": "5432", # 默认PostgreSQL端口,如有变动请修改 + }, + } +# + +# *****mysql数据库的配置部分*********************************************************************** + +# *****asg配置部分*********************************************************************** +CHANNEL_LAYERS = { + "default": { + "BACKEND": "channels_redis.core.RedisChannelLayer", # 使用Redis作为通道层 + "CONFIG": { + "hosts": [f"redis://default:com792282@{redis数据库地址}:6379/2"], # Redis连接字符 + }, + }, + } + +# *****asg配置部分*********************************************************************** + + +# *****CACHES 缓存配置*********************************************************************** +# REDIS_IP = "127.0.0.1" +# CACHES = { +# "default": { +# "BACKEND": "django.core.cache.backends.redis.RedisCache", # 需要安装 dejango_redis库 +# "LOCATION": f"redis://default:com792282@{REDIS_IP}:6379/3", +# }, +# "celery": { +# "BACKEND": "django.core.cache.backends.redis.RedisCache", # 需要安装 dejango_redis库 +# "LOCATION": f"redis://default:com792282@{REDIS_IP}:6379/4", +# }, +# "xiao": { +# "BACKEND": "django.core.cache.backends.redis.RedisCache", +# "LOCATION": f"redis://default:com792282@{REDIS_IP}:6379/5", +# }, +# "demo": { +# "BACKEND": "django.core.cache.backends.redis.RedisCache", # 需要安装 dejango_redis库 +# "LOCATION": f"redis://default:com792282@{REDIS_IP}:6379/11", +# } +# } +# *****CACHES 缓存配置*********************************************************************** +# CORS_ALLOW_ALL_ORIGINS = True +# CORS_ALLOWED_ORIGINS = [ +# "https://www.sixgou.com", +# ] + +# REST_FRAMEWORK = { +# "DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.coreapi.AutoSchema", +# } +# 添加一个注释 + +# 允许跨域访问的源列表 +CORS_ALLOWED_ORIGINS = [ + "http://localhost:5173", # 👈 允许你的本地开发服务器 这里的作用是,解决跨域的问题, 这里的地址就是前端服务器的地址; + # 如果还有其他前端地址,可以继续添加,例如: + "https://six.sixgou.com", + "https://xiao.sixgou.com", + "http://localhost:3000", + "http://192.168.1.159:3000", + "https://wechat.sixgou.com", + "http://0.0.0.0:3000", + ] diff --git a/sixGuoDjango/urls.py b/sixGuoDjango/urls.py new file mode 100644 index 0000000..b86a7ee --- /dev/null +++ b/sixGuoDjango/urls.py @@ -0,0 +1,104 @@ +""" +URL configuration for sixGuoDjango project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/6.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import include, path +from django.views.generic import TemplateView + +from django_app.views import DemoXiaoViewSetsDemoRouter +from django_app.业务订单接口 import 业务订单接口ViewSetsViewSetsRouter +from django_celery.测试接口 import Celery测试接口ViewSetsRouter +from django_routes.企业微信管理端接口列表 import 企业微信管理端接口列表Router +from django_routes.小程序前端页面分享接口列表 import 小程序前端分享页面Router +from django_routes.小程序服务端接口管理列表 import 小程序服务端管理接口列表ViewSetsRouter +from django_routes.小程序用户地址定位地图路由列表 import 小程序用户地址定位地图Router +from django_routes.服务号接口列表 import 服务号接口列表Router +from django_routes.桌面端接口列表 import 桌面端企业微信接口ViewSets列表Router +from django_web_微信开放平台应用用户登陆.网页端验证文件接口 import 网页端验证文件接口ViewSets +from django_wechat_服务号.服务号接收微信code网页授权 import 服务号网页授权接口ViewSets +# from django_定时器.幸运拼团业务模型接口 import 拼团业务接口ViewSetsRouter +from wechat_接口.商品订单模拟接口.商品数据接口 import 商品接口ViewSetsRouter +from wechat_接口.商品订单模拟接口.订单管理接口 import 订单管理接口ViewSetsRouter +from wechat_接口.小程序用户接口.小程序用户头像昵称手机号接口 import 小程序用户头像昵称接口ViewSetsRouter +from wechat_接口.小程序用户接口.小程序用户登陆接口 import 六果科技小程序用户登陆Router +from wechat_接口.小程序用户接口.小程序订阅消息 import miniMsg订阅消息Router +from wechat_接口.微信支付接口.代金券相关接口 import 代金券接口ViewSetsRouter +from wechat_接口.微信支付接口.商家转账 import six商家转账ViewSetsRouter +from wechat_接口.微信支付接口.微信支付测试接口 import 微信支付ViewSetsRouter +from wechat_接口.页面接口.分页接口 import 分页接口ViewSetsRouter +from wechat_接口.页面接口.首页 import htmlViewSets +from wechat_第三方接口.蕊烨打印机.蕊烨打印机管理 import 蕊烨打印机接口ViewSetsRouter +from wechat_项目授权.企业微信消息服务器授权接口 import sixwecom +from wechat_项目授权.小程序授权接口 import sixmini +from wechat_项目授权.服务号认证接口 import sixwechat + +# 注册子路由 +urlpatterns = [ + path("api-auth/", include("rest_framework.urls")), + path(route="six/", view=include(arg=业务订单接口ViewSetsViewSetsRouter.urls)), + path(route="", view=htmlViewSets.as_view({"get": "home"})), # 项目首页 + # path( route="lucky/", view=include( arg=拼团业务接口ViewSetsRouter.urls ) ), # 幸运拼团的业务demo接口 + path('robots.txt', TemplateView.as_view(template_name="robots.txt", content_type='text/plain')), + # path( 'favicon.ico', TemplateView.as_view( template_name="favicon.ico", content_type='image/x-icon' ) ), + # 积分测试接口 + path("admin/", admin.site.urls), + path(route="page/", view=include(arg=分页接口ViewSetsRouter.urls)), + # 小程序前端页面分享 + path(route="share/", view=include(arg=小程序前端分享页面Router.urls)), # 小程序前端页面分享 + path(route="demo/", view=include(arg=DemoXiaoViewSetsDemoRouter.urls)), + path(route="mini/", view=include(arg=六果科技小程序用户登陆Router.urls)), + # 用户配送地址 + path(route="address/", view=include(arg=小程序用户地址定位地图Router.urls)), + # 处理前端分享业务的接口 + # 微信支付测试接口 + path(route="demopay/", view=include(arg=微信支付ViewSetsRouter.urls, )), + path(route="demopay/", view=include(arg=six商家转账ViewSetsRouter.urls)), + # celery测试接口 + path(route="celery/", view=include(arg=Celery测试接口ViewSetsRouter.urls)), + # 小程序用户头像和昵称接口 + path(route="user/", view=include(arg=小程序用户头像昵称接口ViewSetsRouter.urls)), + path(route="submsg/", view=include(arg=miniMsg订阅消息Router.urls)), + # 企业微信相关的业务逻辑接口 + # 用户角色权限接口 + path(route="mini_msg/", view=sixmini.as_view({"get": "api_get", "post": "api_post"})), + # 本接口授权,是小程序配置项中, 消息推送的配置 + path(route="ryo32y0UxI.txt", view=sixmini.as_view({"get": "web_view_auth"})), # 本接口是对小程序页面中使用web时的域名授权 + # 企业微信授权接口 (江苏六果科技有限公司) + path(route="wecom_msg/", view=sixwecom.as_view({"get": "api_get", "post": "api_post"})), # 对企业微信的应用授权的接口 + path(route="WW_verify_EhbJf3fcwi8bNijV.txt", view=sixwecom.as_view({"get": "api_text", })), # 对企业微信的应用授权的接口 + path(route="MP_verify_kMmcLX8ZO79apUxA.txt", view=服务号网页授权接口ViewSets.as_view({"get": "认证接口文件"})), + # 江苏六果科技有限公司 (服务号) + path(route="wechat_msg/", view=sixwechat.as_view({"get": "api_get", "post": "api_post"})), # 服务号消息推送接口授权 + # 此接口为: 服务号的网页授权认证的接口(授权的域名认证) + # 代金券相关接口 + path(route="coupons/", view=include(arg=代金券接口ViewSetsRouter.urls)), + # 商品信息相关接口 + path(route="goods/", view=include(arg=商品接口ViewSetsRouter.urls)), + # 所有的小程序后端管理的接口 + # 分享关系接口 + # 企业微信相关群管理接口 + path(route="wecom_chat/", view=include(arg=企业微信管理端接口列表Router.urls)), + path(route="order/", view=include(arg=订单管理接口ViewSetsRouter.urls)), + # 小程序服务端管理接口 + path(route="", view=include(arg=小程序服务端管理接口列表ViewSetsRouter.urls)), + path(route="wechat_mini/", view=include(arg=小程序服务端管理接口列表ViewSetsRouter.urls)), + path(route="print/", view=include(arg=蕊烨打印机接口ViewSetsRouter.urls)), + # 用户管理后台所有的接口 + path(route="web/", view=include(arg=桌面端企业微信接口ViewSets列表Router.urls)), + path(route="wechat/", view=include(arg=服务号接口列表Router.urls)), + # 这是验验网站使用 微信登陆的 验证文件接口 + path(route="0p7rS8xxjR.txt/", view=网页端验证文件接口ViewSets.as_view({"get": "网页端验证文件接口"})), + ] diff --git a/sixGuoDjango/wsgi.py b/sixGuoDjango/wsgi.py new file mode 100644 index 0000000..30afb51 --- /dev/null +++ b/sixGuoDjango/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for sixGuoDjango project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sixGuoDjango.settings") + +application = get_wsgi_application() diff --git a/templates/favicon.ico b/templates/favicon.ico new file mode 100644 index 0000000..7f02960 Binary files /dev/null and b/templates/favicon.ico differ diff --git a/templates/robots.txt b/templates/robots.txt new file mode 100644 index 0000000..14267e9 --- /dev/null +++ b/templates/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / \ No newline at end of file diff --git a/templates/xiao.html b/templates/xiao.html new file mode 100644 index 0000000..772f0dc --- /dev/null +++ b/templates/xiao.html @@ -0,0 +1,441 @@ + + + + + + 江苏六果科技有限公司 - 专业小程序开发服务 + + + + + +
+ + +
+ + + + + +
+

经营主体信息

+
    +
  • 公司名称:江苏六果科技有限公司
  • +
  • 经营类目:软件开发 / 小程序定制 / 互联网技术服务
  • +
  • 客服电话:请填写贵司联系电话
  • +
  • 售后说明:7×12小时在线客服,交付后提供30天免费维护
  • +
+
+ + +
— 小程序开发服务套餐 —
+
根据您的业务需求,选择最适合的开发模板
+ +
+ + +
+
基础模板
+

标准展示型小程序

+
+ 适用于企业官网展示、产品目录、新闻资讯等基础场景,快速上线,性价比高。 +
+
    +
  • 企业信息展示页面(首页/关于/联系)
  • +
  • 产品/服务分类展示(最多20个)
  • +
  • 新闻资讯模块
  • +
  • 在线客服(微信客服对接)
  • +
  • 基础数据统计后台
  • +
  • 1次免费修改调整
  • +
+
+
+
¥988/套
+
+ 立即下单 +
+
+ + +
+
推荐
+
高级模板
+

电商交互型小程序

+
+ 适用于电商零售、会员管理、在线预约等交互场景,功能丰富,助力业务增长。 +
+
    +
  • 包含基础模板全部功能
  • +
  • 商品管理 + 购物车 + 在线支付
  • +
  • 会员注册/积分/等级体系
  • +
  • 在线预约/订单管理
  • +
  • 营销工具(优惠券/拼团/秒杀)
  • +
  • 数据可视化报表后台
  • +
  • 3次免费修改调整 + 7天运维支持
  • +
+
+
+
¥1988/套
+
+ 立即下单 +
+
+ +
+ + +
— 服务流程 —
+
+
+

标准交付流程

+
+
+
1
+
需求沟通
+
确认功能清单
+
+
+
2
+
UI设计
+
原型+视觉稿
+
+
+
3
+
开发测试
+
前端+后端联调
+
+
+
4
+
上线交付
+
发布+运维
+
+
+
+
+ + +
+ 💡 支付说明:下单后请在15分钟内完成支付,支付成功后我们将在1个工作日内与您联系确认需求。支持微信H5支付、支付宝等多种支付方式。 +
+ + + + + + \ No newline at end of file diff --git a/wechat_mini_服务端接口目录/小程序交易管理服务接口列表/发货信息录入.py b/wechat_mini_服务端接口目录/小程序交易管理服务接口列表/发货信息录入.py new file mode 100644 index 0000000..305af8b --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序交易管理服务接口列表/发货信息录入.py @@ -0,0 +1,83 @@ +import datetime +from zoneinfo import ZoneInfo + +import orjson +import pydash +import requests +from django.forms import model_to_dict +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_数据库.支付订单数据库.商品订单数据 import order订单 + + +class 发货信息录入ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="enter_the_order") + def 录入用户下单的订单(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) # 小程序的openid + self_mini_unionid = request.data.get("self_mini_unionid", None) # 小程序的 + out_trade_no = request.data.get("out_trade_no", None) # 商家侧的订单号 + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", out_trade_no) + 订单对象 = order订单.objects.get(order支付订单号=out_trade_no, order支付状态="支付成功") + 商品标题 = pydash.get(obj=model_to_dict(instance=订单对象, fields=None), path="order商品数据.商品标题") + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token={mini_token}" + upload_time = datetime.datetime.now(tz=ZoneInfo("Asia/Shanghai")).isoformat(timespec="seconds") + 录入订单数据 = { + "order_key": { + "order_number_type": 1, # 订单单号类型,用于确认需要上传详情的订单。枚举值1,使用下单商户号和商户侧单号;枚举值2,使用微信支付单号 + "mchid": "1700383419", + "out_trade_no": out_trade_no, + }, + "logistics_type": 1, # 物流模式,发货方式枚举值:1、实体物流配送采用快递公司进行实体物流配送形式 2、同城配送 3、虚拟商品,虚拟商品,例如话费充值,点卡等,无实体配送形式 4、用户自提 + "delivery_mode": 1, # 发货模式,发货模式枚举值:1、UNIFIED_DELIVERY(统一发货)2、SPLIT_DELIVERY(分拆发货) 示例值: UNIFIED_DELIVERY + "shipping_list": [ + { + "express_company": "EMS", + "tracking_no": 订单对象.order物流公司订单编号, + "item_desc": "元宝零售", + # "contact": {"consignor_contact": "18860891975", "receiver_contact": "18860891970"} + }, + ], + "upload_time": upload_time, + # "payer": {"openid": "ohQkD7NJ5EASxdh6ajad4QR_6i78"} + "payer": {"openid": self_mini_openid}, + } + json_data = orjson.dumps(录入订单数据, option=orjson.OPT_SORT_KEYS, ).decode(encoding="utf-8") + data = requests.post(url=uri, data=json_data) + resData = data.json() + # 最后更新物流的状态 + 订单对象.order物流状态 = order订单.order订单choosies物流状态.待收货.value + 订单对象.save() + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=resData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="configure_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) + mini_token = sixToken.get_mini_token() + data = requests.post(url="https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path", + params={"access_token": mini_token, }, json={"path": "/pages/OrderPages/OrderPages"}, + ) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", data.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="notifyConfirmReceive") + def 确认收货提醒(self, request: Request): + """如你已经从你的快递物流服务方获知到用户已经签收相关商品,可以通过该接口提醒用户及时确认收货,以提高资金结算效率,每个订单仅可调用一次。""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + mini_token = sixToken.get_mini_token() + requests.post(url="https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receives", + params={"access_token": mini_token, }) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序前端分享页面/主面分享页面接口.py b/wechat_mini_服务端接口目录/小程序前端分享页面/主面分享页面接口.py new file mode 100644 index 0000000..b57fe18 --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序前端分享页面/主面分享页面接口.py @@ -0,0 +1,50 @@ +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 + + +class 主页分享页面接口ViewSets(ViewSet): + img_主页面分享时的图片 = "https://hudie.sixgou.com/six/aa35a95a5be61ba1bc38f856fabf3978.png" + + @action(detail=False, methods=["post", ], url_path="onShareAppMessage") + def 主页群分享接口(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + page_path = request.data.get("page_path", None) + # 如果需要携带参数, 需要在路由的后面 ? 添加 key=value的格式; + 分享参数 = { + "superior_unionid": self_mini_unionid, + "shareType": "小程序推荐", + } + print(分享参数) + result = "&".join([f"{key}={value}" for key, value in 分享参数.items()]) + print("================", result, self_mini_openid, "炎什么值拿不到了呢?") + messageData = { + "title": "🧧🧧🧧无门槛代金券,快来领!!!", + "path": f"{page_path}?{result}", + "imageUrl": self.img_主页面分享时的图片, + } + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=messageData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="onShareTimeline") + def 主页朋友圈分享的功能接口(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + + page_path = request.data.get("page_path", None) + # 如果需要携带参数, 需要在路由的后面 ? 添加 key=value的格式 + messageData = { + "title": "🧧🧧🧧无门槛代金券,快来领!!!", + "path": f"{page_path}", + "imageUrl": self.img_主页面分享时的图片, + "query": f"superior_unionid={self_mini_unionid}&shareType=小程序推荐", + } + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=messageData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序前端分享页面/商品详情页面分享接口.py b/wechat_mini_服务端接口目录/小程序前端分享页面/商品详情页面分享接口.py new file mode 100644 index 0000000..153d2f6 --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序前端分享页面/商品详情页面分享接口.py @@ -0,0 +1,65 @@ +import uuid + +import pydash +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_数据库.洗衣液商品数据库.六果洗衣液商品 import Goods + + +class 商品详情页面分享接口ViewSets(ViewSet): + @action(detail=False, methods=["post"], url_path="goods_detaile") + def 商品详情页面分享群好友接口(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + page_path = request.data.get("page_path", None) + idKey = request.data.get("idKey", None) + my_uuid = uuid.UUID(idKey) + goods = Goods.objects.get(idKey=idKey) + print(goods.goods_商品销售规格) + 主图图片链接 = pydash.get(obj=goods, path="goods_商品销售规格.0.goods_商品详情图片.主图.0") + 分享参数 = { + "superior_unionid": self_mini_unionid, + "shareType": "好物推荐", + "goodID": idKey, + } + result = "&".join([f"{key}={value}" for key, value in 分享参数.items()]) + messageData = { + "title": "🧧“洗”出好运,免费带走,📢 刚薅到的羊毛!这瓶洗衣液真的不要钱!!!!!", + "path": f"{page_path}?{result}", + "imageUrl": 主图图片链接, + } + print(messageData) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=messageData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="timeline_goods_detaile") + def 商品详情页面分享朋友圈接口(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + + page_path = request.data.get("page_path", None) + idKey = request.data.get("idKey", None) + goods = Goods.objects.get(idKey=idKey) + 主图图片链接 = pydash.get(obj=goods, path="goods_商品销售规格.0.goods_商品详情图片.主图.0") + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", 主图图片链接) + 分享参数 = { + "superior_unionid": self_mini_unionid, + "shareType": "好物推荐", + "goodID": idKey, + } + result = pydash.join(array=[f"{key}={value}" for key, value in 分享参数.items()], separator="&") + messageData = { + "title": "🧧“洗”出好运,免费带走,📢 刚薅到的羊毛!这瓶洗衣液真的不要钱!!!!!", + "path": f"{page_path}", + "imageUrl": 主图图片链接, + "query": result, + } + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=messageData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序前端分享页面/幸运拼团分享接口.py b/wechat_mini_服务端接口目录/小程序前端分享页面/幸运拼团分享接口.py new file mode 100644 index 0000000..913af79 --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序前端分享页面/幸运拼团分享接口.py @@ -0,0 +1,61 @@ +import pydash +from django.forms import model_to_dict +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 ResData, BaseResponse +from wechat_数据库.洗衣液商品数据库.六果洗衣液商品 import goods商品 + + +class 幸运拼团分享接口ViewSets(ViewSet): + @action(detail=False, methods=["post"], url_path="message_lucky") + def 幸运拼团群分享接口奖励积分(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + # 如果需要携带参数, 需要在路由的后面 ? 添加 key=value的格式; + page_path = request.data.get("page_path", None) + idKey = request.data.get("idKey", None) + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 难道我没有拿到值的吗?", idKey) + 参团商品对象 = goods商品.objects.get(id_主键_goods商品=idKey) + goods数据 = model_to_dict(instance=参团商品对象, fields=None) + 分享图片链接 = pydash.get(obj=goods数据, path="goods商品数据.商品图片.主图.0") + messageData = { + "title": "🧧🧧🧧洗衣液,居然还可以这样买!!!!", + "path": f"{page_path}?superior_unionid={self_user_unionid}&shareType=幸运拼团", + "imageUrl": 分享图片链接, + } + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=messageData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="timeline_lucky") + def 幸运拼团朋友圈分享的奖励接口(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + page_path = request.data.get("page_path", None) + # 如果需要携带参数, 需要在路由的后面 ? 添加 key=value的格式 + idKey = request.data.get("idKey", None) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", idKey) + # goods = goods商品.objects.get(idKey=idKey) + goods = goods商品.objects.get(id_主键_goods商品=idKey) + goods数据 = model_to_dict(instance=goods, fields=None) + 分享图片链接 = pydash.get(obj=goods数据, path="goods商品数据.商品图片.主图.0") + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", 分享图片链接) + messageData = { + "title": "🧧🧧🧧洗衣液,居然还可以这样买!!!!", + "path": f"{page_path}", + "imageUrl": "https://hudie.xiao.band/icon/Ll8-7G-3PFWEc6e26d282e20a598c05c15161ea19b5e.png", + "query": f"superior_unionid={self_user_unionid}" + } + 积分朋友圈数据 = { + "title": "🧧🧧🧧洗衣液,居然还可以这样买!!!!", + "path": f"{page_path}", + "imageUrl": 分享图片链接, + "query": f"superior_unionid={self_user_unionid}&shareType=商品详情分享朋友圈" + } + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=积分朋友圈数据), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户的位置接口.py b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户的位置接口.py new file mode 100644 index 0000000..aab4e4a --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户的位置接口.py @@ -0,0 +1,63 @@ +import pydash +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_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.腾讯地图.腾讯地图工具 import wei地图工具 + + +class 小程序用户的位置接口ViewSets(ViewSet): + @action(detail=False, methods=["post"], url_path="locating") + def 解析用户的定位(self, request: Request): + """前端用户:发起定位请求的时候, """ + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + result = request.data.get("result", None) + print("\n🍎 🍏 🍊 获取用户定位的请求进来了🍊 🍎 🍏 \n", self_mini_openid, self_mini_unionid) + six六果对象, sixBool = weiuser.objects.get_or_create(unionid=self_mini_unionid) # 拿到当前的用户请求的对象 + # 判断 当前用户,是否已经拿有位置的信息数据了 + if six六果对象.user_区县: + # 当这里为true的时候就可以直接返回了 + return Response() + else: + 纬度 = pydash.get(obj=result, path="latitude") + 经度 = pydash.get(obj=result, path="longitude") + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 用户的定位的数据", result) + 地图解析结果 = wei地图工具.经纬度转换为地址(location=f"{纬度},{经度}") + 省 = pydash.get(obj=地图解析结果, path="result.address_component.province") + 市 = pydash.get(obj=地图解析结果, path="result.address_component.city") + 区 = pydash.get(obj=地图解析结果, path="result.address_component.district") + 街道 = pydash.get(obj=地图解析结果, path="result.address_component.street_number") + 街道号码 = pydash.get(obj=地图解析结果, path="result.address_component.street") + # 开始更新数据库 + six六果对象.user_区县 = 区 + six六果对象.user_省份 = 省 + six六果对象.user_城市 = 市 + six六果对象.user_街道信息 = 街道 + 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="ip") + def 解析用户IP地址接口(self, request: Request): + """ """ + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + 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: + 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") + district_区县 = pydash.get(obj=weiData, path="result.ad_info.district") or None + mini_unionid_user.user_省份 = province_省份 + mini_unionid_user.user_城市 = city_城市 + mini_unionid_user.user_区县 = district_区县 + mini_unionid_user.user_IP地址 = ip + mini_unionid_user.save() + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户配送地址接口.py b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户配送地址接口.py new file mode 100644 index 0000000..713e952 --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序用户地址定位/小程序用户配送地址接口.py @@ -0,0 +1,246 @@ +import jmespath +import orjson +import pydash +from asgiref.sync import async_to_sync +from channels.layers import BaseChannelLayer, get_channel_layer +from django.forms import model_to_dict +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, RedisClientManager, ResData +from wechat_数据库.地图定位.用户定位数据库 import weiuser地图定位 +from wechat_数据库.用户数据库.小程序用户地址 import weiuser微信用户地址 +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.腾讯地图.腾讯地图工具 import OriginPointOptional, wei地图工具 + +redis_socked = RedisClientManager().get_client(db_name="redis_5") + +example通道层实例: BaseChannelLayer = get_channel_layer(alias="default") + + +class 用户配送地址ViewSets(ViewSet): + def update更新用户头像事件(self, self_mini_unionid): + channel_id = redis_socked.get(self_mini_unionid) + user_obj = weiuser.objects.get(unionid=self_mini_unionid) + user_data = model_to_dict(instance=user_obj, fields=None, exclude=None) + async_to_sync(awaitable=example通道层实例.send)(channel=channel_id, + message={"type": "update_更新用户头像", + "text": orjson.dumps(user_data, + option=orjson.OPT_SORT_KEYS).decode( + encoding="utf-8") + }) + + def update更新用户手机号码方法(self, address, self_mini_openid, self_user_unionid): + pass + 用户手机号码 = pydash.get(obj=address, path="telNumber") + 用户昵称 = pydash.get(obj=address, path="userName") + 用户所在省 = pydash.get(obj=address, path="provinceName") + 用户所在市 = pydash.get(obj=address, path="cityName") + 用户所在区县 = pydash.get(obj=address, path="countyName") + 用户所在街道 = pydash.get(obj=address, path="detailInfo") + weiuser.objects.filter(unionid=self_user_unionid).update( + uesr_手机号码=用户手机号码, user_昵称=用户昵称, + user_省份=用户所在省, user_城市=用户所在市, user_区县=用户所在区县, + user_街道信息=用户所在街道 + ) + + @action(detail=False, methods=["post"], url_path="first_add") + def 首次添加用户收件地址(self, request: Request): + """""" + addressData = request.data.get("addressData", None) + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + self.update更新用户手机号码方法(address=addressData, self_mini_openid=self_mini_openid, + self_user_unionid=self_mini_unionid) + self.update更新用户头像事件(self_mini_unionid=self_mini_unionid) + + a, b = weiuser微信用户地址.objects.update_or_create( + address=addressData, mini_unionid=self_mini_unionid, mini_openid=self_mini_openid, + isDefaultAddress=weiuser微信用户地址.choicesAddress.是默认地址.value, + ) + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid, ).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress") + 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="query_all") + def 查询当前用户的全部地址(self, request: Request): + """查询当前用户所有的配置过的配送地址""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_openid=self_mini_openid, + mini_unionid=self_mini_unionid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress", "mini_unionid", "mini_openid") + httpResData = BaseResponse( + resData=ResData(listData=查询当前用户的全部地址, dictData={"demo": "在这里返回的吗"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post", ], url_path="add") + def 添加用户地址(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + addressData = request.data.get("addressData", None) + self.update更新用户手机号码方法(address=addressData, self_mini_openid=self_mini_openid, + self_user_unionid=self_mini_unionid) + + self.update更新用户头像事件(self_mini_unionid=self_mini_unionid) + + 是否新存在 = weiuser微信用户地址.objects.filter(address=addressData, mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid).exists() + if 是否新存在: + # 这里说明的是用户首次添加新地址成功了,应该更新数据为 默认地址, + weiuser微信用户地址.objects.filter(mini_openid=self_mini_openid, mini_unionid=self_mini_unionid).update( + isDefaultAddress=weiuser微信用户地址.choicesAddress.不是默认地址.value) + print("判断,同时更新的当前所有的地址都为不是默认的值,") + weiuser微信用户地址.objects.filter(address=addressData, mini_openid=self_mini_openid, + mini_unionid=self_mini_unionid).update( + isDefaultAddress=weiuser微信用户地址.choicesAddress.是默认地址.value, + ) + print("将当前的地址更新为默认值") + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_openid=self_mini_openid, + mini_unionid=self_mini_unionid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress", + ) + httpResData = BaseResponse( + resData=ResData(listData=查询当前用户的全部地址, dictData={"demo": "地址相同"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + else: + # 同时还需要将以前的地址全部更新为非默认地址, + 创建新对象, 是否首次创建 = weiuser微信用户地址.objects.update_or_create( + address=addressData, mini_openid=self_mini_openid, + mini_unionid=self_mini_unionid) # 在这里更新了所有的地址都不是 默认的地址 + (weiuser微信用户地址.objects.filter(mini_openid=self_mini_openid, mini_unionid=self_mini_unionid) + .update(isDefaultAddress=weiuser微信用户地址.choicesAddress.不是默认地址.value)) + # 创建新对象.isDefaultAddress = weiuser微信用户地址.choicesAddress.是默认地址.value + # 创建新对象.save() + weiuser微信用户地址.objects.filter(address=addressData, mini_openid=self_mini_openid, + mini_unionid=self_mini_unionid).update( + isDefaultAddress=weiuser微信用户地址.choicesAddress.是默认地址.value, + ) + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_openid=self_mini_openid, + mini_unionid=self_mini_unionid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress", + ) + httpResData = BaseResponse( + resData=ResData(listData=查询当前用户的全部地址, dictData={"demo": "添加成功"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="delete") + def 单独删除地址(self, request: Request): + """删除单个地址""" + idKey = request.data.get("idKey", None) + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + a, b = weiuser微信用户地址.objects.filter(id_主键_配送地址=idKey).delete() + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_openid=self_mini_openid, + mini_unionid=self_mini_unionid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress") + 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="all_delete") + def 删除当前用户所有的配送地址(self, request: Request): + """删除全部的地址""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + weiuser微信用户地址.objects.filter(mini_unionid=self_mini_unionid, mini_openid=self_mini_openid).delete() + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress") + 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="change_default") + def 设为默认地址(self, request: Request): + """""" + idKey = request.data.get("idKey", None) + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + addressData = weiuser微信用户地址.objects.get(id_主键_配送地址=idKey).address + self.update更新用户手机号码方法(address=addressData, + self_mini_openid=self_mini_openid, + self_user_unionid=self_mini_unionid) + self.update更新用户头像事件(self_mini_unionid=self_mini_unionid) + + # 将所有的先更新为非默认地址 + weiuser微信用户地址.objects.filter(mini_unionid=self_mini_unionid, mini_openid=self_mini_openid).update( + isDefaultAddress=weiuser微信用户地址.choicesAddress.不是默认地址.value) + weiuser微信用户地址.objects.filter(id_主键_配送地址=idKey, mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid).update( + isDefaultAddress=weiuser微信用户地址.choicesAddress.是默认地址.value) + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress") + 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="update") + def 更新当前配送地址(self, request: Request): + """""" + addressData = request.data.get("addressData", None) + idkey = request.data.get("idkey", None) + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + self.update更新用户手机号码方法(address=addressData, self_mini_openid=self_mini_openid, + self_user_unionid=self_mini_unionid) + 对象是否存在 = weiuser微信用户地址.objects.filter(address=addressData, + mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid).exists() + self.update更新用户头像事件(self_mini_unionid=self_mini_unionid) + if 对象是否存在: + # 说明用户当前是存在的啦(说明,addressData)是有相同的值存在的 + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress") + httpResData = BaseResponse( + resData=ResData(listData=查询当前用户的全部地址, dictData={"demo": "没有更新"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + else: + weiuser微信用户地址.objects.filter(id_主键_配送地址=idkey).update(address=addressData) + 查询当前用户的全部地址 = weiuser微信用户地址.objects.filter(mini_unionid=self_mini_unionid, + mini_openid=self_mini_openid).values( + "id_主键_配送地址", "id_str", "address", "isDefaultAddress") + 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="locating") + def 解析用户的定位(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + result = request.data.get("result", None) + errMsg = jmespath.search(data=result, expression="errMsg") + latitude = jmespath.search(data=result, expression="latitude") + longitude = jmespath.search(data=result, expression="longitude") + speed = jmespath.search(data=result, expression="speed") + accuracy = jmespath.search(data=result, expression="accuracy") + altitude = jmespath.search(data=result, expression="altitude") + verticalAccuracy = jmespath.search(data=result, expression="verticalAccuracy") + horizontalAccuracy = jmespath.search(data=result, expression="horizontalAccuracy") + res = wei地图工具.经纬度转换为地址(location=f"{latitude},{longitude}") + standard_address = jmespath.search(data=res, expression="result.formatted_addresses.standard_address") + 省 = jmespath.search(data=res, expression="result.address_component.province") + 市 = jmespath.search(data=res, expression="result.address_component.city") + 区 = jmespath.search(data=res, expression="result.address_component.district") + # 再计算一下距离 + 起点数据: OriginPointOptional = {"经度": f"{longitude}", "纬度": f"{latitude}", } + 终点数据: OriginPointOptional = {"经度": str(longitude), "纬度": str(latitude)} + 两地相多少公里 = wei地图工具.腾讯地图计算二点之间的距离(toData终点=终点数据, fromData起点=起点数据) + # print(f"两地相距了{两地相多少公里 / 1000}公里", type(两地相多少公里)) + weiuser地图定位.objects.update_or_create( + map用户openid=self_mini_openid, map用户uniond=self_user_unionid, map两点距离=两地相多少公里, + map原点经纬度=起点数据, map终点经纬度=终点数据, map纬度latitude=latitude, map经度longitude=longitude, + map省=省, map市=市, map区=区) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/ShortLink接口.py b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/ShortLink接口.py new file mode 100644 index 0000000..77def4d --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/ShortLink接口.py @@ -0,0 +1,27 @@ +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 ResData, BaseResponse +from wechat_token.token工具包 import sixToken + + +class ShortLinkViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="genwxashortlink") + def 获取ShortLink(self, request: Request): + """获取小程序 Short Link,适用于微信内拉起小程序的业务场景。目前对所有非个人主体小程序开放。通过该接口,可以选择生成到期失效和永久有效的小程序短链""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + mini_token = sixToken.get_mini_token() + requests.post(url="https://api.weixin.qq.com/wxa/genwxashortlink", params={"access_token": mini_token, }, + json={ + "page_url": f"pageTabBar/Home/Home?superior_unionid={self_mini_unionid}", + "page_title": "Homework title", # 短链标题,可自定义,不能包含违法信息,超过 20 字符会用... 截断代替 + "is_permanent": False, + } + ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/URLLink接口.py b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/URLLink接口.py new file mode 100644 index 0000000..153b05e --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/URLLink接口.py @@ -0,0 +1,35 @@ +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 wechat_token.token工具包 import sixToken + + +class URLLinkViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="generate_urllink") + def 获取加密URLLink(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + mini_token = sixToken.get_mini_token() + linkData = requests.post(url="https://api.weixin.qq.com/wxa/generate_urllink", + params={"access_token": mini_token, }, + json={ + "path": "/pageTabBar/Home/Home", + "query": f"superior_unionid={self_mini_unionid}", + "expire_type": 1, # 类型 + "expire_interval": 30, # 多少天后失效 + "env_version": "develop", # 默认值"release"。要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效。 + }, + ) + print(linkData.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/scheme码接口.py b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/scheme码接口.py new file mode 100644 index 0000000..17a3279 --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/scheme码接口.py @@ -0,0 +1,49 @@ +from datetime import datetime +from zoneinfo import ZoneInfo + +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 + + +class Scheme接口ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="queryscheme") + def 查询scheme码(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="generatescheme") + def 获取加密scheme码(self, request: Request): + """该接口用于获取小程序 scheme 码,适用于短信、邮件、外部网页、微信内等拉起小程序的业务场景。""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + mini_token = sixToken.get_mini_token() + expire_time = str(int(datetime.now(tz=ZoneInfo("Asia/Shanghai")).timestamp())) + schemeData = requests.post(url="https://api.weixin.qq.com/wxa/generatescheme", + params={"access_token": mini_token, }, + json={ + "jump_wxa": { + "path": "/pageTabBar/Home/Home", + "query": f"superior_unionid={self_mini_unionid}", + }, + "is_expire": True, # 这里好像是必须要填的 + "expire_interval": 30, # 有效天数,1-30天 + "expire_type": 1 + } + ) + print(schemeData.json()) + openlink = pydash.get(obj=schemeData.json(), path="openlink") + print("生成的小程序 scheme 码", openlink) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/小程序码接口.py b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/小程序码接口.py new file mode 100644 index 0000000..df50e67 --- /dev/null +++ b/wechat_mini_服务端接口目录/小程序码与小程序链接口列表/小程序码接口.py @@ -0,0 +1,54 @@ +import io + +import requests +from django.core.files.storage import default_storage +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 ResData, BaseResponse +from wechat_token.token工具包 import sixToken + + +class 小程序码接口ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="getwxacode") + def 获取小程序码(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + mini_token = sixToken.get_mini_token() + requests.post(url="https://api.weixin.qq.com/wxa/getwxacode", params={"access_token": mini_token, }, + json={ + "path": "/pageTabBar/Home/Home?superior_unionid=123", + "env_version": "develop", # 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版 + }, + ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="getwxacodeunlimit") + def 获取不限制的小程序码(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + mini_token = sixToken.get_mini_token() + miniCode = requests.post(url="https://api.weixin.qq.com/wxa/getwxacodeunlimit", params={"access_token": mini_token, }, + json={ + "page": "tabPage/Home/Home", + "scene": f"{self_mini_unionid}", # 这里的值最终会显示 "query": {"scene":"self_mini_unionid"} + "env_version": "develop", # 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 + }, + ) + default_storage.save(name=f"{self_mini_unionid}.png", content=io.BytesIO(miniCode.content)) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="createwxaqrcode") + def 获取小程序二维码(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/手机号/获取手机号接口.py b/wechat_mini_服务端接口目录/手机号/获取手机号接口.py new file mode 100644 index 0000000..4271cd8 --- /dev/null +++ b/wechat_mini_服务端接口目录/手机号/获取手机号接口.py @@ -0,0 +1,22 @@ +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 ResData, BaseResponse +from wechat_token.token工具包 import sixToken + + +class 获取手机号ViewSets(ViewSet): + @action(detail=False, methods=["post"], url_path="get") + def 测试路由接口(self, request: Request): + """""" + code = request.data.get("code", None) # 前端传递过来的 code的值 + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/wxa/business/getuserphonenumber" + phoneData = requests.post(url=uri, params={"access_token": mini_token, }, json={"code": code}) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 获取用户手机号", phoneData.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/接口调用凭证/获取稳定版接口调用凭据接口.py b/wechat_mini_服务端接口目录/接口调用凭证/获取稳定版接口调用凭据接口.py new file mode 100644 index 0000000..1b19951 --- /dev/null +++ b/wechat_mini_服务端接口目录/接口调用凭证/获取稳定版接口调用凭据接口.py @@ -0,0 +1,27 @@ +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 ResData, BaseResponse +from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司 + + +class 获取稳定版接口调用凭据ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="getStableAccessToken") + def 测试路由接口(self, request: Request): + """""" + uri = f"https://api.weixin.qq.com/cgi-bin/stable_token" + json_data = { + "grant_type": "client_credential", "appid": sixpay六果科技公司.appid, "secret": sixpay六果科技公司.appsecret, + "force_refresh": True + } + tokenData = requests.post(url=uri, json=json_data) + print(tokenData.json()) + access_token = pydash.get(obj=tokenData.json(), path="access_token") + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", access_token) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py b/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py new file mode 100644 index 0000000..fe63c70 --- /dev/null +++ b/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py @@ -0,0 +1,361 @@ +import time +from datetime import datetime +from typing import Literal +from zoneinfo import ZoneInfo + +import orjson +import pydash +import requests +from django.core.handlers.wsgi import WSGIRequest +from django.db.models import QuerySet +from django.forms import model_to_dict +from pydantic import BaseModel, Field +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 ulid import ULID + +from sixGuoDjango import BaseResponse, ResData +from wechat_token.token工具包 import sixToken +from wechat_数据库.支付订单数据库.商品订单数据 import order订单, order订单商品数据 + + +class ems物流状态更新模型(BaseModel): + """物流状态更新请求模型""" + + biz_id: Literal["test_biz_id", "1100244903172"] = Field(..., description="业务ID,仅允许 xiao 或 zizi") + order_id: str = Field(..., description="商家生成的订单号") + delivery_id: Literal["EMS"] = Field(..., description="配送商ID(如 TEST、EMS)") + waybill_id: str = Field(..., description="物流订单号") + action_time: int = Field(..., description="更新时间戳(秒级)") + action_type: int = Field(..., description="操作类型编码") + action_msg: str = Field(..., description="操作描述") + + +class EMS物流ViewSets(ViewSet): + ems_biz_id = "1100244903172" + ems_delivery_id = "EMS" + ems_password = "xiao792282" + + def ems发件人信息(self): + ems发件人信息数据 = { + "name": "六果泡泡", # 否 发/收件人姓名,不超过64字节 + "tel": "18860891975", # string 否 发/收件人座机号码,若不填写则必须填写 mobile,不超过32字节 + "mobile": "18860891970", # string 否 发/收件人手机号码,若不填写则必须填写 tel,不超过32字节 + "company": "江苏六果科技有限公司", # string 否 发/收件人公司名称,不超过64字节 + "post_code": "225300", # string 否 发/收件人邮编,不超过10字节 + "country": "中国", # string 否 发/收件人国家,不超过64字节 + "province": "江苏省", # string 否 发/收件人省份,比如:"广东省",不超过64字节 + "city": "泰州市", # string 否 发/收件人市/地区,比如:"广州市",不超过64字节 + "area": "海陵区", # string 否 发/收件人区/县,比如:"海珠区",不超过64字节 + "address": "", # string 否 发/收件人详细地址,比如:"XX路XX号XX大厦XX",不超过512 字节 + } + return ems发件人信息数据 + + def ems收件人信息(self, order订单号): + 订单对象 = order订单.objects.get(order物流订单号=order订单号) + orderData = model_to_dict(instance=订单对象, fields=None) + provinceName = pydash.get(obj=orderData, path="order用户配送地址.address.provinceName") + cityName = pydash.get(obj=orderData, path="order用户配送地址.address.cityName") # 市 + countyName = pydash.get(obj=orderData, path="order用户配送地址.address.countyName") # 区 + detailInfoNew = pydash.get(obj=orderData, path="order用户配送地址.address.detailInfoNew") # 详细地址 + telNumber = pydash.get(obj=orderData, path="order用户配送地址.address.telNumber") # 详细地址 + detailInfo = pydash.get(obj=orderData, path="order用户配送地址.address.detailInfo") # 详细地址 + userName = pydash.get(obj=orderData, path="order用户配送地址.address.userName") # 详细地址 + nationalCode = pydash.get(obj=orderData, path="order用户配送地址.address.nationalCode") # 详细地址 + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", telNumber) + return { + "name": userName, # 否 发/收件人姓名,不超过64字节 + "tel": telNumber, # string 否 发/收件人座机号码,若不填写则必须填写 mobile,不超过32字节 + "mobile": telNumber, # string 否 发/收件人手机号码,若不填写则必须填写 tel,不超过32字节 + "company": "", # string 否 发/收件人公司名称,不超过64字节 + "post_code": nationalCode, # string 否 发/收件人邮编,不超过10字节 + "country": "中国", # string 否 发/收件人国家,不超过64字节 + "province": provinceName, # string 否 发/收件人省份,比如:"广东省",不超过64字节 + "city": cityName, # string 否 发/收件人市/地区,比如:"广州市",不超过64字节 + "area": countyName, # string 否 发/收件人区/县,比如:"海珠区",不超过64字节 + "address": detailInfoNew, # string 否 发/收件人详细地址,比如:"XX路XX号XX大厦XX",不超过512 字节 + } + + def cargo包裹信息(self): + return { + "count": 1, # number 是 包裹数量, 默认为1 + "weight": 4, # number 是 货物总重量,比如1.2,单位是千克(kg) + "space_x": 1, # number 是 货物长度,比如20.0,单位是厘米(cm) + "space_y": 1, # number 是 货物宽度,比如15.0,单位是厘米(cm) + "space_z": 1, # number 是 货物高度,比如10.0,单位是厘米(cm) + "detail_list": [ + { + "name": "商品名称", # string 是 商品名,不超过128字节 + "count": 1, # number 是 商品数量 + }, + ], + } + + def shop商品信息(self, order订单号): + 订单对象 = order订单.objects.get(order物流订单号=order订单号) + orderData = model_to_dict(instance=订单对象, fields=None) + 购物车商品列表: QuerySet[order订单商品数据] = order订单商品数据.objects.filter(wai_订单=订单对象) + print(购物车商品列表) + detail_list = [] + for goods in 购物车商品列表: + 商品数据 = model_to_dict(instance=goods, fields=None, exclude=None) + detail_list.append( + { + "goods_name": pydash.get(obj=商品数据, path="order_商品标题"), + "goods_img_url": pydash.get(obj=商品数据, path="order_商品详情图片.主图.0"), + "goods_desc": "", + }, + ) + goods_count = pydash.get(obj=orderData, path="order购物车商品数量") + shop商品信息数据 = { + "wxa_path": "/pages/OrderPages/OrderPages", # string 否 商家小程序的路径,建议为订单页面 + # "img_url": "", # string 否 商品缩略图 url;shop.detail_list为空则必传,shop.detail_list非空可不传。 + # "goods_name": "", # string 否 商品名称, 不超过128字节;shop.detail_list为空则必传,shop.detail_list非空可不传。 + # goods_count 否 商品详情列表,适配多商品场景,用以消息落地页展示。(新规范,新接入商家建议用此字段) + "goods_count": goods_count, # 商品数量;shop.detail_list为空则必传。shop.detail_list非空可不传,默认取shop.detail_list的size + "detail_list": detail_list, + } + return shop商品信息数据 + + def insured保价信息(self): + insured保价信息数据 = { + "use_insured": 0, # number 否 是否保价,0 表示不保价,1 表示保价 + "insured_value": 0, # number 否 保价金额,单位是分,比如: 10000 表示 100 元 + } + return insured保价信息数据 + + def service服务类型(self): + service服务类型数据 = { + "service_type": 6, # number 是 服务类型ID,详见已经支持的快递公司基本信息 + "service_name": "标准快递", # string 是 服务名称,详见已经支持的快递公司基本信息 + } + return service服务类型数据 + + def 生成最终完整的数据(self, order物流订单号): + 订单对象 = order订单.objects.get(order物流订单号=order物流订单号) + orderData = model_to_dict(instance=订单对象, fields=None) + order_id = pydash.get(obj=orderData, path="order物流订单号") + 收件人openid = pydash.get(obj=orderData, path="order支付者openid") + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", self.ems发件人信息()) + 完整数据 = { + "add_source": 0, + "order_id": order_id, + "openid": 收件人openid, + "delivery_id": "TEST", + "biz_id": "test_biz_id", + "custom_remark": "易碎物品", + "sender": self.ems收件人信息(order订单号=order物流订单号), # 收件人的信息 + "receiver": self.ems发件人信息(), # 发件人的信息 + "shop": self.shop商品信息(order订单号=order物流订单号), # 商品的信息 + "cargo": self.cargo包裹信息(), # 包果的信息 + "insured": self.insured保价信息(), # 保价信息 + "service": self.service服务类型(), # 服务类型 + } + return 完整数据 + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="bindAccount") + def 绑定账号(self, request: WSGIRequest | Request): + """""" + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/account/bind?access_token={mini_token}" + ems数据 = { + "type": "bind", + "biz_id": "1100244903172", + "delivery_id": "EMS", + "password": "xiao@792282", + } + data = requests.post(url=uri, json=ems数据) + print("🍎 🍏 🍊 🍎 🍏 🍊 绑定账号🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="unbindAccount") + def 解绑账号(self, request: WSGIRequest | Request): + """""" + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/account/bind?access_token={mini_token}" + ems数据 = { + "type": "unbind", + "biz_id": "1100244903172", + "delivery_id": "EMS", + "password": "xiao@792282", + } + data = requests.post(url=uri, json=ems数据) + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json()) + 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="getAllDelivery") + def 获取支持的快递公司列表(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/delivery/getall?access_token={mini_token}" + data = requests.get(url=uri, ) + emdData = orjson.loads(data.content.decode(encoding="utf-8")) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=emdData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post", ], url_path="getAllAccount") + def 获取所有绑定的物流账号(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/account/getall?access_token={mini_token}" + data = requests.get(url=uri) + print(orjson.loads( + orjson.dumps(data.content.decode(encoding="utf-8"), option=orjson.OPT_SORT_KEYS, ).decode( + encoding="utf-8"))) + 返回数据 = orjson.loads(data.content.decode(encoding="utf-8")) + print(返回数据, type(返回数据)) + print(orjson.loads(data.content.decode(encoding="utf-8"))) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=返回数据), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="addOrder") + def 生成运单(self, request: Request): + """""" + # 需要的参数 + order物流订单号 = request.data.get("order物流订单号", None) + print(order物流订单号, "这里没有值的吗") + order订单对象 = order订单.objects.get(order物流订单号=order物流订单号) + res = self.生成最终完整的数据(order物流订单号=order物流订单号) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎order物流订单号order物流订单号 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", order物流订单号) + mini_token = sixToken.get_mini_token() + 运单请求接口 = f"https://api.weixin.qq.com/cgi-bin/express/business/order/add?access_token={mini_token}" + json_完整的数据 = orjson.dumps(res).decode(encoding="utf-8") + data = requests.post(url=运单请求接口, data=json_完整的数据, ) + print("请求生成运单的接口,生成数据", data.json()) + waybill_id = pydash.get(obj=data.json(), path="waybill_id") + 更新订单对象 = order订单.objects.get(order物流订单号=order物流订单号) + 更新订单对象.order物流公司订单编号 = waybill_id + # 更新订单对象.order物流数据 = 物流订单默认数据 + 更新订单对象.save() + # print( "🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 运单返回数据", data.json( ) ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="testUpdateOrder") + def 模拟更新订单状态(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + order物流公司订单编号 = request.data.get("order物流公司订单编号", None) + order物流订单号 = request.data.get("order物流订单号", None) + print(order物流公司订单编号, order物流订单号, "为什么这里没有值啊") + mini_token = sixToken.get_mini_token() + utcDate = datetime.now(tz=ZoneInfo("utc")) + timestamp = int(datetime.now(tz=ZoneInfo("Asia/Shanghai")).timestamp()) + milliseconds_int = ULID().milliseconds + 模拟更新物流状态 = f"https://api.weixin.qq.com/cgi-bin/express/business/test_update_order?access_token={mini_token}" + 模拟数据_揽件成功 = { + "biz_id": "test_biz_id", + "order_id": order物流订单号, # 商家生成的订单号 + "delivery_id": "TEST", # + "waybill_id": order物流公司订单编号, # 物流订单号 + "action_time": int(time.time()), # 这里是更新发的时间戳 + "action_type": 100001, + "action_msg": "揽件阶段-揽件成功", + } + 模拟数据_分配业务员 = { + "biz_id": "test_biz_id", + "order_id": order物流订单号, # 商家生成的订单号 + "delivery_id": "TEST", # + "waybill_id": order物流公司订单编号, # 物流订单号 + "action_time": int(time.time()), # 这里是更新发的时间戳 + "action_type": 100003, + "action_msg": "揽件阶段-分配业务员", + } + 模拟数据_更新运输轨迹 = { + "biz_id": "test_biz_id", + "order_id": order物流订单号, # 商家生成的订单号 + "delivery_id": "TEST", # + "waybill_id": order物流公司订单编号, # 物流订单号 + "action_time": int(time.time()), # 这里是更新发的时间戳 + "action_type": 200001, + "action_msg": "运输阶段-更新运输轨迹", + } + 模拟数据_开始派送 = { + "biz_id": "test_biz_id", + "order_id": order物流订单号, # 商家生成的订单号 + "delivery_id": "TEST", # + "waybill_id": order物流公司订单编号, # 物流订单号 + "action_time": int(time.time()), # 这里是更新发的时间戳 + "action_type": 300002, + "action_msg": "派送阶段-开始派送", + } + 模拟数据_签收成功 = { + "biz_id": "test_biz_id", + "order_id": order物流订单号, # 商家生成的订单号 + "delivery_id": "TEST", # + "waybill_id": order物流公司订单编号, # 物流订单号 + "action_time": int(time.time()), # 这里是更新发的时间戳 + "action_type": 300003, + "action_msg": "派送阶段-签收成功", + } + + data = requests.post(url=模拟更新物流状态, + data=orjson.dumps(模拟数据_揽件成功, option=orjson.OPT_SORT_KEYS, ).decode(encoding="utf-8")) + print("🍎 🍏 🍊 🍎 🍏 模拟更新物流状态 🍎 ", data.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="getpath") + def 查询运单轨迹(self, request: Request): + """查询当前物流订单的轨迹""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/path/get?access_token={mini_token}" + order物流订单号 = request.data.get("order物流订单号", None) + order物流公司订单编号 = request.data.get("order物流公司订单编号", None) + postData = requests.post(url=uri, json={"openid": self_mini_openid, "delivery_id": self.ems_delivery_id, + "waybill_id": order物流公司订单编号}) + print(postData.json()) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊物流订单查询接口", order物流公司订单编号, order物流订单号) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=postData.json()), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="update_logistics_information") + def 更新物流快递数据(self, request: Request): + """这个接口:相当于实时查询当前的 物流的轨迹""" + waybill_id = request.data.get("waybill_id", "生成的运单号") + order物流公司订单编号 = request.data.get("order物流公司订单编号", None) + order物流订单号 = request.data.get("order物流订单号", None) + print(order物流公司订单编号, "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", waybill_id) + 查询对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号, order物流订单号=order物流订单号) + print("查询对象", 查询对象) + 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": "TEST", "waybill_id": 查询对象.order物流公司订单编号, + }, + ) + print(orjson.loads(emsGetPathData.content.decode(encoding="utf-8")), "=================") + resData = orjson.loads(emsGetPathData.content.decode(encoding="utf-8")) + 查询对象.order物流数据 = resData + 查询对象.save() + + 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="确认收货") + def 确认收货(self, request: Request): + """""" + print( + "确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了确认收货请求进来了") + order物流公司订单编号 = request.data.get("order物流公司订单编号", None) + order物流订单号 = request.data.get("order物流订单号", None) + 订单更新对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号, + order物流订单号=order物流订单号) + 订单更新对象.order物流状态 = order订单.order订单choosies物流状态.待评价.value + 订单更新对象.save() + httpResData = BaseResponse(resData=ResData(listData=[], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_mini_服务端接口目录/用工关系接口列表/用工关系接口.py b/wechat_mini_服务端接口目录/用工关系接口列表/用工关系接口.py new file mode 100644 index 0000000..b6b37b9 --- /dev/null +++ b/wechat_mini_服务端接口目录/用工关系接口列表/用工关系接口.py @@ -0,0 +1,85 @@ +import json + +import requests +from django.forms import model_to_dict +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_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser用户角色 + + +class 用工关系接口ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="send") + def 推送用工消息(self, request: Request): + """""" + mini_token = sixToken.get_mini_token() + + template_content = { + "data": { # ⚠️ 这个外层 "data" 是微信接口强制要求的嵌套结构 + "thing1": {"value": "aaaaaaa"}, # 替换为模板实际字段名 + "amount1": {"value": "12"} # 金额建议纯数字(无¥符号) + } + } + + # 2. 转为JSON字符串(ensure_ascii=False保留中文,但微信要求最终是转义后的字符串) + data_string = json.dumps(template_content, ensure_ascii=False) + + msgData = requests.post(url="https://api.weixin.qq.com/cgi-bin/message/wxopen/employeerelationmsg/send", + params={"access_token": mini_token, }, + json={"template_id": "SFFgGF1bN56_KNd_4HicCFBBfu2PCRwCyQ5upr-EVk9Vdyl4wyyQ7B1mJvjceR29", # 推送消息模板 + "page": "pageTabBar/Home/Home", # 跳转路径 + "touser": "ohQkD7A-N93kljcFmkCyG6e_D9vg", # 被推送用户openid + "data": data_string + }) + print(msgData.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).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): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + openid_list = request.data.get("openid_list", None) + wecom_token = sixToken.get_wecom_token() + infoData = requests.post(url="https://api.weixin.qq.com/wxa/business/unbinduserb2cauthinfo", params={"access_token": wecom_token, }, json={"openid_list": ["oL7T268t3zlOb64IvrN64-XXXXXX"]}, ) + print(infoData.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).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): + pass + """绑定用工关系, 前端调用成功了, 就会发送请求到本接口,我们只需要更新一下weiuser数据信息就可以了""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + six六果对象, sixBool = weiuser.objects.get_or_create(unionid=self_mini_unionid) + print("开始绑定用工关系了") + if six六果对象.user_绑定用工关系 == miniUser用户角色().用工关系已绑定: + six_data_user = model_to_dict(instance=six六果对象, fields=None, exclude=None) + print("这里的状态为原来已经绑定用工关系了") + return Response(data=six_data_user) + else: + six六果对象.user_绑定用工关系 = miniUser用户角色().用工关系已绑定 + six六果对象.save() + print("绑定用工关系成功了") + six_data_user = model_to_dict(instance=six六果对象, fields=None, exclude=None) + return Response(data=six_data_user) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="更新用工关系") + def 添加商品数据(self, request: Request): + pass + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + six六果对象, sixBool = weiuser.objects.get_or_create(unionid=self_mini_unionid) + six六果对象.user_绑定用工关系 = miniUser用户角色().用工关系已绑定 + six六果对象.save() + six_currend_当前用户对象的字典数据 = model_to_dict(instance=six六果对象, fields=None, exclude=None) + print("更新用工关系更新用工关系更新用工关系更新用工关系更新用工关系更新用工关系", self_mini_unionid, self_mini_openid) + return Response(data=six_currend_当前用户对象的字典数据) diff --git a/wechat_mini_服务端接口目录/附近小程序/附近小程序接口.py b/wechat_mini_服务端接口目录/附近小程序/附近小程序接口.py new file mode 100644 index 0000000..fc631ec --- /dev/null +++ b/wechat_mini_服务端接口目录/附近小程序/附近小程序接口.py @@ -0,0 +1,39 @@ +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 ResData, BaseResponse + + +class 附近小程序ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="addNearbyPoi") + def 添加地点(self, request: Request): + """""" + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="deleteNearbyPoi") + def 删除地点(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="getNearbyPoiList") + def 查看地点(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="setShowStatus") + def 设置展示状态(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_token/token工具包.py b/wechat_token/token工具包.py new file mode 100644 index 0000000..b053c66 --- /dev/null +++ b/wechat_token/token工具包.py @@ -0,0 +1,242 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:39 +FilePath: django_公共认证接口/微信TOKEN.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" + +import os +from zoneinfo import ZoneInfo + +import django + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value="sixGuoDjango.settings") +django.setup() +from wechat_token.token数据库 import weitoken + +import jmespath +import pydash +import requests +from datetime import timedelta, datetime + + +class sixToken: + """注释""" + corp_id = "wwbe6369dc26a9d83a" # 企业微信(当前的值为 江苏六果科技有限公司 企业微信ID) + corpsecret = "SIRyum7vQh-Bt36AxnqKMX0HIiE-zkYbjYgSat7reZw" # 企业微信 secret(重点,这里的值为 创建的应用的 元宝零售的 值) 各个应用都会有不同的值,需要注意分别的; + 通讯录Secret = "WNxZZdcU3FRS5msq_kHZaV021qxsZh9kCNExxXCbM9I" + mini_appid = "wxf612e825377328f0" # 小程序appid(当前的值为 元宝零售 江苏六果科技有限公司) + mini_appsecret = "8691f774e3c0c5a876b21a3e84109ef0" # 小程序属性 + # wechat_appid = "wx92441a2398fa8cc0" # 服务号的appid + wechat_appid = "wx654fffabd4b1f5cf" # TODO 服务号的测试的 + # wechat_appsecret = "1c76fbfea91f36bede14e2cf2dc756dc" #TODO 服务号的appsecret + wechat_appsecret = "b1017a44b93fb08ae95b408fd19ff9d9" # 服务号测试的appsecret + + @classmethod + def get_wecom_token(cls): + """""" + 查询对象, 是否存在 = weitoken.objects.get_or_create(token_name="wecom_token") + if 查询对象.token_value is None: + print("为空,get_wecom_token 新调用一下") + 创建的新对象 = cls.token统一调用企微获取接口() + return 创建的新对象.token_value + if 查询对象.token_value is not None: + # 对时间进行比较 (这里有一个点: 从数据中取出的时间值为utc时间) + nowDateTime = datetime.now(tz=ZoneInfo("utc")) + if (nowDateTime - 查询对象.updateTime) > timedelta(seconds=6000): + print("tokentoken超过时间了需要重新创建") + 创建的新对象 = cls.token统一调用企微获取接口() + return 创建的新对象.token_value + else: + return 查询对象.token_value + return 查询对象.token_value + + @classmethod + def get_wecom_tick(cls): + pass + """""" + 查询对象, 是否存在 = weitoken.objects.get_or_create(token_name="wecom_token") + if 查询对象.tick_value is None: + print("为空,所以需要重 新调用一下") + 创建的新对象 = cls.token统一调用企微获取接口() + return 创建的新对象.phone_token_value + if 查询对象.tick_value is not None: + # 对时间进行比较 (这里有一个点: 从数据中取出的时间值为utc时间) + nowDateTime = datetime.now(tz=ZoneInfo("utc")) + if (nowDateTime - 查询对象.updateTime) > timedelta(seconds=6000): + print("token超过时间了需要重新创建") + 创建的新对象 = cls.token统一调用企微获取接口() + return 创建的新对象.tick_value + else: + print("在有效时间内") + return 查询对象.tick_value + return 查询对象.tick_value + + @classmethod + def mini_token(cls): + """""" + url = "https://api.weixin.qq.com/cgi-bin/stable_token" # 固定请求地址官网请求的地址 + data = {"grant_type": "client_credential", "appid": cls.mini_appid, "secret": cls.mini_appsecret, "force_refresh": True} + token_data = requests.post(url=url, json=data) + token: dict = token_data.json() + 小程序token: str = jmespath.search(data=token, expression="access_token", ) + 返回对象, _ = weitoken.objects.update_or_create(token_name="mini_token", defaults={"token_value": 小程序token}) + return 返回对象 + + @classmethod + def get_mini_token(cls): + """ + 实时的获取mini_token的值 + :return: + :rtype: + """ + 查询对象, 是否存在 = weitoken.objects.get_or_create(token_name="mini_token") + if 查询对象.token_value is None: + 创建的新对象 = cls.mini_token() + return 创建的新对象.token_value + if 查询对象.token_value is not None: + # 对时间进行比较 (这里有一个点: 从数据中取出的时间值为utc时间) + nowDateTime = datetime.now(tz=ZoneInfo("utc")) + if (nowDateTime - 查询对象.updateTime) > timedelta(seconds=6000): + print("token超过时间了需要重新创建") + 创建的新对象 = cls.mini_token() + return 创建的新对象.token_value + else: + return 查询对象.token_value + return None + + @classmethod + def token统一调服务号(cls): + """获取了六果服务号的token:注意不是授权时的token""" + params = {"appid": cls.wechat_appid, "secret": cls.wechat_appsecret, "grant_type": "client_credential", "force_refresh": False, } + token_data = requests.post(url="https://api.weixin.qq.com/cgi-bin/stable_token", json=params) + token: dict = token_data.json() + print(token) + wechat_token服务号 = token.get("access_token") + print("服务 号的token", wechat_token服务号) + # return wechat_token + jsapo_url = f"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={wechat_token服务号}&type=jsapi" + json_data = requests.get(url=jsapo_url).json() + ticket服务号 = pydash.get(obj=json_data, path="ticket", default=None) + 返回对象, _ = weitoken.objects.update_or_create(token_name="mini_token", defaults={"token_value": wechat_token服务号, "tick_value": ticket服务号}) + return 返回对象 + + @classmethod + def get_wechat_token(cls): + """""" + + 查询对象, 是否存在 = weitoken.objects.get_or_create(token_name="wechat_token") + if 查询对象.token_value is None: + print("为空,所以需要重 新调用一下") + 创建的新对象 = cls.token统一调服务号() + return 创建的新对象.token_value + if 查询对象.token_value is not None: + # 对时间进行比较 (这里有一个点: 从数据中取出的时间值为utc时间) + nowDateTime = datetime.now(tz=ZoneInfo("utc")) + if (nowDateTime - 查询对象.updateTime) > timedelta(seconds=6000): + print("token超过时间了需要重新创建") + 创建的新对象 = cls.token统一调服务号() + return 创建的新对象.token_value + else: + print("在有效时间内") + return 查询对象.token_value + return None + + @classmethod + def get_wechat_tick_token(cls): + 查询对象, 是否存在 = weitoken.objects.get_or_create(token_name="wechat_token") + if 查询对象.tick_value is None: + print("为空,所以需要重 新调用一下") + 创建的新对象 = cls.token统一调服务号() + return 创建的新对象.tick_value + if 查询对象.tick_value is not None: + # 对时间进行比较 (这里有一个点: 从数据中取出的时间值为utc时间) + nowDateTime = datetime.now(tz=ZoneInfo("utc")) + if (nowDateTime - 查询对象.updateTime) > timedelta(seconds=6000): + print("token超过时间了需要重新创建") + 创建的新对象 = cls.token统一调服务号() + return 创建的新对象.tick_value + else: + print("在有效时间内") + return 查询对象.tick_value + return None + + @classmethod + def token统一调用企微获取接口(cls): + """手机端的token""" + phone_token_uri = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken" + phone_token_data = requests.get(url=phone_token_uri, params={"corpid": "wwbe6369dc26a9d83a", "corpsecret": cls.通讯录Secret}) + phone_token = jmespath.search(data=phone_token_data.json(), expression="access_token") + # 拿到企微的正常token + wecom_token_uri = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" + # 发起请求 + token_data = requests.get(url=wecom_token_uri, params={"corpid": cls.corp_id, "corpsecret": cls.corpsecret, }, ).json() + 企微token = jmespath.search(data=token_data, expression="access_token", ) + print(企微token) + # 调用发起 拿到wecom-tick-value + wecom_tick_url = f"https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token={企微token}" + tick_data = requests.get(url=wecom_tick_url) + wecom_tick_data = jmespath.search(data=tick_data.json(), expression="ticket", ) + 返回对象, _ = weitoken.objects.update_or_create(token_name="wecom_token", defaults={ + "phone_token_value": phone_token, "token_value": 企微token, "tick_value": wecom_tick_data, + }) + return 返回对象 + + @classmethod + def get_weom_phone_token(cls): + 查询对象, 是否存在 = weitoken.objects.get_or_create(token_name="wecom_token") + if 查询对象.phone_token_value is None: + print("为空,所以需要重 新调用一下") + 创建的新对象 = cls.token统一调用企微获取接口() + return 创建的新对象.phone_token_value + if 查询对象.phone_token_value is not None: + # 对时间进行比较 (这里有一个点: 从数据中取出的时间值为utc时间) + nowDateTime = datetime.now(tz=ZoneInfo("utc")) + if (nowDateTime - 查询对象.updateTime) > timedelta(seconds=6000): + print("token超过时间了需要重新创建") + 创建的新对象 = cls.token统一调用企微获取接口() + return 创建的新对象.phone_token_value + else: + print("在有效时间内") + return 查询对象.phone_token_value + return None + + @classmethod + def 服务号网页授权TOKEN(cls, code: str): + """用户授权时,需要的token; + https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html + """ + params = { + "appid": "wx92441a2398fa8cc0", # 公众号的唯一标识 + "secret": "1c76fbfea91f36bede14e2cf2dc756dc", # 公众号的appsecret + "grant_type": "authorization_code", # "code": code + "code": code, # 填写第一步获取的code参数 + } + # 返回值 = """ + # { + # "access_token":"ACCESS_TOKEN", + # "expires_in":7200, + # "refresh_token":"REFRESH_TOKEN", + # "openid":"OPENID", + # "scope":"SCOPE", + # "is_snapshotuser": 1, + # "unionid": "UNIONID" + # } + # """ + oauth_token_url = f"https://api.weixin.qq.com/sns/oauth2/access_token" + oauth_token_data = requests.get(url=oauth_token_url, params=params) + # oauth_token: dict = oauth_token_data.json() + # oauth_token_str = oauth_token.get("access_token") + # refresh_token = oauth_token.get("refresh_token") + # unionid = oauth_token.get("unionid") + + +if __name__ == "__main__": + pass + # mini_token = sixToken.get_mini_token() + # wecom_token = sixToken.get_wecom_token() + sixToken.token统一调用企微获取接口() + # wecom_phone_token = sixToken.get_weom_phone_token() + # print(wecom_phone_token) diff --git a/wechat_token/token数据库.py b/wechat_token/token数据库.py new file mode 100644 index 0000000..713171f --- /dev/null +++ b/wechat_token/token数据库.py @@ -0,0 +1,21 @@ +"""微信token二小时有的效期""" + +from django.db import models + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name + + +class weitoken(models.Model): + """存储微信的token的值""" + objects = models.Manager() # + token_name = models.CharField(primary_key=True, max_length=120) + token_value = models.TextField(null=True, blank=True) + tick_value = models.TextField(null=True, blank=True, ) + phone_token_value = models.TextField(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 = "weitoken" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["dateAndTime", "updateTime"] diff --git a/wechat_wecom_企业微信管理/企微通讯录管理/企微通讯录管理数据库/企微员工数据.py b/wechat_wecom_企业微信管理/企微通讯录管理/企微通讯录管理数据库/企微员工数据.py new file mode 100644 index 0000000..35546f1 --- /dev/null +++ b/wechat_wecom_企业微信管理/企微通讯录管理/企微通讯录管理数据库/企微员工数据.py @@ -0,0 +1,22 @@ +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 new file mode 100644 index 0000000..c8fb0fd --- /dev/null +++ b/wechat_wecom_企业微信管理/企微通讯录管理/通讯录管理接口.py @@ -0,0 +1,41 @@ +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 new file mode 100644 index 0000000..2daa527 --- /dev/null +++ b/wechat_wecom_企业微信管理/客户管理/客户管理接口.py @@ -0,0 +1,50 @@ +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_项目工具包.企业微信工具包.客户管理 import wecom客户好友管理 + + +class 客户管理接口ViewSets(ViewSet): + + @action(detail=False, methods=["post"], url_path="获取当前企微员工所有添加的客户列表") + def 获取当前企微员工所有添加的客户列表(self, request: Request): + """""" + userid = request.data.get("userid", None) + print("获取当前企微员工所有添加的客户列表获取当前企微员工所有添加的客户列表获取当前企微员工所有添加的客户列表获取当前企微员工所有添加的客户列表获取当前企微员工所有添加的客户列表") + get_data = wecom客户好友管理().获取客户列表(userid="YuanBao1975") + print(get_data) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=get_data), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="获取客户详情") + def 获取客户详情(self, request: Request): + """通过 external_userid 获取用户的详情,最主要的就是拿到用户的 unionid """ + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + external_userid = request.data.get("external_userid", "wmj4zANAAAGlCZ2zNRhu1qzEMSBF0a9g") + wecom_token = sixToken.get_wecom_token() + uri = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get" + data = requests.get(url=uri, params={"access_token": wecom_token, "external_userid": external_userid}) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", data.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=data.json()), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @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) + + wecom客户好友管理().批量获取客户详情并存储到数据库(state企微员工创建时添加的唯一值=state企微员工创建时添加的唯一值, userid企微员工账号ID=userid企微员工账号ID) + + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_wecom_企业微信管理/客服账号管理/客服账号管理接口.py b/wechat_wecom_企业微信管理/客服账号管理/客服账号管理接口.py new file mode 100644 index 0000000..8a1d84d --- /dev/null +++ b/wechat_wecom_企业微信管理/客服账号管理/客服账号管理接口.py @@ -0,0 +1,48 @@ +import threading + +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 + + + + + +class 客服账号管理接口ViewSets( ViewSet ): + lock = threading.Lock( ) + + + + @action( detail=False, methods=[ "post" ], url_path="添加客服账号" ) + def 添加客服账号( self, request: Request ): + """""" + wecom_token = sixToken.get_wecom_token( ) + phone_token = sixToken.get_weom_phone_token( ) + uri = f"https://qyapi.weixin.qq.com/cgi-bin/kf/account/add?access_token={wecom_token}" + json_data = { + "name": "新建的客服账号", + "media_id": "294DpAog3YA5b9rTK4PjjfRfYLO0L5qpDHAJIzhhQ2jAEWjb9i661Q4lk8oFnPtmj" + } + print( "==============" ) + postData = requests.post( url=uri, json=json_data ) + print( postData.json( ) ) + httpResData = BaseResponse( resData=ResData( listData=[ ], dictData=postData.json( ) ), ).model_dump( ) + return Response( data=httpResData, status=status.HTTP_200_OK ) + + + + @action( detail=False, methods=[ "post" ], url_path="获取客服账号列表" ) + def 获取客服账号列表( self, request: Request ): + """""" + wecom_token = sixToken.get_wecom_token( ) + uri = f"https://qyapi.weixin.qq.com/cgi-bin/kf/account/list?access_token={wecom_token}" + postData = requests.post( url=uri, ) + print( postData.json( ) ) + httpResData = BaseResponse( resData=ResData( listData=[ ], dictData=postData.json( ) ), ).model_dump( ) + return Response( data=httpResData, status=status.HTTP_200_OK ) diff --git a/wechat_wecom_企业微信管理/素材管理/素材管理接口.py b/wechat_wecom_企业微信管理/素材管理/素材管理接口.py new file mode 100644 index 0000000..d6e8a7b --- /dev/null +++ b/wechat_wecom_企业微信管理/素材管理/素材管理接口.py @@ -0,0 +1,59 @@ +from pathlib import Path + +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, settings +from wechat_token.token工具包 import sixToken + + +class 素材管理接口列表ViewSets(ViewSet): + media_id: str | None = "35EgYWaFHZN6Uk5pAbF4ZiGIk7NV-A7osJgK4CET3zCrbt42GM_nU4N3DNoK3vs9SxuZOZNRk7jZGqSZKJjFxjg" + + @action(detail=False, methods=["post"], url_path="上传临时素材") + def 上传临时素材(self, request: Request): + """""" + wecom_token = sixToken.get_wecom_token() + TYPE = request.data.get("TYPE", "image") + uri = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={wecom_token}&type={TYPE}" + imgPath = Path(settings.BASE_DIR).joinpath("django_static_directory/media/app.png").read_bytes() + uploadFile = requests.post(url=uri, files={"media": imgPath}) + print(uploadFile.json()) + 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="上传图片") + def 上传图片(self, request: Request): + """返回的图片URL,仅能用于图文消息正文中的图片展示,或者给客户发送欢迎语等;若用于非企业微信环境下的页面,图片将被屏蔽。""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + 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="获取临时素材") + def 获取临时素材(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + 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="jssdk") + def 获取高清语音素材(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + 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="upload_by_url") + def 异步上传临时素材(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_wecom_企业微信管理/联系我与客户群管理/加入群聊管理接口.py b/wechat_wecom_企业微信管理/联系我与客户群管理/加入群聊管理接口.py new file mode 100644 index 0000000..a5d955d --- /dev/null +++ b/wechat_wecom_企业微信管理/联系我与客户群管理/加入群聊管理接口.py @@ -0,0 +1,96 @@ +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.routers import DefaultRouter +from rest_framework.viewsets import ViewSet + +from sixGuoDjango import ResData, BaseResponse +from wechat_token.token工具包 import sixToken + + +class 加入群聊管理ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="add_join_way") + def 配置客户群进群方式(self, request: Request): + """""" + print("配置请求进来了吗") + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/add_join_way?access_token={wecom_token}" + 请求数据 = { + "scene": 2, + "remark": "测试一下", # 联系方式的备注信息,用于助记,超过30个字符将被截断 + "auto_create_room": 1, # 当群满了后,是否自动新建群。0-否;1-是。 默认为1 + "room_base_name": "销售客服群", # 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符 + "room_base_id": 10, # 自动建群的群起始序号,当auto_create_room为1时有效 + "chat_id_list": [ + "wrj4zANAAAHe5FbvwFBoDZ-dpQVpFf_w", + ], + "state": "xiaozizi", # 企业自定义的state参数,用于区分不同的入群渠道。 + # "mark_source": True, # 是否标记客户添加来源为该应用创建的「加入群聊」, 默认值为true; 仅对「营销获客」应用生效 + } + data = requests.post(url=uri, json=请求数据) + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="get_join_way") + def 获取客户群进群方式配置(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/get_join_way?access_token={wecom_token}" + 请求数据 = { + "config_id": "a4fa615e41b10db5c2b7d52cbcc6131a" + } + data = requests.post(url=uri, json=请求数据) + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="update_join_way") + def 更新客户群进群方式配置(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + config_id = request.data.get("config_id", None) ## 企业联系方式的配置id + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/update_join_way" + json_data = { + "config_id": "9ad7fa5cdaa6511298498f979c4722de", # 企业联系方式的配置id + "scene": 2, # 场景。 1 - 群的小程序插件 2 - 群的二维码插件 + "remark": "bb_remark", # 联系方式的备注信息,用于助记,超过30个字符将被截断 + "auto_create_room": 1, # 当群满了后,是否自动新建群。0-否;1-是。 默认为1 + "room_base_name": "销售客服群", # 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符 + "room_base_id": 10, # 自动建群的群起始序号,当auto_create_room为1时有效 + "chat_id_list": ["wrOgQhDgAAH2Yy-CTZ6POca8mlBEdaaa", "wrOgQhDgAALPUthpRAKvl7mgiQRw_aaa"], + # 用该配置的客户群ID列表,最多支持5个。见客户群ID获取方法 + "state": "klsdup3kj3s1", # 企业自定义的state参数,用于区分不同的入群渠道。 + # "mark_source": True, # 是否标记客户添加来源为该应用创建的「加入群聊」, 默认值为true; 仅对「营销获客」应用生效, 且只能由创建此二维码的应用更新 + } + data = requests.post(url=uri, params={"access_token": wecom_token, }, json=json_data) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", data.json(), "\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=["get", "post", "put", "delete"], url_path="del_join_way") + def 删除客户群进群方式配置(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + config_id = request.data.get("config_id", None) + + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/del_join_way?access_token={wecom_token}" + 请求数据 = { + "config_id": "a4fa615e41b10db5c2b7d52cbcc6131a" + } + data = requests.post(url=uri, json=请求数据) + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json(), "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n") + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +加入群聊管理ViewSetsRouter = DefaultRouter() +加入群聊管理ViewSetsRouter.register(prefix="chat", viewset=加入群聊管理ViewSets, basename="") diff --git a/wechat_wecom_企业微信管理/联系我与客户群管理/联系我管理接口.py b/wechat_wecom_企业微信管理/联系我与客户群管理/联系我管理接口.py new file mode 100644 index 0000000..228dafd --- /dev/null +++ b/wechat_wecom_企业微信管理/联系我与客户群管理/联系我管理接口.py @@ -0,0 +1,218 @@ +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 ResData, BaseResponse +from wechat_token.token工具包 import sixToken +from wechat_数据库.企业微信数据库.推广二维码数据表 import wecom推广码 +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser + + +class 联系我管理ViewSets(ViewSet): + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="add_contact_way") + def 配置客户联系方式(self, request: Request): + """对指定的企微员工,创建一个独立的二维码,带有分享信息""" + # https://developer.work.weixin.qq.com/document/path/92228 + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_contact_way?access_token={wecom_token}" + state = request.data.get("state", "oy4Jw6Lyfyj1VvgZFodzq9oqJzHE") + userID = request.data.get("userID", "HuDie_1") + remark = request.data.get("remark", None) # 备注 + 请求数据 = { + "type": 1, # 联系方式类型,1-单人, 2-多人 + "scene": 2, # 场景,1-在小程序中联系,2-通过二维码联系 + # "style": 1, # 否 在小程序中联系时使用的控件样式,详见附表 + "remark": remark, # 否 联系方式的备注信息,用于助记,不超过30个字符 + "skip_verify": True, # 否 外部客户添加时是否无需验证,默认为true + "state": state, # 是 区分业务用的; + "user": userID, # "party": [ # 否 使用该联系方式的部门id列表,只在type为2时有效 + "is_exclusive": True, # 否 是否开启同一外部企业客户只能添加同一个员工,默认为否,开启后,同一个企业的客户会优先添加到同一个跟进人 + } + data = requests.post(url=uri, json=请求数据).json() + print(data) + config_id = pydash.get(obj=data, path="config_id") + qr_code = pydash.get(obj=data, path="qr_code") + wecom推广码.objects.update_or_create( + codeConfigId=config_id, codeQrCode=qr_code, codeState=state, codeRemark=remark, codeUser=userID, + wai外键weiuser表_id=state, + ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + # @action(detail=False, methods=["get", "post", "put", "delete"], url_path="get_contact_way") + def 获取企业已配置的方式(self, config_id): + """根据 传递的 config_id 来拿到详细的数据""" + # https://developer.work.weixin.qq.com/document/path/92228 + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_contact_way?access_token={wecom_token}" + data = requests.post(url=uri, json={"config_id": config_id}) + config_id = pydash.get(obj=data.json(), path="contact_way.config_id") + type = pydash.get(obj=data.json(), path="contact_way.type") + qr_code = pydash.get(obj=data.json(), path="contact_way.qr_code") + user = pydash.get(obj=data.json(), path="contact_way.user") + state = pydash.get(obj=data.json(), path="contact_way.state") + # 更新或者添加数据 + + remark = pydash.get(obj=data.json(), path="contact_way.remark") + print("=====================", state) + six六果默认对象, _ = weiuser.objects.get_or_create(unionid="六果") + weiuser表对象, _ = weiuser.objects.get_or_create(unionid=state) + if weiuser表对象.parent is None: + # 判断当前用户是否有父级, 如果没有 则默认创建一个 为 六果的 父级 + print("判断为None了", six六果默认对象, weiuser表对象) + wecom推广码.objects.update_or_create( + codeConfigId=config_id, codeQrCode=qr_code, codeState=state, codeRemark=remark, codeUser=user, + code省="江苏省", code市="泰州市", code区="海陵区", + ) + weiuser表对象.codeQrCode = qr_code + weiuser表对象.codeRemark = remark + weiuser表对象.codeConfigId = config_id + weiuser表对象.parent = six六果默认对象 + weiuser表对象.save() + else: + print("判断不为None了", six六果默认对象, weiuser表对象) + # 如果有 父级, 则直接处理数据 + wecom推广码.objects.update_or_create( + codeConfigId=config_id, codeQrCode=qr_code, codeState=state, codeRemark=remark, codeUser=user, + wai外键weiuser表_id=state, code省="江苏省", code市="泰州市", code区="海陵区", + ) + weiuser表对象.codeQrCode = qr_code + weiuser表对象.codeRemark = remark + weiuser表对象.codeConfigId = config_id + weiuser表对象.save() + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", data.json(), "\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=["get", "post", "put", "delete"], url_path="list_contact_way") + def 获取企业已配置的列表(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list_contact_way?access_token={wecom_token}" + data = requests.post(url=uri) + list_data = pydash.get(obj=data.json(), path="contact_way") + for config_data in list_data: + config_id = pydash.get(obj=config_data, path="config_id") + self.获取企业已配置的方式(config_id=config_id) + + print("\n🍎 🍏 🍊 🍎 🍏 🍊获取企业已配置的列表 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", data.json(), + "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n") + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=data.json()), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="save_list_contact_way") + def 获取全部配置列表并保存数据库(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + data = requests.post(url="https://xiao.sixgou.com/wecom_chat/contact/list_contact_way/") + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", data) + list_data_code = wecom推广码.objects.filter().values("codeConfigId") + print(list_data_code) + for config_id in list_data_code: + codeConfigId = pydash.get(obj=config_id, path="codeConfigId") + print(codeConfigId, "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n") + data = requests.post(url="https://xiao.sixgou.com/wecom_chat/contact/get_contact_way/", + data={"config_id": codeConfigId}) + + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="update_contact_way") + def 更新企业已配置联系我的方式(self, request: Request): + """""" + data = requests.post(url="https://xiao.sixgou.com/wecom_chat/contact/list_contact_way/") + apiData = BaseResponse(**data.json()) + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", apiData) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="del_contact_way") + def 删除企业已配置的联系我的方式(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + wecom_token = sixToken.get_wecom_token() + config_id = request.data.get("config_id", None) + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/del_contact_way?access_token={wecom_token}" + config_id = request.data.get("config_id", None) + json_data = { + "config_id": config_id, + } + data = requests.post(url=uri, json=json_data) + wecom推广码.objects.filter(codeConfigId=config_id).delete() + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎删除企业已配置的联系我的方式 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", data.json(), + "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n") + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=data.json()), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="del_list_contact_way") + def 删除全部数据信息(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + data = requests.post(url="https://xiao.sixgou.com/wecom_chat/contact/list_contact_way/") + apiData = BaseResponse(**data.json()) + contact_way = pydash.get(obj=apiData.resData.dictData, path="contact_way") + for way in contact_way: + config_id = pydash.get(obj=way, path="config_id") + requests.post(url="https://xiao.sixgou.com/wecom_chat/contact/del_contact_way/", + data={"config_id": config_id}) + wecom推广码.objects.all().delete() + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="zizi") + def 删除所有的配置方式(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="close_temp_chat") + def 结束临时会话(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="configureTheSpecifiedContactPerson") + def 配置指定的联系单人(self, request: Request): + """对指定的企微员工,创建一个独立的二维码,带有分享信息""" + # https://developer.work.weixin.qq.com/document/path/92228 + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_contact_way?access_token={wecom_token}" + state = request.data.get("state", "oy4Jw6Lyfyj1VvgZFodzq9oqJzHE") + userID = request.data.get("userID", None) + remark = request.data.get("remark", None) # 备注 + print(userID, type(userID)) + 请求数据 = { + "type": 1, # 联系方式类型,1-单人, 2-多人 + "scene": 2, # 场景,1-在小程序中联系,2-通过二维码联系 + # "style": 1, # 否 在小程序中联系时使用的控件样式,详见附表 + "remark": remark, # 否 联系方式的备注信息,用于助记,不超过30个字符; + "skip_verify": True, # 否 外部客户添加时是否无需验证,默认为true; + "state": state, # 是 区分业务用的; + "user": [userID], # "party": [ # 否 使用该联系方式的部门id列表,只在type为2时有效 + "is_exclusive": True, # 否 是否开启同一外部企业客户只能添加同一个员工,默认为否,开启后,同一个企业的客户会优先添加到同一个跟进人 + } + print(请求数据) + data = requests.post(url=uri, json=请求数据).json() + print(data) + config_id = pydash.get(obj=data, path="config_id") + qr_code = pydash.get(obj=data, path="qr_code") + wecom推广码.objects.update_or_create( + codeConfigId=config_id, codeQrCode=qr_code, codeState=state, codeRemark=remark, codeUser=userID, + wai外键weiuser表_id=state, code省="江苏省", code市="泰州市", code区="海陵区", + ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_cert.pem b/wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_cert.pem new file mode 100644 index 0000000..d3a338d --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEITCCAwmgAwIBAgIUUwFg1U6PVnJvUG3uQNf6SaVY6OAwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjQxMjAyMTEyODUxWhcNMjkxMjAxMTEyODUxWjB7MRMwEQYDVQQDDAox +NzAwMzgzNDE5MRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xJzAlBgNVBAsM +Huaxn+iLj+WFreaenOenkeaKgOaciemZkOWFrOWPuDELMAkGA1UEBhMCQ04xETAP +BgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +sVeGgbcwEo6HKNboXSf6/KOtFVOZMGEezDeVTwa34Y7bWPzqPjEe191efPhy9BEm +oYId1l9SsT+QGUUnxAblWJgiPhS0Ux7pPSqLmzxHFbv0JZaqXvOVVfWcNnqHBFHn +5fwQcep3hlibldes9txTr2uhMNo2u5MdKfQ5XfZ2EU8rVk3GFgaNgxijWPPEbmeZ +Kwbh2rH1Gyjt9024b60JJBOGR3hISBCKUWQIPMhaODvWtmy2IzXzONt0b1l0i2D4 +Y9ebahAwpHmq3rbRgwnjXOrUpFydm/H2USfejw4im2dyNmN6vZQPy6zR3fV142SS +wfrgQ6JFC23XK9t7eWgihwIDAQABo4G5MIG2MAkGA1UdEwQCMAAwCwYDVR0PBAQD +AgP4MIGbBgNVHR8EgZMwgZAwgY2ggYqggYeGgYRodHRwOi8vZXZjYS5pdHJ1cy5j +b20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3 +NTQ5ODQ2QzAxQzNFOEVCRDImc2c9SEFDQzQ3MUI2NTQyMkUxMkIyN0E5RDMzQTg3 +QUQxQ0RGNTkyNkUxNDAzNzEwDQYJKoZIhvcNAQELBQADggEBACtST6/7F/1xqzZz +rk+lG6DMIQe97lrBOHeIofHUM7mDUrKoW/SqhSifjUnMTgphAzjJpj/ORNuaYc0M +pg36HF3vuJ7eGJ81l3Blmvjt+IEQDuHw4Jm9KLbpTJG+IPtypZvGvaXDsymSotNS +yRSsnyJSKHcsgLVYrkcERC0c4yZhbdLESTT3+BAtFP6aohwEJ2wWUrz5xVzEs5Mz +htf/9QD3rOrFckR57ikwNF6VCp0WV9fiv1nybACfbGi9tIOCUXe6Pg34QnzmpT8K +Nh6q2BUSoSYPcn22hQzvWFEvs3zTWv8+7v/Y+YJsphwcSJx54AzPHbKRSy5z+u2i +Vvv7Tgs= +-----END CERTIFICATE----- diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_key.pem b/wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_key.pem new file mode 100644 index 0000000..897961d --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxV4aBtzASjoco +1uhdJ/r8o60VU5kwYR7MN5VPBrfhjttY/Oo+MR7X3V58+HL0ESahgh3WX1KxP5AZ +RSfEBuVYmCI+FLRTHuk9KoubPEcVu/Qllqpe85VV9Zw2eocEUefl/BBx6neGWJuV +16z23FOva6Ew2ja7kx0p9Dld9nYRTytWTcYWBo2DGKNY88RuZ5krBuHasfUbKO33 +TbhvrQkkE4ZHeEhIEIpRZAg8yFo4O9a2bLYjNfM423RvWXSLYPhj15tqEDCkeare +ttGDCeNc6tSkXJ2b8fZRJ96PDiKbZ3I2Y3q9lA/LrNHd9XXjZJLB+uBDokULbdcr +23t5aCKHAgMBAAECggEAeMX6vGxdOMYIFjAFnyuTKmrtfRCpyuDZcIqKDH+uytXX +XAsiG6ioMKp5pvIslzr27BcI6u2QC1YWdJ88LavklSlGaLEA/XqXrShEWzv5zTtr +Ug4BiRiqIxhZgmB/gtmk7GN1b58WN1Aw5SM0kAoMk/Lgm7yAec3+lovUZcFrNu1p +hfPAkesl0W9DU/dI2GwmnOUlBaJGhnV3DRkg19yohsQXwR1DPVR94jWuwXJM/0UJ +d8LUW8wKr/pqEUuEUIxOUwkX7qu0I/yp2TZkbHOE0/re3DoAWQ8s/OJCWtlA1c+r +Yzbeo+iZN0ulzvx8fedtJtmJqsFiz5DHbHuTBqVOAQKBgQDWC9Mf6It6UGJmfCBf +VprGh98C7sLm65FR+AyOcUzeyPcmRjiQddxkiXtJ0n9//yu2NtXr0ObZ3HzDqFx9 +bU7zvD5Y0GELdiWKMV9rJIH0pkaLIw+in+C6ahav+R1N0NDAdKJRSt8+NN4duaRx +V254P38HmXNvWOSFJIasV0ni4QKBgQDUGf4q/HPrES+Isbk2SmJTevAP3c4KDUrP +VEfrz9x4KNa6XwMIA/3v9rFaeswwKLc9p5PIuS8UPo90vJX20Z7CE81S+60zrs5K +H+sTY/Im7VcLSdG0EpmqU+n0GOE1bvNgwDozEXo9AnmOIgJNfgkJfumDBCYJ3V+p +UfigUQMaZwKBgFIoOcI+nQK2xf42WKqfcEsRrdzPTkoaUy4WOqOWA35jvtGXFHEG +fDCuwH7GaB/2Do4jIBsilOk8gzsKbW3LPgm50GiAmy8uCxyu9MQIQEVqaRtQutid +60FCJTEoOkI7C1VDr2XqiiOzYSohrme+um03WgfNs4win5wnN/YAjyChAoGBAKTi +4BiC0Yq4fX+Cyj1Obkn/lIiBIh/mXXX4S0EjAn3XIbcZDb45fDwER7PTKtF1lZ40 +nEq6y8KtL9DMmriaFRVDV6dfSDKZfn1ZeuJEHIfuknCQHpoiq5siSQoeHVXwvvtD +9PqmZ6TuO5knDys3A8eCBf54Ryn8EtYKh4H5+LOZAoGAcv4t+f6xXB9qNKBorOQY +pLu2y8epaLd/9rzmfleffGBeLsHaCvljMSgwCuioHy2RjQnEQn3EVYK/DIZFa/QC +hCD1a6h4FtPfo5DhaoB63V/JuwqteuNOUAAjbJDYNoxnpJqaJIHB6nIOwpQLDhPN +2EbiGbkjTyLBmqYc+z3a3ZI= +-----END PRIVATE KEY----- diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/private_key.pem b/wechat_微信支付证书/江苏六果科技有限公司支付证书/private_key.pem new file mode 100644 index 0000000..5206b7f --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/private_key.pem @@ -0,0 +1,28 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArmYVW4KTJ+TsksYNA7aI3rBSHBQGjC0Tzak55DrzkTP/8r1b +Y8M9RXxi+ji1ebsWRbBG23fh5yKzv2LPpsHOMwDDa1i6LkfH7CCZ0OfL9My+/wFW +zR3jU1mwcJiHyKuFk0cx7quqscZ/c5dKPBcUL+7HZEwagEM5RKIt4wSosqtI9J0+ +v0H6wspiXyScUYysr3+mvWg8CRw7fR3xW+RC3e8b0T7DW3yaT+r8KasRRVWtW8BN +Ox+58qrJcaYa0YydzAJXzme4KrszUbkaQIiChp+L1Kie41vAuJiDGuLlIzqJXPIR +qCTB4xnsoLvKqFtEmRbFvsYLxA9XmdsL5FqY5wIDAQABAoIBAQCtThiPNXTSwjUt +rc4lEHF3CjSuXmAbUHhLeY1j9gkxFEGWkQGOY+gxcuhQy6XbcEUzv3bKhZlhvSRu +Xd0IU7N7D5kixatOblqHleYEqTQO8qAifMwrTTYoEAq7+XeFvJ0ivC8shD8+Jolk +7sUAbdbLwzc1vkLfju4L/DYpUOnrkZMBQzBBOdDunTJ975+asKXejKDrgtdW+NV0 +RA+B3AAiEdR/ZG56QqxBw9b8gkzrZx3SPlMczb6OFulTrwobh0BzUm4850J8USAo +wbOpC4fwMj674nuG/RV2YLIIWZwxr7kgVeqbPuZwF404Mxm5ELwtk6gaY7U/+nNL +iWiMhz/BAoGBANgujgPfiwcIGoS8pkNSnak2a5+a9WtizV3HEpCLj8F0UACF64oP +PMDkUm4lmNgVjkpjVNI0BbbJRulA359dEaWiC0ynnVOM1A23GeQOwNMqWqR61S55 +RZKkOnfkXtRDL+8/qVwqh77veLlpU2E86sfwwpCFMsFOuj2Azy5xp4DxAoGBAM6F +XWyW7E0DP/NKCpIH9zoRUVng0/VhUjSiKALl/7OZ7oPnpKXVYlQfrN3LflLjPMO8 +CJ9YIvAZBjK+ZO1scLvKs5eQVe61fU+gCgbZNKLeiVoLYphGdICxNxZpZ+1DtlBP +BVKgHMHcY/3gOnfqfYJFAUzDOe+2T3fNIZQjWjdXAoGASFeT6JHm6Ux5609h6Ad+ +gQCYFUn6tJvUk3wppzs8uQUePH6UKpgcwYPmXbuxISZdfmEtIkaMXvWOCEJQUvkH +DcFjPJyeljX7RDewr1OMjV2QBZihPDMS6BaTBknive9Z3BsWpqQI1wk2Af3QDCsh +ehUEVu5r5KpewnQXYLhh0FECgYAl7l7TZADwwCkNwUqhua7Rzn53mJC1n/NeUW4x +4haN4TbqqTAXeVK/CrZQYmDITo5JkQ6wXZrFKIN37HpTFTi7dSZ5LvxphJIIfud4 +jIpbY64siKzKNR6OyH3Ksv9wl6Azrd/XZisB/D2tUnLKtZnpxEzR0YWhnoWIBngl +YjzerwKBgGYYEECkq0a7Xo6Ia3x8kqyG5e86fHTO2o10pOGiielVVBo4eB87whb5 +TgsrxtB1OyS5bApQ6HdNsw1HAJ4SHo3jvtQZXGPVWpFk3xgPNhbXq6PYurqMvB2x +xIQlM6W1chiS/AZTWmhgRryQVCfUn1MjUC0j7dAfKrv2FPRG+kfy +-----END RSA PRIVATE KEY----- + diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/public_key.pem b/wechat_微信支付证书/江苏六果科技有限公司支付证书/public_key.pem new file mode 100644 index 0000000..5e8e213 --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/public_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArmYVW4KTJ+TsksYNA7aI +3rBSHBQGjC0Tzak55DrzkTP/8r1bY8M9RXxi+ji1ebsWRbBG23fh5yKzv2LPpsHO +MwDDa1i6LkfH7CCZ0OfL9My+/wFWzR3jU1mwcJiHyKuFk0cx7quqscZ/c5dKPBcU +L+7HZEwagEM5RKIt4wSosqtI9J0+v0H6wspiXyScUYysr3+mvWg8CRw7fR3xW+RC +3e8b0T7DW3yaT+r8KasRRVWtW8BNOx+58qrJcaYa0YydzAJXzme4KrszUbkaQIiC +hp+L1Kie41vAuJiDGuLlIzqJXPIRqCTB4xnsoLvKqFtEmRbFvsYLxA9XmdsL5FqY +5wIDAQAB +-----END PUBLIC KEY----- diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem b/wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem new file mode 100644 index 0000000..dbbddd9 --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIUEddigo6UcQQCjy0EXeePqAbQ1PIwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjQxMjAyMTEyODUxWhcNMjkxMjAxMTEyODUxWjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQgu4d2xZGins+LxHX +IgMnIv/6Ijz7uMFBX4VPciZnC9tLxXesgc0KbpfsSWaYCx0f2R4J1nWMJQ3qDg1c +DtDEICwX6ZSgA+B9bcjopA0EAgvOveJKYf0b0KM2GQ6nIkw8REmbr1sFAKl6+KdU +GvXDqklS3VTVFSTATod5Qe3KGlgQV3R8vZnZSKMJl0E8cEy+3Fc5YEr/Hs5X0Xa8 +oW/DxQzV0LnCIU9x3Z0b4FbXM+aJuvSMx3JK6wdyeZxH8mJ4OYa8zIXGlTTxrzEX +nGR56PengIp2lQAD8hVJBVXq7qK90oef0SfQTuva+tu6bfy8ntPe8ZF6yW3WCtDD ++F9LAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAhsc8sIri4HQBdiGvcKW19vrcWoxQUPqe +j7m+teru+LvtjjFr6NYL2XzfdDLvl7jrbz+kegReXBthvnd7AA11JBEY/VdwjWVQ +J2elOrqsBO5g2f8oowUyZQtdGwsHmZtWp2N/a0YIR7ptqdZDtet9MPnQC1ClZu6q +eXqP5vrQVtqJuTEvbYhqBzxuiB+2TUgqfCCALU7kFJBhJa0neEyzzwJcLrfdKVwg +Uqmibm9rhn0K94PD+bDvnQnkNNQ7knu6zO0umpvr13w+qY1YlStQqh5HqCn4Tk1h +mekE+G5TjueiXZ/sjLsluHQ0qW/lFcqgcJOH2XFSaZAauwqdCShAdA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/开放平台证书.pem b/wechat_微信支付证书/江苏六果科技有限公司支付证书/开放平台证书.pem new file mode 100644 index 0000000..c66bbcf --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/开放平台证书.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9DCCAtygAwIBAgIUaB2siA/X11h8JSI6eZy5JFqS9EIwDQYJKoZIhvcNAQEL +BQAwbTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzERMA8GA1UEBwwI +U2hlblpoZW4xEDAOBgNVBAoMB1RlbmNlbnQxEDAOBgNVBAsMB1RlbmNlbnQxEzAR +BgNVBAMMCnRzbTAwMDAwMDYwHhcNMjUwMzIxMDk0MzM5WhcNMzUwMzE5MDk0MzM5 +WjCBmDEeMBwGCSqGSIb3DQEJARYPd2VpeGlubXBAcXEuY29tMRswGQYDVQQDDBJ3 +eGY2MTJlODI1Mzc3MzI4ZjAxFTATBgNVBAoMDFRlbmNlbnQgSW5jLjEOMAwGA1UE +CwwFV3hnTXAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxETAPBgNV +BAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsKzj +VjuulJIlMNUtNsbtczsR0tXD34987zaPDnv0aM7woQv9b9aOgZ8NSo+gOcxp9xXo +hek/r2F+IZi4Wo2ojDugtDF4V/8BJbv+wgPkKWeK0q5zGSmoiGV+pyA6Th9c9Xwk +X0TaOZl2sAXYYi0jdvzXt2MTrtkTv4HjsUG22svFc3D4SXXQ1MdWB4mWlevpSgqb +T7GXrLg6GJ0sk5HZuaUMjL2n81SguvRq76GRsFVylgMjbaGj1xf4kiuo5MyJStp5 +xyPSxN2R23gg6NnLOJQOa3jZgqWPTnVF6l7J1xqdEtkK1F386y3hjP9IcB95VwLp +sJRW7ZZmuabvDmy4tQIDAQABo2AwXjAdBgNVHQ4EFgQU+RzLjExXyXwuTRyzT9Vm +RFdVCz4wHwYDVR0jBBgwFoAURM1183H4z2eJGmP5z/zWI7tjRZAwDAYDVR0TAQH/ +BAIwADAOBgNVHQ8BAf8EBAMCBsAwDQYJKoZIhvcNAQELBQADggEBAE0w60N+N9ZF +nasTtkN4Ee8GQtDUNAqF0icuGKSp+HvgZB1svIxG1DCtkSe8coaq+wFojKrepW+c ++eZXmmR55YlQSrqQa9YuPfAWNgJ5BvzBsRdUz2IyClAqQPtyAq22a9SwR3z3OGUu +sQnoqFgi6jShgqOhdOmy92N/DoWEmIIlZJrchVUs2JLHuq9gaKZWMqrSUsTNrAi1 +lWbpmf9nDa92AhGtphMXU0tgYChFCYka3e0RPq5UQnMFPKH58tbIkqQqCeYKyVIT +hHNyPaB/7M6jhrF0rwn2R5Crj3oW/+FuYITHH+Tg4G+XvXgkhyx7ZS/ZA9PI3qz7 +Tf68XuBEJoI= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/wechat_微信支付证书/江苏六果科技有限公司支付证书/江苏六果科技有限公司支付参数.py b/wechat_微信支付证书/江苏六果科技有限公司支付证书/江苏六果科技有限公司支付参数.py new file mode 100644 index 0000000..52df58d --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技有限公司支付证书/江苏六果科技有限公司支付参数.py @@ -0,0 +1,46 @@ +import os + +import django + +from sixGuoDjango.settings import BASE_DIR + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() + +from pathlib import Path + +from django.conf import settings + +公钥证书 = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_cert.pem").read_text() + +私钥证书 = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_key.pem").read_text() + +平台证书 = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem").read_text() + + +class sixpay六果科技公司: + """微信支付参数:江苏六果科技有限公司 信息""" + public_key = 公钥证书 # 公钥 + private_key = 私钥证书 # 钥私 + wechat_certificate = 平台证书 # 平台证书 + mchid = "1700383419" # 江苏六果科技有限公司商户号(微信支付商户号) + serial_no = "530160D54E8F56726F506DEE40D7FA49A558E8E0" # 江苏六果科技有限公司 商户证书序列号 + appsecret = "8691f774e3c0c5a876b21a3e84109ef0" # 未生成 微信支付=>小程序密钥(小程序注册) + apiv3 = "YWMGAIPTJTWZN4YB3YUTHWK34K9U9M1W" + apiv2 = "OXRNKGGUYHGNJSSIHKFGVMAAOHRPXJAT" # + appid = "wxf612e825377328f0" + get_method = "GET" # 请求方法常量 + post_method = "POST" # 请求方法常量 wechatPay + + +class sixWeCom企业微信: + pass + token = "bVWt1PEUCG" # url验证的token(当前的值为江苏六果科技有限公司) + EncodingAESKey = "LS6VsiJA6Vpb3nJlt34vMZFAbuKDJkFuH2KxuEXYuUR" # 配置的解密(当前的值为江苏六果科技有限公司) + corp_id = "wwbe6369dc26a9d83a" # 企业微信🆔(当前的值为 江苏六果科技有限公司) + corpsecret = "SIRyum7vQh-Bt36AxnqKMX0HIiE-zkYbjYgSat7reZw" # 企业微信 secret(当前的值为 江苏六果科技有限公司) + + +if __name__ == "__main__": + pass + print(私钥证书) diff --git a/wechat_微信支付证书/江苏六果科技服务商支付证书/六果服务商平台证书.pem b/wechat_微信支付证书/江苏六果科技服务商支付证书/六果服务商平台证书.pem new file mode 100644 index 0000000..64c3d5e --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技服务商支付证书/六果服务商平台证书.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIUcKsBbDvpkYXZ7l84yMzltvOEClcwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjUwNzE3MTY1MTA0WhcNMzAwNzE2MTY1MTA0WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtGZs3J575YYTTutzv +5vpyif6tEBbRsnJZ3qIV/S6Rc+NJjAkHz9ADbEiN2QPyrxmZiCL34NEJ6MY3Zf2R +jDfG6Bgx+UBmyl3ETjVCz7YA/Bn78TJcqudRGljlUlT3B8mt14NCccI9jfM86zxQ +gs3ivFPFfBcjnKA3YWs2Dko+XDwe/SYgCc+0fNtHG7MrjlX9tBzDLztr0pTz/Zgp +/Jdj6KdwXEe7qNXGD2fxlAVJPwgzBlddm0s1EcyDmQypiMj6bfHmMmCXva6Wh5cL +OvXlIc36Z90NyJJqA1mnHhzkUcFEyL8obbe8IOgbTwul0eOBI7homIlcRX0uBGSc ++NB7AgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAgjdwM+uOBluLCbW6EKf5rIBvE7VEXlmb +CBmfDM0UdwYgFcCxaMP7EXYTihyOr9b17MFyU6qr2uoKlTR5uxOYItI1uqJLE1i1 +vLuVPieb0/jYKjOUZq/Q4L0pyvEW2A91d4LvctY5POIAUzcOHo6MNSPwOcb2u4x7 ++Cx/G8oMaAfZkCs5Lhc0hN7l5ru5+LE1z7A9Y+gutQ4yluLyHBq3UWgPlIEQS4BS +41nSXGUWbhyCJ9s45DcNJt3UUF1mOZ/Q98hwgMKy6FjHop0FmRlLW0WA8p7z07oF +Nhv10CGepGXvJOgVeJuiTRAO+to88/UV4iQsWZjTXEGXgJYhX0FNwg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/wechat_微信支付证书/江苏六果科技服务商支付证书/商户公钥.pem b/wechat_微信支付证书/江苏六果科技服务商支付证书/商户公钥.pem new file mode 100644 index 0000000..c63e2ee --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技服务商支付证书/商户公钥.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEITCCAwmgAwIBAgIUGICpcvRACvZToQj18MenFYWkM44wDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjUwNzE3MTY1MTA1WhcNMzAwNzE2MTY1MTA1WjB7MRMwEQYDVQQDDAox +NzIyNzExMTA4MRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xJzAlBgNVBAsM +Huaxn+iLj+WFreaenOenkeaKgOaciemZkOWFrOWPuDELMAkGA1UEBhMCQ04xETAP +BgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xVIxZ5i9u8wZZiVVowTChNlj2VcaA1uSli/+mhvVd7Cci9S4A85B/QfWVlg6wI3l +xOS3ZJKnJ855LhV4lyOc6eyRnPDOheZpeT4eC1dpgLnHyhEHVStJzeXoaODcAdBD +3V0AT/2hkvfKw7MyZdZAL/yr6w9ul9kEa7NFYjJzY4LpCAJbAYjxvnjcSLvFGD5t +QYsyvOo4S0c6Pyk9WsG6Sj6ClZhmdLrEsLmo2x4DXT0b3SJFmQm3svczja6EXRsU +5sxU6KkOt0deyXNavkKoUb84r1mzk5KEOFtQxbcXKm5jw76apqYr4EzFjzC1xt/d +Lhl4T6TjJK34BjR+QtvYYwIDAQABo4G5MIG2MAkGA1UdEwQCMAAwCwYDVR0PBAQD +AgP4MIGbBgNVHR8EgZMwgZAwgY2ggYqggYeGgYRodHRwOi8vZXZjYS5pdHJ1cy5j +b20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3 +NTQ5ODQ2QzAxQzNFOEVCRDImc2c9SEFDQzQ3MUI2NTQyMkUxMkIyN0E5RDMzQTg3 +QUQxQ0RGNTkyNkUxNDAzNzEwDQYJKoZIhvcNAQELBQADggEBAByacn33V2w47kP/ +6rUSxkFDfoxszC63DFNQF7GyItUhSbIV8oy1JiXkpBMNcko9CXL/owZEGp4wvBzJ +BnrS5JKu5XP2O93iORH9FoVjfFHEUezNLHOrava6OxIuGq2cAg9KIzvXnHprrjXH +MDz8+Lp3SYhqYjRWQi9Hi+Rv2okZkvuxw7z/wjtsjSUfbpCVbjFyZy8YXzlvY+Dt +dU+VXneXwNghSZ46azp8izi+vEwmdsqPfU7ktrGmHVWDyoLD/ec20IUOE2G1tDj+ +DxWYGLALlcJ5WamgfETdva+60Z8pXZ38157R82ONVs+dI7c09qi9z6ybEViD9+Mj +AxYFHlY= +-----END CERTIFICATE----- diff --git a/wechat_微信支付证书/江苏六果科技服务商支付证书/商户私钥.pem b/wechat_微信支付证书/江苏六果科技服务商支付证书/商户私钥.pem new file mode 100644 index 0000000..11638c4 --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技服务商支付证书/商户私钥.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDFUjFnmL27zBlm +JVWjBMKE2WPZVxoDW5KWL/6aG9V3sJyL1LgDzkH9B9ZWWDrAjeXE5Ldkkqcnznku +FXiXI5zp7JGc8M6F5ml5Ph4LV2mAucfKEQdVK0nN5eho4NwB0EPdXQBP/aGS98rD +szJl1kAv/KvrD26X2QRrs0ViMnNjgukIAlsBiPG+eNxIu8UYPm1BizK86jhLRzo/ +KT1awbpKPoKVmGZ0usSwuajbHgNdPRvdIkWZCbey9zONroRdGxTmzFToqQ63R17J +c1q+QqhRvzivWbOTkoQ4W1DFtxcqbmPDvpqmpivgTMWPMLXG390uGXhPpOMkrfgG +NH5C29hjAgMBAAECggEAdM+0mZyNbbhkrNibOrddpCHBf2+V4bj7LVfaREcH9yQh +eJIEIZSf8fgKxfDTTxxxkj7H5oz+0Yzkpghl7CtUABNhHGReDlyZwgGo7ZPgzCiv +AotUKPJIbdCV5kh/Vb+B/XDJ95CxbvysF3Bk/G56by4IZE4tbU021b856ujs8FIL +R21g1IihrVAywEvSO3DwRTdK8GITClR4XM1HuRlcdLstK40mWp/a4MzyNU5Oic5d +rLs5Yy1NmiEXY6WcHt1oCcYh4ciHFvNaXpiroUBBTFBRIMpCa5dvNeWv8YS5jnaJ +EB03b3v84KjSfAIl8+0nkjSlVgPOzIrW+Y/dx9nviQKBgQDzcTDz9XB85OkYsq1a +Y5lejyWvXnpvKxX8vmdlSdZveI7X4kpe9MP9lhvwntJ0g/mckwgyA/Fu4MbQNaaV +E1RvasWnroANNkYUZ15UcnR8USNpXqEuSPMKEYuvn4X5NeWVub1B4O+o4Z1c4yJj +Tl0cSDo8Zlvb54HDRTtiqITk7wKBgQDPf/GD9lSviWybZ6pavgUgSYzRsCHIWC7z +3nviQGhXpweXfn7MjrJqHUNjCOIb9l0LEgJVoVZHQR4X/3d05aQaq/ZyXp0owUOw +SjccVeAW8xdIntgG4SC/qFAYgdVTVC2k0HVWVucDto89kMfHRPaFHsaNYMF9o6LB +yVCHRYnLzQKBgFERIHwc/5iXogfXeGLhR/F1OddsXtkmP+wqe8P/EqmMPAUoFhwI +5jtMAYHfYbXrPPQnAlOlfICv2YT8WLzL8xInPCrasUm1CSFCSudUNfYwDtrH6GTB +Zi20KhARz0tt50Y01BFcFnLmrsB/4rOvJNKGOt5iN7TDIzMjmuL/u0GBAoGAa9K5 +JnBvSxPnGs4AiMyrDz8I7MFQnLGuHE0lJMmBLuL9n+w8aYFRFrEEHkc0b4FSkfkW +u3ZtxfMBd0jpwxW9c5qeIoolslLTIJ1AC/pXyrUhCTx5VwHPKaiFjmaQ+o8IdNdZ +0bawro5D2qMMHPEqBLycQkTf5rCMV5SLwu8QjpUCgYB/7Ti6Iqxpp3OFnigXHcSB +fMeK36GCgVAkTB+QztVjh5a3XzJjFBXqMd7SWr87n+7/SJkQv/U4RN/VXddTyjzg +vO4r+SZoh1aBKdvklwGn5m565cJP6SkAXZANLmoUFzJM1SexdbadR/Z+kBjZ9uS5 +unY0rUP/Ey94dcxThR9RAw== +-----END PRIVATE KEY----- diff --git a/wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技有限公司服务商支付参数.py b/wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技有限公司服务商支付参数.py new file mode 100644 index 0000000..50cc3e2 --- /dev/null +++ b/wechat_微信支付证书/江苏六果科技服务商支付证书/江苏六果科技有限公司服务商支付参数.py @@ -0,0 +1,40 @@ +import os + +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() +六果服务商商户公钥证书 = Path(settings.BASE_DIR).joinpath( + "wechat_微信支付证书/江苏六果科技服务商支付证书/商户公钥.pem").read_text() +六果服务商商户私钥证书 = Path(settings.BASE_DIR).joinpath( + "wechat_微信支付证书/江苏六果科技服务商支付证书/商户私钥.pem").read_text() + + +class six六果服务商支付参数: + public_key = 六果服务商商户公钥证书 # 公钥 + private_key = 六果服务商商户私钥证书 # 钥私 + wechat_certificate = 六果服务商平台证书 # 平台证书 + apiv3 = "282615f26decd7ba1db3a3fa3fd93d75" + apiv2 = "e3011ce65c8320cdde5815a04b582022" # + serial_no = "1880A972F4400AF653A108F5F0C7A71585A4338E" # 商户证书序列号 + appid = "wx92441a2398fa8cc0" # 开放平台获取的appid(需要注意) + mchid = "1722711108" + get_method = "GET" # 请求方法常量 + post_method = "POST" # 请求方法常量 + xiao_name = "xiao_name" + + +if __name__ == "__main__": + pass diff --git a/wechat_微信支付证书/萌新食品/apiclient_cert.pem b/wechat_微信支付证书/萌新食品/apiclient_cert.pem new file mode 100644 index 0000000..121c215 --- /dev/null +++ b/wechat_微信支付证书/萌新食品/apiclient_cert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID6TCCAtGgAwIBAgIUPerhyrUSMhNiEGouoIF/U7rmJyIwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjIxMjIxMTUxMzU4WhcNMjcxMjIwMTUxMzU4WjB7MRMwEQYDVQQDDAox +NjM2MzEyODA1MRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xJzAlBgNVBAsM +Huaxn+iLj+iQjOaWsOmjn+WTgeaciemZkOWFrOWPuDELMAkGA1UEBgwCQ04xETAP +BgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +03oTbBeQhRy/sbITwGCpT9igS4J6MqJOOpd6wTsXARGzz5VmG1j+aaP9cSX0miLj +ifRIReMgbXbn06AsioitFJtKGbVPb/Vq2ml6rQ3DiODNmOfX4kVM8hl8osCJ9Upb +q7okljh4SaeAtbSF8KtlnONrAJNUPX3vsURJ48tZXCAJcVnNq3/F6Ew9YFU8yRYT +stQx/esCv25SEKKuCMJ9xIJUSWjwwsXZDMXvNiHd7UsXsfu1eJ+CuFf5FvI/XpEF +t1ai7Veblg6iJGl93fB6s08EOh1wKhQRE0adjV3ylOT59BzCO3sSy3OkKk4BI3Qg +kfGDfmx0vV22sT9SJK8y8wIDAQABo4GBMH8wCQYDVR0TBAIwADALBgNVHQ8EBAMC +A/gwZQYDVR0fBF4wXDBaoFigVoZUaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1 +YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMw +MUMzRThFQkQyMA0GCSqGSIb3DQEBCwUAA4IBAQB+ycj84P1IpaFDslc8stNx0Qp3 +pM53igbI/NEBcZewqi07IewCADmpalZQ7F4JszhyR/+nDI3Mb6ra1EF3w9frkw1H +uqxkQKcChw8L8s/a5rHVTmVaQofVp2FXI/pLc2MvLPlyxMj5rqmqUmQ3Mxg6Atiw +1PR1vFe+jbn7fHeCqL7o48xjw1fRCDiicfd3KDLRWIwjNJ/3qKVyMweNk7ZBsohb +PxbimnCNM0f5Ipb+XISuNDkEYPQfYfxkz0gJkkqYI8c8z4N6ibR2hF/ZWLQg28zS +GMCGB0Je8SWo7jy4OHm6iLE84JSSjhc6AhJim6r/qMUDBpa0UzEyHNoXJeYT +-----END CERTIFICATE----- diff --git a/wechat_微信支付证书/萌新食品/apiclient_key.pem b/wechat_微信支付证书/萌新食品/apiclient_key.pem new file mode 100644 index 0000000..984ba3b --- /dev/null +++ b/wechat_微信支付证书/萌新食品/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTehNsF5CFHL+x +shPAYKlP2KBLgnoyok46l3rBOxcBEbPPlWYbWP5po/1xJfSaIuOJ9EhF4yBtdufT +oCyKiK0Um0oZtU9v9WraaXqtDcOI4M2Y59fiRUzyGXyiwIn1SluruiSWOHhJp4C1 +tIXwq2Wc42sAk1Q9fe+xREnjy1lcIAlxWc2rf8XoTD1gVTzJFhOy1DH96wK/blIQ +oq4Iwn3EglRJaPDCxdkMxe82Id3tSxex+7V4n4K4V/kW8j9ekQW3VqLtV5uWDqIk +aX3d8HqzTwQ6HXAqFBETRp2NXfKU5Pn0HMI7exLLc6QqTgEjdCCR8YN+bHS9Xbax +P1IkrzLzAgMBAAECggEBAJxFsIaG30/OT8WS70+Q3mzXipRiBcTW9XIMsDSMYtJy +b2ptXzfESrRr74QmZRtlvrkZ4DJsxXC+lk9nJKL2ntgEbPyUY/A67cwaeAHbkuva +G3PrlzdouJSKyvRFzWyKlzVOZ2zuq8zZz532maegMIV/9HlHZc/O+UoISYXgpdcR +qPGqgjGPhe2r6V9CWx41pL2x0ac3FEoQj0MJEacwK2yPkMMUnImPeDVzqpq9olnA +boN32DVdynOcRBaS2Mk//e+9r8JfYm/3lwzaB19Hvj5xA46z8XB7QnvDPcPfqxUg +0OR7YrBLe0WBphUvDY4UHTIN5q38yolcSS0RqUnHH/ECgYEA+B1EzcoEAMn1APTg +kfqZ4+IIk9zc+d7NuvK9TGuY3Ka70oD6vjstiZdAyEQ/NjYY99N+RRwU3ZQUwqPj +7Lxqr9IAEapz6VLJaUs4OZ7ceGWC41DGi62SfVgPNdNUCN23ZnL3poJM/K4IMZ45 +3EAyGzjMBmNdHacXf2rSwM9c7/kCgYEA2jK2vnhp05B6lXfif+Qgq0KFyrpIuo7Y +1n0R/17fTcA2Me2IEyaJe+/HBu4e04JBu5/OP8KUNsAI1bA8y9Je4T0SyADzM5G4 +mfemhXxVLwdM/NB0hTJzG/bbBHVplLCbo0K/GgtIXExjFO0X85K3K3Rqt3sGwLfW +2IPJLvI/TUsCgYBIK4NS9LsbW6NXhuM3sxRGU/44vFrOl79x7J+hdf692AX0Ii5N +XTtOtV9ToX5dj3jNxYgKJDPxi9xKDZAD0X6a69O3T8RtjvYlGYseP5ZTsvtSkbFe ++bsNmKq79l+QQKXTOAfPOEGakiix/htIdKfegTPfe9GfCXZtSq5JBUg8SQKBgQCU +3DpucaoJKy1mYZbGF7XuAQFUEIjjtebbVhJ8PZZs7fBLWbkXD5iGVExdPwEK3XfI +8Dp+p1oEjDi6yHSBvXD7i3YPuw4wpX7ik+Eoem2HGxz78Z886/E6J8y+Gvg/98kG +tde4hfAFABwsv6AyjWqnm9HegXFW81UA+8+6Voy3RwKBgHH/BOaLOzaHb7gr8fIf +FW5BCvYN45/3ZetCxG+BmSJDmf8oPwuQ0Wtc1qSWC2VGqblPLy9h2nfh4OZYWNmv +8NIEZYgpmtGyd7SAumsfW0zKNDzIng9uXsOvb6vqoT+KBK0dA+auQHRyF7Glge1s +RXkbdQLNyv5XmpD6PaDL4mug +-----END PRIVATE KEY----- diff --git a/wechat_微信支付证书/萌新食品/mengxin_ping_tai_zheng_shu.pem b/wechat_微信支付证书/萌新食品/mengxin_ping_tai_zheng_shu.pem new file mode 100644 index 0000000..f90d6ce --- /dev/null +++ b/wechat_微信支付证书/萌新食品/mengxin_ping_tai_zheng_shu.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3DCCAsSgAwIBAgIUNs+AblQhe2kmcxS6X7LtYEPPMoIwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjIxMjIxMTUxMzU3WhcNMjcxMjIwMTUxMzU3WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCq2BY/hfq6rldQUHTF +gsNrc1od2wD38+rNcMomdY3wZiwzpv3qLA70NPc5O0TEIYTAsT8yWiIXibchlkm0 +TVezcmrteykmpGzLOdEpWBhHDSID/cccdxX8uthStZ69o3bHY7QbZDSEzjZg3138 +uUEZgFj/SNGClotnqYPLIZyItW8nyrAwgcq9EUE76+v1wmxNyPAknVzMglm3q5uS +C+06KdZJ6MvKVKhJ8BnXvPyNdnFuw12qP4WpmIGzkBEEsQYY0tkA7l3iHETWGaLu +T9kGD6dAt2IeqNaHY4Cy9MSSkwNOQkjRV3GezYYWIVasRGxr0X3eWr4uvJXbFBoe +U7wLAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwID+DBlBgNVHR8EXjBc +MFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js +P0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ +KoZIhvcNAQELBQADggEBAGyjlPMIUl8fFBA9mA6DkVpPAKCiXzt1YRGkped56L2S +HuRMcM0IrjyWnzMKYsxUkC++/Fjt8Jxf7DIkdkyvmh5jeFx/Xcq0Ov8ofta12OoA +7Jvbf/iPRfhjMnVpizstbxAQ0BcSfSE2vedrsczSG4DMTHe8cAkiw26Y7gyaZSd3 +1gPlrfyy8lTA3c2lTjkW5Yif4322xf6F0L/TEjeEfinm5Kr9ds6N2RePuQt88euQ +2kV/fIzAFUXFWs+y7g3ed4oYLjh0s5GVxHRV4VLtY206asoGKl67S9+5XZCZw6UY +Sqfz+N8NO8cAyPE9UPn71z4gTX5aDXU/QR28jLqbJQ4= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/wechat_微信支付证书/萌新食品/萌新食品参数.py b/wechat_微信支付证书/萌新食品/萌新食品参数.py new file mode 100644 index 0000000..8684c08 --- /dev/null +++ b/wechat_微信支付证书/萌新食品/萌新食品参数.py @@ -0,0 +1,51 @@ +"""注释""" + +import os + +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( + "django_微信支付/支付证书_参数/萌新食品/mengxin_ping_tai_zheng_shu.pem" ).read_text( ) +demo = Path( "apiclient_cert.pem" ).resolve( ).read_text( ) + +萌新食品商户公钥证书 = Path( settings.BASE_DIR ).joinpath( + "django_微信支付/支付证书_参数/萌新食品/apiclient_cert.pem" ).read_text( ) +萌新食品商户私钥证书 = Path( settings.BASE_DIR ).joinpath( + "django_微信支付/支付证书_参数/萌新食品/apiclient_key.pem" ).read_text( ) + + + + + +class meng萌新食品支付参数: + public_key = 萌新食品商户公钥证书 # 公钥 + private_key = 萌新食品商户私钥证书 # 钥私 + wechat_certificate = 萌新食品平台证书 # 平台证书 + apiv3 = "RclX1cKk4rttb8Uqk25FaWAmYSI4DgBP" # 新 + apiv2 = "LxVJUYrWShVUbymQoYJ3TUEZAy3THmi3" + serial_no = "3DEAE1CAB512321362106A2EA0817F53BAE62722" # 新:微信支付=>证书序列号(微信支付账号)新 + appsecret = "228c2959d1d985b04baae4124cf58167" # 未生成 微信支付=>小程序密钥(小程序注册) + appid = "wx2c09d3fd01406ab2" # 萌新食品小程序appid + mchid = "1636312805" # 微信支付=>商户号(微信支付账号)新,萌新食品mchid账号 get_method = "GET" # 请求方法常量 + post_method = "POST" # 请求方法常量 + get_method = "GET" + + + + + +if __name__ == "__main__": + pass + print( demo ) diff --git a/wechat_接口/商品订单模拟接口/商品数据接口.py b/wechat_接口/商品订单模拟接口/商品数据接口.py new file mode 100644 index 0000000..4b3643c --- /dev/null +++ b/wechat_接口/商品订单模拟接口/商品数据接口.py @@ -0,0 +1,108 @@ +from django.forms import model_to_dict +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 BaseResponse, ResData +from wechat_数据库.洗衣液商品数据库.六果洗衣液商品 import Goods, goods商品, goods商品Choices + + +class 商品接口ViewSets(ViewSet): + @action(detail=False, methods=["post"], url_path="filter_query_goods") + def 根据条件查询商品接口(self, request: Request): + """""" + # 2. 创建一个新的、按键排序后的字典 + goodsDataList = goods商品.objects.filter(goods商品类型=goods商品Choices.商城商品.value).values( + "id_主键_goods商品", "goods商品数据", "id_str") + print("商城查询所有的商品数据", goodsDataList) + 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): + pass + 赢免单商品数据 = Goods.objects.filter(goods_商品销售场景=goods商品Choices.赢免单.value).first() + data = model_to_dict(instance=赢免单商品数据, fields=None, exclude=None) + return Response(data=data) + + @action(detail=False, methods=["post"], url_path="query") + def 返回商城所有的销售商品信息数据(self, request: Request): + """返回所有的商品信息数据""" + data = Goods.objects.filter(goods_商品销售场景=goods商品Choices.商城商品.value).values() + httpResData = BaseResponse(resData=ResData(listData=data, dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="current_goods") + def 分享商品查询接口(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + goodID = request.data.get("goodID", None) + goodsDdata = goods商品.objects.get(id_主键_goods商品=goodID) + data = model_to_dict(instance=goodsDdata, fields=None) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=data), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @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_商品信息={ + "品牌": "六果泡泡", + "净重": "20斤装/桶", + "香型": "熏衣草", + "洁净": "源自天然酵素迅速渗入衣物,去除99种污渍🫟", + "除菌": "99%除菌🦠,污渍菌螨,一洗即净,守护健康", + }, + goods_商品标题="六果泡泡 (超划算) 源自天然酵素迅速渗入衣物,99%除菌🦠一洗即净,守护健康", + goods_商品标签=["99%除菌🦠", "99种污渍🫟", ], + # 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_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_商家推荐标签=["厂家直销", "独家配方", "自产自销", "量大实惠", "品质保证"], + ) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +商品接口ViewSetsRouter = DefaultRouter() +商品接口ViewSetsRouter.register(prefix="", viewset=商品接口ViewSets, basename="") diff --git a/wechat_接口/商品订单模拟接口/订单管理接口.py b/wechat_接口/商品订单模拟接口/订单管理接口.py new file mode 100644 index 0000000..b439684 --- /dev/null +++ b/wechat_接口/商品订单模拟接口/订单管理接口.py @@ -0,0 +1,26 @@ +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 sixGuoDjango import BaseResponse, ResData +from wechat_数据库.支付订单数据库.商品订单数据 import order订单 + + +class 订单管理接口ViewSets(ViewSet): + + @action(detail=False, methods=["post", ], url_path="query") + def 查询当前用户的订单列表(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + 订单查询列表 = order订单.objects.filter(order支付者openid=self_mini_openid, order支付状态="支付成功").values() + + httpResData = BaseResponse(resData=ResData(listData=订单查询列表, dictData={"demo": "11111111111"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +订单管理接口ViewSetsRouter = DefaultRouter() +订单管理接口ViewSetsRouter.register(prefix="", viewset=订单管理接口ViewSets, basename="") diff --git a/wechat_接口/小程序用户接口/小程序用户头像昵称手机号接口.py b/wechat_接口/小程序用户接口/小程序用户头像昵称手机号接口.py new file mode 100644 index 0000000..1a3ff3b --- /dev/null +++ b/wechat_接口/小程序用户接口/小程序用户头像昵称手机号接口.py @@ -0,0 +1,68 @@ +import jmespath +import requests +from django.core.files.uploadedfile import InMemoryUploadedFile +from django.forms import model_to_dict +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 sixGuoDjango import BaseResponse, ResData +from wechat_token.token工具包 import sixToken +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser + + +class 小程序用户头像昵称接口ViewSets(ViewSet): + @action(detail=False, methods=["post"], url_path="chooseAvatar") + def 用户头像接口(self, request: Request): + """""" + chooseAvatar: InMemoryUploadedFile | None = request.FILES.get("chooseAvatar", None) + print(chooseAvatar) + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + print(self_user_unionid) + 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="nickName") + def 更新用户昵称(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + nickName = request.data.get("nickName", None) + print("获取到的用户昵称", nickName) + 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="getPhoneNumber") + def 获取用户手机号码(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + code = request.data.get("code", None) + mini_token = sixToken.get_mini_token() + url = f"https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={mini_token}" + jsonData = {"code": code} + resData = requests.post(url=url, json=jsonData).json() + print(resData, "❌❌❌❌❌❌❌❌❌❌❌❌") + phoneNumber = jmespath.search(data=resData, expression="phone_info.phoneNumber") + print(phoneNumber) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"phoneNumber": phoneNumber}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="search") + def 查询用户头像和昵称(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + 用户头像信息 = weiuser.objects.get(unionid=self_mini_unionid) + resData = model_to_dict(instance=用户头像信息, fields=["avatar", "nickName"]) + print(self_mini_unionid) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=resData), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +小程序用户头像昵称接口ViewSetsRouter = DefaultRouter() +小程序用户头像昵称接口ViewSetsRouter.register(prefix="", viewset=小程序用户头像昵称接口ViewSets, basename="") diff --git a/wechat_接口/小程序用户接口/小程序用户登陆接口.py b/wechat_接口/小程序用户接口/小程序用户登陆接口.py new file mode 100644 index 0000000..81f0778 --- /dev/null +++ b/wechat_接口/小程序用户接口/小程序用户登陆接口.py @@ -0,0 +1,119 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:40 +FilePath: django_小程序/小程序服务端服务接口/小程序用户登陆接口.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" + +import jmespath +from django.forms import model_to_dict +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 +from rest_framework.viewsets import ViewSet + +from sixGuoDjango import BaseResponse, ResData +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.小程序工具包.小程序用户授权数据 import wei小程序服务端工具 +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay + +上级分享者的默认值 = "六果" + + +class 六果科技小程序用户登陆(ViewSet): + + def res_obj_data_func(self, self_user: weiuser) -> dict[str, str]: + """""" + res_obj_data = model_to_dict(instance=self_user, fields=None, exclude=None) + return res_obj_data + + @action(detail=False, methods=["post", ], url_path="mini_login") + def 小程序用户(self, request: Request, *args, **kwargs): + """""" + encryptedData = request.data.get("encryptedData", None) # 解密群号所需要的参数 + iv = request.data.get("iv", None) # 解密群号所需要的参数 iv + code: str = request.data.get("code", "") + # superior_openid = request.data.get( "superior_openid", ) # 如果上级是默认的值 则说明是没有上级的, + superior_unionid = request.data.get("superior_unionid", 上级分享者的默认值) # 如果上级是默认的值 则说明是没有上级的, + scene = request.data.get("scene", None) # 微信用户进入小程的场景值 + shareTicket = request.data.get("shareTicket", None) # 微信用户的shareTicket值 + res = wei小程序服务端工具.获取OPENID(js_code=code, appid=paymentCategory.appid, + secret=paymentCategory.appsecret, ) + # 代码能往下执行:则说明,已经正确拿到结果; + self_openid = jmespath.search(data=res, expression="openid") + session_key = jmespath.search(data=res, expression="session_key") + self_unionid = jmespath.search(data=res, expression="unionid") + # 准备好,需要的数据 + + share分享者对象, share分享者对象是新创建 = weiuser.objects.update_or_create(unionid=superior_unionid, ) + # 首次进来的用户要全部的添加上默认的 用户 角色 + click点击者对象, self_bool = weiuser.objects.update_or_create(unionid=self_unionid, + defaults={"mini_openid": self_openid}) + + six六果对象, sixBool = weiuser.objects.get_or_create(unionid="六果") + if superior_unionid == 上级分享者的默认值: + share分享者对象 = six六果对象 + print("登陆成功了,同时打印一下上级的用户是谁", superior_unionid) + if click点击者对象.parent is not None: + # 不为空说明已经有上级存在了 + res_obj_data = self.res_obj_data_func(self_user=click点击者对象) # 函数调用返回数据 + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=res_obj_data), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + if superior_unionid == self_unionid and share分享者对象是新创建 == True: + # 说明是自己点了自己 + print("说明是自己点了自己说明是自己点了自己说明是自己点了自己") + click点击者对象.parent = six六果对象 + click点击者对象.codeConfigId = six六果对象.codeConfigId + click点击者对象.codeQrCode = six六果对象.codeQrCode + click点击者对象.codeRemark = six六果对象.codeRemark + click点击者对象.user_用户当前的等级 = six六果对象.user_用户当前的等级 + 1 + click点击者对象.user_绑定企微UNIONID = six六果对象.user_绑定企微UNIONID + click点击者对象.save() + res_obj_data = self.res_obj_data_func(self_user=click点击者对象) # 函数调用返回数据 + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=res_obj_data), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + if click点击者对象.parent is None and scene == 1044: + openGId, timestamp, appid = wechatPay(payment=paymentCategory).解密群号(iv=iv, encryptedData=encryptedData, + sessionKey=session_key, ) + # TODO 在这里需要完成,对群号数据的添加 + click点击者对象.parent = share分享者对象 + click点击者对象.codeConfigId = share分享者对象.codeConfigId + click点击者对象.codeQrCode = share分享者对象.codeQrCode + click点击者对象.codeRemark = share分享者对象.codeRemark + click点击者对象.user_用户当前的等级 = share分享者对象.user_用户当前的等级 + 1 + click点击者对象.user_绑定企微UNIONID = share分享者对象.user_绑定企微UNIONID + click点击者对象.save() + res_obj_data = self.res_obj_data_func(self_user=click点击者对象) # 函数调用返回数据 + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=res_obj_data), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + if click点击者对象.parent is None: + # 说明没有上级存在,更新数据 + print("说明没有上级存在,更新数据") + # use, use_bool = weiuser.objects.update_or_create( + # unionid=self_unionid, + # defaults={ "mini_openid": self_openid, "user_用户当前的等级": share分享者对象.user_用户当前的等级 + 1, "parent": share分享者对象, + # "codeConfigId": share分享者对象.codeConfigId, "codeQrCode": share分享者对象.codeQrCode, + # "codeRemark": share分享者对象.codeRemark, + # }, ) + click点击者对象.parent = share分享者对象 + click点击者对象.codeConfigId = share分享者对象.codeConfigId + click点击者对象.codeQrCode = share分享者对象.codeQrCode + click点击者对象.codeRemark = share分享者对象.codeRemark + click点击者对象.user_用户当前的等级 = share分享者对象.user_用户当前的等级 + 1 + click点击者对象.user_绑定企微UNIONID = share分享者对象.user_绑定企微UNIONID + click点击者对象.save() + print("自己点了自已,同时还没有创建数据时的情况", share分享者对象.user_角色权限) + res_obj_data = self.res_obj_data_func(self_user=click点击者对象) # 函数调用返回数据 + httpResData = BaseResponse(resData=ResData(listData=[""], dictData=res_obj_data), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + # 在所有的业务判断都不成功时,直接返回 + return Response(data="", status=status.HTTP_200_OK) + + +六果科技小程序用户登陆Router = SimpleRouter() +六果科技小程序用户登陆Router.register(prefix="", viewset=六果科技小程序用户登陆, basename="六果科技小程序用户登陆") diff --git a/wechat_接口/小程序用户接口/小程序订阅消息.py b/wechat_接口/小程序用户接口/小程序订阅消息.py new file mode 100644 index 0000000..b81ff7f --- /dev/null +++ b/wechat_接口/小程序用户接口/小程序订阅消息.py @@ -0,0 +1,106 @@ +import datetime +import secrets + +import orjson +from django.core.handlers.wsgi import WSGIRequest +from requests import get, post +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 sixGuoDjango import BaseResponse, ResData +from wechat_token.token工具包 import sixToken +from wechat_数据库.小程序后端数据库.订阅消息 import miniSub订阅消息模板 +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class miniMsg订阅消息(ViewSet): + """miniMsg订阅消息工具""" + + @action(detail=False, methods=["post"], url_path="查询服务卡片状态") + def 查询服务卡片状态(self, request: WSGIRequest | Request): + """ + 查询服务卡片状态 + :return: + :rtype: + """ + uri = f"https://api.weixin.qq.com/wxa/get_user_notify" + notify_code = secrets.token_hex(10) + post_data = {"openid": "o6oV610oYhpoJYaCJ9tDJKehsJTc", # string 是 用户身份标识符 + "notify_type": "vknIxXIC1O0IMhHI0yiS-zPUt3UvPYO-ihDM_mcHRJw", # + "notify_code": notify_code, + } + mini_token = sixToken.get_mini_token() + result_data = post(url=uri, params={"access_token": mini_token}, json=post_data) + print(result_data.json()) + return Response() + + @action(detail=False, methods=["post"], url_path="gettemplate") + def 获取消息列表(self, request: WSGIRequest | Request): + """""" + """ + 获取个人模板列表 + :return: + :rtype: + """ + print("----------------------------------------") + uri = f"https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate" + mini_token = sixToken.get_mini_token() + print(mini_token) + post_data = {} + result_data = get(url=uri, params={"access_token": mini_token}, ) + print(orjson.loads(result_data.content.decode(encoding="utf-8"))) + 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="sendmsg") + def 发送模板消息(self, request: WSGIRequest | Request): + """ + 如果不知道模板格式,就需要调用上面的接口 + {'priTmplId': 'xCfF4yeTlKaEfZ4sh3z9C6r-wG845W4Bst2JO9hWR6A', + 'title': '卡券到期提醒', + 'content': + '卡券名称:{{thing1.DATA}}\n + 到期时间:{{time2.DATA}}\n + 使用规则:{{thing3.DATA}}\n + 状态:{{phrase4.DATA}}\n', ' + example': '卡券名称:软件维护服务1次\n到期时间:2020年10月14日 23:59\n使用规则:将有专业服务人员上门服务并核销卡券\n状态:未使用\n', 'type': 2, 'keywordEnumValueList': []}, + content内的内容就是模板的信息 格式为 thing1:{value:"内容,"},time2:{"value":"时间字符串"} + """ + pass + uri = f"https://api.weixin.qq.com/cgi-bin/message/subscribe/send" + datetimd_str = datetime.datetime.now().strftime(format="%Y-%m-%d %H:%M:%S") + random_str = generator.generate_str() + post_data = {"touser": "ohQkD7A-N93kljcFmkCyG6e_D9vg", + "template_id": "RvGf7wyALX4djhBgeIp6jqlfAKNzd_weXRFEd1P54fk", + "page": "tabPage/Home/Home", + "data": { + "thing1": {"value": "100优惠券"}, + "thing2": {"value": "random_str"}, + }, + } + mini_token = sixToken.get_mini_token() + result_data = post(url=uri, params={"access_token": mini_token}, json=post_data) + print(result_data.json(), "订阅消息发送成功了啦") + return Response(data={"msg": "订阅消息"}) + + @action(detail=False, methods=["post"], url_path="add_messages") + def 计数订阅成功的次数(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + + sub对象, sub对象是否存在 = miniSub订阅消息模板.objects.update_or_create(sub订阅用户ID=self_mini_openid, + sub订阅模板ID="RvGf7wyALX4djhBgeIp6jqlfAKNzd_weXRFEd1P54fk", + ) + sub对象.sub订阅次数 = sub对象.sub订阅次数 + 1 + sub对象.save() + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +miniMsg订阅消息Router = DefaultRouter() +miniMsg订阅消息Router.register(prefix="", viewset=miniMsg订阅消息, basename="") diff --git a/wechat_接口/微信支付接口/代金券相关接口.py b/wechat_接口/微信支付接口/代金券相关接口.py new file mode 100644 index 0000000..59155da --- /dev/null +++ b/wechat_接口/微信支付接口/代金券相关接口.py @@ -0,0 +1,67 @@ +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.routers import DefaultRouter +from rest_framework.viewsets import ViewSet + +from sixGuoDjango import BaseResponse, ResData +from wechat_数据库.雪花算法.雪花算法工具 import generator +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay + + +class 代金券接口ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="send_coupons") + def 发放指定代金券接口(self, request: Request): + """""" + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + 发放接口 = f"https://api.mch.weixin.qq.com/v3/marketing/favor/users/{self_mini_openid}/coupons" + out_request_no = generator.generate_str() + 发放的数据 = { + "stock_id": "22512292", # 发放的批次号 + "out_request_no": out_request_no, # 【商户单据号】商户此次发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性 + "appid": "wxf612e825377328f0", + "stock_creator_mchid": "1700383419", # 创建批次的商户号】批次创建方商户号。 + # "coupon_value": 100, # 指定面额发券,面额】指定面额发券场景,券面额,其他场景不需要填,单位:分。 + } + 返回签名后的 = wechatPay(payment=paymentCategory).构造签名串(uri=发放接口, body_data=发放的数据, method="POST") + data = requests.post(url=发放接口, json=发放的数据, headers=返回签名后的) + print(data.json()) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"couponsMessages": "发券成功"}), ).model_dump() + return Response(data=data.json(), status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="setting_url") + def 设置代金券消息通知地址(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + 请求接口 = f"https://api.mch.weixin.qq.com//v3/marketing/favor/callbacks" + 请求数据 = { + "mchid": paymentCategory.mchid, + "notify_url": "https://xiao.sixgou.com/coupons/coupons_callback/", + } + headers = wechatPay(payment=paymentCategory).构造签名串(uri=请求接口, body_data=请求数据) + data = requests.post(url=请求接口, json=请求数据, headers=headers) + print("请求后的结果", data.json()) # 请求后的结果 {'notify_url': 'https://xiao.sixgou.com/coupons/coupons_callback/', 'update_time': '2026-03-25T23:51:54+08:00'} + + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"couponsMessages": "发券成功"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="coupons_callback") + def 代金券的回调接口(self, request: Request): + """""" + self_user_unionid = request.data.get("self_user_unionid", None) + self_mini_openid = request.data.get("self_mini_openid", None) + # 回调解密内容 = wechatPay(payment=paymentCategory).callBack回调解密(headers=request.headers, response_body=request.body) + # print("回调解密内容", 回调解密内容) + wechat_data支付回调数据 = wechatPay(payment=paymentCategory).callBack回调解密(headers=request.headers, response_body=request.data, ) + print(wechat_data支付回调数据, "wechat_data支付回调数据🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 ") + print("🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏") + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +代金券接口ViewSetsRouter = DefaultRouter() +代金券接口ViewSetsRouter.register(prefix="", viewset=代金券接口ViewSets, basename="") diff --git a/wechat_接口/微信支付接口/商家转账.py b/wechat_接口/微信支付接口/商家转账.py new file mode 100644 index 0000000..a0c665e --- /dev/null +++ b/wechat_接口/微信支付接口/商家转账.py @@ -0,0 +1,101 @@ +import pydash +from django.core.handlers.wsgi import WSGIRequest +from django.db import models +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 sixGuoDjango import BaseResponse, ResData +from wechat_数据库.雪花算法.雪花算法工具 import generator +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay + + +class six商家转账ViewSets(ViewSet): + + @action(detail=False, methods=["post"], url_path="transfer") + def six发起转账(self, request: Request): + """ """ + self_mini_openid = request.data.get("self_mini_openid", None) + self_mini_unionid = request.data.get("self_mini_unionid", None) + 提取积分值 = request.data.get("提取积分值", None) + # 逻辑一: 先比较积分值是否超出提现的金额 + # 积分值sum = share分享者积分.objects.filter(share分享者unionid=self_mini_unionid).values("share分享者unionid").annotate(xiao_age_sum=models.Sum("share分享积分值"), ) # 只有value(字段1,字段2)二个值完全相同的才会分配为一组 + # 添加 order_by + # result = 积分值sum.order_by("share分享者unionid").first() + # print(result) + # xiao_age_sum = pydash.get(obj=result, path="xiao_age_sum") + # print(xiao_age_sum) + # httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": xiao_age_sum}), ).model_dump() + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": {}}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + if xiao_age_sum > 0 and xiao_age_sum >= 提取积分值: + pass + # 说明这里可以提现 + # 业务逻辑 第一步.需要判断这个用户是否已经领过 新手红包 如何判断, 查询新手红包数据库,如果对象存在,则直接不能再领取了; + out_bill_no = generator.generate_str() + transfer_amount = 10 # 必须参数转账的金额 + transferAccountsBody = { + "appid": paymentCategory.appid, + "out_bill_no": out_bill_no, # 必填 integer【商户单号】 + # 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 + "transfer_scene_id": "1000", + # 必填 integer【转账场景ID】 该笔转账使用的转账场景,可前往“商户平台-产品中心-商家转账”中申请。如:1000(现金营销),1006(企业报销)等 + # "openid":"ohQkD7A-N93kljcFmkCyG6e_D9vg", + "openid": self_mini_openid, # 必填 integer【收款用户OpenID】 用户在商户appid下的唯一标识。发起转账前需获取到用户的OpenID,获取方式详见参数说明。 + # "user_name":"757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45", # 【收款用户姓名】 + # 收款方真实姓名。需要加密传入,支持标准RSA算法和国密算法,公钥由微信侧提供。 + "transfer_amount": transfer_amount, # 必填 integer【转账金额】 转账金额单位为“分”。 + "transfer_remark": "新会员开通有礼", # 必填 string(32)【转账备注】 转账备注,用户收款时可见该备注信息,UTF8编码,最多允许32个字符 + "notify_url": "https://xiao.sixgou.com/demopay/transfer_back/", + # 选填【通知地址】 异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数。 + "user_recv_perception": "现金奖励", # 选填 【用户收款感知】 用户收款时感知到的收款原因将根据转账场景自动展示默认内容。如有其他展示需求, + # 必填 array[TransferSceneReportInfo] 【转账场景报备信息】 各转账场景下需报备的内容,商户需要按照所属转账场景规则传参,详见转账场景报备信息字段说明。 + "transfer_scene_report_infos": [ + { + "info_type": "活动名称", # 必填 string(15)【信息类型】 不能超过15个字符,商户所属转账场景下的信息类型,此字段内容为固定值 + "info_content": "新会员有礼", # 必填 【信息内容】 不能超过32个字符,商户所属转账场景下的信息内容,商户可按实际业务场景自定义传参 + }, + { + "info_type": "奖励说明", "info_content": "注册会员抽奖一等奖", + }, + ], + } + # wechat_data = wechatPay(payment=paymentCategory).transferAccounts商家转账到零钱(transferAccountsBody=transferAccountsBody) + # print("返回的数据", wechat_data) + # package_info = jmespath.search(data=wechat_data, expression="package_info") + # create_time = jmespath.search(data=wechat_data, expression="create_time") + # out_bill_no = jmespath.search(data=wechat_data, expression="out_bill_no") + # state = jmespath.search(data=wechat_data, expression="state") + # transfer_bill_no = jmespath.search(data=wechat_data, expression="transfer_bill_no") + # WechatTransferOrder.objects.create( + # out_bill_no=out_bill_no, transfer_bill_no=transfer_bill_no, wx_create_time=create_time, + # state=state, transfer_amount=transfer_amount, package_info=package_info + # ) + # 前端调用的数据 = { + # "mchId": paymentCategory.mchid, "appId": paymentCategory.appid, "package": package_info, + # } + # # 操作数据库,减掉提取的积分值 + # share分享者积分.objects.create(share分享者unionid=self_mini_unionid, share分享类型="提取积分", share分享积分=-1) + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + else: + pass + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + # 说明这里不能提现 + httpResData = BaseResponse(resData=ResData(listData=[""], dictData={}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post"], url_path="transfer_back") + def six发起转账回调(self, request: WSGIRequest | Request): + pass + wechat_data = wechatPay(payment=paymentCategory).callBack回调解密(response_body=request.body, headers=request.headers) + print(wechat_data) + return Response() + + +six商家转账ViewSetsRouter = DefaultRouter() +six商家转账ViewSetsRouter.register(prefix="", viewset=six商家转账ViewSets, basename="") diff --git a/wechat_接口/微信支付接口/微信支付测试接口.py b/wechat_接口/微信支付接口/微信支付测试接口.py new file mode 100644 index 0000000..0978264 --- /dev/null +++ b/wechat_接口/微信支付接口/微信支付测试接口.py @@ -0,0 +1,189 @@ +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 sixGuoDjango import ResData, BaseResponse +from wechat_数据库.支付订单数据库.商品订单数据 import order订单 +from wechat_数据库.雪花算法.雪花算法工具 import generator +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory, wechatPay + + + + + +class 微信支付ViewSets( ViewSet ): + + + @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, # 【直连商户号】 直连商户号 + "out_trade_no": out_trade_no, # 【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。 + "appid": paymentCategory.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 ) + + + + @action( detail=False, methods=[ "post" ], url_path="navite" ) + def 二维码支付( self, request: WSGIRequest | Request ) -> Response: + """ + 生成收款的二维码链接,可以让用户来扫码支付 + :param request: + :return: + """ + out_trade_no = f"{generator.generate_id( )}" + native_body = { + "mchid": paymentCategory.mchid, # 服务商户号 + "out_trade_no": out_trade_no, # 商户系统内部订单号 + "appid": paymentCategory.appid, # 服务商应用ID + "description": "测试", # 商品的描述信息 + "notify_url": "https://server.xiao.band/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 ) + 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, ) + + + + @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 ) # 前端扫码读取的付款码的数据信息 + # auth_code = "123497182327333282" # TODO 扫码支付付款码,设备读取用户微信中的条码或者二维码信息(这个值需要小程序端,扫码,将数据传递进来) + # fu_kuan_data 是微信官方要求组装的数据类型 + fu_kuan_data = { + "appid": paymentCategory.appid, # 小程序的appid + "mch_id": paymentCategory.mchid, # 微信支付分配的商户号 + "nonce_str": nonce_str, # 随机字符串 + "out_trade_no": order_random, # 商户订单号 + "body": "test", + "auth_code": auth_code, + "total_fee": 1, # 订单总金额,单位为分,只能为整数,详见支付金额(必填) + } + 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_msg 通信返回信息:当 return_code 为 'FAIL' 时,此字段包含错误描述;成功时通常为 'OK' + 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" ) + # mch_id 商户号(MCH ID):微信支付分配给商户的唯一标识 + mch_id = jmespath.search( data=wechat_data, expression="xml.mch_id" ) + # appid 公众号或小程序的 AppID:发起支付的应用身份标识 + appid = jmespath.search( data=wechat_data, expression="xml.appid" ) + # 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" ) + # total_fee 订单总金额(单位:分):例如 '1' 表示 0.01 元 + 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" ) + # 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" ) + # 附加数据:商户在支付请求中可自定义传入,微信原样返回(常用于传递门店ID、商品类型等) + 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 ) + + + + @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 ) + + + + @action( detail=False, methods=[ "post" ], url_path="callback_navite" ) + def 二维码支付回调( self, request: WSGIRequest | 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="" ) diff --git a/wechat_接口/管理后端接口/用户角色权限接口.py b/wechat_接口/管理后端接口/用户角色权限接口.py new file mode 100644 index 0000000..af21ec3 --- /dev/null +++ b/wechat_接口/管理后端接口/用户角色权限接口.py @@ -0,0 +1,63 @@ +# from django.core.files.storage import default_storage +# from django.core.files.uploadedfile import InMemoryUploadedFile +# from django.core.handlers.wsgi import WSGIRequest +# from django.forms import model_to_dict +# 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 wechat_数据库.用户数据库.小程序登陆用户 import weiuser用户角色表choicesStatus +# +# +# class 用户角色管理接口ViewSets(ViewSet): +# @action(detail=False, methods=["get", "post", "put", "delete"], url_path="add_role") +# def 添加用户角色接口(self, request: Request): +# """ angular_permissions。""" +# try: +# pass +# self_mini_openid = request.data.get("self_mini_openid", None) +# self_mini_unionid = request.data.get("self_mini_unionid", None) +# weiuser用户角色表.objects.get_or_create(user用户的unionid=self_mini_unionid, user用户角色名称=weiuser用户角色表choicesStatus.推广员.value, ) +# httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "添加成功了"}), ).model_dump() +# return Response(data=httpResData, status=status.HTTP_200_OK) +# except Exception as e: +# pass +# httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() +# return Response(data=httpResData, status=status.HTTP_200_OK) +# +# @action(detail=False, methods=["get", "post", "put", "delete"], url_path="delete_role") +# def 删除用户角色接口(self, request: Request): +# """""" +# self_mini_openid = request.data.get("self_mini_openid", None) +# self_mini_unionid = request.data.get("self_mini_unionid", None) +# print("🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏", self_mini_unionid) +# httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() +# return Response(data=httpResData, status=status.HTTP_200_OK) +# +# @action(detail=False, methods=["get", "post", "put", "delete"], url_path="query_role") +# def 查询用户角色(self, request: Request): +# """""" +# self_mini_openid = request.data.get("self_mini_openid", None) +# self_mini_unionid = request.data.get("self_mini_unionid", None) +# +# print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 查询进来了") +# 用户角色状态 = weiuser用户角色表.objects.filter(user用户的unionid=self_mini_unionid, user用户角色名称=weiuser用户角色表choicesStatus.推广员.value).first() +# print(用户角色状态) +# if 用户角色状态 is None: +# # 这里表示用户角色不存在 +# httpResData = BaseResponse(resData=ResData(listData=[""], dictData={'idKey': '', 'user用户角色名称': '不是推广员', 'wai键用户表': ''}), ).model_dump() +# return Response(data=httpResData, status=status.HTTP_200_OK) +# if 用户角色状态 is not None: +# data = model_to_dict(instance=用户角色状态, fields=None) +# httpResData = BaseResponse(resData=ResData(listData=[""], dictData=data), ).model_dump() +# return Response(data=httpResData, status=status.HTTP_200_OK) +# httpResData = BaseResponse(resData=ResData(listData=[""], dictData={"demo": "xiaozizi"}), ).model_dump() +# return Response(data=httpResData, status=status.HTTP_200_OK) +# +# +# 用户角色管理接口ViewSetsDemoRouter = DefaultRouter() +# 用户角色管理接口ViewSetsDemoRouter.register(prefix="", viewset=用户角色管理接口ViewSets, basename="") diff --git a/wechat_接口/页面接口/分页接口.py b/wechat_接口/页面接口/分页接口.py new file mode 100644 index 0000000..0b9a653 --- /dev/null +++ b/wechat_接口/页面接口/分页接口.py @@ -0,0 +1,47 @@ +from rest_framework import status +from rest_framework.decorators import action +from rest_framework.pagination import PageNumberPagination +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 sixGuoDjango import BaseResponse, ResData + + +# 创建一个自定义分页器 +class CustomPagination(PageNumberPagination): + page_size = 10 # 默认每页显示10条 + page_size_query_param = 'page_size' # 允许客户端通过参数指定每页数量 + max_page_size = 100 # 最大每页数量限制 + page_query_param = 'page' # 页码参数名 + + +class 分页接口ViewSets(ViewSet): + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="xio") + def 分页器接口(self, request: Request): + """""" + # page_all = xiaozizi.objects.all( ) + + # 创建分页器实例 + paginator = CustomPagination() + + # 对查询集进行分页 + # paginated_data = paginator.paginate_queryset( queryset=page_all, request=request ) + + # 序列化数据 + # page_list_data = [ ] + # print( paginated_data ) + # for item in paginated_data: + # print( type( item ) ) + # print( model_to_dict( instance=item, fields=None ) ) + # page_list_data.append( model_to_dict( instance=item, fields=None ) ) + # listData = orjson.dumps(paginated_data, option=orjson.OPT_SORT_KEYS, ).decode(encoding="utf-8") + httpResData = BaseResponse( + resData=ResData(listData=[], dictData={"demo": "xiaozizi"}), ).model_dump() + return Response(data=httpResData, status=status.HTTP_200_OK) + + +分页接口ViewSetsRouter = DefaultRouter() +分页接口ViewSetsRouter.register(prefix="", viewset=分页接口ViewSets, basename="") diff --git a/wechat_接口/页面接口/首页.py b/wechat_接口/页面接口/首页.py new file mode 100644 index 0000000..351a915 --- /dev/null +++ b/wechat_接口/页面接口/首页.py @@ -0,0 +1,16 @@ +from django.core.handlers.wsgi import WSGIRequest +from django.http import HttpResponseRedirect +from django.shortcuts import render +from rest_framework.request import Request +from rest_framework.viewsets import ViewSet + + + + +class htmlViewSets( ViewSet ): + + + def home( self, request: WSGIRequest | Request ): + """""" + return render( request=request, template_name="xiao.html" ) + # return HttpResponseRedirect( redirect_to="https://www.qq.com/" ) diff --git a/wechat_数据库/企业微信数据库/企业微信标签数据库.py b/wechat_数据库/企业微信数据库/企业微信标签数据库.py new file mode 100644 index 0000000..5df01a9 --- /dev/null +++ b/wechat_数据库/企业微信数据库/企业微信标签数据库.py @@ -0,0 +1,25 @@ +from django.db import models +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class wecom企微用户标签(models.Model): + """城市信息表""" + objects = models.Manager() # + idKeywecom企微用户标签 = models.UUIDField(primary_key=True, default=uuid8) + id_str = models.CharField(max_length=128, default=generator.generate_str) + groupTag标签组ID = models.CharField(max_length=128, db_comment="标签组名") + groupTag标签组名 = models.CharField(max_length=128, db_comment="标签组名") + groupTag标签创建时间 = models.IntegerField() + tag子标签ID = models.CharField(max_length=128, ) + tag子标签名称 = models.CharField(max_length=128, ) + tag子标签创建时间 = models.IntegerField() + 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 = models_app_name + ordering = ["-dateAndTime", "-updateTime"] diff --git a/wechat_数据库/企业微信数据库/企业微信素材管理库.py b/wechat_数据库/企业微信数据库/企业微信素材管理库.py new file mode 100644 index 0000000..02fbac5 --- /dev/null +++ b/wechat_数据库/企业微信数据库/企业微信素材管理库.py @@ -0,0 +1,18 @@ +from django.db import models +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name + + +class wecom素材库(models.Model): + """城市信息表""" + objects = models.Manager() # + idKeywecom素材库 = models.UUIDField(primary_key=True, default=uuid8) + address = models.JSONField() + 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 = models_app_name + ordering = ["-idKeywecom素材库"] diff --git a/wechat_数据库/企业微信数据库/企微用户表.py b/wechat_数据库/企业微信数据库/企微用户表.py new file mode 100644 index 0000000..04a7ecb --- /dev/null +++ b/wechat_数据库/企业微信数据库/企微用户表.py @@ -0,0 +1,36 @@ +# 企微用户的数据表 +from django.db import models + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + +defautl_img = ( + "https://oss.fujugongxiang.com/six/%E7%A6%8F%E8%81%9A%E8%B4%A1%E7%BF%94%E5%B0%8F%E7%A8%8B%E5%BA%8F/home%E9%A1%B5%E9%9D%A2%E4%B8%BB%E5" + "%9B%BE/%E5%A4%B4%E5%83%8F.png") + + +class wecom企微用户(models.Model): + """城市信息表""" + objects = models.Manager() # + idKeyWecom企微用户 = models.CharField(primary_key=True, default=generator.generate_str, ) + wecom企微ID = models.CharField(max_length=128, ) + wecom企微状态State = models.CharField(max_length=128, default="", null=True) + wecom对好友打的标签 = models.JSONField(default=list, blank=True, null=True, ) # 'tag_id': [], + wecom对好友的备注名称 = models.CharField(max_length=128, ) # 'remark': '胡蝶', + wecom对好友的添加时间 = models.BigIntegerField(blank=True, null=True, ) # 时间戳类型 + wecom对好友的备注信息 = models.CharField(max_length=128, default="") + wecom企微对好友添加的手机号码 = models.JSONField(default=list, blank=True, null=True, ) # 'remark_mobiles': [], + wecom企微好友添加方式 = models.CharField(max_length=128, ) # 'oper_userid': 'wmj4zANAAAGqQ7gHSPJb3yUw_PW6bXCg' + wecom好友UNIONID = models.CharField(max_length=128, ) # 'unionid': 'oy4Jw6Lyfyj1VvgZFodzq9oqJzHE' + wecom好友昵称 = models.CharField(max_length=128, ) # 'name': '胡蝶', + wecom好友头像 = models.TextField(default="https://hudie.xiao.band/default_avacitve.jpeg") # 'avatar': 'http://wx.qlogo.cn/mmhead/hIz3ylFIYSibsiaymBicSrKXruslWCA0wcu9TNtnXbAeT8WpsthMVJfpj69h9bPHibC1NbFLzgUTnM0/0', + wecom好友性别 = models.CharField(max_length=128, ) + wecom好友的ID = models.CharField(max_length=128, ) # 'external_userid': 'wmj4zANAAAGqQ7gHSPJb3yUw_PW6bXCg', + wecom好友关系状态 = models.CharField(max_length=128, blank=True, null=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 = models_app_name + ordering = ["-dateAndTime", "-updateTime"] diff --git a/wechat_数据库/企业微信数据库/企微群数据库.py b/wechat_数据库/企业微信数据库/企微群数据库.py new file mode 100644 index 0000000..a8b219e --- /dev/null +++ b/wechat_数据库/企业微信数据库/企微群数据库.py @@ -0,0 +1,31 @@ +from django.db import models + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class wecom企微群(models.Model): + """城市信息表""" + objects = models.Manager() # + idKeyWecom企微群 = models.CharField(primary_key=True, default=generator.generate_str, ) + chat_id群 = models.CharField(max_length=128, ) + chat群名称 = models.CharField(max_length=128, blank=True, null=True, ) + chat群主ID = models.CharField(max_length=128, blank=True, null=True, ) + chat群成员外部好友external_userid = models.CharField(max_length=128, blank=True, null=True, ) + chat群成员外部好友unionid = models.CharField(max_length=128, blank=True, null=True, ) + chat群成员外部好友名称 = models.CharField(max_length=128, blank=True, null=True, ) # 如果是微信用户,则返回其在微信中设置的名字 + chat群成员外部好友群名称 = models.CharField(max_length=128, blank=True, null=True, ) + chat群成员外部好友类型 = models.IntegerField(blank=True, null=True, ) + # 1 - 由群成员邀请入群(直接邀请入群) 2 - 由群成员邀请入群(通过邀请链接入群) 3 - 通过扫描群二维码入群 + chat群成员外部好友加入方式 = models.IntegerField(blank=True, null=True, ) + chat群成员外部好友邀请者 = models.CharField(max_length=128, blank=True, null=True, ) # 邀请者目前仅当是由本企业内部成员邀请入群时会返回该值 + chat群管理员列表 = models.JSONField(default=list) + chat群创建时间 = models.IntegerField(blank=True, null=True, ) # 时间戳 + chat群成员加入时间 = models.IntegerField(blank=True, null=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 = models_app_name + ordering = ["-dateAndTime", "-updateTime"] diff --git a/wechat_数据库/企业微信数据库/推广二维码数据表.py b/wechat_数据库/企业微信数据库/推广二维码数据表.py new file mode 100644 index 0000000..442201d --- /dev/null +++ b/wechat_数据库/企业微信数据库/推广二维码数据表.py @@ -0,0 +1,29 @@ +from django.db import models +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name, weiuser +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class wecom推广码(models.Model): + """城市信息表""" + objects = models.Manager() # + idKey = models.UUIDField(primary_key=True, default=uuid8) + id_str = models.CharField(max_length=128, default=generator.generate_str) + codeConfigId = models.CharField(max_length=128, ) + codeType = models.IntegerField(blank=True, null=True, ) # 联系方式类型,1-单人, 2-多人 + codeQrCode = models.CharField(max_length=256, blank=True, null=True, ) # 二维码图片链接 + codeRemark = models.CharField(max_length=128, blank=True, null=True, ) # 备注的信息 + codeState = models.CharField(max_length=128, blank=True, null=True, ) # 唯一的值(重要) + codeUser = models.JSONField(blank=True, null=True, ) # 使用该联系方式的用户userID列表,在type为1时为必填,且只能有一个 + code省 = models.CharField(max_length=128, blank=True, null=True, ) + code市 = models.CharField(max_length=128, blank=True, null=True, ) + code区 = models.CharField(max_length=128, blank=True, null=True, ) + wai外键weiuser表 = models.ForeignKey(to=weiuser, on_delete=models.CASCADE, ) + 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 = models_app_name + ordering = ["-dateAndTime", "-updateTime"] diff --git a/wechat_数据库/地图定位/用户定位数据库.py b/wechat_数据库/地图定位/用户定位数据库.py new file mode 100644 index 0000000..012be0f --- /dev/null +++ b/wechat_数据库/地图定位/用户定位数据库.py @@ -0,0 +1,28 @@ +from django.db import models +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class weiuser地图定位(models.Model): + """城市信息表""" + objects = models.Manager() # + idKey = models.UUIDField(primary_key=True, default=uuid8) + id_str = models.CharField(max_length=128, default=generator.generate_str) + map用户uniond = models.CharField(max_length=128, ) + map用户openid = models.CharField(max_length=128, ) + map经度longitude = models.DecimalField(max_digits=10, decimal_places=6, blank=True, null=True, ) + map纬度latitude = models.DecimalField(max_digits=10, decimal_places=6, blank=True, null=True, ) + map省 = models.CharField(max_length=128, blank=True, null=True, ) + map市 = models.CharField(max_length=128, blank=True, null=True, ) + map区 = models.CharField(max_length=128, blank=True, null=True, ) + map街道 = models.CharField(max_length=128, blank=True, null=True, ) + map街道号码 = models.CharField(max_length=128, blank=True, null=True, ) + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "weiuser地图定位" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["dateAndTime", "updateTime"] diff --git a/wechat_数据库/地图定位/腾讯地图解析数据库.py b/wechat_数据库/地图定位/腾讯地图解析数据库.py new file mode 100644 index 0000000..40ff54c --- /dev/null +++ b/wechat_数据库/地图定位/腾讯地图解析数据库.py @@ -0,0 +1,22 @@ +from django.db import models +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class map地图IP转地址(models.Model): + """城市信息表""" + objects = models.Manager() # + id_map = models.UUIDField(primary_key=True, default=uuid8) + id_str = models.CharField(max_length=128, default=generator.generate_str) + map用户unionid = models.CharField(max_length=128, ) + map用户openid = models.CharField(max_length=128, ) + map解析结果 = models.JSONField() + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "map地图IP转地址" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["-id_map"] diff --git a/wechat_数据库/小程序后端数据库/订阅消息.py b/wechat_数据库/小程序后端数据库/订阅消息.py new file mode 100644 index 0000000..db732e2 --- /dev/null +++ b/wechat_数据库/小程序后端数据库/订阅消息.py @@ -0,0 +1,20 @@ +from django.db import models + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class miniSub订阅消息模板(models.Model): + """城市信息表""" + objects = models.Manager() # + idKey = models.CharField(primary_key=True, default=generator.generate_str, ) + sub订阅用户ID = models.CharField(max_length=128, ) # 小程序的openid + sub订阅次数 = models.IntegerField(default=0) + sub订阅模板ID = models.CharField(max_length=128, ) + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "miniSub订阅消息模板" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["dateAndTime", "updateTime"] diff --git a/wechat_数据库/支付数据库/商家转账数据库.py b/wechat_数据库/支付数据库/商家转账数据库.py new file mode 100644 index 0000000..702347f --- /dev/null +++ b/wechat_数据库/支付数据库/商家转账数据库.py @@ -0,0 +1,80 @@ +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 new file mode 100644 index 0000000..5dc80d0 --- /dev/null +++ b/wechat_数据库/支付订单数据库/商品订单数据.py @@ -0,0 +1,79 @@ +from django.db import models +from django.utils.translation import gettext_lazy +from uuid6 import uuid8 + +from django_定时器.幸运拼团数据库 import lucky拼团 +from wechat_数据库.洗衣液商品数据库.六果洗衣液商品 import goods商品Choices +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class order订单(models.Model): + """城市信息表""" + objects = models.Manager() # + + class order订单choosies物流状态(models.TextChoices): + 待发货 = "待发货", gettext_lazy("待发货") # 用户支付订单时的状态 + 待揽件 = "待揽件", gettext_lazy("待揽件") # 用户支付成功后的状态 + 已发货 = "已发货", gettext_lazy("已发货") # 物流状态变为 已揽件时的状态 + 已签收 = "已签收", gettext_lazy("已签收") # 物流状态变为 用户已签收时的状态 + 待评价 = "待评价", gettext_lazy("待评价") # 交易完成后 的状态 + 待收货 = "待收货", gettext_lazy("待收货") # 物流签收后, 小程序发出来的状态 + + id_主键_order订单 = models.UUIDField(primary_key=True, default=uuid8) + id_str = models.CharField(max_length=128, default=generator.generate_str) + order支付商家侧订单号 = models.CharField(max_length=128) + order支付微信官方订单号 = models.CharField(max_length=128, null=True, blank=True) + order支付者openid = models.CharField(max_length=128) + order支付者unionid = models.CharField(max_length=128) + order分享者unionid = models.CharField(max_length=128, default="六果") + wai外键lucky拼团表 = models.ForeignKey(to=lucky拼团, on_delete=models.CASCADE, blank=True, null=True, ) + # order商品ID = models.CharField( max_length=128, ) + order购物车商品数据 = models.JSONField(default=list, null=True, blank=True) + order购物车商品总价 = models.IntegerField() + order购物车商品数量 = models.IntegerField() + order支付数据 = models.JSONField(default=dict) + order支付状态 = models.CharField(max_length=128, default="支付中") + order用户配送地址 = models.JSONField(default=dict) + order物流状态 = models.CharField(max_length=128, blank=True, null=True, ) + order物流订单号 = models.CharField(max_length=128, blank=True, null=True, ) + order物流数据 = models.JSONField(default=dict) + order订单类型 = models.CharField(max_length=128, blank=True, null=True, ) + order物流公司订单编号 = models.CharField(max_length=128, blank=True, null=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 + 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..7cb9767 --- /dev/null +++ b/wechat_数据库/洗衣液商品数据库/六果洗衣液商品.py @@ -0,0 +1,79 @@ +from django.db import models +from django.utils.translation import gettext_lazy +from ulid import ULID +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name +from wechat_数据库.雪花算法.雪花算法工具 import generator + + + + + +class goods商品Choices( models.TextChoices ): + 幸运拼团 = "幸运拼团", gettext_lazy( "幸运拼团" ) + 商城商品 = "商城商品", gettext_lazy( "商城商品" ) + 赢免单 = "赢免单", gettext_lazy( "赢免单" ) + + + + +class goods商品( models.Model ): + """城市信息表""" + + objects = models.Manager( ) # + id_主键_goods商品 = models.UUIDField( primary_key=True, default=uuid8 ) + id_str = models.CharField( max_length=128, default=generator.generate_str ) + goods商品数据 = models.JSONField( ) + goods商品类型 = models.CharField( max_length=128, choices=goods商品Choices, + default=goods商品Choices.商城商品.value ) + dateAndTime = models.DateTimeField( auto_now_add=True, db_comment="创建时间" ) # 数据创建时间 + updateTime = models.DateTimeField( auto_now=True, db_comment="更新时间" ) # 更新时间(需要用 save() ) + + class Meta: + db_table = "goods商品" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = [ "dateAndTime", "updateTime" ] + + + + + +class Goods( models.Model ): + """城市信息表""" + objects = models.Manager( ) # + + idKey = models.UUIDField( primary_key=True, default=uuid8 ) + goods_id商品 = models.CharField( max_length=128, default=ULID) + goods_商品品牌 = models.CharField( max_length=128, ) + goods_商品标题 = models.CharField( max_length=128, ) + goods_商品信息 = models.JSONField( default=dict, null=True, blank=True ) + goods_商品标签 = models.JSONField( default=list, null=True, blank=True ) + goods_商品销售规格 = models.JSONField( null=True, blank=True, default=list ) + goods_商品销售场景 = models.CharField( max_length=128, choices=goods商品Choices, null=True, blank=True ) + goods_商品搜索标签 = models.JSONField( null=True, blank=True, default=list ) + goods_商家推荐标签 = models.JSONField( null=True, blank=True, default=list ) + goods_其它参数 = models.JSONField( 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 = "Goods" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + + + + + +if __name__ == "__main__": + pass + 洗衣液商品数据 = { + "商品销售参数": [ { "价格": 300, "会员价": 280, "销售规格": "8斤装" }, + { "价格": 500, "会员价": 380, "销售规格": "20斤装" }, ], + "销售数量": 1, + "商品标题": "六果香 8斤装(超划算) 源自天然酵素迅速渗入衣物,去除99种污渍🫟99%除菌🦠一洗即净,守护健康", + "商品信息参数": { + "品牌": "六果香", "净重": "8斤装", "香型": "熏衣草", + "洁净": "源自天然酵素迅速渗入衣物,去除99种污渍🫟", "除菌🦠": "99%除菌🦠,污渍菌螨,一洗即净,守护健康", + }, + } diff --git a/wechat_数据库/测试数据库/测试数据表.py b/wechat_数据库/测试数据库/测试数据表.py new file mode 100644 index 0000000..8dc8873 --- /dev/null +++ b/wechat_数据库/测试数据库/测试数据表.py @@ -0,0 +1,4 @@ +from django.db import models + + + diff --git a/wechat_数据库/用户数据库/__init__.py b/wechat_数据库/用户数据库/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wechat_数据库/用户数据库/小程序用户地址.py b/wechat_数据库/用户数据库/小程序用户地址.py new file mode 100644 index 0000000..ef2049c --- /dev/null +++ b/wechat_数据库/用户数据库/小程序用户地址.py @@ -0,0 +1,36 @@ +from django.db import models +from django.utils.translation import gettext_lazy +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name, weiuser +from wechat_数据库.雪花算法.雪花算法工具 import generator + + +class weiuser微信用户地址(models.Model): + """城市信息表""" + objects = models.Manager() # + + class choicesAddress(models.TextChoices): + 是默认地址 = "是默认地址", gettext_lazy("是默认地址") + 不是默认地址 = "不是默认地址", gettext_lazy("不是默认地址") + + # idKey = models.CharField(primary_key=True, default=generator.generate_str, ) + id_主键_配送地址 = models.UUIDField(primary_key=True, default=uuid8) + id_str = models.CharField(max_length=128, default=generator.generate_str) + mini_openid = models.CharField() + mini_unionid = models.CharField() + address = models.JSONField() + # key_weiuser = models.ForeignKey(to=weiuser, on_delete=models.SET_NULL, null=True,blank=True, ) ## 删除用户时,级联删除地址 + isDefaultAddress = models.CharField(choices=choicesAddress, max_length=120, ) + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "weiuser微信用户地址" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["-id_主键_配送地址", ] + + +if __name__ == "__main__": + pass + user = weiuser.objects.get(unionid="") diff --git a/wechat_数据库/用户数据库/小程序登陆用户.py b/wechat_数据库/用户数据库/小程序登陆用户.py new file mode 100644 index 0000000..9d8b3be --- /dev/null +++ b/wechat_数据库/用户数据库/小程序登陆用户.py @@ -0,0 +1,207 @@ +"""注释""" +from django.db import models +from uuid6 import uuid8 + +from wechat_数据库.雪花算法.雪花算法工具 import generator + +""" + 输入 :当前用户实例(self) + 输出 :包含所有下级用户的 扁平化列表 (多级结构被展开) + 递归逻辑 : +先获取当前用户的直接下级(通过 self.subordinates.all()) +对每个下级用户 递归调用自身,继续向下查找 +合并所有结果到一个列表中 +用户A +├─ 用户B +│ ├─ 用户C +│ └─ 用户D +└─ 用户E + +[用户B, 用户C, 用户D, 用户E] # 按深度优先顺序 +语法: wei = weiuser.objects.get(unionid="元宝零售") +print( wei.get_all_subordinates( ) ) +结果: [] + +""" +defautl_img = ( + "https://oss.fujugongxiang.com/six/%E7%A6%8F%E8%81%9A%E8%B4%A1%E7%BF%94%E5%B0%8F%E7%A8%8B%E5%BA%8F/home%E9%A1%B5%E9%9D%A2%E4%B8%BB%E5" + "%9B%BE/%E5%A4%B4%E5%83%8F.png") + +from django.utils.translation import gettext_lazy + +models_app_name = "django_app" + + +class weiuser用户角色表choicesStatus(models.TextChoices): + """商家转账订单状态""" + 推广员 = "推广员", gettext_lazy("推广员") + 企微员工 = "企微员工", gettext_lazy("企微员工") + 无状态 = "无状态", gettext_lazy("无状态") + 普通会员 = "普通会员", gettext_lazy("普通会员") + 六果科技有限公司 = "六果科技有限公司", gettext_lazy("六果科技有限公司") + 群好友 = "群好友", gettext_lazy("群好友") + + +class weiuser(models.Model): + """用户基础信息表""" + objects = models.Manager() # + + class ChoicesStatus(models.TextChoices): + """商家转账订单状态""" + 推广员 = "推广员", gettext_lazy("推广员") + 企微员工 = "企微员工", gettext_lazy("企微员工") + 无状态 = "无状态", gettext_lazy("无状态") + + unionid = models.CharField(primary_key=True, max_length=120) + user_角色权限 = models.CharField(choices=weiuser用户角色表choicesStatus, default=weiuser用户角色表choicesStatus.普通会员) + user_企微角色权限 = models.CharField(max_length=128, null=True, blank=True, ) + mini_openid = models.CharField(max_length=100, db_comment="自身id", null=True, blank=True, unique=True) + wechat_openid = models.CharField(max_length=100, db_comment="服务号自身id", null=True, blank=True, unique=True) + wecom_openid = models.CharField(max_length=100, db_comment="企微自身id", null=True, blank=True, unique=True) + external_userid = models.CharField(max_length=100, db_comment="外部联系人ID", null=True, blank=True, ) + uesr_手机号码 = models.CharField(null=True, blank=True, ) + user_昵称 = models.CharField(max_length=120, db_comment="用户的昵称", default="匿名用户") + user_头像 = models.CharField(max_length=245, db_comment="用户头像", + default="https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png") + user_用户当前的等级 = models.IntegerField(default=1, ) # 自身的等级 + user_省份 = models.CharField(max_length=128, null=True, blank=True, ) + user_城市 = models.CharField(max_length=128, null=True, blank=True, ) + user_区县 = models.CharField(max_length=128, null=True, blank=True, ) + user_街道信息 = models.CharField(max_length=128, null=True, blank=True, ) + user_绑定企微usrID账号 = models.CharField(max_length=128, null=True, blank=True, ) + user_绑定企微UNIONID = models.CharField(max_length=128, null=True, blank=True, ) + user_IP地址 = models.GenericIPAddressField(null=True, blank=True, ) + user_绑定用工关系 = models.CharField(max_length=128, null=True, blank=True, ) + codeConfigId = models.TextField(blank=True, null=True, ) # 企微的标签ID + codeQrCode = models.TextField(blank=True, null=True, ) # 企微的二维码 + codeRemark = models.TextField(blank=True, null=True, ) # 企微备注的信息 + parent = models.ForeignKey(to="self", on_delete=models.SET_NULL, related_name="children", null=True, + blank=True, ) # 模式:保护模式,有数据话是不能删除的; + add_time = models.DateTimeField(null=True, blank=True, db_comment="用户添加好友的时间") + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "weiuser" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name + ordering = ["-dateAndTime", "-updateTime"] + + def get_all_subordinates(self): + """递归获取所有下级(包括间接下级)""" + subs = [] + for sub in self.children.all(): + subs.append(sub) + subs.extend(sub.get_all_subordinates()) + return subs + + # ↓↓↓ 新增方法:获取所有上级(递归实现)↓↓↓ + def get_all_superiors(self): + """ + 返回列表格式:[直接上级, 上上级, 上上上级...] + """ + superiors = [] + # 递归终止条件:没有上级时停止 + if self.parent: + superiors.append(self.parent) + # 递归获取上级的上级 + superiors.extend(self.parent.get_all_superiors()) + return superiors + + def get_nth_level_superior(self, n): + """ + 获取第n级上级 + :param n: 上级层级 (1=直接上级, 2=上上级, 以此类推) + :return: Weiuser对象或None + """ + """ + 获取当前用户往上 n 级的父元素 + :param n: 要查询的上级层级数 (必须 >=1) + :return: weiuser 对象或 None (如果不存在) + """ + if n < 1: + raise ValueError("n 必须大于或等于 1") + + current = self + # 循环向上查询 n 次 + for _ in range(n): + if not current.parent: + return None # 没有父级时提前终止 + current = current.parent + return current + + """ + 这种实现方式更加简洁,但需要注意: + 它使用了链式递归调用,可能会增加递归深度 + 每次递归都会重新检查字段是否存在,虽然安全但效率稍低 + 性能考虑 + 对于树形结构操作,递归实现通常更简洁,但在实际应用中需要注意: + Python递归深度限制:默认1000层,可通过sys.setrecursionlimit()调整 + 性能开销:递归调用比循环有更高的开销 + 内存使用:递归会占用更多栈空间 + 在大多数实际应用中,树结构的深度不会超过100层,因此递归实现通常是可行的。但如果预期树结构会非常深(如超过1000层),建议使用循环实现或混合实现。 + """ + + def find_ancestor_by_field(self, field_name, target_value, include_self=False): + """ + 从当前用户向上查找,找到第一个指定字段等于目标值的祖先 + :param field_name: 要查找的字段名 + :param target_value: 目标值 + :param include_self: 是否包含自身 + :return: Weiuser对象或None + """ + # 验证字段名是否有效 - 修复方法 + if not hasattr(self, field_name): + raise ValueError(f"无效字段名: {field_name}") + + # 如果包含自身且满足条件,直接返回 + if include_self and getattr(self, field_name) == target_value: + return self + + # 向上遍历祖先 + current = self.parent + while current: + if getattr(current, field_name) == target_value: + return current + current = current.parent + return None + + def find查找指定的上级(self, field_name, target_value, include_self=False): + """ + 从当前用户向上查找,找到第一个指定字段等于目标值的祖先 + :param field_name: 要查找的字段名 + :param target_value: 目标值 + :param include_self: 是否包含自身 + :return: Weiuser对象或None + """ + # 验证字段名是否有效 - 修复方法 + if not hasattr(self, field_name): + raise ValueError(f"无效字段名: {field_name}") + + # 如果包含自身且满足条件,直接返回 + if include_self and getattr(self, field_name) == target_value: + return self + + # 向上遍历祖先 + current = self.parent + while current: + if getattr(current, field_name) == target_value: + return current + current = current.parent + return None + + +# class weiuser用户角色表(models.Model): +# """城市信息表""" +# objects = models.Manager() # +# idKeyweiuser用户角色表 = models.UUIDField(primary_key=True, default=uuid8) +# id_str = models.CharField(max_length=128, default=generator.generate_str) +# user用户角色名称 = models.CharField(max_length=128, choices=weiuser用户角色表choicesStatus, +# default=weiuser用户角色表choicesStatus.普通会员.value) +# user用户的unionid = models.CharField(max_length=128, ) +# dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 +# updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) +# +# class Meta: +# db_table = "weiuser用户角色表" # 给数据表自定义一个名称;默认的会是在 应用名+类名 +# app_label = models_app_name +# ordering = ["-dateAndTime", "-updateTime"] diff --git a/wechat_数据库/用户数据库/小程序积分数据库.py b/wechat_数据库/用户数据库/小程序积分数据库.py new file mode 100644 index 0000000..b7bda7c --- /dev/null +++ b/wechat_数据库/用户数据库/小程序积分数据库.py @@ -0,0 +1,48 @@ +from django.db import models +from django.utils.translation import gettext_lazy +from ulid import ULID +from uuid6 import uuid8 + +from wechat_数据库.用户数据库.小程序登陆用户 import models_app_name + + +class share积分类型choosies(models.TextChoices): + 商品详情分享群好友 = "商品详情分享群好友", gettext_lazy("商品详情分享群好友") + 幸运拼团分享 = "幸运拼团分享", gettext_lazy("幸运拼团分享") + 好友支付助力 = "好友支付助力", gettext_lazy("好友支付助力") + 每日签到 = "每日签到", gettext_lazy("每日签到") + 首次添加企微好友 = "首次添加企微好友", gettext_lazy("首次添加企微好友") + 推荐好友添加企微 = "推荐好友添加企微", gettext_lazy("推荐好友添加企微") + + +class share积分表(models.Model): + """城市信息表""" + objects = models.Manager() # + + id_主键 = models.UUIDField(primary_key=True, default=uuid8) + id_str = models.CharField(max_length=128, default=ULID) + share分享者unionid = models.CharField(max_length=128, ) + share分享者openid = models.CharField(max_length=128, blank=True, null=True, ) + share分享类型 = models.CharField(max_length=128, blank=True, null=True, ) + share分享者昵称 = models.CharField(max_length=128, blank=True, null=True, ) + share分享者头像 = models.TextField(blank=True, null=True, ) + share分享者积分值 = models.IntegerField(default=0) + share点击者unionid = models.CharField(max_length=128, blank=True, null=True, ) + share点击者openid = models.CharField(max_length=128, blank=True, null=True, ) + share点击者昵称 = models.CharField(max_length=128) + share点击者头像 = models.TextField(null=True, blank=True, ) + share分享的商品ID = models.CharField(null=True, blank=True, ) + share支付订单商家侧的订单号 = models.CharField(max_length=128, null=True, blank=True, ) + share支付用户提现状态 = models.CharField(max_length=128, null=True, blank=True, ) + share支付微信侧返回的提现状态 = models.CharField(max_length=128, null=True, blank=True, ) + share支付提现微信公司生成的转账数据 = models.JSONField(null=True, blank=True, default=dict) + share积分是否可以提现的状态 = models.CharField(null=True, blank=True, ) + + share日期 = models.DateField(blank=True, null=True) + share日期时间 = models.DateTimeField(blank=True, null=True, ) + dateAndTime = models.DateTimeField(auto_now_add=True, db_comment="创建时间") # 数据创建时间 + updateTime = models.DateTimeField(auto_now=True, db_comment="更新时间") # 更新时间(需要用 save() ) + + class Meta: + db_table = "share积分表" # 给数据表自定义一个名称;默认的会是在 应用名+类名 + app_label = models_app_name diff --git a/wechat_数据库/雪花算法/雪花算法工具.py b/wechat_数据库/雪花算法/雪花算法工具.py new file mode 100644 index 0000000..aee0d24 --- /dev/null +++ b/wechat_数据库/雪花算法/雪花算法工具.py @@ -0,0 +1,70 @@ +import threading +import time + + +class SnowflakeIDGenerator: + # 目标:总比特数约40位,十进制最多12位(2^40 ≈ 1.1e12) + # 时间戳用28位(可覆盖约8.5年),机器ID用6位(64台),序列号用6位(每毫秒64个) + TIMESTAMP_BITS = 28 + WORKER_ID_BITS = 6 + SEQUENCE_BITS = 6 + + # 起始时间戳(2025-01-01 00:00:00 UTC),单位毫秒 + CUSTOM_EPOCH = 1735689600000 + + MAX_WORKER_ID = -1 ^ (-1 << WORKER_ID_BITS) + MAX_SEQUENCE = -1 ^ (-1 << SEQUENCE_BITS) + + # 移位计算 + WORKER_ID_SHIFT = SEQUENCE_BITS + TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + + def __init__(self, worker_id, sequence=0): + if worker_id > self.MAX_WORKER_ID or worker_id < 0: + raise ValueError(f"Worker ID must be between 0 and {self.MAX_WORKER_ID}") + self.worker_id = worker_id + self.sequence = sequence + self.last_timestamp = -1 + self.lock = threading.Lock() + + def _wait_next_ms(self, last_ts): + ts = self._now() + while ts <= last_ts: + ts = self._now() + return ts + + def _now(self): + return int(time.time() * 1000) + + def generate_id(self): + with self.lock: + ts = self._now() + if ts < self.last_timestamp: + raise Exception("Clock moved backwards") + if ts == self.last_timestamp: + self.sequence = (self.sequence + 1) & self.MAX_SEQUENCE + if self.sequence == 0: + ts = self._wait_next_ms(self.last_timestamp) + else: + self.sequence = 0 + self.last_timestamp = ts + + # 相对时间(毫秒),只取低TIMESTAMP_BITS位 + relative_ts = (ts - self.CUSTOM_EPOCH) & ((1 << self.TIMESTAMP_BITS) - 1) + new_id = (relative_ts << self.TIMESTAMP_SHIFT) | \ + (self.worker_id << self.WORKER_ID_SHIFT) | \ + self.sequence + return new_id + + def generate_str(self): + return str(self.generate_id()) + + +# 全局生成器实例 (worker_id和datacenter_id需在分布式环境中保证唯一) +# 单机开发环境可暂时固定,生产环境建议通过配置中心或启动参数传入 +generator = SnowflakeIDGenerator(worker_id=1) + +if __name__ == "__main__": + print(generator.generate_id()) + print(type(generator.generate_id())) + print(generator.generate_str()) diff --git a/wechat_第三方接口/极兔物流/极兔快递业务.py b/wechat_第三方接口/极兔物流/极兔快递业务.py new file mode 100644 index 0000000..1a6ecc2 --- /dev/null +++ b/wechat_第三方接口/极兔物流/极兔快递业务.py @@ -0,0 +1,243 @@ +"""注释""" +import base64 +from datetime import datetime, time +from zoneinfo import ZoneInfo + +import jmespath +import orjson +import pydash +import requests +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 +from rest_framework.viewsets import ViewSet +from uuid6 import uuid8 + +from wechat_token.token工具包 import sixToken + + +class JiTu极名物流ViewSets(ViewSet): + biz_id = "J008610224928" + delivery_id = "JTSD" + # delivery_id = "TEST" + # service_name = "test_service_name" + service_name = "标准快递" + service_type = 0 + 发件人 = { + "name": "莫建海", # 发件人名称 + # "tel": "", + "mobile": "18081158055", + "company": "莫大帅科技有限公司", + "post_code": "610500", # 发/收件人邮编,不超过 10 字节 + "country": "中国", + "province": "四川省", + "city": "成都市", + "area": "新都区", + "address": "桂湖街道五桂村一社16号" + } + + @action(detail=False, methods=["post", ], url_path="获取所有绑定的物流账号") + def 获取所有绑定的物流账号(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/account/getall?access_token={mini_token}" + data = requests.get(url=uri) + return Response(data={"xiao": "get_xiao接口被调用了"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="生成运单") + def 生成运单(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/order/add?access_token={mini_token}" + afternoon_datetime = datetime.combine( + date=datetime.today(), time=time(15, 00), + tzinfo=ZoneInfo("Asia/Shanghai"), + ) + afternoon_datetime_int = int(afternoon_datetime.timestamp()) + receiver收件人信息 = { + "name": "元宝", # string 否 发/收件人姓名,不超过 64 字节 + # "tel": "020-88888888", # string 否 发/收件人座机号码,若不填写则必须填写 mobile,不超过32字节 + "mobile": "18860891975", # string 否 发/收件人手机号码,若不填写则必须填写 tel,不超过32字节 + # "company": "", # string 否 发/收件人公司名称,不超过64字节 + "post_code": "225300", # string 否 发/收件人邮编,不超过10字节 + "country": "中国", # string 否 发/收件人国家,不超过64字节 + "province": "江苏省", # string 否 发/收件人省份,比如:"广东省",不超过64字节 + "city": "泰州市", # string 否 发/收件人市/地区,比如:"广州市",不超过64字节 + "area": "海陵区", # string 否 发/收件人区/县,比如:"海珠区",不超过64字节 + "address": "西郊乡任景村603号" # string 否 发/收件人详细地址,比如:"XX路XX号XX大厦XX",不超过512字节 + } + cargo包裹信息 = { + "count": 2, # number 是 包裹数量, 默认为1 + "weight": 0.9, # number 是 货物总重量,比如1.2,单位是千克(kg) + "space_x": 30.5, # number 是 货物长度,比如20.0,单位是厘米(cm) + "space_y": 20, # number 是 货物宽度,比如15.0,单位是厘米(cm) + "space_z": 20, # number 是 货物高度,比如10.0,单位是厘米(cm) + "detail_list": [{"name": "商品名称", "count": 1}] + } + shop商品信息 = { + # 这里路由配置了,是当用户收到微信通知时, + "wxa_path": "/tabPage/Home/Home", # string 否 商家小程序的路径,建议为订单页面 + # "img_url": "", # img_urlstring 否 商品缩略图 url;shop.detail_list为空则必传,shop.detail_list非空可不传。 + # "goods_name": "", # string 否 商品名称, 不超过128字节;shop.detail_list为空则必传,shop.detail_list非空可不传。 + # "goods_count": "", # number 否 商品数量;shop.detail_list为空则必传。shop.detail_list非空可不传,默认取shop.detail_list的size + "detail_list": [ + { + "goods_name": "微信气泡狗抱枕(小号)", + "goods_img_url": "https://mmbiz.qpic.cn/mmbiz_png/OiaFLUqewuIDNQnTiaCInIG8ibdosYHhQHPbXJUrqYSNIcBL60vo4LIjlcoNG1QPkeH5GWWEB41Ny895CokeAah8A/640", + "goods_desc": "40cm * 40cm尺寸" + }, + { + "goods_name": "微信气泡狗抱枕(中号)", + "goods_img_url": "https://mmbiz.qpic.cn/mmbiz_png/OiaFLUqewuIDNQnTiaCInIG8ibdosYHhQHPbXJUrqYSNIcBL60vo4LIjlcoNG1QPkeH5GWWEB41Ny895CokeAah8A/640", + "goods_desc": "50cm * 50cm尺寸" + } + ], + + } + insured保价信息 = { + "use_insured": 0, # number 否 是否保价,0 表示不保价,1 表示保价 + # "insured_value": 100, # number 否 保价金额,单位是分,比如: 10000 表示 100 元 + } + service服务类型 = { + "service_type": self.service_type, # number 是 服务类型ID,详见已经支持的快递公司基本信息 + "service_name": self.service_name, # string 是 服务名称,详见已经支持的快递公司基本信息 + } + post_address_data = { + "add_source": 0, # number 是 订单来源,0为小程序订单,2为App或H5订单,填2则不发送物流服务通知 + "order_id": uuid8().hex, # string 是 订单ID,须保证全局唯一,不超过512字节 + "openid": "o6oV61xoMYAFNpi4RpVjn3BFGB1U", + "delivery_id": self.delivery_id, + "biz_id": self.biz_id, + "custom_remark": "易碎物品", # string 否 快递备注信息,比如"易碎物品",不超过 1024 字节 + "expect_time": afternoon_datetime_int, + # 预约收件时间Unix 时间戳, 单位秒,顺丰必须传。 预期的上门揽件时间,0表示已事先约定取件时间;否则请传预期揽件时间戳,需大于当前时间,收件员会在预期时间附近上门。 + "sender": self.发件人, + "receiver": receiver收件人信息, + "cargo": cargo包裹信息, + "shop": shop商品信息, + "insured": insured保价信息, + "service": service服务类型, + } + print(repr(receiver收件人信息["name"])) # 应该输出 '元宝',而不是 '\\u5143\\u5b9d' + print(post_address_data) + raw_text = orjson.dumps(post_address_data) + print(raw_text) + # 发起下订单的请求 + data = requests.post( + url=uri, data=orjson.dumps(post_address_data), + headers={"Content-Type": "application/json; charset=utf-8"}, + ) + print(orjson.loads(data.content.decode(encoding="utf-8"))) + # delivery_resultmsg = pydash.get(obj=data.json(), path="delivery_resultmsg") + # print(delivery_resultmsg.encode('latin-1').decode('utf-8')) + return Response(data={"message": "post_xiao接口被调用了啦"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post", ], url_path="取消运单") + def 取消运单(self, request: WSGIRequest | Request): + """ + + :param request: + :type request: + :return: + :rtype: + """ + pass + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/order/cancel?access_token={mini_token}" + post_data = { + "order_id": "019a071e892789c2a3c4a1de897f43a0", + "openid": "o6oV61xoMYAFNpi4RpVjn3BFGB1U", + "delivery_id": self.delivery_id, + "waybill_id": "JT0019529487771" + } + data = requests.post(url=uri, json=post_data) + print(data.json()) + return Response() + + @action(detail=False, methods=["post", ], url_path="获取电子面单余额") + def 获取电子面单余额(self, request: WSGIRequest | Request, *args, **kwargs): + """ + :param request: + :param args: + :param kwargs: + :return: + """ + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/quota/get?access_token={mini_token}" + post_data = { + "delivery_id": self.delivery_id, + "biz_id": self.biz_id + } + data = requests.post(url=uri) + print(orjson.loads(data.content.decode(encoding="utf-8"))) + return Response(data={"message": "xiao方法被调用了"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post", ], url_path="获取运单数据") + def 获取面单的HTML(self, request: WSGIRequest | Request, *args, **kwargs): + """ + :param request: + :param args: + :param kwargs: + :return: + """ + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/order/get?access_token={mini_token}" + post_data = { + "order_id": "019a07f5a4f88e45a8423f54bc0f4040", # string 是 订单 ID,需保证全局唯一 + "openid": "o6oV61xoMYAFNpi4RpVjn3BFGB1U", + # string 否 该参数仅在getOrder接口生效,batchGetOrder接口不生效。用户openid,当add_source=2时无需填写(不发送物流服务通知) + "delivery_id": self.delivery_id, # string 是 快递公司ID,参见getAllDelivery, 必须和waybill_id对应 + "waybill_id": "JT0019534640361", # string 否 运单ID + "print_type": 1 # number 否 该参数仅在getOrder接口生效,batchGetOrder接口不生效。获取打印面单类型【1:一联单,0:二联单】,默认获取二联单 + } + data = requests.post(url=uri, data=orjson.dumps(post_data).decode()) + print_html = pydash.get(obj=orjson.loads(data.content.decode(encoding="utf-8")), path="print_html") + print(base64.b64decode(print_html)) + html = base64.b64decode(print_html).decode(encoding="utf-8") + return Response(data={"message": html}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["post", ], url_path="查询运单轨迹") + def 查询运单轨迹(self, request: WSGIRequest | Request, *args, **kwargs): + """ + :param request: + :param args: + :param kwargs: + :return: + """ + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/path/get?access_token={mini_token}" + print("轨迹查询") + waybill_id = request.data.get("waybill_id", ) # + idOrders = request.data.get("idOrders", False) # + self_mini_openid = request.data.get("self_mini_openid", False) # + print("在这里确认一下订单号是多少", waybill_id) + post_data = { + "order_id": idOrders, + "openid": self_mini_openid, + "delivery_id": self.delivery_id, + "waybill_id": waybill_id + } + data = requests.post(url=uri, json=post_data) + messageData = orjson.loads(data.content.decode(encoding="utf-8")) + print(messageData) + path_item_list = jmespath.search(expression="path_item_list", data=messageData, ) + waybill_id = jmespath.search(expression="waybill_id", data=messageData, ) + for path in path_item_list: + action_type = path.get("action_type") + if action_type == 300003: + pass + # Orders.objects.filter(order_wuliu_number=waybill_id, order_wuliu_status=Orders.OrdersStatus.运输中).update(order_wuliu_status=Orders.OrdersStatus.已签收) + return Response(data={"message": messageData}, status=status.HTTP_200_OK) + + +JiTu极名物流ViewSetsRouter = SimpleRouter() +JiTu极名物流ViewSetsRouter.register(prefix="", viewset=JiTu极名物流ViewSets, basename="JiTu极名物流ViewSets") diff --git a/wechat_第三方接口/蕊烨打印机/蕊烨打印机管理.py b/wechat_第三方接口/蕊烨打印机/蕊烨打印机管理.py new file mode 100644 index 0000000..3489b61 --- /dev/null +++ b/wechat_第三方接口/蕊烨打印机/蕊烨打印机管理.py @@ -0,0 +1,48 @@ +import hashlib +from datetime import datetime +from zoneinfo import ZoneInfo + +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.routers import DefaultRouter +from rest_framework.viewsets import ViewSet + +from sixGuoDjango import BaseResponse, ResData + + + + + +class 蕊烨打印机接口ViewSets( ViewSet ): + user: str = "792282@qq.com" # 注册的账号 + user_key: str = "bcdfac0dfdf444b8a4539fcc7dea905c" # 生成的密钥 + sn: str = "30MYD1UMLT0B448" # 打印机机身的SN码 + + @action( detail=False, methods=[ "get", "post", "put", "delete" ], url_path="lable" ) + def 打印标签订单有胶水的( self, request: Request ): + """""" + timestamp = str( int( datetime.now( tz=ZoneInfo( "Asia/Shanghai" ) ).timestamp( ) ) ) + 签名字符串 = f"{self.user}{self.user_key}{timestamp}" + sign = hashlib.sha1( data=签名字符串.encode( encoding="utf-8" ), ).hexdigest( ) + json_data = { + "sn": self.sn, + "content": """""", + "copies": 1, + "voice": 2, + "user": self.user, + "timestamp": timestamp, + "sign": sign, + } + printData = requests.post( url="https://open.xpyun.net/api/openapi/xprinter/printLabel", json=json_data ) + httpResData = BaseResponse( resData=ResData( listData=[ "" ], dictData={ "demo": "xiaozizi" } ), ).model_dump( ) + return Response( data=httpResData, status=status.HTTP_200_OK ) + + + + + +蕊烨打印机接口ViewSetsRouter = DefaultRouter( ) +蕊烨打印机接口ViewSetsRouter.register( prefix="", viewset=蕊烨打印机接口ViewSets, basename="蕊烨打印机接口ViewSets" ) diff --git a/wechat_第三方接口/顺丰物流/顺丰业务接口.py b/wechat_第三方接口/顺丰物流/顺丰业务接口.py new file mode 100644 index 0000000..c7d56c7 --- /dev/null +++ b/wechat_第三方接口/顺丰物流/顺丰业务接口.py @@ -0,0 +1,162 @@ +import datetime + +import jmespath +import orjson +import requests +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 +from rest_framework.viewsets import ViewSet + +from wechat_第三方接口.顺丰物流.顺丰参数 import sfToken + + +class SF顺丰业务接口ViewSets(ViewSet): + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="order_create") + def 快递下订单接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + print('============') + + requestID = f"SF{datetime.date.strftime(datetime.datetime.now(), format="%Y%m%d%H%M%S%f")}" + + accessToken = sfToken() + 沙箱环境 = f"https://sfapi-sbox.sf-express.com/std/service" + sftimestamp = str(int(datetime.datetime.now().timestamp())) + cargoDetails托寄物信息 = [{"name": "物品", "count": 1}] + 寄件人 = { + "contactType": 1, + "company": "1", + "contact": "元宝", + "mobile": "13800138000", + "country": "CN", + "province": "江苏省", + "city": "泰州市", + "county": "海陵区", + "address": "城西街道任景路603号" + } + 收件人 = { + "contactType": 2, + "company": "2", + "contact": "大帅", + "mobile": "13800138001", + "country": "CN", + "province": "四川省", + "city": "成都市", + "county": "新都区", + "address": "桂湖街道一社16号" + } + msgData = { + # 响应报文的语言,缺省值为zh-CN + "language": "zh-CN", + "parcelQty": 1, + # 客户订单号,重复使用订单号时返回第一次下单成功时的运单信息 + "orderId": f"SFOD{datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d%H%M%S%f")}", + # 托寄物信息 + "cargoDetails": cargoDetails托寄物信息, + "contactInfoList": [寄件人, 收件人], + "isReturnRoutelabel": 1, + "isGenWaybillNo": 1, + "payMethod": 1, + "isDocall": 0, + "monthlyCard": "7551234567" + } + formData = { + "serviceCode": "EXP_RECE_CREATE_ORDER", + "accessToken": accessToken, + "timestamp": sftimestamp, + "partnerID": "MDSKJJ1KDLJN", + "requestID": requestID, + "msgData": orjson.dumps(msgData).decode(encoding="utf-8") + } + response_data = requests.post( + url=沙箱环境, data=formData, + headers={"Content-Type": "application/x-www-form-urlencoded", }, + ) + apiResultData = jmespath.search(data=response_data.json(), expression="apiResultData") + return Response(data=orjson.loads(apiResultData), status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="order_update") + def 订单确认取消接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + uri = f"https://sfapi-sbox.sf-express.com/std/service" + accessToken = sfToken() + sftimestamp = str(int(datetime.datetime.now().timestamp())) + requestID = datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d%H%M%S%f") + msgData = { + "dealType": 1, + "orderId": "SFOD20251126214101523682", + # "totalHeight": 29.98, + # "totalLength": 29.98, + # "totalVolume": 26946.035992000005, + # "totalWeight": 2.09, + # "totalWidth": 29.98, + "waybillNoInfoList": [ + { + "waybillNo": "SF7444700285553", + "waybillType": 1 + } + ] + } + formData = { + "serviceCode": "EXP_RECE_UPDATE_ORDER", + "accessToken": accessToken, + "timestamp": sftimestamp, + "partnerID": "MDSKJJ1KDLJN", + "requestID": requestID, + "msgData": orjson.dumps(msgData).decode(encoding="utf-8") + } + response_data = requests.post( + url=uri, data=formData, + headers={"Content-Type": "application/x-www-form-urlencoded", "charset": "UTF-8"}, + ) + print(response_data.json(), "=========") + res = response_data.json() + apiResultData = jmespath.search(data=res, expression="apiResultData") + apiResultData = orjson.loads(apiResultData) + return Response(data=apiResultData, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="order_search_resp") + def 订单结果查询接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + uri = f"https://sfapi-sbox.sf-express.com/std/service" + accessToken = sfToken() + sftimestamp = str(int(datetime.datetime.now().timestamp())) + requestID = datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d%H%M%S%f") + msgData = { + "searchType": "1", + "orderId": "SFOD20251126214101523682", + "language": "zh-cn" + } + formData = { + "serviceCode": "EXP_RECE_SEARCH_ORDER_RESP", + "accessToken": accessToken, + "timestamp": sftimestamp, + "partnerID": sfID, + "requestID": requestID, + "msgData": orjson.dumps(msgData).decode(encoding="utf-8") + } + response_data = requests.post( + url=uri, data=formData, + headers={"Content-Type": "application/x-www-form-urlencoded", "charset": "UTF-8"}, + ) + res = response_data.json() + apiResultData = jmespath.search(data=res, expression="apiResultData") + apiResultData = orjson.loads(apiResultData) + return Response(data=apiResultData, status=status.HTTP_200_OK) + + +SF顺丰业务接口ViewSetsRouter = SimpleRouter() +SF顺丰业务接口ViewSetsRouter.register(prefix="", viewset=SF顺丰业务接口ViewSets, basename="") diff --git a/wechat_第三方接口/顺丰物流/顺丰参数.py b/wechat_第三方接口/顺丰物流/顺丰参数.py new file mode 100644 index 0000000..66042c3 --- /dev/null +++ b/wechat_第三方接口/顺丰物流/顺丰参数.py @@ -0,0 +1,22 @@ +import pydash +import requests +from furl import furl + +sfID = "MDSKJJ1KDLJN" +sfCode沙箱码 = "ligo0CNwIN8HLP8kmEguzFRJqpLtsvkQ" +sfCode生产环境 = "lxfzgUcYCsVbVaZXFCpN2N6jPnfWYjrs" +顺风回调路由 = furl(url=f"https://wecom.fujugongxiang.com/sf/sf_callback/").url + + +def sfToken(): + tokneUri = f"https://sfapi-sbox.sf-express.com/oauth2/accessToken" + + response_data = requests.post(url=tokneUri, data={"partnerID": sfID, "secret": sfCode沙箱码}) + print(response_data.json()) + accessToken = pydash.get(obj=response_data.json(), path="accessToken") + apiResponseID = pydash.get(obj=response_data.json(), path="apiResponseID") + return accessToken + + +if __name__ == "__main__": + pass diff --git a/wechat_第三方接口/顺丰物流/顺丰推送接口.py b/wechat_第三方接口/顺丰物流/顺丰推送接口.py new file mode 100644 index 0000000..ecd040d --- /dev/null +++ b/wechat_第三方接口/顺丰物流/顺丰推送接口.py @@ -0,0 +1,102 @@ +import datetime + +import jmespath +import orjson +import requests +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 +from rest_framework.viewsets import ViewSet + +from wechat_第三方接口.顺丰物流.顺丰参数 import sfToken + + +class SF推送ViewSets(ViewSet): + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="push_router") + def 路由推送接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + print('路由推送接口', request.data) + return Response(data={"xiao": "get_xiao接口被调用了"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="pushorderstate") + def 订单状态推送接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + print(request) + postparams = request.data + print(postparams, "订单状态推送接口") + return Response(data={"message": "post_xiao接口被调用了啦"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="push_fee") + def 清单运费推送接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + print("清单运费推送接口", request.data) + return Response(data={"message": "post_xiao接口被调用了啦"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="push_img") + def 图片注册及推送接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + postparams = request.data.get("postparams", False) # + print(request.data, "图片注册推送接口") + return Response(data={"message": "post_xiao接口被调用了啦"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="push_subsidy") + def 国补通知推送接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + return Response(data={"message": "post_xiao接口被调用了啦"}, status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", ], url_path="push_register") + def 路由注册接口(self, request: WSGIRequest | Request): + """ + :param request: + :return: + """ + uri = f"https://sfapi-sbox.sf-express.com/std/service" + accessToken = sfToken() + sftimestamp = str(int(datetime.datetime.now().timestamp())) + requestID = datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d%H%M%S%f") + msgData = { + "attributeNo": "SF7444700293847", # 订单号或者运单号 + "type": "2", # 1-按订单号注册, 2-按运单号注册 + "checkPhoneNo": "9784", # 电话号码后四位 + "orderId": "SFOD20251127113410676181", + # "clientIp": "10.118.92.11", + "language": "zh-CN", # 响应报文的语言, 缺省值为zh-CN, + "country": "CN" # 国家编码 + } + formData = { + "serviceCode": "EXP_RECE_REGISTER_ROUTE", + "accessToken": accessToken, + "timestamp": sftimestamp, + "partnerID": "MDSKJJ1KDLJN", + "requestID": requestID, + "msgData": orjson.dumps(msgData).decode(encoding="utf-8") + } + response_data = requests.post(url=uri, data=formData, + headers={"Content-Type": "application/x-www-form-urlencoded", "charset": "UTF-8"}) + print(response_data.json(), "=========") + res = response_data.json() + apiResultData = jmespath.search(data=res, expression="apiResultData") + apiResultData = orjson.loads(apiResultData) + return Response(data=apiResultData, status=status.HTTP_200_OK) + + +SF推送ViewSetsRouter = SimpleRouter() +SF推送ViewSetsRouter.register(prefix="", viewset=SF推送ViewSets, basename="SF推送ViewSets") diff --git a/wechat_项目工具包/EMS中国邮政/ems邮政.py b/wechat_项目工具包/EMS中国邮政/ems邮政.py new file mode 100644 index 0000000..aa21b1b --- /dev/null +++ b/wechat_项目工具包/EMS中国邮政/ems邮政.py @@ -0,0 +1,302 @@ +from typing import Literal, Optional + +import emoji +import orjson +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 +from wechat_数据库.支付订单数据库.商品订单数据 import order订单 +from wechat_项目工具包.小程序交易管理服务.小程序交易订单管理工具 import miniTransaction交易管理服务工具 + + +class ems_parameters物流的状态(BaseModel): + demo_必填: int = Field(..., description="描述") # 必传属发生 + demo_可选: Optional[int] = None # 可选值 + demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + 揽件成功: str = Field("揽件成功", description="描述") + 揽件失败: str = Field("揽件失败", description="描述") + 分配业务员: str = Field("分配业务员", description="分配业务员") + 更新运输轨迹: str = Field("更新运输轨迹", description="更新运输轨迹") + 开始派送: str = Field("开始派送", description="开始派送") + 签收成功: str = Field("签收成功", description="签收成功") + 签收失败: str = Field("签收失败", description="签收失败") + 订单取消: str = Field("订单取消", description="订单取消") + 订单滞留: str = Field("订单滞留", description="订单滞留") + + +class ems邮政物流工具(BaseModel): + # ems_biz_id: str = "1100244903172" + # ems_delivery_id: str = "EMS" + ems_password: str = "xiao@792282" + ems_biz_id: str = Field("test_biz_id", description="ems_biz_id") + ems_delivery_id: str = Field("TEST", description="ems_biz_id") + + def ems发件人信息(self): + ems发件人信息数据 = { + "name": "六果泡泡", # 否 发/收件人姓名,不超过64字节 + "tel": "18860891975", # string 否 发/收件人座机号码,若不填写则必须填写 mobile,不超过32字节 + "mobile": "18860891970", # string 否 发/收件人手机号码,若不填写则必须填写 tel,不超过32字节 + "company": "江苏六果科技有限公司", # string 否 发/收件人公司名称,不超过64字节 + "post_code": "225300", # string 否 发/收件人邮编,不超过10字节 + "country": "中国", # string 否 发/收件人国家,不超过64字节 + "province": "江苏省", # string 否 发/收件人省份,比如:"广东省",不超过64字节 + "city": "泰州市", # string 否 发/收件人市/地区,比如:"广州市",不超过64字节 + "area": "海陵区", # string 否 发/收件人区/县,比如:"海珠区",不超过64字节 + "address": "", # string 否 发/收件人详细地址,比如:"XX路XX号XX大厦XX",不超过512 字节 + } + return ems发件人信息数据 + + def ems收件人信息(self, order物流商家侧订单号): + 订单对象 = order订单.objects.get(order物流订单号=order物流商家侧订单号) + orderData = model_to_dict(instance=订单对象, fields=None) + provinceName = pydash.get(obj=orderData, path="order用户配送地址.address.provinceName") + cityName = pydash.get(obj=orderData, path="order用户配送地址.address.cityName") # 市 + countyName = pydash.get(obj=orderData, path="order用户配送地址.address.countyName") # 区 + detailInfoNew = pydash.get(obj=orderData, path="order用户配送地址.address.detailInfoNew") # 详细地址 + telNumber = pydash.get(obj=orderData, path="order用户配送地址.address.telNumber") # 详细地址 + detailInfo = pydash.get(obj=orderData, path="order用户配送地址.address.detailInfo") # 详细地址 + userName = pydash.get(obj=orderData, path="order用户配送地址.address.userName") # 详细地址 + nationalCode = pydash.get(obj=orderData, path="order用户配送地址.address.nationalCode") # 详细地址 + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", telNumber) + return { + "name": userName, # 否 发/收件人姓名,不超过64字节 + "tel": telNumber, # string 否 发/收件人座机号码,若不填写则必须填写 mobile,不超过32字节 + "mobile": telNumber, # string 否 发/收件人手机号码,若不填写则必须填写 tel,不超过32字节 + "company": "", # string 否 发/收件人公司名称,不超过64字节 + "post_code": nationalCode, # string 否 发/收件人邮编,不超过10字节 + "country": "中国", # string 否 发/收件人国家,不超过64字节 + "province": provinceName, # string 否 发/收件人省份,比如:"广东省",不超过64字节 + "city": cityName, # string 否 发/收件人市/地区,比如:"广州市",不超过64字节 + "area": countyName, # string 否 发/收件人区/县,比如:"海珠区",不超过64字节 + "address": detailInfoNew, # string 否 发/收件人详细地址,比如:"XX路XX号XX大厦XX",不超过512 字节 + } + + def cargo包裹信息(self): + return { + "count": 1, # number 是 包裹数量, 默认为1 + "weight": 4, # number 是 货物总重量,比如1.2,单位是千克(kg) + "space_x": 1, # number 是 货物长度,比如20.0,单位是厘米(cm) + "space_y": 1, # number 是 货物宽度,比如15.0,单位是厘米(cm) + "space_z": 1, # number 是 货物高度,比如10.0,单位是厘米(cm) + "detail_list": [ + { + "name": "商品名称", # string 是 商品名,不超过128字节 + "count": 1, # number 是 商品数量 + }, + ], + } + + def shop商品信息(self, order物流商家侧订单号): + 订单对象 = order订单.objects.get(order物流订单号=order物流商家侧订单号) + orderData = model_to_dict(instance=订单对象, fields=None) + 购物车商品列表 = pydash.get(obj=orderData, path="order购物车商品数据") + detail_list = [] + for goods in 购物车商品列表: + detail_list.append( + { + "goods_name": emoji.replace_emoji(pydash.get(obj=goods, path="goods_商品标题")), + "goods_img_url": pydash.get(obj=goods, path="goods_sku_主图"), + "goods_desc": emoji.replace_emoji(pydash.get(obj=goods, path="goods_商品品牌")), + }, + ) + goods_count = pydash.get(obj=orderData, path="order购物车商品数量") + shop商品信息数据 = { + # "wxa_path": "/pages/OrderPages/OrderPages", # string 否 商家小程序的路径,建议为订单页面 + # "img_url": "", # string 否 商品缩略图 url;shop.detail_list为空则必传,shop.detail_list非空可不传。 + # "goods_name": "", # string 否 商品名称, 不超过128字节;shop.detail_list为空则必传,shop.detail_list非空可不传。 + # goods_count 否 商品详情列表,适配多商品场景,用以消息落地页展示。(新规范,新接入商家建议用此字段) + "goods_count": goods_count, # 商品数量;shop.detail_list为空则必传。shop.detail_list非空可不传,默认取shop.detail_list的size + "detail_list": detail_list, + } + return shop商品信息数据 + + def insured保价信息(self): + insured保价信息数据 = { + "use_insured": 0, # number 否 是否保价,0 表示不保价,1 表示保价 + "insured_value": 0, # number 否 保价金额,单位是分,比如: 10000 表示 100 元 + } + return insured保价信息数据 + + def service服务类型(self): + service服务类型数据 = { + "service_type": 6, # number 是 服务类型ID,详见已经支持的快递公司基本信息 + "service_name": "标准快递", # string 是 服务名称,详见已经支持的快递公司基本信息 + } + return service服务类型数据 + + def 生成最终完整的数据(self, order物流商家侧订单号): + 订单对象 = order订单.objects.get(order物流订单号=order物流商家侧订单号) + 收件人openid = 订单对象.order支付者openid + 完整数据 = { + "add_source": 0, # 订单来源,0为小程序订单,2为App或H5订单,填2则不发送物流服务通知 + "order_id": order物流商家侧订单号, + "openid": 收件人openid, # 是 用户openid,当add_source=2时无需填写(不发送物流服务通知) + "delivery_id": self.ems_delivery_id, # 是 快递公司ID, + "biz_id": self.ems_biz_id, # 快递客户编码或者现付编码 + "sender": self.ems收件人信息(order物流商家侧订单号=order物流商家侧订单号), # 收件人的信息 + "receiver": self.ems发件人信息(), # 发件人的信息 + "shop": self.shop商品信息(order物流商家侧订单号=order物流商家侧订单号), # 商品的信息 + "cargo": self.cargo包裹信息(), # 包果的信息 + "insured": self.insured保价信息(), # 保价信息 + "service": self.service服务类型(), # 服务类型 + } + return 完整数据 + + def 绑定账号(self): + """请求接口,通过接口来实现绑定物流的账号, 也可以在小程序的管理后台来操作""" + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/account/bind?access_token={mini_token}" + ems数据 = { + "type": "bind", + "biz_id": "1100244903172", + "delivery_id": "EMS", + "password": "xiao@792282", + } + data = requests.post(url=uri, json=ems数据) + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json()) + + def 获取支持的快递公司列表(self, ): + """请求接口,可以查询当前支持的物流公司列表""" + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/delivery/getall?access_token={mini_token}" + data = requests.get(url=uri, ) + emdData = orjson.loads(data.content.decode(encoding="utf-8")) + print(emdData) + + def 获取所有绑定的物流账号(self, ): + """请求接口,可以查询所有小程序已经绑定的物流账号""" + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/cgi-bin/express/business/account/getall?access_token={mini_token}" + data = requests.get(url=uri) + print(orjson.loads(data.content.decode(encoding="utf-8"))) + + def 生成运单(self, out_trade_no商家侧支付订单号: str): + """在实际项目中,这里的不是需要自己生成的""" + # 需要的参数 + order订单对象 = order订单.objects.get(order支付商家侧订单号=out_trade_no商家侧支付订单号) + print(order订单对象.order物流订单号) + res = self.生成最终完整的数据(order物流商家侧订单号=order订单对象.order物流订单号) + mini_token = sixToken.get_mini_token() + 运单请求接口 = f"https://api.weixin.qq.com/cgi-bin/express/business/order/add?access_token={mini_token}" + json_完整的数据 = orjson.dumps(res).decode(encoding="utf-8") + + data = requests.post(url=运单请求接口, data=json_完整的数据, headers={"Content-Type": "application/json; charset=utf-8"}) + waybill_id = pydash.get(obj=data.json(), path="waybill_id") + order当前订单对象 = order订单.objects.get(order支付商家侧订单号=out_trade_no商家侧支付订单号, ) # 拿到当前的订单号生成的订单对象 + order当前订单对象.order物流订单号 = order订单对象.order物流订单号 + order当前订单对象.order物流公司订单编号 = waybill_id + order当前订单对象.save() + print(data.json()) + # 这里的作用是, 当订单生成了 就调用 小程序交易管理的发货管理接口, 自动录入订单号 + mini调用微信小程序交易管理服务录入订单接口.apply_async(kwargs={"order支付商家侧订单号": order当前订单对象.order支付商家侧订单号}, countdown=30) + + def 模拟更新订单状态(self, 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}" + 模拟数据 = { + "biz_id": self.ems_biz_id, + "order_id": order物流商家侧订单号, # 商家生成的订单号 + "delivery_id": self.ems_delivery_id, # + "waybill_id": "", # 物流订单号 + "action_time": milliseconds_int, # 这里是更新发的时间戳 + "action_type": 100001, + "action_msg": "揽件成功", + } + 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(查询对象) + + def 更新物流快递数据(self, order物流公司订单编号, order物流订单号): + """""" + 查询对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号, 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物流公司订单编号, + }, + ) + resData = orjson.loads(emsGetPathData.content.decode(encoding="utf-8")) + print("请求物流更新接口返回数据", resData) + # 根据实时的状态,来更新当前的物流状态 + action_type = pydash.get(obj=resData, path="path_item_list.0.action_type") + path_item_list = pydash.get(obj=resData, path="path_item_list") + if action_type == 100001: + # 100001 揽件阶段-揽件成功 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "揽件成功" + 查询对象.save() + if action_type == 100002: + # 100002 揽件阶段-揽件失败 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "揽件失败" + 查询对象.save() + if action_type == 100003: + # 100003 揽件阶段-分配业务员 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "分配业务员" + 查询对象.save() + if action_type == 200001: + # 200001 运输阶段-更新运输轨迹 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "更新运输轨迹" + 查询对象.save() + if action_type == 300002: + # 300002 派送阶段-开始派送 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "开始派送" + 查询对象.save() + if action_type == 300003: + # 300003 派送阶段-签收成功 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "签收成功" + 查询对象.save() + # 当用户确认签收以后: 调用微信交易管理服务,推送用户确认的通知 + miniTransaction交易管理服务工具().确认收货提醒(order支付微信官方订单号=查询对象.order支付微信官方订单号, order物流数据=path_item_list) + if action_type == 300004: + # 300004 派送阶段-签收失败 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "签收失败" + 查询对象.save() + if action_type == 400001: + # 400001 异常阶段-订单取消 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "订单取消" + 查询对象.save() + if action_type == 400002: + # 400002 异常阶段-订单滞留 + 查询对象.order物流数据 = resData + 查询对象.order物流状态 = "订单滞留" + 查询对象.save() + + def 确认收货(self, order支付微信侧订单号): + """调用的时机为: 微信小程序官方的消息推送, 当用户确认了收货 或者 时间到了自动确认时,会调用,主要就是更新 下单商品的状态 """ + 订单更新对象 = order订单.objects.get(order支付微信官方订单号=order支付微信侧订单号) + 订单更新对象.order物流状态 = "已确认" + 订单更新对象.save() + # 备注一下返回数据类型 + responseDataa = {'ToUserName': 'gh_f754c53eb962', 'FromUserName': 'ohQkD7HmLYEYrFjFau6juOhduRU8', 'CreateTime': 1784666355, 'MsgType': 'event', 'Event': 'trade_manage_order_settlement', + 'transaction_id': '4200003114202607213777723688', 'merchant_id': '1700383419', 'sub_merchant_id': '', 'merchant_trade_no': 'OAT01KY1BZ3T9SFSSRNS10R95B5XH', 'pay_time': 1784605024, + 'shipped_time': 1784666354, + 'estimated_settlement_time': 1784839154 + } + + +if __name__ == "__main__": + # 当脚本直接运行时执行的代码 + ems邮政物流工具().生成运单(out_trade_no商家侧支付订单号="") diff --git a/wechat_项目工具包/企业微信工具包/企业推广二维码接口.py b/wechat_项目工具包/企业微信工具包/企业推广二维码接口.py new file mode 100644 index 0000000..44c3ea5 --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/企业推广二维码接口.py @@ -0,0 +1,11 @@ +class wecom推广二维码: + @classmethod + def 设置授权应用可见范围(cls): + """ + 调用该接口前提是开启通讯录迁移,收到授权成功通知后可调用。企业注册初始化安装应用后,应用默认可见范围为根部门。 + 如需修改应用可见范围,服务商可以调用该接口设置授权应用的可见范围。 + 该接口只能使用注册完成回调事件或者查询注册状态返回的access_token, + 调用设置通讯录同步完成后或者access_token超过30分钟失效(即解除通讯录锁定状态)则不能继续调用该接口 + :return: + :rtype: + """ diff --git a/wechat_项目工具包/企业微信工具包/企微回调业务处理逻辑.py b/wechat_项目工具包/企业微信工具包/企微回调业务处理逻辑.py new file mode 100644 index 0000000..cb4e28a --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/企微回调业务处理逻辑.py @@ -0,0 +1,63 @@ +import dataclasses + +import jmespath +import pydash +import requests +from asgiref.sync import async_to_sync +from channels.layers import get_channel_layer + +from sixGuoDjango import redis_5 +from wechat_项目工具包.企业微信工具包.客户管理 import wecom客户管理 +from wechat_项目工具包.企业微信工具包.消息推送工具 import wecom消息推送 + + +@dataclasses.dataclass +class six企微回调业务处理方法(): + pass + + def 添加企业客户事件(self, as_data): + """""" + """ + 添加企业客户事件 + 参数 说明 配置了客户联系功能的成员添加外部联系人时,回调该事件 + ToUserName 企业微信CorpID + FromUserName 此事件该值固定为sys,表示该消息由系统生成 + CreateTime 消息创建时间 (整型) + MsgType 消息的类型,此时固定为event + Event 事件的类型,此时固定为change_external_contact + ChangeType 此时固定为add_external_contact + UserID 企业服务人员的UserID + ExternalUserID 外部联系人的userid,注意不是企业成员的账号 + State 添加此用户的「联系我」方式配置的state参数,或在获客链接中指定的customer_channel参数,可用于识别添加此用户的渠道 + WelcomeCode 欢迎语code,可用于发送欢迎语 + """ + # 这是用户在添加企微好友成功时的回调信息; + ToUserName = pydash.get(obj=as_data, path="xml.ToUserName") # toUser 企业微信CorpID + FromUserName = pydash.get(obj=as_data, path="xml.FromUserName") # sys 此事件该值固定为sys,表示该消息由系统生成 + CreateTime = pydash.get(obj=as_data, path="xml.CreateTime") # 1403610513 消息创建时间 (整型) + MsgType = pydash.get(obj=as_data, path="xml.MsgType") # event 消息的类型,此时固定为event + Event = pydash.get(obj=as_data, path="xml.Event") # change_external_contact 事件的类型,此时固定为change_external_contact + ChangeType = pydash.get(obj=as_data, path="xml.ChangeType") # add_external_contact 此时固定为add_external_contact + UserID = pydash.get(obj=as_data, path="xml.UserID") # UserID 企业服务人员的UserID + ExternalUserID = pydash.get(obj=as_data, path="xml.ExternalUserID", ) # woAJ2GCAAAXtWyujaWJHDDGi0mAAAA 外部联系人的userid,注意不是企业成员的账号 + State = pydash.get(obj=as_data, path="xml.State", ) # teststate 添加此用户的「联系我」方式配置的state参数,或在获客链接中指定的customer_channel参数,可用于识别添加此用户的渠道 + WelcomeCode = pydash.get(obj=as_data, path="xml.WelcomeCode") # WELCOMECODE 欢迎语code,可用于发送欢迎语 + # 发送欢迎语 + print("添加企业客户事件") + + res_welcom_code = wecom消息推送.发送新客户欢迎语(CALLBACK_CODE=WelcomeCode) + # 获取用户的 unionid (主要就是获取用户的unionid的值) + res = wecom客户管理.获取客户详情(external_userid=ExternalUserID) + print(res) + unionid = jmespath.search(data=res, expression="external_contact.unionid") + print(unionid) + wecom_pay_data = requests.post(url="https://xiao.sixgou.com/demopay/transfer/", json={"unionid": unionid}) + # 存储数据(用户添加后的数据) + print("打印数据类型", wecom_pay_data.json()) + print("打印数据类型", type(wecom_pay_data.json())) + payData = wecom_pay_data.json() + channels_name = redis_5.get(name=unionid) + default_channel_layer = get_channel_layer(alias="default") + async_to_sync(awaitable=default_channel_layer.send)(channel=channels_name, message={"type": "chat_subMsg", "data": payData}) + pass + # 调用发红包的功能 diff --git a/wechat_项目工具包/企业微信工具包/客户标签管理工具.py b/wechat_项目工具包/企业微信工具包/客户标签管理工具.py new file mode 100644 index 0000000..77be0b0 --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/客户标签管理工具.py @@ -0,0 +1,168 @@ +"""客户标签管理工具""" +import os + +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() + +import datetime + +import jmespath +import requests + +from requests import post + + +class wecom管理企业标签: + """ + 管理企业标签 + 最后更新:2023/12/01 + 企业客户标签是针对企业的外部联系人进行标记和分类的标签,由企业统一配置后,企业成员可使用此标签对客户进行标记。 + """ + + @classmethod + def 获取企业标签库(cls): + """ + 在这里返回结果为:企业微信创建的所有的企业标签,不包含个人标签 + 企业可通过此接口获取企业客户标签详情。请求方式: POST(HTTP) + """ + pass + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_corp_tag_list?access_token={wecom_token}" + data = post(url=uri).json() + print(data) + tag_group = jmespath.search(data=data, expression="tag_group") + for tag in tag_group: + print(tag) + + return data + + @classmethod + def 添加企业客户标签(cls): + """ + 企业可通过此接口向客户标签库中添加新的标签组和标签,每个企业最多可配置10000个企业标签。 + 注意: + 1. 如果要向指定的标签组下添加标签,需要填写group_id参数; + 2. 如果要创建一个全新的标签组以及标签,则需要通过group_name参数指定新标签组名称, + 3. 如果填写的groupname已经存在,则会在此标签组下新建标签。 + 4. 如果填写了group_id参数,则group_name和标签组的order参数会被忽略。 + 不支持创建空标签组。 + 标签组内的标签不可同名,如果传入多个同名标签,则只会创建一个。 + :return: + :rtype: + """ + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_corp_tag?access_token={wecom_token}" + 请求数据示例 = { + "group_id": "etj4zANAAA1Zh_RyLIpjOr6IbuMPRB8g", # 否 标签组id + # "group_name": "泰州市", # 否 标签组名称,最长为30个字符 + "order": 1, + "tag": [ + { + "name": "未知", # 是 添加的标签名称,最长为30个字符 + "order": 1, # 否 标签次序值。order值大的排序靠前。有效的值范围是[0, 2^32) + }, + ], + # "agentid": 1000014, # 授权方安装的应用agentid。仅旧的第三方多应用套件需要填此参数 + } + data = post(url=uri, json=请求数据示例).json() + print(data) + + @classmethod + def 编辑客户企业标签(cls, userid: str, external_userid: str, add_tag: str): + """ + 企业可通过此接口为指定成员的客户添加上由企业统一配置的标签;注意,每个成员对同一个客户最多可以添加3000个标签。 + :return: + :rtype: + """ + + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/mark_tag?access_token={wecom_token}" + 请求数据示例 = { + # "userid": "YuanBao1975", # 是 添加外部联系人的userid + "userid": userid, # 是 添加外部联系人的userid + # "external_userid": "wmj4zANAAAGlCZ2zNRhu1qzEMSBF0a9gs", # 这里测试的是葫芦娃本人的标签 + "external_userid": external_userid, # 这里测试的是葫芦娃本人的标签 + # "add_tag": ["etj4zANAAAGtArlV00IwBWzIqinXf5vQ"], # 要添加的标签列表一定要填写🆔(对某一个用户添加某些标签) + "add_tag": [add_tag], # 要添加的标签列表一定要填写🆔(对某一个用户添加某些标签) + # "remove_tag": [] # 要移除的标签列表(对某一个用户移除某些标签) + } + data = post(url=uri, json=请求数据示例).json() + print(data) + + @classmethod + def 更新所有的企业标签并存储到数据库(cls): + pass + data = cls.获取企业标签库() + tag_group = jmespath.search(data=data, expression="tag_group", ) + for tag_list in tag_group: + print(tag_list) + # tag_list = jmespath.search(data=tag_list, expression="tag", ) + group_id = jmespath.search(data=tag_list, expression="group_id", ) + group_name = jmespath.search(data=tag_list, expression="group_name", ) + create_time = jmespath.search(data=tag_list, expression="create_time", ) + # create_time = pydash.get(obj=tag_list, path="create_time", ) + # 需要将时间戳转为时间格式 + print(create_time, "========", ) + create_time_1 = datetime.datetime.fromtimestamp(create_time) + # + + tag_child_list = jmespath.search(data=tag_list, expression="tag", ) + + @classmethod + def 更新所有的用户性别组标签(cls): + pass + + @classmethod + def 打标签性别(cls, userid: str, external_userid: str, gender: int): + """ + :param gender: + :type gender: + :param userid: + :type userid: + :param external_userid: + :type external_userid: + """ + print("单独更新用户性别标签") + if gender == 1: + cls.编辑客户企业标签( + userid=userid, external_userid=external_userid, + add_tag="et74kdKAAAO9rCHIG-GcT7ZU_gsTslkg", + ) + if gender == 2: + cls.编辑客户企业标签( + userid=userid, external_userid=external_userid, + add_tag="et74kdKAAAJUou62OZwyu3LeavfmxAhw", + ) + if gender == 0: + cls.编辑客户企业标签( + userid=userid, external_userid=external_userid, + add_tag="et74kdKAAAI_VNWc-Gzakmo_jGnK-Glw", + ) + + def 给个微好友打标签(self): + pass + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/mark_tag" + 请求数据 = { + "userid": "YuanBao", + "external_userid": "wm74kdKAAAwE4T5vvLoUgHq9dEu7eTgA", # 给小豆豆测试打标签 + "add_tag": ["et74kdKAAAO9rCHIG-GcT7ZU_gsTslkg"], # 测试标签ID + # "remove_tag": ["et74kdKAAAO9rCHIG-GcT7ZU_gsTslkg"] # 删除企业微信好友的 标签 + } + wecom_token = sixToken.get_wecom_token() + response_data = requests.post(url=uri, params={"access_token": wecom_token}, json=请求数据) + print(response_data.json()) + + +if __name__ == '__main__': + pass + wecom管理企业标签.获取企业标签库() + # wecom管理企业标签.添加企业客户标签() + # wecom管理企业标签.更新所有的用户性别组标签() + # wecom管理企业标签.更新所有的企业标签并存储到数据库() + # wecom管理企业标签.获取企业标签库() + # wecom管理企业标签().给个微好友打标签() diff --git a/wechat_项目工具包/企业微信工具包/客户管理.py b/wechat_项目工具包/企业微信工具包/客户管理.py new file mode 100644 index 0000000..347c33c --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/客户管理.py @@ -0,0 +1,220 @@ +import io +from typing import List, Literal + +import pydash +import requests +from pydantic import BaseModel + +from wechat_token.token工具包 import sixToken +from wechat_数据库.企业微信数据库.企微用户表 import wecom企微用户 +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser用户角色 +from 第三方工具目录.腾讯云 import oss上传腾讯云图片 + + +class wecomData客户列表响应(BaseModel): + errcode: int + errmsg: str + external_userid: List[str] + + +from pydantic import BaseModel +from typing import List, Optional + + +class wecomData外部联系人基本信息(BaseModel): + """外部联系人基本信息""" + external_userid: str + name: str + type: int + avatar: str + gender: int + unionid: Optional[str] = None + + +class wecomData跟进人标签(BaseModel): + """跟进人标签""" + group_name: str + tag_name: str + type: int + tag_id: Optional[str] = None + + +class wecomData跟进成员信息(BaseModel): + """跟进成员信息""" + userid: str + remark: Optional[str] = None + description: Optional[str] = None + createtime: int + state: Optional[str] = None + tags: List[wecomData跟进人标签] = [] + remark_mobiles: List[str] = [] + remark_corp_name: Optional[str] = None + add_way: int + oper_userid: str + + +class wecomData获取客户详情响应(BaseModel): + """获取客户详情接口返回""" + errcode: int + errmsg: str + external_contact: Optional[wecomData外部联系人基本信息] = None + follow_user: List[wecomData跟进成员信息] = [] + + +six六果对象xiao, six是否新创建值 = weiuser.objects.update_or_create(unionid="六果", + defaults={ + "user_IP地址": None, "user_昵称": "六果", "user_用户当前的等级": 0, "user_省份": "六果", "user_城市": "六果", "user_区县": "六果", + "user_街道信息": "六果", "user_头像": "https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png", "user_绑定企微usrID账号": "六果", "user_角色权限": "六果", "external_userid": "六果", + "parent_id": "六果", "mini_openid": "wxf612e825377328f0", "wechat_openid": "六果", "wecom_openid": "wwbe6369dc26a9d83a", "codeConfigId": "六果", "codeRemark": "六果", + "codeQrCode": "https://hudie.xiao.band/mini.jpg", + "user_企微角色权限": "六果", "user_绑定企微UNIONID": "六果" + }) + + +class wecom客户好友管理(BaseModel): + # demo_必填: int = Field(..., description="描述") # 必传属发生 + # demo_可选: Optional[int] = None # 可选值 + # demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + + def 企微原用户处理接口(self, data): + """""" + state上级用户 = pydash.get(obj=data, path="state", default="六果") # 上级分享者的uniond值 这里是企微二维码绑定的 uninoid + external_userid = pydash.get(obj=data, path="external_userid") + unionid下级用户 = pydash.get(obj=data, path="unionid") + print(f"state上级用户===>{state上级用户}", f"unionid下级用户===>{unionid下级用户}") + 上级用户, 上级用户状态 = weiuser.objects.get_or_create(unionid=state上级用户) # 如果state的状态不为None:则创建这个用户 + 下级用户, 下级用户状态 = weiuser.objects.get_or_create(unionid=unionid下级用户) + six六果对象, sixBool = weiuser.objects.get_or_create(unionid="六果") + if 上级用户.parent is None: + # 当这里企微号的state绑定的小程序用户的时候 的 上级用户为None的时候 + 上级用户.parent = six六果对象 + 上级用户.external_userid = external_userid + 上级用户.user_用户当前的等级 = six六果对象.user_用户当前的等级 + 1 + 上级用户.codeQrCode = six六果对象.codeQrCode + 上级用户.codeRemark = six六果对象.codeRemark + 上级用户.codeConfigId = six六果对象.codeConfigId + 上级用户.user_绑定企微UNIONID = six六果对象.user_绑定企微UNIONID + 上级用户.save() + # # 第二步就只需要查询,如果下级用户已经有上级了就直接忽略 + if 上级用户.parent is not None: + print("这里是上上级用户不为None的时候", ) + + # 还需要判断一下,下级用户的 父元素为six公司对象的时候,还得更新一下当前的数据,因为这个用户原来就是属于 企微员工的绑定者 + if 下级用户.parent == six六果对象 and 下级用户.user_企微角色权限 != miniUser用户角色().企微员工: + print(下级用户, "🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎判断成功了") + 下级用户.parent = 上级用户 + 下级用户.user_用户当前的等级 = 上级用户.user_用户当前的等级 + 1 + 下级用户.user_绑定企微UNIONID = 上级用户.user_绑定企微UNIONID + 下级用户.codeConfigId = 上级用户.codeConfigId + 下级用户.codeQrCode = 上级用户.codeQrCode + 下级用户.codeRemark = 上级用户.codeRemark + 下级用户.user_绑定企微usrID账号 = 上级用户.user_绑定企微usrID账号 + 下级用户.save() + if 下级用户.parent is not None: + # 这里判断出下级用户有上级,直接原样处理,不做任何的更改状态 + print("下级用户的父不为不为不为元素为None的时候", 上级用户) + 下级用户.external_userid = external_userid + 下级用户.save() + if 下级用户.parent is None: + print("下级用户的父元素为None的时候", 上级用户) + 下级用户.parent = 上级用户 + 下级用户.user_用户当前的等级 = 上级用户.user_用户当前的等级 + 1 + 下级用户.external_userid = external_userid + 下级用户.codeQrCode = 上级用户.codeQrCode + 下级用户.codeRemark = 上级用户.codeRemark + 下级用户.codeConfigId = 上级用户.codeConfigId + 下级用户.user_绑定企微UNIONID = 上级用户.user_绑定企微UNIONID + 下级用户.save() + + def 获取客户列表(self, userid: Literal["YuanBao1975"]) -> wecomData客户列表响应: + """根据企微员工的ID,一次获取当前企微员所有的好友列表""" + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list" + json_data = requests.get(url=uri, params={"access_token": wecom_token, "userid": userid}) + # print("获取客户列表获取客户列表获取客户列表获取客户列表获取客户列表获取客户列表获取客户列表", json_data.json()) + get_data = wecomData客户列表响应(**json_data.json()) + return get_data.model_dump() + + def 获取客户详情(self, external_userid) -> wecomData获取客户详情响应: + """通过 external_userid 获取用户的详情,最主要的就是拿到用户的 unionid """ + wecom_token = sixToken.get_wecom_token() + uri = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get" + data = requests.get(url=uri, params={"access_token": wecom_token, "external_userid": external_userid}) + print("\n🍎 🍏 🍊获取客户详情 🍎 🍏 \n", data.json()) + return wecomData获取客户详情响应(**data.json()) + + def 批量获取客户详情并存储到数据库(self, state企微员工创建时添加的唯一值, userid企微员工账号ID: Literal["YuanBao1975"]): + """根据企微员工的ID,获取当前企微员添加的所有的外 部联系人好友,并存储到数据库""" + + def request_recursive(userid_list=None, cursor="", ): + """""" + # 初始化参数 + wecom_token_inner = sixToken.get_wecom_token() + # 构建请求参数 + uri = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/batch/get_by_user" + json_data = {"userid_list": userid_list, "limit": 200, "cursor": cursor} + + # 发送请求 + try: + data = requests.post(url=uri, params={"access_token": wecom_token_inner}, json=json_data, ) + response_json = data.json() + # 提取当前页的外部联系人 + # 获取下一页游标 + external_contact_list = pydash.get(obj=response_json, path="external_contact_list") + next_cursor = pydash.get(obj=response_json, path="next_cursor", default="") + + print(f"当前获取到 {len(external_contact_list)} 个外部联系人,总计 {len(external_contact_list)} 个") + # 如果还有下一页,递归调用 + for post_data in external_contact_list: + userid = pydash.get(obj=post_data, path="follow_info.userid") # 添加了此外部联系人的企业成员userid 如 HuDie_1 + remark = pydash.get(obj=post_data, path="follow_info.remark") # 该成员对此微信客户备注的企业名称(仅微信客户有该字段) + description = pydash.get(obj=post_data, path="follow_info.description") + createtime = pydash.get(obj=post_data, path="follow_info.createtime") + state = pydash.get(obj=post_data, path="follow_info.state") # 企业自定义的state参数,用于区分客户具体是通过哪个「联系我」或获客链接添加;由企业通过创建「联系我」或在获客链接中添加customer_channel参数进行指定 + tag_id = pydash.get(obj=post_data, path="follow_info.tag_id") + remark_mobiles = pydash.get(obj=post_data, path="follow_info.remark_mobiles") # 该成员对此客户备注的手机号码,第三方应用和代开发应用均不可获取,上游企业不可获取下游企业客户该字段 + add_way = pydash.get(obj=post_data, path="follow_info.add_way") # 该成员添加此客户的来源add_way为10时,对应的视频号信息 + oper_userid = pydash.get(obj=post_data, path="follow_info.oper_userid") # 发起添加的userid,如果成员主动添加,为成员的userid;如果是客户主动添加,则为客户的外部联系人userid;如果是内部成员共享/管理员分配,则为对应的成员/管理员userid + external_userid = pydash.get(obj=post_data, path="external_contact.external_userid") # 外部联系人的userid + name = pydash.get(obj=post_data, path="external_contact.name") # 外部联系人的名称[注1] + type_data = pydash.get(obj=post_data, path="external_contact.type") # 外部联系人的类型,1表示该外部联系人是微信用户,2表示该外部联系人是企业微信用户 + avatar = pydash.get(obj=post_data, path="external_contact.avatar") # 外部联系人头像。第三方应用和代开发应用均不可获取,上游企业不可获取下游企业客户该字段 + gender = pydash.get(obj=post_data, path="external_contact.gender") # 外部联系人性别 0-未知 1-男性 2-女性。 + unionid = pydash.get(obj=post_data, path="external_contact.unionid") # 外部联系人在微信开放平台的唯一身份标识(微信unionid), + print("看看这里的值是多少看看这里的值是多少看看这里的值是多少看看这里的值是多少看看这里的值是多少看看这里的值是多少看看这里的值是多少看看这里的值是多少", state) + if avatar and type_data == 1: + img_file = requests.get(url=avatar).content + src = oss上传腾讯云图片.上传图片(key=f"{userid}/{name}.png", file=io.BytesIO(img_file), ) + avatar = src + # time.sleep( 1 ) + # avatar = "https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png" + if bool(avatar) == False and type_data == 1: + avatar = "https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png" + if type_data == 1: + weiuser.objects.update_or_create(unionid=unionid, defaults={"user_头像": avatar, "user_昵称": name, "external_userid": external_userid, }) + wecomData = {"state": state企微员工创建时添加的唯一值, "external_userid": external_userid, "unionid": unionid} + self.企微原用户处理接口(data=wecomData) + wecom企微用户.objects.update_or_create(wecom企微ID=userid, wecom企微对好友添加的手机号码=remark_mobiles, wecom企微好友添加方式=oper_userid, wecom企微状态State=state企微员工创建时添加的唯一值, wecom对好友打的标签=tag_id, + wecom对好友的备注信息=description, wecom对好友的备注名称=remark, wecom对好友的添加时间=createtime, wecom好友头像=avatar, wecom好友性别=gender, wecom好友昵称=name, wecom好友的ID=external_userid, + wecom好友UNIONID=unionid, ) + + if next_cursor: + print(f"发现下一页,游标: {next_cursor}") # 递归调用 + request_recursive(userid_list=userid_list, cursor=next_cursor, ) + + + except requests.exceptions.RequestException as e: + print(f"网络请求异常: {e}", ) + except Exception as e: + print(f"处理异常: {e}") + + request_recursive(userid_list=[userid企微员工账号ID], ) + + +if __name__ == "__main__": + pass + wai_external_userid = "wmj4zANAAAGlCZ2zNRhu1qzEMSBF0a9g" + # data_wecom_客户详情数据 = wecom客户好友管理().获取客户详情(external_userid=wai_external_userid) + wecom客户好友管理().批量获取客户详情并存储到数据库(state企微员工创建时添加的唯一值="oy4Jw6A1T3WkKOOhMxcbQTDSM8rs", userid企微员工账号ID="YuanBao1975") # 此方法会直接更新数据库并且保存数据 diff --git a/wechat_项目工具包/企业微信工具包/客户群管理工具.py b/wechat_项目工具包/企业微信工具包/客户群管理工具.py new file mode 100644 index 0000000..9ef95a6 --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/客户群管理工具.py @@ -0,0 +1,123 @@ +"""客户群管理工具""" +import os + +import django +from pydantic import BaseModel + +from sixGuoDjango.settings import BASE_DIR + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() + +from wechat_token.token工具包 import sixToken + +from requests import post + + +# class emsParameters(BaseModel): +# demo_必填: int = Field(..., description="描述") # 必传属发生 +# demo_可选: Optional[int] = None # 可选值 +# demo_默认值: int = Field(default=100001, description="描述") # 有默认值 +# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") +# + + +class wecom客户群管理(BaseModel): + """类注释""" + pass + + def get获取客户群列表(self): + """ + 该接口用于获取配置过客户群管理的客户群列表。 + :return: + :rtype: + """ + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/list?access_token={wecom_token}" + 请求数据示例 = { + # "status_filter": 0, + # "owner_filter": { + # "userid_list": ["abel"] + # }, + # "cursor": "r9FqSqsI8fgNbHLHE5QoCP50UIg2cFQbfma3l2QsmwI", + "limit": 10 + } + data = post(url=uri, json=请求数据示例).json() + print(data) + + def get获取客户群详情(self, chat_id群号ID): + """ + 通过客户群ID,获取详情。包括群名、群成员列表、群成员入群时间、入群方式。(客户群是由具有客户群使用权限的成员创建的外部群) + 需注意的是,如果发生群信息变动,会立即收到群变更事件,但是部分信息是异步处理,可能需要等一段时间调此接口才能得到最新结果 + :return: + :rtype: + """ + + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/get?access_token={wecom_token}" + 请求数据示例 = { + "chat_id": chat_id群号ID, # 是 客户群ID + "need_name": 1, # 否 是否需要返回群成员的名字group_chat.member_list.name。0-不返回;1-返回。默认不返回 + } + data = post(url=uri, json=请求数据示例).json() + print(data) + + def 客户群opengid转换(self): + """ + 用户在微信里的客户群里打开小程序时,某些场景下可以获取到群的opengid,如果该群是企业微信的客户群,则企业或第三方可以调用此接口将一个opengid转换为客户群chat_id + :return: + :rtype: + """ + + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/opengid_to_chatid?access_token={wecom_token}" + 请求数据示例 = { + "opengid": "oAAAAAAA", # 是 小程序在微信获取到的群ID,参见wx.getGroupEnterInfo + } + data = post(url=uri, json=请求数据示例).json() + print(data) + + def 入群欢迎语素材管理(self): + """ + 企业可通过此API向企业的入群欢迎语素材库中添加素材。每个企业的入群欢迎语素材库中,最多容纳100个素材。 + :return: + :rtype: + """ + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/add?access_token={wecom_token}" + 请求数据示例 = { + "text": { + "content": "亲爱的%NICKNAME%用户,你好" + }, + "image": { + "media_id": "MEDIA_ID", + "pic_url": "http://p.qpic.cn/pic_wework/3474110808/7a6344sdadfwehe42060/0" + }, + "link": { + "title": "消息标题", + "picurl": "https://example.pic.com/path", + "desc": "消息描述", + "url": "https://example.link.com/path" + }, + "miniprogram": { + "title": "消息标题", + "pic_media_id": "MEDIA_ID", + "appid": "wx8bd80126147dfAAA", + "page": "/path/index" + }, + "file": { + "media_id": "1Yv-zXfHjSjU-7LH-GwtYqDGS-zz6w22KmWAT5COgP7o" + }, + "video": { + "media_id": "MEDIA_ID" + }, + "agentid": 1000014, + "notify": 1 + } + data = post(url=uri, json=请求数据示例).json() + print(data) + + +if __name__ == '__main__': + wecom客户群管理().get获取客户群列表() + wecom客户群管理().get获取客户群详情(chat_id群号ID="wrj4zANAAAmHh0Yqe23edo4TI462Bhpg") diff --git a/wechat_项目工具包/企业微信工具包/消息推送工具.py b/wechat_项目工具包/企业微信工具包/消息推送工具.py new file mode 100644 index 0000000..d37e18d --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/消息推送工具.py @@ -0,0 +1,380 @@ +import os + +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( ) + +from pathlib import Path + +import pydash +import requests +from django.conf import settings + +from requests import post + + + + + +class wecom消息推送: + pass + + @classmethod + 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", ) } ) + + @classmethod + def 欢迎语类型IMG( cls ): + pass + IMG = { + "msgtype": "link", + "link": { + "title": "消息标题", + "picurl": "https://example.pic.com/path", + "desc": "消息描述", + "url": "https://example.link.com/path" + } + } + return IMG + + @classmethod + def 欢迎语类型小程序( cls ): + pass + miniprogram = { + "msgtype": "miniprogram", # 附件类型,可选image、link、miniprogram或者video + "miniprogram": { + "title": "小程序领现金红包", # 是 小程序消息标题,最长为 64 字节 + "pic_media_id": "3AIBtUrVvuc2qwuSjJSWK9AXyQF_omNpWJqz_4onX_shiGW9U6OsWauNImkKVwJsON0xkcnywtAQJnaXfgmCbIA", + # 小程序消息封面的mediaid,封面图建议尺寸为520*416 + "appid": "wx3acee999f873005a", + "page": "/tabPage/Home/Home", + }, + } + return miniprogram + + @classmethod + def 欢迎语类型LINK( cls ): + """ + 欢迎语类型LINK + """ + IMG = { + "msgtype": "link", # 附件类型,可选image、link、miniprogram或者video + "image": { + "media_id": "MEDIA_ID", # 图片的media_id,可以通过素材管理接口获得 + "pic_url": "http://p.qpic.cn/pic_wework/3474110808/7a6344sdadfwehe42060/0" # 图片的链接,仅可使用上传图片接口得到的链接 + } + } + + @classmethod + def 欢迎语类型VIDEO( cls ): + pass + VIDEO = { + "msgtype": "video", + "video": { + "media_id": "MEDIA_ID" + } + } + return VIDEO + + @classmethod + def 创建企业群发( cls ): + pass + wecom_token = sixToken.get_wecom_token( ) + url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_msg_template" + json_data = { + "chat_type": "single", + "external_userid": [ + "wmj4zANAAAGlCZ2zNRhu1qzEMSBF0a9g", "wmj4zANAAA-lsKNm2U2U-EBCcVGuFGIA", + ], + "attachments": [ + { + "msgtype": "link", + "link": { + "title": "消息标题", + "desc": "消息描述", + "url": "https://www.sixgou.com/", + "picurl": "https://fastly.picsum.photos/id/82/200/200.jpg?hmac" + "=ATNAhTLN2dA0KmTzSE5D9XiPe3GMX8uwxpFlhU7U5OY", + }, + }, + ], + } + data = post( + url=url, json=json_data, params={ + "access_token": wecom_token, + }, + ) + print( data.json( ) ) + + @classmethod + def 提醒成员群发( cls ): + """ + 提醒成员群发 + """ + pass + + @classmethod + def 停止企业群发( cls ): + pass + + @classmethod + 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.欢迎语类型小程序( ) + json_data = { + "welcome_code": CALLBACK_CODE, + "text": { + "content": """ +🎉恭喜!您已成功解锁 给【好友发红包】特权!🔓 + + +🚀更多惊喜权益,开启您的收益之旅: + + +1️⃣ 双向红包💰:给好友发红包🧧,您也能获得现金奖励💸,分享快乐😊,双倍收获! + + +2️⃣ 加入赚佣金🤝:成为我们的一员👨‍👩‍👧‍👦,推荐心仪好物❤️,轻松赚取商品推荐分成📈。 + + +3️⃣ 超越赢未来🏆:与我们并肩前行👣,共享海量商品🛍️、优质服务🛠️与庞大流量🌊,共创价值!✨ + """, + }, + } + data = 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" ) + + + + + +class wecom获取企业的全部群发记录: + """ + 企业跟第三方应用可通过该接口获取群发给客户的消息和群发到客户群的消息 + 1. 群发助手和客户群群发有以下两种类型 + 2. 企业发表 + 1. 管理员或者业务负责人创建内容,成员确认后,即可发送给客户或者客户群 + 3. 个人发表 + 1. 成员自己创建的内容,可直接发送给客户或客户群 + :return: + :rtype: + """ + + @classmethod + def 获取群发记录列表( cls ): + """ + 企业和第三方应用可通过此接口获取企业与成员的群发记录。 + :return: + :rtype: + """ + 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", + "start_time": 1605171726, + "end_time": 1605172726, + "creator": "zhangshan", + "filter_type": 1, + "limit": 50, + "cursor": "CURSOR" + } + data = post( url=url, json=请求数据示例 ).json( ) + print( data ) + + @classmethod + def 获取群发成员发送任务列表( cls ): + """ + :return: + :rtype: + """ + 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 ) + + @classmethod + def 获取企业群发成员执行结果( cls ): + """ + + :return: + :rtype: + """ + 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", + "userid": "zhangsan ", + "limit": 50, + "cursor": "CURSOR" + } + data = post( url=url, json=请求数据示例 ).json( ) + print( data ) + + + + + +class wecom入群欢迎语素材管理: + """ + 添加入群欢迎语素材 + 企业可通过此API向企业的入群欢迎语素材库中添加素材。每个企业的入群欢迎语素材库中,最多容纳100个素材。 + """ + + @classmethod + 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": { + "content": "亲爱的%NICKNAME%用户,你好" + }, + "image": { + "media_id": "MEDIA_ID", + "pic_url": "http://p.qpic.cn/pic_wework/3474110808/7a6344sdadfwehe42060/0" + }, + "link": { + "title": "消息标题", + "picurl": "https://example.pic.com/path", + "desc": "消息描述", + "url": "https://example.link.com/path" + }, + "miniprogram": { + "title": "消息标题", + "pic_media_id": "MEDIA_ID", + "appid": "wx8bd80126147dfAAA", + "page": "/path/index" + }, + "file": { + "media_id": "1Yv-zXfHjSjU-7LH-GwtYqDGS-zz6w22KmWAT5COgP7o" + }, + "video": { + "media_id": "MEDIA_ID" + }, + "agentid": 1000014, + "notify": 1 + } + data = post( url=url, json=请求数据示例 ).json( ) + print( data ) + + @classmethod + 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", + "text": { + "content": "文本消息内容" + }, + "image": { + "media_id": "MEDIA_ID", + "pic_url": "http://p.qpic.cn/pic_wework/3474110808/7a6344sdadfwehe42060/0" + }, + "link": { + "title": "消息标题", + "picurl": "https://example.pic.com/path", + "desc": "消息描述", + "url": "https://example.link.com/path" + }, + "miniprogram": { + "title": "消息标题", + "pic_media_id": "MEDIA_ID", + "appid": "wx8bd80126147df384", + "page": "/path/index" + }, + "file": { + "media_id": "1Yv-zXfHjSjU-7LH-GwtYqDGS-zz6w22KmWAT5COgP7o" + }, + "video": { + "media_id": "MEDIA_ID" + }, + "agentid": 1000014 + } + data = post( url=uri, json=请求数据示例 ).json( ) + print( data ) + + @classmethod + 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 ) + + @classmethod + def 删除入群欢迎语素材( cls ): + """ + 删除入群欢迎语素材 + """ + 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 ) + + + + + +class uploadTempMedia上传附件资源: + + @classmethod + def upload_file( cls ): + """ + 参数 必须 说明 + access_token 是 调用接口凭证 + media_type 是 媒体文件类型,分别有图片(image)、视频(video)、普通文件(file) + attachment_type 是 附件类型,不同的附件类型用于不同的场景。1:朋友圈;2:商品图册 + :return: + :rtype: + """ + 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", ) } + + data = 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( ) + 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 ) + + + + + +if __name__ == '__main__': + pass + uploadTempMedia上传附件资源.上传临时素材( ) diff --git a/wechat_项目工具包/企业微信工具包/联系我与客户入群方式(加入群聊)工具.py b/wechat_项目工具包/企业微信工具包/联系我与客户入群方式(加入群聊)工具.py new file mode 100644 index 0000000..9dc8f22 --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/联系我与客户入群方式(加入群聊)工具.py @@ -0,0 +1,36 @@ +"""联系我与客户入群方式(加入群聊)工具""" +from requests import post + +from wechat_token.token工具包 import sixToken + + +class wecom客户群_加入群聊_管理: + """注释""" + @classmethod + def 配置客户群进群方式(cls): + """ + 企业可调用此接口来生成并配置「加入群聊」的二维码或者小程序按钮,客户通过扫描二维码或点击小程序上的按钮,即可加入特定的客户群 + 如果配置的是小程序按钮,需要开发者的小程序接入小程序插件。 + 通过API添加的配置不会在管理端进行展示,每个企业可通过API最多配置50万个「加入群聊」(与「联系我」共用50万的额度) + :return: + :rtype: + """ + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/add_join_way?access_token={wecom_token}" + 请求数据示例 = { + "scene": 2, # 是 场景。1 - 群的小程序插件 2 - 群的二维码插件 + "remark": "aa_remark", # 否 联系方式的备注信息,用于助记,超过30个字符将被截断 + "auto_create_room": 1, # 否 当群满了后,是否自动新建群。0-否;1-是。 默认为1 + "room_base_name": "销售客服群", # 否 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符 + "room_base_id": 10, # 否 自动建群的群起始序号,当auto_create_room为1时有效 + # chat_id_list 是 使用该配置的客户群ID列表,最多支持5个。见客户群ID获取方法 + "chat_id_list": [ + "wrOgQhDgAAH2Yy-CTZ6POca8mlBEdaaa", + "wrOgQhDgAALPUthpRAKvl7mgiQRwAAA" + ], + # 否 企业自定义的state参数,用于区分不同的入群渠道。不超过30个UTF-8字符 + # 如果有设置此参数,在调用获取客户群详情接口时会返回每个群成员对应的该参数值,详见文末附录2 + "state": "klsdup3kj3s1" + } + data = post(uri, json=请求数据示例).json() + print(data) diff --git a/wechat_项目工具包/企业微信工具包/联系我与客户入群方式(联系我)工具.py b/wechat_项目工具包/企业微信工具包/联系我与客户入群方式(联系我)工具.py new file mode 100644 index 0000000..998de1f --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/联系我与客户入群方式(联系我)工具.py @@ -0,0 +1,187 @@ +"""客户联系我管理""" +import os +from datetime import datetime + +import django +import requests +from pydantic import BaseModel, Field + +from sixGuoDjango.settings import BASE_DIR +from wechat_token.token工具包 import sixToken +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser用户角色 + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() + +import pydash + +from requests import post + +six六果对象xiao, six是否新创建值 = weiuser.objects.update_or_create(unionid="六果", + defaults={ + "user_IP地址": None, "user_昵称": "六果", "user_用户当前的等级": 0, "user_省份": "六果", "user_城市": "六果", "user_区县": "六果", + "user_街道信息": "六果", "user_头像": "https://hudie.xiao.band/%E6%9C%AA%E5%91%BD%E5%90%8D.png", "user_绑定企微usrID账号": "六果", "user_角色权限": "六果", "external_userid": "六果", + "parent_id": "六果", "mini_openid": "wxf612e825377328f0", "wechat_openid": "六果", "wecom_openid": "wwbe6369dc26a9d83a", "codeConfigId": "六果", "codeRemark": "六果", + "codeQrCode": "https://hudie.xiao.band/mini.jpg", + "user_企微角色权限": "六果", "user_绑定企微UNIONID": "六果" + }) + + +class wecom客户联系_联系我_管理(BaseModel): + """ + https://developer.work.weixin.qq.com/document/path/92228#%E9%99%84%E5%BD%95 + """ + addres_省: str = Field(..., description="addres_省") + address_市: str = Field(..., description="address_市") + address_区县: str = Field(..., description="address_区县") + + def 配置客户联系_联系我_方式(self, state企微二维码绑定的唯一值: str, userid_list: list[str]): + """ + 通过API添加的「联系我」不会在管理端进行展示,每个企业可通过API最多配置50万个「联系我」。 + 用户需要妥善存储返回的config_id,config_id丢失可能导致用户无法编辑或删除「联系我」。 + 临时会话模式不占用「联系我」数量,但每日最多添加10万个,并且仅支持单人。 + 临时会话模式的二维码,添加好友完成后该二维码即刻失效。 + 请求方式:POST(HTTPS) + 请求地址:https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_contact_way?access_token=ACCESS_TOK + :return: + :rtype: + """ + + # wecom_token = "500hJr2pfJIa5vCJoUOK_zJRcKG_4fKdC_pilCgsEds7lQ3VZGlg1FN6iGDKZsMpUqZO4Di9BJfEMxk7V01yz5NYNwaekvby9vw3gZBw40uXr-YqlAVkP6ZRA0Wf6IkHfiYUTDQAk1 + # -hUANg42srD6f3AfooEi1ZbbmAvXRjsPa17HVgzxLP7NnGTZPbaTOZRU2Cr269GjxZhgx0dVHu1Q" + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_contact_way?access_token={wecom_token}" + state = "oy4Jw6Lyfyj1VvgZFodzq9oqJzHE" + 请求数据 = { + "type": 1, # 联系方式类型,1-单人, 2-多人 + "scene": 2, # 场景,1-在小程序中联系,2-通过二维码联系 + "style": 1, # 否 在小程序中联系时使用的控件样式,详见附表 + "remark": "渠道客户", # 否 联系方式的备注信息,用于助记,不超过30个字符 + "skip_verify": True, # 否 外部客户添加时是否无需验证,默认为true + "state": state企微二维码绑定的唯一值, # 是 区分业务用的; + "user": userid_list, + } + data = requests.post(url=uri, json=请求数据).json() + print(data) + config_id = pydash.get(obj=data, path="config_id") + qr_code = pydash.get(obj=data, path="qr_code") + + def 获取企业已配置的_联系我_列表(self, start时间戳): + """ + 获取六果公司已经创建的全部的添加我联系我二维码 列表数据🆔 + """ + wecom_token = sixToken.get_wecom_token() # list_contact_way + print(datetime(year=2026, month=1, day=1).timestamp()) + start时间戳 = int(datetime(year=2026, month=1, day=1).timestamp()) + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list_contact_way?access_token={wecom_token}" + data = post(url=uri, json={"start_time": start时间戳}).json() + print(data, "=========") + return data + + def 获取企业已配置的_联系我_方式(self, config_id: str): + """ + 获取企业已配置的_联系我_方式 + :param config_id: + :type config_id: + """ + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_contact_way?access_token={wecom_token}" + 请求数据 = {"config_id": config_id} + data = post(url=uri, json=请求数据).json() + return data + + def 更新企业已配置的_联系我_方式(self): + """ + 更新企业配置的「联系我」二维码和「联系我」小程序按钮中的信息,如使用人员和备注等。 + 请求方式:POST(HTTPS) + 请求地址:https://qyapi.weixin.qq.com/cgi-bin/externalcontact/update_contact_way?access_token=ACCESS_TOKEN + """ + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/update_contact_way?access_token={wecom_token}" + # oy4Jw6A1T3WkKOOhMxcbQTDSM8rs + 请求示例数据 = {"config_id": "9b18a3ac534e236162a850f77bdd20d0", "remark": "渠道客户", "skip_verify": True, "style": 1, "state": "oy4Jw6A1T3WkKOOhMxcbQTDSM8rs", "type": 2, + "user": ["YuanBao1975"], + } + data = post(url=uri, json=请求示例数据).json() + print("更新企业已配置的_联系我_方式", data) + + def 删除企业已配置的_联系我_方式(self, config_id: str): + """ + 删除一个已配置的「联系我」二维码或者「联系我」小程序按钮。 + 请求方式:POST(HTTPS) + 请求地址:https://qyapi.weixin.qq.com/cgi-bin/externalcontact/del_contact_way?access_token=ACCESS_TOKEN + """ + print(config_id, type(config_id)) + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/del_contact_way?access_token={wecom_token}" + 请求数据 = {"config_id": config_id} + data = post(url=uri, json=请求数据).json() + print(data, "==========") + return data + + def 结束临时会话(self): + """ + 结束临时会话 + """ + pass + + def 结束语定义(self): + """ + 结束语定义 + """ + pass + + def 最终处理完整的企微二维码信息(self, start时间戳): + # 调用获取所有的 原先创建的 列表 得到 config_id + config_id_list_data = self.获取企业已配置的_联系我_列表(start时间戳=start时间戳) + contact_way = pydash.get(obj=config_id_list_data, path="contact_way") + for configID in contact_way: + config_id = pydash.get(obj=configID, path="config_id") + data_详情数据 = self.获取企业已配置的_联系我_方式(config_id=config_id) + qr_code = pydash.get(obj=data_详情数据, path="contact_way.qr_code") + state = pydash.get(obj=data_详情数据, path="contact_way.state") + userID = pydash.get(obj=data_详情数据, path="contact_way.user.0") + remark = pydash.get(obj=data_详情数据, path="contact_way.remark") + print(qr_code) + wei_obj对象, wei_obj首次创建 = weiuser.objects.get_or_create(unionid=state) + if wei_obj首次创建: + # 当对象是首次创建时:需要更新一下数据 + wei_obj对象.user_绑定企微usrID账号 = userID + wei_obj对象.codeConfigId = config_id + wei_obj对象.codeQrCode = qr_code + wei_obj对象.codeRemark = remark + wei_obj对象.parent_id = "六果" # 如果是首次创建就需要将当前对象的父元素 默认为 六果公司 + wei_obj对象.user_企微角色权限 = "企微员工" + wei_obj对象.user_省份 = self.addres_省 + wei_obj对象.user_城市 = self.address_市 + wei_obj对象.user_区县 = self.address_区县 + wei_obj对象.user_绑定企微UNIONID = state + wei_obj对象.save() + print("首次创建,并且数据库更新成功了") + else: + wei_obj对象.user_绑定企微usrID账号 = userID + wei_obj对象.codeConfigId = config_id + wei_obj对象.codeQrCode = qr_code + wei_obj对象.codeRemark = remark + wei_obj对象.user_企微角色权限 = miniUser用户角色().企微员工 + wei_obj对象.parent_id = wei_obj对象 + wei_obj对象.user_用户当前的等级 = 1 + wei_obj对象.user_省份 = self.addres_省 + wei_obj对象.user_城市 = self.address_市 + wei_obj对象.user_区县 = self.address_区县 + wei_obj对象.user_绑定企微UNIONID = state + wei_obj对象.save() + print("企微员的用户已经存在,并且更新了相关的信息") + # 接着 查询所有的 父元素为当前对象的所有用户,再将绑定的二维码信息,更新为当前的对象 + weiuser.objects.filter(parent=wei_obj对象).update(codeConfigId=wei_obj对象.codeConfigId, user_绑定企微usrID账号=userID, + codeQrCode=wei_obj对象.codeQrCode, codeRemark=wei_obj对象.codeRemark) + + +if __name__ == '__main__': + pass + # + # resData = wecom客户联系_联系我_管理().获取企业已配置的_联系我_方式( config_id="bbc5220b82e614ceeff98fd9f2b04827" ) + # wecom客户联系_联系我_管理().获取企业已配置的_联系我_列表() + start时间戳 = datetime(year=2026, month=1, day=1).timestamp() + wecom客户联系_联系我_管理(addres_省="江苏省", address_市="泰州市", address_区县="海陵区").最终处理完整的企微二维码信息(start时间戳=start时间戳) # wecom客户联系_联系我_管理().删除企业已配置的_联系我_方式(config_id="13ee9dcd9a4f7a50ab0f293af90daf3c") diff --git a/wechat_项目工具包/企业微信工具包/获取配置了客户联系功能的成员列表.py b/wechat_项目工具包/企业微信工具包/获取配置了客户联系功能的成员列表.py new file mode 100644 index 0000000..daa87c0 --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/获取配置了客户联系功能的成员列表.py @@ -0,0 +1,39 @@ +"""注释""" + +from requests import get + +from wechat_token.token工具包 import sixToken + + + + + +class wecom获取配置了客户联系功能的成员列表: + """ + 获取配置了客户联系功能的成员列表 + 最后更新:2023/12/01 + 企业和第三方服务商可通过此接口获取配置了客户联系功能的成员列表。 + + 请求方式:GET(HTTPS) + 请求地址:https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list?access_token=ACCESS_TOKEN + """ + + + + @classmethod + def 获取配置了客户联系功能的成员列表( cls ) -> dict: + """ + 获取配置了客户联系功能的成员列表 + """ + wecom_token = sixToken.get_wecom_token( ) + url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list?access_token={wecom_token}" + data = get( url=url ).json( ) + print( data ) + return data + + + + + +if __name__ == '__main__': + print( wecom获取配置了客户联系功能的成员列表.获取配置了客户联系功能的成员列表( ) ) diff --git a/wechat_项目工具包/企业微信工具包/设置接收事件服务器通讯录.py b/wechat_项目工具包/企业微信工具包/设置接收事件服务器通讯录.py new file mode 100644 index 0000000..80e28ba --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/设置接收事件服务器通讯录.py @@ -0,0 +1,80 @@ +import base64 +import hashlib + +import jmespath +import xmltodict +from Crypto.Cipher import AES +from django.core.handlers.wsgi import WSGIRequest +from rest_framework.request import Request + + +class wecom设置接收事件服务器通讯录: + """https://work.weixin.qq.com/wework_admin/frame#apps/contactsApi""" + # 跟认证目录下的功能是一样的(这里是留一个备份) + token = "bVWt1PEUCG" # url验证的token(当前的值为江苏六果科技有限公司) + EncodingAESKey = "LS6VsiJA6Vpb3nJlt34vMZFAbuKDJkFuH2KxuEXYuUR" # 配置的解密(当前的值为江苏六果科技有限公司) + corp_id = "wwbe6369dc26a9d83a" # 企业微信🆔(当前的值为 江苏六果科技有限公司) + corpsecret = "SIRyum7vQh-Bt36AxnqKMX0HIiE-zkYbjYgSat7reZw" # 企业微信 secret(当前的值为 江苏六果科技有限公司) + + # phone_secret = "WNxZZdcU3FRS5msq_kHZaaZOBauBEjJZdQV3VrAxu0c" # 通讯录 secret + + @classmethod + def post解密推送消息体(cls, msg_content: bytes): + """""" + # 从XML中找到Encrypt标签的内容,即加密数据 + xmldict = xmltodict.parse(msg_content.decode()) + Encrypt = jmespath.search(data=xmldict, expression="xml.Encrypt", ) + # 将EncodingAESKey进行Base64解码,并补足填充字符'=' + AESKey = base64.b64decode(cls.EncodingAESKey + '=') + + # 创建一个AES加密器对象,使用CBC模式和指定的初始化向量(IV) + cipher = AES.new(key=AESKey, mode=AES.MODE_CBC, IV=AESKey[:16]) + # 对加密数据进行Base64解码 + aes_msg = base64.b64decode(Encrypt) + # 使用解密器对象解密数据 + de_text = cipher.decrypt(plaintext=aes_msg) + print(de_text) + # 去除解密数据地前16个字节的随机字符串 + content = de_text[16:] + # 解析前4个字节以获取XML内容的实际长度,并将其从网络字节序转换为主机字节序 + # xml_len = socket.ntohl(struct.unpack("I", content[:4])[0]) + xml_len = int.from_bytes(content[:4], byteorder='big') + # 根据解析出的长度提取实际的XML内容 + xml_content = content[4: xml_len + 4] + # 打印XML内容 + # 将XML内容解析为字典格式 + as_dict = xmltodict.parse(xml_input=xml_content) + + # 打印解析后的字典 + return as_dict + + @classmethod + def get请求算法(cls, echostr): + """""" + AESKey = base64.b64decode(cls.EncodingAESKey + '=') + aes_msg = base64.b64decode(echostr) + aes = AES.new(key=AESKey, mode=AES.MODE_CBC, iv=aes_msg[:16]) + de_text = aes.decrypt(plaintext=aes_msg) + content = de_text[16:] # 去掉前16随机字节 + # 取出4字节的msg_len + xml_len = int.from_bytes(content[:4], byteorder='big') + xml_content = content[4: xml_len + 4] + return xml_content + + @classmethod + def get解密验证消息(cls, request: WSGIRequest | Request, ): + """接受微信发过来的get请求,拿到参数后解决,并且回复值,结果为验证成功""" + GET_OBJ = request.query_params + signature = jmespath.search(data=GET_OBJ, expression="msg_signature", ) + timestamp = jmespath.search(data=GET_OBJ, expression="timestamp", ) + nonce = jmespath.search(data=GET_OBJ, expression="nonce", ) + echostr = jmespath.search(data=GET_OBJ, expression="echostr", ) + # TODO:sorted([token, timestamp, nonce])这是就是对三个参数进行字典排序 + hashstr = ''.join(sorted([cls.token, timestamp, nonce, echostr, ])) # 这是就是对三个参数进行字典排序 + sig = hashlib.new(name="sha1", data=hashstr.encode()).hexdigest() + if sig == signature: + ret = cls.get请求算法(echostr) + s = ret.decode().strip() + return s + else: + raise Exception("没有验yghd成功") diff --git a/wechat_项目工具包/企业微信工具包/通讯录管理类.py b/wechat_项目工具包/企业微信工具包/通讯录管理类.py new file mode 100644 index 0000000..6d3b1b6 --- /dev/null +++ b/wechat_项目工具包/企业微信工具包/通讯录管理类.py @@ -0,0 +1,99 @@ +import jmespath +import requests +from requests import post + +from wechat_token.token工具包 import sixToken + + +class 通讯录管理: + """注释""" + + def 成员扩展属性(self): + """ + + """ + pass + """ + 成员自定义属性需要先在WEB管理端添加,见扩展属性添加方法,否则忽略未知属性的赋值。 + • 新增/更新:仅通讯录同步助手或第三方通讯录应用可以进行 + • 查询:代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 + """ + + def 创建成员(self): + """ + + """ + pass + + def 读取成员(self): + """ + + """ + pass + """ + 应用只能获取可见范围内的成员信息,且每种应用获取的字段有所不同,在返回结果说明中会逐个说明。企业通讯录安全特别重要,企业微信将持续升级加固通讯录接口的安全机制,以下是关键的变更点: + 从2022年6月20号20点开始,除通讯录同步以外的基础应用(如客户联系、微信客服、会话存档、日程等),以及新创建的自建应用与代开发应用,调用该接口时,不再返回以下字段:头像、性别、手机、邮箱、企业邮箱、员工个人二维码、地址,应用需要通过oauth2手工授权的方式获取管理员与员工本人授权的字段。 + 【重要】从2022年8月15日10点开始,“企业管理后台 - 管理工具 - 通讯录同步”的新增IP将不能再调用此接口,企业可通过「获取成员ID列表」和「获取部门ID列表」接口获取userid和部门ID列表。查看调整详情。 + """ + wecom_phone_token = sixToken.get_weom_phone_token() + print(wecom_phone_token) + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/user/get" + data = requests.get(url=uri, params={"access_token": wecom_phone_token, "userid": "HuDie_1"}) + print(data.json()) + + def 更新成员(self): + """ + + """ + pass + + def 删除成员(self): + """ + + """ + pass + + def 获取成员ID列表(self): + """ + + """ + pass + """ + 获取企业成员的userid与对应的部门ID列表,预计于2022年8月8号发布。若需要获取其他字段,参见「适配建议」。 + 请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token=ACCESS_TOKEN + """ + + wecom_phone_token = sixToken.get_weom_phone_token() + print(wecom_phone_token) + uri = f"https://qyapi.weixin.qq.com/cgi-bin/user/list_id" + data = requests.post(url=uri, params={"access_token": wecom_phone_token}) + print(data.json()) + + def unionid与external_userid的关联(self): + """本接口自建应用是不能调用的,所以,本接口无效,仅限了服务商代开发或""" + pass + wecom_token = sixToken.get_wecom_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/idconvert/unionid_to_external_userid?access_token={wecom_token}" + post_data = { + "unionid": "oy4Jw6A1T3WkKOOhMxcbQTDSM8rs", + "openid": "o6oV61xoMYAFNpi4RpVjn3BFGB1U", + "subject_type": 0 + } + data = post(url=uri, json=post_data).json() + print(data) + + @classmethod + def userid转openid(cls): + wecom_phone_token = sixToken.get_weom_phone_token() + uri = f"https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid" + data = requests.post(url=uri, params={"access_token": wecom_phone_token}, json={"userid": "YuanBao1975"}) + print(data.json()) + + +if __name__ == '__main__': + pass + 通讯录管理().获取成员ID列表() + # 通讯录管理.userid转openid() + # 通讯录管理().unionid与external_userid的关联() + # 通讯录管理().读取成员() diff --git a/wechat_项目工具包/小程序交易管理服务/小程序交易订单管理工具.py b/wechat_项目工具包/小程序交易管理服务/小程序交易订单管理工具.py new file mode 100644 index 0000000..3f690c4 --- /dev/null +++ b/wechat_项目工具包/小程序交易管理服务/小程序交易订单管理工具.py @@ -0,0 +1,92 @@ +from datetime import datetime +from zoneinfo import ZoneInfo + +import orjson +import pydash +import requests +from pydantic import BaseModel + +from wechat_token.token工具包 import sixToken +from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司 +from wechat_数据库.支付订单数据库.商品订单数据 import order订单 + + +class miniTransaction交易管理服务工具(BaseModel): + # demo_必填: int = Field(..., description="描述") # 必传属发生 + # demo_可选: Optional[int] = None # 可选值 + # demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + def 发货信息录入(self, order支付商家侧订单号, ): + pass + print("开始调用录入订单信息了") + mini_token = sixToken.get_mini_token() + order订单对象 = order订单.objects.get(order支付商家侧订单号=order支付商家侧订单号) + goods_商品标题: str = pydash.get(obj=pydash.head(order订单对象.order购物车商品数据), path="goods_商品标题") + print(goods_商品标题, "00000000000000", order订单对象.order购物车商品数据) + print("打印检测 order商家生成的交易订单号", order支付商家侧订单号) + print("打印检测 order支付微信官方订单号", order订单对象.order支付微信官方订单号) + print("打印检测 order物流公司订单编号", order订单对象.order物流公司订单编号) + + upload_time_上传时间 = datetime.now(tz=ZoneInfo("Asia/Shanghai")).isoformat(timespec="seconds") + uri = f"https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token={mini_token}" + 录入订单需要的数据 = { + "order_key": { # 订单,需要上传物流信息的订单,必传 + "order_number_type": 1, # 订单单号类型,1-商户号单号 2-微信交易单号,必传 + "out_trade_no": order支付商家侧订单号, + "transaction_id": order订单对象.order支付微信官方订单号, # 原支付交易对应的微信订单号,必传 + "mchid": sixpay六果科技公司.mchid, # 支付下单商户的商户号,由微信支付生成并下发,必传 + }, + "logistics_type": 1, # 物流模式,1-实体物流配送 2-同城配送 3-虚拟商品 4-用户自提,必传 + "delivery_mode": 1, # 发货模式,1-UNIFIED_DELIVERY(统一发货)2-SPLIT_DELIVERY(分拆发货),必传 + # "is_all_delivered": True, # 分拆发货模式时必填,标识是否已全部发货完成,非必传 + "shipping_list": [ # 物流信息列表,支持1~15个物流单,必传 + { + "tracking_no": order订单对象.order物流公司订单编号, + "express_company": "EMS", # 物流公司编码,快递公司ID,参见获取运力 id 列表get_delivery_list,物流快递发货时必填, 示例值: DHL 字符字节限制: [1, 128] + "item_desc": goods_商品标题, # 商品信息,例如:微信红包抱枕*1个,限120个字以内 + }, + ], + "upload_time": upload_time_上传时间, # 上传时间,用于标识请求的先后顺序,必传 + "payer": { # 支付者信息,必传 + "openid": order订单对象.order支付者openid, # 用户在商户appid下的唯一标识,必传 + }, + } + json_data = orjson.dumps(录入订单需要的数据, option=orjson.OPT_SORT_KEYS, ).decode(encoding="utf-8") + postData = requests.post(url=uri, data=json_data) + print(postData.json(), "00000000000000000") + + def 查询订单发货状态(self, order支付商家侧订单号): + pass + mini_token = sixToken.get_mini_token() + order订单对象 = order订单.objects.get(order支付商家侧订单号=order支付商家侧订单号) + uri = f"https://api.weixin.qq.com/wxa/sec/order/get_order?access_token={mini_token}" + 查询订单发货状态需要的数据 = { + "transaction_id": order订单对象.order支付微信官方订单号, # 原支付交易对应的微信订单号。否 + "merchant_id": sixpay六果科技公司.mchid, # 否 支付下单商户的商户号,由微信支付生成并下发 + "merchant_trade_no": order支付商家侧订单号, # 商户系统内部订单号,只能是数字、大小写字母`_-*`且在同一个商户号下唯一。 + } + postData = requests.post(url=uri, json=查询订单发货状态需要的数据) + print(postData.json()) + + def 确认收货提醒(self, order物流数据, order支付微信官方订单号): + pass + """这里的调用的时机为: 目前的业务逻辑是,物流的状态更新用户已签收了 , 我会在此时调用户确认接口 用户会收得到一个 确认收货的提示""" + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive?access_token={mini_token}" + # 快递签收时间设定为 2026-07-24 04:11:24 + action_time_签收时间戳 = pydash.get(obj=pydash.head(order物流数据), path="action_time") + data = { + "transaction_id": order支付微信官方订单号, # 原支付交易对应的微信订单号,非必传 + "received_time": action_time_签收时间戳, # 快递签收时间,时间戳形式,必传 + } + postData = requests.post(url=uri, json=data) + # 当请求发送后, 因为只能发送一次,所以需要直接更新状态, + 更新对象 = order订单.objects.get(order支付微信官方订单号=order支付微信官方订单号) + 更新对象.order物流状态 = "待用户确认收货" + 更新对象.save() + + +if __name__ == "__main__": + pass + # miniTransaction交易管理服务工具().查询订单发货状态(order支付商家侧订单号="OAT01KYDFM1E8NS7DXRX18RRYVR52") + miniTransaction交易管理服务工具().发货信息录入(order支付商家侧订单号="OAT01KYNF9MXZ0CZ8A7Q0R3TBS55E") diff --git a/wechat_项目工具包/小程序工具包/同城配送工具/同城配送.py b/wechat_项目工具包/小程序工具包/同城配送工具/同城配送.py new file mode 100644 index 0000000..d475cfd --- /dev/null +++ b/wechat_项目工具包/小程序工具包/同城配送工具/同城配送.py @@ -0,0 +1,222 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:40 +FilePath: django_小程序/同城配送工具/同城配送.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" +import os + +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() + +import json +import time +from dataclasses import dataclass, field +from pathlib import Path + +import pydash +from django.conf import settings + +from pydantic import BaseModel + +import base64 +from requests import Response, post +import orjson +from Crypto.Cipher import AES +from Crypto.Hash import SHA256 +from Crypto.PublicKey import RSA +from Crypto import Random +from Crypto.Signature import pss + +public_key = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/public_key.pem").read_text() +# public_key = Path("../../../wechat_微信支付证书/江苏六果科技有限公司支付证书/public_key.pem").resolve().read_text() +private_key = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/private_key.pem").read_text() +# private_key = Path("../../../wechat_微信支付证书/江苏六果科技有限公司支付证书/private_key.pem").resolve().read_text() +平台证书文本 = Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/开放平台证书.pem").read_text() + + +# 平台证书文本 = Path("../../../wechat_微信支付证书/江苏六果科技有限公司支付证书/开放平台证书.pem").resolve().read_text() + + +class postData请求体类型(BaseModel): + iv: str + data: str + authtag: str + + +@dataclass(kw_only=True) +class six同城加解密工具: + """同城配送类加签,解密""" + # add数据: bytes + uri_urls: str + data_body: dict + _timestamp: int = field(init=False) + uri_path: str = field(init=False) + mini_token: str = field(init=False) + add_GCM使用的认证数据_ADD数据: bytes = field(init=False) + postData加密后的数据: postData请求体类型 = field(init=False) + heardes_请求头数据: dict = field(init=False) + aes_key对称密钥 = base64.b64decode("CV/RZev/1A1eg7TOgzvEOy5/to2aM8SE6Ab/R9E3BgI=") + aes_str对称密钥 = "CV/RZev/1A1eg7TOgzvEOy5/to2aM8SE6Ab/R9E3BgI=" + aes对称密钥编号 = "b02be3855ff9b990b2183505f165317e" + rsa非对称密钥编号 = "442e1b521422ec70844a3272e5c857dd" + api开放平台证书编号 = "5330e9294308d338a5e145fd03d0ea6a" + 平台证书对象 = 平台证书文本 + rsa_private = private_key + rsa_public = public_key + mini_appid = "wxf612e825377328f0" + mini_AppSecret = "8691f774e3c0c5a876b21a3e84109ef0" + + def __post_init__(self): + self.mini_token = sixToken.get_mini_token() + self._timestamp = int(time.time()) + + # self.本地解密( ) + + def 加密(self, ): + """ + :return: + :rtype: + """ + iv_random_bytes = Random.get_random_bytes(12) + iv_base64_12 = base64.b64encode(iv_random_bytes).decode() + random_bytes_n = Random.get_random_bytes(16) + _n = base64.b64encode(random_bytes_n).decode() # 随机字符串,_n的值 推荐使用16-32 字节非固定长度随机base64字符串 + _appid = self.mini_appid # 当前小程序的Appid + self.add_GCM使用的认证数据_ADD数据 = (f"{self.uri_urls}|{self.mini_appid}|{str(self._timestamp).strip()}|" + f"{self.aes对称密钥编号}").encode(encoding="utf-8") + data明文 = { + "_n": _n, "_appid": self.mini_appid, "_timestamp": self._timestamp, + } + data明文格式 = dict(data明文, **self.data_body) + data明文格式_bytes = orjson.dumps(data明文格式).decode() + cliper = AES.new(key=self.aes_key对称密钥, mode=AES.MODE_GCM, nonce=iv_random_bytes) + """ + AAD + 1:攻击者无法修改 AAD 而不被发现(解密时会验证失败)。 + 2:确保加密数据与特定请求关联(如 API 路径、AppID 等)。 + 3: 不加密但受保护:AAD 本身不加密,但它的完整性会被 MAC 验证。 + """ + cliper.update(assoc_data=self.add_GCM使用的认证数据_ADD数据) # + real_ciphertext, real_authTag = cliper.encrypt_and_digest(data明文格式_bytes.encode()) + data_base64 = base64.b64encode(real_ciphertext).decode() + authtag_base64 = base64.b64encode(real_authTag).decode() + self.postData加密后的数据 = postData请求体类型(**{"iv": iv_base64_12, "data": data_base64, "authtag": authtag_base64, }) + self.本地解密() # 测试调用一下本地解密,是否有效; + print("这里会报错的吗") + + def 本地解密(self, ): + """ + 解密功能 + :return: + :rtype: + """ + # 将base64字符串解码; + iv_bytes = base64.b64decode(self.postData加密后的数据.iv) # 将base64字符串解码; + ciphertext = base64.b64decode(self.postData加密后的数据.data) # 将base64字符串解码; + cipher = AES.new(self.aes_key对称密钥, AES.MODE_GCM, nonce=iv_bytes) + cipher.update(self.add_GCM使用的认证数据_ADD数据) + try: + padded_data = cipher.decrypt(ciphertext) + return + except ValueError: + raise ValueError("解密出错了") + + def 对加密数据进行签名(self, ): + """ + 对返回的加密数据进行解密; + """ + # 转换为紧凑 JSON 格式 + postdata = json.dumps(self.postData加密后的数据.model_dump(), ensure_ascii=False, ) + # 构造签名串 + sign_str = f"{self.uri_urls}\n{self.mini_appid}\n{self._timestamp}\n{postdata}" + # RSA 签名 + private_key_obj = RSA.import_key(self.rsa_private) + h = SHA256.new(sign_str.encode()) + + # ✅ 改为 PSS 签名 + signature = pss.new(private_key_obj).sign(h) + sig = base64.b64encode(signature).decode() + + self.heardes_请求头数据 = { + "Wechatmp-Appid": self.mini_appid, + "Wechatmp-TimeStamp": str(self._timestamp), + "Wechatmp-Signature": sig, + "Content-Type": "application/json", + "Accept": "application/json", + } + + def 验证签名串(self, respose: Response): + """""" + # 获取原始响应文本(避免任何自动转换,我们使用response.content然后手动解码为utf-8) + Wechatmp_TimeStamp = pydash.get(obj=respose.headers, path="Wechatmp-TimeStamp", default=None) + Wechatmp_Appid = pydash.get(obj=respose.headers, path="Wechatmp-Appid", default=None) + Wechatmp_Signature = pydash.get(obj=respose.headers, path="Wechatmp-Signature", default=None) + # 2. 获取原始响应体(非常重要) + raw_body = respose.text.strip() # 去除首尾空白,确保无额外\n + 创建拼接字答串 = f"{self.uri_urls}\n{Wechatmp_Appid}\n{str(Wechatmp_TimeStamp)}\n{raw_body}" + signature = base64.b64decode(Wechatmp_Signature) + msg_hash = SHA256.new(创建拼接字答串.encode(encoding="utf-8")) + public_obj = RSA.import_key(self.平台证书对象) + # 创建PSS签名验证器 + try: + pss.new(rsa_key=public_obj).verify(msg_hash=msg_hash, signature=signature) # type: ignore + print("验证成功了") + return True + except Exception as e: + print(f"❌ 签名验证失败: {str(e)}") + raise e + + def 解签(self, respose: Response): + Wechatmp_TimeStamp = pydash.get(obj=respose.headers, path="Wechatmp-TimeStamp", default=None) + Wechatmp_Appid = pydash.get(obj=respose.headers, path="Wechatmp-Appid", default=None) + # Wechatmp_Signature 平台证书签名数据,使用base64编码 + self.验证签名串(respose=respose) + # ✅ 强制重新构造 AAD,确保与加密端一致 + add_data = f"{self.uri_urls}|{Wechatmp_Appid}|{Wechatmp_TimeStamp}|{self.aes对称密钥编号}" + iv = pydash.get(obj=respose.json(), path="iv", default=None) + authtag = pydash.get(obj=respose.json(), path="authtag", default=None) + data = pydash.get(obj=respose.json(), path="data", default=None) + iv_bytes = base64.b64decode(iv) + ciphertext = base64.b64decode(data) + cipher = AES.new(self.aes_key对称密钥, AES.MODE_GCM, nonce=iv_bytes) + cipher.update(add_data.encode()) # ✅ 使用新构造的 AAD + try: + padded_data = cipher.decrypt(ciphertext) # 只能调用decrypt这个方法() + deciphertext = padded_data.decode() + return deciphertext + except ValueError as e: + raise ValueError("解密出错了,请检查 AAD、IV、密文或密钥一致性") from e + + def call(self): + """""" + self.加密() + self.对加密数据进行签名() + data = post(url=self.uri_urls, params={"access_token": self.mini_token, }, headers=self.heardes_请求头数据, json=self.postData加密后的数据.model_dump()) + print(data.json(), "请求出错了吗") + return self.解签(respose=data) + + +if __name__ == "__main__": + # six同城加解密工具.对加密数据进行签名( urlpath="https://api.weixin.qq.com/wxa/getuserriskrank", data_body={ } ) # # + # six = six同城加解密工具(uri_urls="https://api.weixin.qq.com/cgi-bin/express/intracity/querystore", + # data_body={}).call() + # print(six) + 查询运费请求数据 = { + "wx_store_id": "4000000000016308013", + "user_lng": "119.893083", + "user_lat": "32.474616", + "user_address": "江苏省泰州市海陵区城西街道任景路U牌美容店", + "user_name": "元宝", + "user_phone": "13372551360", + "cargo": {"cargo_name": "测试商品", "cargo_type": 3, "cargo_num": 7, "cargo_price": 5000, "cargo_weight": 2500} + } + res = six同城加解密工具(uri_urls="https://api.weixin.qq.com/cgi-bin/express/intracity/preaddorder", data_body=查询运费请求数据).call() + print(res) diff --git a/wechat_项目工具包/小程序工具包/同城配送工具/小程序用户授权数据.py b/wechat_项目工具包/小程序工具包/同城配送工具/小程序用户授权数据.py new file mode 100644 index 0000000..702487b --- /dev/null +++ b/wechat_项目工具包/小程序工具包/同城配送工具/小程序用户授权数据.py @@ -0,0 +1,73 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:39 +FilePath: django_小程序/同城配送工具/小程序用户授权数据.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" +from wechat_项目工具包.微信支付工具包.微信支付类 import paymentCategory + + + +"""功能模块""" +import jmespath +from requests import post, get + + +class wei小程序服务端工具: + """微信登陆""" + + @classmethod + def 获取OPENID(cls, secret: str, js_code: str, appid: str, ) -> dict: + """ + @param secret: 小程序 appSecret + @type secret: string + @param js_code: 登录时获取的 code,可通过wx.login获取 + @type js_code: string + @param appid: 小程序的app🆔 + @type appid: string + @return:{"session_key":"etC7EOml89Pd8XIhTFyAOA==","expires_in":7200,"openid":"oNTAd0fm1GQAdohfbvywhGstsIPc","unionid":"ojWkM1MnLrdty0S3Vks2pYorp4MY"} + @rtype: dict + """ + url = "https://api.weixin.qq.com/sns/jscode2session" + data = { + "appid": appid, + "secret": secret, + "js_code": js_code, + "grant_type": "authorization_code" + } + res_data = get(url=url, params=data) + res = res_data.json() + errcode = jmespath.search(data=res, expression="errcode", ) + if res_data.status_code == 200: + if errcode is None: + return res + else: + raise Exception(f"登陆错误码:{res}") + raise Exception("请求login登陆时出错了") + + @classmethod + def 获取手机号(cls, url, code: str): + """ + @param url: + @type url: + @param code: + @type code: + @return: {'session_key': 'etC7EOml89Pd8XIhTFyAOA==', 'expires_in': 7200, 'openid': 'oNTAd0fm1GQAdohfbvywhGstsIPc', 'unionid': 'ojWkM1MnLrdty0S3Vks2pYorp4MY'} + @rtype: + """ + data = { + "code": code + } + res_data = post(url=url, json=data) + res = res_data.json() # type: dict + return res + + +if __name__ == '__main__': + pass + res = wei小程序服务端工具.获取OPENID( + js_code="0e1sYCkl2bCmhg4DG2ll2kheh10sYCkn", appid=paymentCategory.appid, + secret=paymentCategory.appsecret, + ) diff --git a/wechat_项目工具包/小程序工具包/同城配送工具/小程序码生成工具.py b/wechat_项目工具包/小程序工具包/同城配送工具/小程序码生成工具.py new file mode 100644 index 0000000..522b0d2 --- /dev/null +++ b/wechat_项目工具包/小程序工具包/同城配送工具/小程序码生成工具.py @@ -0,0 +1,138 @@ +import io +import os + +import django +import pydash +from django.core.files.storage import default_storage + +from wechat_token.token工具包 import sixToken + + + +django.setup() +from requests import post + + +class 小程序码与小程序链接: + """获取所有的小程序码的业务接口""" + + def 小程序码_getQRCode(self): + """ + 该接口用于获取小程序码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制,详见获取小程序码。 + """ + pass + mini_token = sixToken.get_mini_token() + post_url = f"https://api.weixin.qq.com/wxa/getwxacode?access_token={mini_token}" + post_data = { + "path": "tabPage/Home/Home?xiao=zizi", + # 扫码进入的小程序页面路径,最大长度 1024 个字符,不能为空,scancode_time为系统保留参数,不允许配置;对于小游戏,可以只传入 query 部分,来实现传参效果,如:传入 "?foo=bar",即可在 wx.getLaunchOptionsSync 接口中的 query 参数获取到 {foo:"bar"}。 + "is_hyaline": True, # 默认值false;是否需要透明底色,为 true 时,生成透明底色的小程序码 + "env_version": "trial", # 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 + } + data = post(url=post_url, json=post_data) + default_storage.save(name="uploads/xiao.png", content=io.BytesIO(initial_bytes=data.content)) # 作用:是可以自动将图片保存在指定的media目录下的 uploads目录下的图片名 xiao.png + + def 小程序码_getUnlimitedQRCode(self): + """ + 该接口用于获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。 更多用法详见 获取小程序码。 + """ + pass + mini_token = sixToken.get_mini_token() + post_url = f"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={mini_token}" + post_data = { + "path": "tabPage/Home/Home?zizi=xiaozizi", # 非必填 默认是主页,页面 page,例如 pages/index/index,根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面。scancode_time为系统保留参数,不允许配置 + "scene": "abc", # 必填 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符 + "is_hyaline": True, # 默认值false;是否需要透明底色,为 true 时,生成透明底色的小程序码 + "env_version": "trial", # 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 + } + data = post(url=post_url, json=post_data) + print(data.status_code) + default_storage.save(name="uploads/getUnlimitedQRCode.png", content=io.BytesIO(initial_bytes=data.content)) # 作用:是可以自动将图片保存在指定的media目录下的 uploads目录下的图片名 xiao.png + + def 小程序码_createQRCode(self): + """ + 该接口用于获取小程序二维码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。 更多用法详见 获取小程序码。 + """ + pass + mini_token = sixToken.get_mini_token() + post_url = f"https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token={mini_token}" + post_data = { + "path": "tabPage/Home/Home?foo=bar", # 非必填 默认是主页,页面 page,例如 pages/index/index,根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面。scancode_time为系统保留参数,不允许配置 + "scene": "abc", # 必填 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符 + "is_hyaline": True, # 默认值false;是否需要透明底色,为 true 时,生成透明底色的小程序码 + "env_version": "trial", # 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 + } + data = post(url=post_url, json=post_data) + print(data.status_code) + default_storage.save(name="uploads/createQRCode.png", content=io.BytesIO(initial_bytes=data.content)) # 作用:是可以自动将图片保存在指定的media目录下的 uploads目录下的图片名 xiao.png + + def urlScheme_获取加密Scheme(self): + mini_token = sixToken.get_mini_token() + post_url = f"https://api.weixin.qq.com/wxa/generatescheme?access_token={mini_token}" + post_data = { + "jump_wxa": + { + "path": "tabPage/Home/Home", # 通过 scheme 码进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带 query。path 为空时会跳转小程序主页。 + "query": "foo=bar", # 通过 scheme 码进入小程序时的 query,最大1024个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~%` + "env_version": "trial", # 默认值"release"。要打开的小程序版本。正式版为"release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 + }, + "is_expire": True, + "expire_type": 1, # number 否 默认值0,到期失效的 scheme 码失效类型,失效时间:0,失效间隔天数:1 + "expire_interval": 1, # number 否到期失效的 scheme 码的失效间隔天数。生成的到期失效 scheme 码在该间隔时间到达前有效。最长间隔天数为30天。is_expire 为 true 且 expire_type 为 1 时必填 + } + + data = post(url=post_url, json=post_data) + print(data.status_code) + print(data.json()) + openlink = pydash.get(obj=data.json(), path="openlink") + print(openlink) + # default_storage.save(name="uploads/urlScheme.png", content=io.BytesIO(initial_bytes=data.content)) # 作用:是可以自动将图片保存在指定的media目录下的 uploads目录下的图片名 xiao.png + + def shortLink(self): + """ + 获取小程序 Short Link,适用于微信内拉起小程序的业务场景。目前只开放给电商类目(具体包含以下一级类目:电商平台、商家自营、跨境电商)。通过该接口,可以选择生成到期失效和永久有效的小程序短链,详情见获取 Short Link。 + :return: + :rtype: + """ + mini_token = sixToken.get_mini_token() + post_url = f"https://api.weixin.qq.com/wxa/genwxashortlink?access_token={mini_token}" + post_data = { + "page_url": "tabPage/Home/Home?q=1", # 通过 Short Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,可携带 query,最大1024个字符 + "page_title": "Homework title", # string 否 页面标题,不能包含违法信息,超过20字符会用... 截断代替 + "is_permanent": True, # boolean 否 默认值false。生成的 Short Link 类型,短期有效:false,永久有效:true + } + + data = post(url=post_url, json=post_data) + print(data.status_code) + print(data.json()) + link = pydash.get(obj=data.json(), path="link") + print(link) + + def urlLink(self): + """ + 获取小程序 URL Link,适用于短信、邮件、网页、微信内等拉起小程序的业务场景。 + :return: + :rtype: + """ + mini_token = sixToken.get_mini_token() + post_url = f"https://api.weixin.qq.com/wxa/generate_urllink?access_token={mini_token}" + post_data = { + "path": "tabPage/Home/Home", # 通过 URL Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带 query 。path 为空时会跳转小程序主页 + "query": "aaa=bbb", # 通过 URL Link 进入小程序时的query,最大1024个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~% + } + + data = post(url=post_url, json=post_data) + print(data.status_code) + print(data.json()) + url_link = pydash.get(obj=data.json(), path="url_link") + print(url_link) + + +if __name__ == '__main__': + pass + # 小程序码与小程序链接().小程序码_getQRCode() # 生成的是小程序码 + # 小程序码与小程序链接().小程序码_getUnlimitedQRCode() # + # 小程序码与小程序链接().小程序码_createQRCode() # 生成的是二维码 + 小程序码与小程序链接().urlScheme_获取加密Scheme() # weixin://dl/business/?t=vQAOKCN3Shu 生成的链接 必须要有正式版本才可以 + 小程序码与小程序链接().shortLink() # 小程序://元宝零售/Homeworktitle/Lsr22VT1TDJwlyj 生成的是链接 必须要有正式版本才可以 目前只开放给电商类目(具体包含以下一级类目:电商平台、商家自营、跨境电商) + 小程序码与小程序链接().urlLink() # 生成的是链接 必须要有正式版本才可以 https://wxaurl.cn/nJAFXSaIgym diff --git a/wechat_项目工具包/小程序工具包/同城配送工具/小程序订单管理工具.py b/wechat_项目工具包/小程序工具包/同城配送工具/小程序订单管理工具.py new file mode 100644 index 0000000..21c0128 --- /dev/null +++ b/wechat_项目工具包/小程序工具包/同城配送工具/小程序订单管理工具.py @@ -0,0 +1,89 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:40 +FilePath: django_小程序/同城配送工具/小程序订单管理工具.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" +from wechat_token.token工具包 import sixToken + + + +"""小程序订单管理工具""" +import os +from zoneinfo import ZoneInfo + +import orjson + + +from datetime import datetime + +import requests + + +class six订单管理: + """录入订单接口的类""" + + @classmethod + def order发货信息录入接口(cls, iso_format_time_inner: str, transaction_id: str, openid: str): + """ + 调用 录入订单接口,自动录入订单 + """ + mini_token = sixToken.get_mini_token() + uri = f"https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token={mini_token}" + # 订单数据 = { + # "order_key": { # 订单,需要上传物流信息的订单 + # "order_number_type": 2, # 是 订单单号类型,用于确认需要上传详情的订单。枚举值1,使用下单商户号和商户侧单号;枚举值2,使用微信支付单号。 + # "transaction_id": "4200002639202506141300476684" # 否 原支付交易对应的微信订单号 + # }, + # "delivery_mode": 2, # 发货模式,发货模式枚举值:1、UNIFIED_DELIVERY(统一发货)2、SPLIT_DELIVERY(分拆发货) 示例值: UNIFIED_DELIVERY + # "logistics_type": 2, # 是 物流模式,发货方式枚举值:1、实体物流配送采用快递公司进行实体物流配送形式 2、同城配送 3、虚拟商品,虚拟商品,例如话费充值,点卡等,无实体配送形式 4、用户自提 + # "shipping_list": [ # 是 物流信息列表,发货物流单列表,支持统一发货(单个物流单)和分拆发货(多个物流单)两种模式,多重性: [1, 10] + # { + # # "tracking_no": "fake-trackingno-2022121419042711", + # # 否 tracking_no 物流单号,物流快递发货时必填,示例值: 323244567777 字符字节限制: [1, 128] + # # "express_company": "STO", + # # 否 物流公司编码,快递公司ID,参见「获取运力 id 列表get_delivery_list」,物流快递发货时必填, 示例值: DHL 字符字节限制: [1, 128] + # "item_desc": "卷纸", # 是 商品信息,例如:微信红包抱枕*1个,限120个字以内 + # # "contact": { # contact否 联系方式,当发货的物流公司为顺丰时,联系方式为必填,收件人或寄件人联系方式二选一 + # # "consignor_contact": "+86-177****1234" # 否 寄件人联系方式,寄件人联系方式,采用掩码传输,最后4位数字不能打掩码 示例值:0, ****123- + # # } + # } + # ], + # "upload_time": iso_format_time, # 是 上传时间,用于标识请求的先后顺序 示例值: `2022-12-15T13:29:35.120+08:00` + # "payer": { # payer 支付者,支付者信息 + # "openid": "ohQkD7A-N93kljcFmkCyG6e_D9vg" + # # 用户标识,用户在小程序appid下的唯一标识。 下单前需获取到用户的Openid 示例值: oUpF8uMuAJO_M2pxb1Q9zNjWeS6o 字符字节限制: [1, 128] + # } + # } + 订单数据 = { + "order_key": { + "order_number_type": 2, + "transaction_id": transaction_id # 使用真实的微信支付单号 + }, + "delivery_mode": 1, + "logistics_type": 2, + # "is_all_delivered": True, + "shipping_list": [ + { + "item_desc": "卷纸", # 确保中文字符被正确处理 + } + ], + "upload_time": iso_format_time_inner, # 修正时间格式 + "payer": { + "openid": openid # 真实的用户openid + } + } + + data = requests.post(url=uri, data=orjson.dumps(订单数据).decode(), ) + print(data.json()) + + +if __name__ == '__main__': + rfc_3339_time = datetime.now(tz=ZoneInfo("Asia/Shanghai")).isoformat(timespec="seconds") + print(rfc_3339_time) + # 如果报错:则需要查看一下,是不是手机真实支付的,如果是开发工具并且是扫码支付的则不会出现这个订单; + six订单管理.order发货信息录入接口(iso_format_time_inner=rfc_3339_time, + transaction_id="4200002720202508164227110344", + openid="ohQkD7A-N93kljcFmkCyG6e_D9vg") diff --git a/wechat_项目工具包/小程序工具包/小程序用户授权数据.py b/wechat_项目工具包/小程序工具包/小程序用户授权数据.py new file mode 100644 index 0000000..ccb3359 --- /dev/null +++ b/wechat_项目工具包/小程序工具包/小程序用户授权数据.py @@ -0,0 +1,76 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:39 +FilePath: django_小程序/同城配送工具/小程序用户授权数据.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" + +"""功能模块""" +import jmespath +from requests import post, get + + + + + +class wei小程序服务端工具: + """微信登陆""" + + @classmethod + def 获取OPENID( cls, secret: str, js_code: str, appid: str, ) -> dict: + """ + @param secret: 小程序 appSecret + @type secret: string + @param js_code: 登录时获取的 code,可通过wx.login获取 + @type js_code: string + @param appid: 小程序的app🆔 + @type appid: string + @return:{"session_key":"etC7EOml89Pd8XIhTFyAOA==","expires_in":7200,"openid":"oNTAd0fm1GQAdohfbvywhGstsIPc","unionid":"ojWkM1MnLrdty0S3Vks2pYorp4MY"} + @rtype: dict + """ + url = "https://api.weixin.qq.com/sns/jscode2session" + data = { + "appid": appid, + "secret": secret, + "js_code": js_code, + "grant_type": "authorization_code" + } + res_data = get( url=url, params=data ) + res = res_data.json( ) + errcode = jmespath.search( data=res, expression="errcode", ) + if res_data.status_code == 200: + if errcode is None: + return res + else: + raise Exception( f"登陆错误码:{res}" ) + raise Exception( "请求login登陆时出错了" ) + + @classmethod + def 获取手机号( cls, url, code: str ): + """ + @param url: + @type url: + @param code: + @type code: + @return: {'session_key': 'etC7EOml89Pd8XIhTFyAOA==', 'expires_in': 7200, 'openid': 'oNTAd0fm1GQAdohfbvywhGstsIPc', 'unionid': 'ojWkM1MnLrdty0S3Vks2pYorp4MY'} + @rtype: + """ + data = { + "code": code + } + res_data = post( url=url, json=data ) + res = res_data.json( ) # type: dict + return res + + + + + +if __name__ == '__main__': + pass + # res = wei小程序服务端工具.获取OPENID( + # js_code="0e1sYCkl2bCmhg4DG2ll2kheh10sYCkn", appid=paymentCategory.appid, + # secret=paymentCategory.appsecret, + # ) diff --git a/wechat_项目工具包/小程序用工关系管理/小程序用工关系.py b/wechat_项目工具包/小程序用工关系管理/小程序用工关系.py new file mode 100644 index 0000000..bb2e476 --- /dev/null +++ b/wechat_项目工具包/小程序用工关系管理/小程序用工关系.py @@ -0,0 +1,48 @@ +import json + +import requests +from pydantic import BaseModel, Field + +from wechat_token.token工具包 import sixToken + + +class mini用工关系管理工具包(BaseModel): + # demo_必填: int = Field(..., description="描述") # 必传属发生 + # demo_可选: Optional[int] = None # 可选值 + # demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + tmplIds: int = Field(default="SFFgGF1bN56_KNd_4HicCFBBfu2PCRwCyQ5upr-EVk9Vdyl4wyyQ7B1mJvjceR29", description="绑定的模板ID账号") + + def sendMini给绑定员工推送服务消息(self, touser_推送用户的openid: str): + mini_token = sixToken.get_mini_token() + + template_content = { + "data": { # ⚠️ 这个外层 "data" 是微信接口强制要求的嵌套结构 + "thing1": {"value": "aaaaaaa"}, # 替换为模板实际字段名 + "amount1": {"value": "12"}, # 金额建议纯数字(无¥符号) + }, + } + + # 2. 转为JSON字符串(ensure_ascii=False保留中文,但微信要求最终是转义后的字符串) + data_string = json.dumps(template_content, ensure_ascii=False) + + msgData = requests.post(url="https://api.weixin.qq.com/cgi-bin/message/wxopen/employeerelationmsg/send", + params={"access_token": mini_token, }, + json={"template_id": "SFFgGF1bN56_KNd_4HicCFBBfu2PCRwCyQ5upr-EVk9Vdyl4wyyQ7B1mJvjceR29", # 推送消息模板 + "page": "pageTabBar/Home/Home", # 跳转路径 + "touser": touser_推送用户的openid, # 被推送用户openid + "data": data_string, + }) + print(msgData.json()) + + def 解绑用工关系(self, touser_推送用户的openid): + """""" + mini_token = sixToken.get_mini_token() + infoData = requests.post(url="https://api.weixin.qq.com/wxa/business/unbinduserb2cauthinfo", params={"access_token": mini_token, }, json={"openid_list": [touser_推送用户的openid]}, ) + print(infoData.json()) + + +if __name__ == "__main__": + pass + # mini用工关系管理工具包().sendMini给绑定员工推送服务消息(touser_推送用户的openid="ohQkD7NJ5EASxdh6ajad4QR_6i78") + mini用工关系管理工具包().解绑用工关系(touser_推送用户的openid="ohQkD7NJ5EASxdh6ajad4QR_6i78") diff --git a/wechat_项目工具包/小程序管理后API/API安全认证.py b/wechat_项目工具包/小程序管理后API/API安全认证.py new file mode 100644 index 0000000..1a76532 --- /dev/null +++ b/wechat_项目工具包/小程序管理后API/API安全认证.py @@ -0,0 +1,28 @@ +import os + +import django + +from sixGuoDjango.settings import base_dir_name + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings") +django.setup() + +from pathlib import Path + +from django.conf import settings +from pydantic import BaseModel, Field + +非对称密钥公钥文件 = Path(settings.BASE_DIR).joinpath("wechat_项目工具包/小程序管理后API/非对称密钥公钥匙.txt").read_text(encoding="utf-8") +非对称密钥私钥文件 = Path(settings.BASE_DIR).joinpath("wechat_项目工具包/小程序管理后API/非对称密钥私钥.txt").read_text(encoding="utf-8") + + +class api认证(BaseModel): + # demo_必填: int = Field(..., description="描述") # 必传属发生 + # demo_可选: Optional[int] = None # 可选值 + # demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + + 开放平台证书编号: str = Field(default="5330e9294308d338a5e145fd03d0ea6a") + 对称密钥编号: str = Field(default="e7cbfb20e66128744285df68f7d0a712") + 对称密钥原文: str = Field(default="7eTLm4kf0YQBepT3W8Z66gAvh91veExMYjQevnb5weA=", description="对称密钥密钥明文") + 非对称密钥编号: str = Field(default="73792fe24cfe9f3f0b7cb89594883e2f") diff --git a/wechat_项目工具包/小程序管理后API/开放平台证书.cer b/wechat_项目工具包/小程序管理后API/开放平台证书.cer new file mode 100644 index 0000000..c66bbcf --- /dev/null +++ b/wechat_项目工具包/小程序管理后API/开放平台证书.cer @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9DCCAtygAwIBAgIUaB2siA/X11h8JSI6eZy5JFqS9EIwDQYJKoZIhvcNAQEL +BQAwbTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzERMA8GA1UEBwwI +U2hlblpoZW4xEDAOBgNVBAoMB1RlbmNlbnQxEDAOBgNVBAsMB1RlbmNlbnQxEzAR +BgNVBAMMCnRzbTAwMDAwMDYwHhcNMjUwMzIxMDk0MzM5WhcNMzUwMzE5MDk0MzM5 +WjCBmDEeMBwGCSqGSIb3DQEJARYPd2VpeGlubXBAcXEuY29tMRswGQYDVQQDDBJ3 +eGY2MTJlODI1Mzc3MzI4ZjAxFTATBgNVBAoMDFRlbmNlbnQgSW5jLjEOMAwGA1UE +CwwFV3hnTXAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxETAPBgNV +BAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsKzj +VjuulJIlMNUtNsbtczsR0tXD34987zaPDnv0aM7woQv9b9aOgZ8NSo+gOcxp9xXo +hek/r2F+IZi4Wo2ojDugtDF4V/8BJbv+wgPkKWeK0q5zGSmoiGV+pyA6Th9c9Xwk +X0TaOZl2sAXYYi0jdvzXt2MTrtkTv4HjsUG22svFc3D4SXXQ1MdWB4mWlevpSgqb +T7GXrLg6GJ0sk5HZuaUMjL2n81SguvRq76GRsFVylgMjbaGj1xf4kiuo5MyJStp5 +xyPSxN2R23gg6NnLOJQOa3jZgqWPTnVF6l7J1xqdEtkK1F386y3hjP9IcB95VwLp +sJRW7ZZmuabvDmy4tQIDAQABo2AwXjAdBgNVHQ4EFgQU+RzLjExXyXwuTRyzT9Vm +RFdVCz4wHwYDVR0jBBgwFoAURM1183H4z2eJGmP5z/zWI7tjRZAwDAYDVR0TAQH/ +BAIwADAOBgNVHQ8BAf8EBAMCBsAwDQYJKoZIhvcNAQELBQADggEBAE0w60N+N9ZF +nasTtkN4Ee8GQtDUNAqF0icuGKSp+HvgZB1svIxG1DCtkSe8coaq+wFojKrepW+c ++eZXmmR55YlQSrqQa9YuPfAWNgJ5BvzBsRdUz2IyClAqQPtyAq22a9SwR3z3OGUu +sQnoqFgi6jShgqOhdOmy92N/DoWEmIIlZJrchVUs2JLHuq9gaKZWMqrSUsTNrAi1 +lWbpmf9nDa92AhGtphMXU0tgYChFCYka3e0RPq5UQnMFPKH58tbIkqQqCeYKyVIT +hHNyPaB/7M6jhrF0rwn2R5Crj3oW/+FuYITHH+Tg4G+XvXgkhyx7ZS/ZA9PI3qz7 +Tf68XuBEJoI= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/wechat_项目工具包/小程序管理后API/非对称密钥公钥匙.txt b/wechat_项目工具包/小程序管理后API/非对称密钥公钥匙.txt new file mode 100644 index 0000000..ef566f0 --- /dev/null +++ b/wechat_项目工具包/小程序管理后API/非对称密钥公钥匙.txt @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+7fWfsUk5JceJXIG8a3J +Zu30KdKv3uFVP+vJtYDiTspiOd1zl2D7fzTeZ3BNLlW29OGNDFlUEUJGoVSVzh9Z +gKm4ZCpjQYSy03VH25kJHCjVZLX9aBy0DuRUN2Jwq/ma1Z9lgrJuo5Kou2oQQJgq +XON20030CqNkiQA/bMJJnN1MYJZiI7eHdW/HIC42wB31YW0ZNACEP1UfQ4o54zJz +bi6xNus9OyD2DtjV3Q0ZRjuRRUU5krBWeV2kK2XQrKJ0T5TF9q0N+QqJETA6iY33 +ScRqt25SDcpjc4dVuwSveL6fPj5JzrwfRkTtYwDlwfLz7yChJD4aJQ+NWvmyOMVW +xQIDAQAB +-----END PUBLIC KEY----- diff --git a/wechat_项目工具包/小程序管理后API/非对称密钥私钥.txt b/wechat_项目工具包/小程序管理后API/非对称密钥私钥.txt new file mode 100644 index 0000000..6f92e62 --- /dev/null +++ b/wechat_项目工具包/小程序管理后API/非对称密钥私钥.txt @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA+7fWfsUk5JceJXIG8a3JZu30KdKv3uFVP+vJtYDiTspiOd1z +l2D7fzTeZ3BNLlW29OGNDFlUEUJGoVSVzh9ZgKm4ZCpjQYSy03VH25kJHCjVZLX9 +aBy0DuRUN2Jwq/ma1Z9lgrJuo5Kou2oQQJgqXON20030CqNkiQA/bMJJnN1MYJZi +I7eHdW/HIC42wB31YW0ZNACEP1UfQ4o54zJzbi6xNus9OyD2DtjV3Q0ZRjuRRUU5 +krBWeV2kK2XQrKJ0T5TF9q0N+QqJETA6iY33ScRqt25SDcpjc4dVuwSveL6fPj5J +zrwfRkTtYwDlwfLz7yChJD4aJQ+NWvmyOMVWxQIDAQABAoIBAGIvDAh4p3JOi6C5 +gIHmcqema1Wg6565MAJ120Dj2+I1yOifO4YxewfcPGAGiuRm5K1SCS1m7oao3lnx +X1l+GvA3w0e2zO5ybzpSBcxfPhFw0AOvhP+GKqmgYEUWLbK28rEesn6vUL6W5x/r +OBmqAOQoiWHUhztbDkzt/s9SXVpEpYxoEikg2M8QBGHTY+IuHFWMKSSltWh845zK +MtSARPszxlU10WXH8xZIfTGK5EvZ6U5GHoWlDVnEJjzC5NAvf2tcrFP3suMEjEic +PPEmZXR/FNAr7MNF118hsZ8FckUlt4ngaTwT0dmSqcutCc4ye9v4YpxFOyQPoBB3 +SnfsbMUCgYEA/gIWSKt4PBsBpWvDIHBEjwYCMwZM/xOqtjnAe1gVR1SDb/fMOr/6 +FDW14841I75ez6/GZxHTDzbkxsJ7NVcRrXxKGyxL0+J50qEPnFairyGVd501Dktd +TghTGP5iffesPtRqs36oFURGCPaKetD8Ar33LjXhIzttsPCoJIs0ZbsCgYEA/bEn +VeUicXqwRdarixCgvihMem9Jm0fSyaQc7aeN1xzbI4OEuwq0tWGwJ6UmZOJcbdxx +lc7Z8Y6/U6Gv6oxFgHcOtB4cTHpBSOsKMzXcJNjVVkXzEuq6cvRIEYHZEdzN82t/ +2uMUh9DRyIzNDFJ4/+OEaiRQDT3yS8Z8/KLfLX8CgYEAv1cjIirIr75IRyweGNl5 +S6PjFDyy05MlDZADhuabYNgxCq9HkRn8cCzlj21OalaFZT2r3wh2TQe03mSyG0Qz +dNQjnsSHel0oF5psAADjG7nYtfoedV4gMx/iOPmnh+yCO/IXTo8iXqLHfwj41/uF +Wytuf8jmh3vE7XzbrGuQVPECgYAD9cL2bUg3W0HrJSmyVwUbUse21Yvhl6JrsVse +PpJRPEsTZ9cnkEg32JmGVOafhoUI1fsT6pGuWpsT9B8p2xyun60kFKA+dV4VhE25 +dOrFzHiwCxF7Rxy39KY3V76Kr9arKQ9q3EaSxCiyJ7h/q73lyKhle8GgI0pn8mY7 +D1PKgwKBgCxqlcRlHbQ3pv1NM5efI2bEdg1Dz5zuxL7DU/lBoE10dvlyJgJRbRNZ +x49nykTmM3cWjZStQBvxuqzo8XMOVvZaq9DuR0sDbNUDDI61Og/cAhtyThYsiPpL +HzgEN+3o4mVn5+0w//t1JJNpEpmSA8h4aZ0esa8E3wNe+ZMfZ4ti +-----END RSA PRIVATE KEY----- diff --git a/wechat_项目工具包/微信支付工具包/微信支付类.py b/wechat_项目工具包/微信支付工具包/微信支付类.py new file mode 100644 index 0000000..0178888 --- /dev/null +++ b/wechat_项目工具包/微信支付工具包/微信支付类.py @@ -0,0 +1,466 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:39 +FilePath: django_微信支付/支付工具/微信支付类.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" +import os + +import django + +from sixGuoDjango.settings import base_dir_name + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings") +django.setup() + +from pathlib import Path +import requests +from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司 + +import orjson +from Crypto.Util.Padding import unpad +from django.conf import settings + +"""微信支付清爽版本""" +import base64 +import hashlib +import json +import re +import secrets +import time +from datetime import datetime +from typing import Optional, Literal + +import pydash +import xmltodict +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 dicttoxml import dicttoxml +from pydantic import BaseModel +from requests import Response, post, get + + +class paymentCategory(sixpay六果科技公司): + """1""" + pass + + +class wechatPay(BaseModel): + payment: type[paymentCategory] | type[sixpay六果科技公司] + + def 构造签名串(self, uri: str, body_data: dict | bytes | str | None = None, + method: Optional[Literal["GET", "POST"]] = "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())) # 时间戳 + random_str = secrets.token_hex(nbytes=16) # 随机字符串 + + # 创建签名请求参数 + + signaturestring: str | None = None + if isinstance(body_data, str): + signaturestring = f"{method}\n{url_data}\n{shi_jian_chou}\n{random_str}\n{body_data}\n" + if isinstance(body_data, dict): + body_inner = json.dumps(obj=body_data) + signaturestring = f"{method}\n{url_data}\n{shi_jian_chou}\n{random_str}\n{body_inner}\n" + if body_data is None: + body_inner = "" + signaturestring = f"{method}\n{url_data}\n{shi_jian_chou}\n{random_str}\n{body_inner}\n" + if isinstance(body_data, bytes): + body_inner = body_data.decode() + signaturestring = f"{method}\n{url_data}\n{shi_jian_chou}\n{random_str}\n{body_inner}\n" + + # 构造一个哈希对象 + hash_obj = SHA256.new(signaturestring.encode(encoding="utf-8")) + # 加载商户私钥 + # 调用了 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() + # 组装成微信官方需要的数据; + data = { + "mchid": self.payment.mchid, + "nonce_str": random_str, + "serial_no": self.payment.serial_no, + "timestamp": shi_jian_chou, + "signature": encoded_signature, + } # 组装好的字典数据; + ftr = "WECHATPAY2-SHA256-RSA2048" + s_with_space = ftr.ljust(len(ftr) + 1) # 将字符串长度 +1(填充空格) + str_list = ",".join([f'{key}="{value}"' for key, value in data.items()]) + # 生成请求头 + Authorization = f"{s_with_space}{str_list}" + headers = { + "Content-Type": "application/json", "Authorization": Authorization, + } + 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) + if 验证签名结果: + prepay_id = f"prepay_id={prepay_id}" + # 调用方法生成返回给前端的对象 + return self.返回前端支付数据(prepay_id=prepay_id, + wechat_appid=self.payment.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: + """ + key_bytes = self.payment.apiv3.encode() + nonce_bytes = nonce.encode(encoding="utf-8") + ad_bytes = associated_data.encode(encoding="utf-8") + encrypted_data = base64.b64decode(ciphertext) + + cipher = AES.new(key=key_bytes, 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 getpay_navite(self, navite_body: dict, ): + """ + @param navite_body: + @type navite_body: + @return: + @rtype: + """ + native_url = "https://api.mch.weixin.qq.com/v3/pay/transactions/native" + headers = self.构造签名串(body_data=navite_body, uri=native_url, method="POST") + response = post(url=native_url, headers=headers, json=navite_body) + 生成的支付链接 = response.json() + print(生成的支付链接) + return 生成的支付链接 + + def callBack回调解密(self, headers, response_body: dict) -> dict: + """ + 执行微信支付回调方法(获取返回的参数数据) + @param request: + @type request: + """ + # response_data = response_body.decode() + # 调用验证签名串方法,(必需要验证确保是微信官方的回调数据;) + 验证签名串结果数据 = self.验证签名串(response_headers=headers, response_data=response_body) + print("🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏🍎 🍏", 验证签名串结果数据) + # 验证成功后;拿到返回的json数据 + # res_data = json.loads(s=response_data) # TODO 一定要序列化. + 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 返回前端支付数据(self, prepay_id: str, wechat_appid: str): + """ + 小程序调起支付 + 通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付。 + @param prepay_ids + @type prepay_id: + @return: + @rtype: + """ + shi_jian_chou = str(int(time.time())) # 生在时间戳 + random_string = secrets.token_hex(nbytes=30) # 随机字符串 + # 组装微信官方要求的格式; + qian_mian_chuan = f"{wechat_appid}\n{shi_jian_chou}\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.payment.private_key) + # 生成签名 + signature = pkcs1_15.new(private_key).sign(hash_obj) + # 将生成的签名串,转换为base格式 + encoded_signature = base64.b64encode(signature).decode() + + data_obj = { + "appId": self.payment.appid, + "timeStamp": shi_jian_chou, + "nonceStr": random_string, + "package": prepay_id, + "signType": "RSA", + "paySign": encoded_signature, + } + return { + "response": data_obj, + } + + def transferAccounts商家转账到零钱(self, transferAccountsBody): + """ + 向微信用户发起转账接口;(实测已经领到钱了)前端直接调用 wx就可以,(目前没有解决ts报错的 问题) + """ + # uri = "https://api.mch.weixin.qq.com/v3/transfer/batches" # (旧接口) + uri = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills" + # transferAccountsBody = { + # "appid": self.payment.appid, "out_bill_no": order_random, # 必填 integer【商户单号】 + # # 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 + # "transfer_scene_id": "1000", + # # 必填 integer【转账场景ID】 该笔转账使用的转账场景,可前往“商户平台-产品中心-商家转账”中申请。如:1000(现金营销),1006(企业报销)等 + # # "openid":"ohQkD7A-N93kljcFmkCyG6e_D9vg", + # "openid": mini_openid, # 必填 integer【收款用户OpenID】 用户在商户appid下的唯一标识。发起转账前需获取到用户的OpenID,获取方式详见参数说明。 + # # "user_name":"757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45", # 【收款用户姓名】 + # # 收款方真实姓名。需要加密传入,支持标准RSA算法和国密算法,公钥由微信侧提供。 + # "transfer_amount": transfer_amount, # 必填 integer【转账金额】 转账金额单位为“分”。 + # "transfer_remark": "新会员开通有礼", # 必填 string(32)【转账备注】 转账备注,用户收款时可见该备注信息,UTF8编码,最多允许32个字符 + # "notify_url": "https://www.sixgou.site", # 选填【通知地址】 异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数。 + # "user_recv_perception": "现金奖励", # 选填 【用户收款感知】 用户收款时感知到的收款原因将根据转账场景自动展示默认内容。如有其他展示需求, + # # 必填 array[TransferSceneReportInfo] 【转账场景报备信息】 各转账场景下需报备的内容,商户需要按照所属转账场景规则传参,详见转账场景报备信息字段说明。 + # "transfer_scene_report_infos": [ + # { + # "info_type": "活动名称", # 必填 string(15)【信息类型】 不能超过15个字符,商户所属转账场景下的信息类型,此字段内容为固定值 + # "info_content": "新会员有礼", # 必填 【信息内容】 不能超过32个字符,商户所属转账场景下的信息内容,商户可按实际业务场景自定义传参 + # }, { + # "info_type": "奖励说明", "info_content": "注册会员抽奖一等奖", + # }, + # ], + # } + headers = self.构造签名串(uri=uri, body_data=transferAccountsBody, method="POST") + data = post(url=uri, json=transferAccountsBody, headers=headers) + package = data.json() + package_info = pydash.get(obj=package, path="package_info") + 前端调用的数据 = { + "mchId": self.payment.mchid, "appId": self.payment.appid, "package": package_info, + } + # return 前端调用的数据 + return package + """ + 前端调用的示例 + const demo_fun = () => { + wx.requestMerchantTransfer({ + // 你的参数 + mchId: '1700383419', + appId: "wxf612e825377328f0", + package: "ABBQO+oYAAABAAAAAAB99dFZt82j95u0HhbyZxAAAADnGpepZahT9IkJjn90 + +1qgGS6abB6UNQ9r1BZy26rL41bBjlwNMlDnYxPA/nGPWXtoOeFekxLE3iayC1CrxUngRWxwI/X79IcQ1+mBcUFwAUn3+f8=", + success: (res: any) => { + // res.err_msg将在页面展示成功后返回应用时返回ok,并不代表付款成功 + console.log('success:', res); + }, + }); + } + """ + + def transferAccounts商家转账查询(self, transfer_bill_no: str): + """ + :param transfer_bill_no: + :type transfer_bill_no: + """ + uri = (f"https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/" + f"{transfer_bill_no}") + header = self.构造签名串(method="GET", uri=uri) + data = get(url=uri, headers=header) + print(data.json()) + + 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.payment.wechat_certificate) + 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" # 构造验签名串 + 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 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 + # 得到params_str就是需要 参与 签名的字符串 + signature = hashlib.md5(string=params_str.encode()).hexdigest().upper() # 使用MD5加密模式 + sign_data.update(sign=signature) # 将sign(签名的数据添加到dict数据中) + xml = dicttoxml(obj=sign_data, custom_root="xml", xml_declaration=False, attr_type=False, cdata=True) + return xml + + def getpay_code扫用户付款码(self, body_data, ) -> dict: + """ + 商家扫用户的付款码,收款 + :param body_data: + :type body_data: + :return: + :rtype: + """ + xml = self.v2签名返回XML(sign_data=body_data) + fu_kuan_url = "https://api.mch.weixin.qq.com/pay/micropay" + res = post(url=fu_kuan_url, data=xml) + # 返回的数据 是 ISO-8859-1 类型 + responseStr = res.text.encode("ISO-8859-1") + # 将请求得到的数据 转换为字典格式; + xml_dict = xmltodict.parse(responseStr.decode()) + # 得到请求结果并进行解密 + print(xml_dict) + return xml_dict + + def 获取平台证书(self, ): + """ + @param save_path: + @type save_path: + @return: + @rtype: + """ + # save_path为首次保存存商户平台证书的路径(首次使用小程序需要获取这个证书,)就是调用本类方法就可以获取 + + certificate_url = "https://api.mch.weixin.qq.com/v3/certificates" + headers = self.构造签名串(uri=certificate_url, method="GET") + print(headers) + res = get(url=certificate_url, headers=headers, ) + data = json.loads(res.text) + print(data) + ciphertext: str = pydash.get(obj=data, path="data[0].encrypt_certificate.ciphertext") + nonce: str = pydash.get(obj=data, path="data[0].encrypt_certificate.nonce") + associated_data: str = pydash.get(obj=data, path="data[0].encrypt_certificate.associated_data") + + ciphertext_data = base64.b64decode(ciphertext.encode()) + # 调用后得到证书信息,需要保存起来 + cipher = AES.new(key=self.payment.apiv3.encode(), mode=AES.MODE_GCM, nonce=nonce.encode()) + # 处理附加关联数据(AAD) - 微信支付中通常是"transaction" + # 这部分数据在加密过程中被验证但未被加密 + # 必须与加密时使用的附加数据完全一致 + cipher.update(associated_data.encode()) + auth_tag = ciphertext_data[-16:] # 提取认证标签(最后16 字节) + # 提取实际加密内容 + ciphertext_bytes = ciphertext_data[:-16] # 提取实际加密内容 + decrypted_data = cipher.decrypt_and_verify(ciphertext=ciphertext_bytes, received_mac_tag=auth_tag) + print(decrypted_data.decode(), "decrypted_data=====================") + save_path = Path(settings.BASE_DIR).joinpath( + "wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem", + ).write_text(decrypted_data.decode()) + + 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) + 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 fai发放代金券(self, openid): + """ + + :param openid: + :return: + """ + pass + date = datetime.now().strftime("%Y%m%d") + random_str = secrets.token_hex(6) + example_out_request_no = f"{paymentCategory.mchid}{date}{random_str}" + post_data = { + "stock_id": "21056560", # 【创建批次的商户号】批次创建方商户号。校验规则:接口传入的批次号需由stock_creator_mchid所创建 + "out_request_no": example_out_request_no, # 【商户单据号】商户此次发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性 + "appid": paymentCategory.appid, + "stock_creator_mchid": paymentCategory.mchid, # 【创建批次的商户号】批次创建方商户号。 + # "coupon_value": 300, # 【指定面额发券,面额】指定面额发券场景,券面额,其他场景不需要填,单位:分。 + # "coupon_minimum": 300, # 【指定面额发券,券门槛】指定面额发券批次门槛,其他场景不需要,单位:分 + } + uri = f"https://api.mch.weixin.qq.com/v3/marketing/favor/users/{openid}/coupons" + headers = self.构造签名串(uri=uri, body_data=post_data, method="POST") + result_data = post(url=uri, json=post_data, headers=headers) + print(result_data.json()) + return result_data.json() + + def 发起退款(self, body): + pass + 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) + print(response_data.json()) + + +if __name__ == '__main__': + pass + + # wechat_data = wechatPay(payment=paymentCategory).获取平台证书() + wechat_data = wechatPay(payment=paymentCategory).fai发放代金券(openid="o6oV61xoMYAFNpi4RpVjn3BFGB1U") + # 方法已经封装了请求结果,直接获得就是请求的结果 url (支付的url) 再由前端生成二维码 + # wechat_data = wechatPay(payment=sixpay六果科技公司).navite用户扫生成的二维码(navite_body=native_body) + # headers = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=native_url, method="POST", body_data=native_body) + +# print(headers) diff --git a/wechat_项目工具包/微信支付工具包/领优惠券工具包.py b/wechat_项目工具包/微信支付工具包/领优惠券工具包.py new file mode 100644 index 0000000..701a5d6 --- /dev/null +++ b/wechat_项目工具包/微信支付工具包/领优惠券工具包.py @@ -0,0 +1,64 @@ +import hashlib +import hmac +from datetime import datetime +from zoneinfo import ZoneInfo + +import pydash +from pydantic import BaseModel, Field +from ulid import ULID + +from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司 + + +class stock发送代金券功能(BaseModel): + # demo_必填: int = Field(..., description="描述") # 必传属发生 + # demo_可选: Optional[int] = None # 可选值 + # demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + pass + stock_id_代金券批次号: str = Field(..., description="发放代金券是创建的批次号") + + def send发券并返回前端需要的数据(self): + """前端请求:将这个字典对象返回给前端,前端调用小程序原生插件领取券""" + pass + # 第一步:准备数据 + out_request_no = str(ULID()) # 商家侧的发券订单号 + rfc3339 = datetime.now().astimezone(tz=ZoneInfo("Asia/Shanghai")).isoformat() # 代金券发券时的时间,因为代金券设置了起效的时间 + mchid = sixpay六果科技公司.mchid + apiv2_key = sixpay六果科技公司.apiv2 + # 第二步: 创建好需要的数据并验名 + params每一张券需要验名的数据格式 = { + "out_request_no0": out_request_no, # 商家侧的发券订单号 + "stock_id0": "22512292", # 代金券创建的批次号 + "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) + # 拼接组装好的数据 + sign_str = "&".join([f"{k}={v}" for k, v in sorted_dict.items() if v]) + f"&key={apiv2_key}" + # # 4. 生成 HMAC-SHA256 签名并转大写 + sign = hmac.new(key=apiv2_key.encode("utf-8"), msg=sign_str.encode("utf-8"), digestmod=hashlib.sha256, ).hexdigest().upper() + # 3. 拼接参数串 + params = { + "out_request_no": out_request_no, + "stock_id": "22512292", + "create_coupon_merchant": sixpay六果科技公司.mchid, + "customize_send_time": rfc3339, + "send_coupon_merchant": sixpay六果科技公司.mchid, + } + send_coupon_params: list[dict] = [params, ] # 发放代金券需要返回给前端的参数必须为列表 list[dict] + return { + "send_coupon_params": send_coupon_params, + "sign": sign, + "send_coupon_merchant": sixpay六果科技公司.mchid, + "suggest_immediate_use": True, + } + + +if __name__ == "__main__": + print(00000000) diff --git a/wechat_项目工具包/数据库的工具包/更新用户积分.py b/wechat_项目工具包/数据库的工具包/更新用户积分.py new file mode 100644 index 0000000..2ca42ce --- /dev/null +++ b/wechat_项目工具包/数据库的工具包/更新用户积分.py @@ -0,0 +1,249 @@ +import os + +import django +import pydash + +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 datetime import datetime +from typing import Literal +from zoneinfo import ZoneInfo + +from pydantic import BaseModel, Field + +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_数据库.用户数据库.小程序积分数据库 import share积分表 + + +class miniUser提现状态(BaseModel): + # demo_必填: int = Field(..., description="描述") # 必传属发生 + # demo_可选: Optional[int] = None # 可选值 + # demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + 不可提现: str = Field("不可提现", description="不可提现") + 可提现: str = Field("可提现", description="可提现") + 提现中: str = Field("提现中", description="提现中") + + +class miniUser用户角色(BaseModel): + # demo_必填: int = Field(..., description="描述") # 必传属发生 + # demo_可选: Optional[int] = None # 可选值 + # demo_默认值: int = Field(default=100001, description="描述") # 有默认值 + # demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述") + 推广员: str = Field("推广员", description="推广员") + 企微员工: str = Field("企微员工", description="企微员工") + 代理商: str = Field("代理商", description="代理商") + 普通会员: str = Field("普通会员", description="普通会员") + 用工关系已绑定: str = Field("用工关系已绑定", description="用工关系已绑定") + 新人红包首次添加企微积分值: int = Field(100, description="新人红包首次添加企微积分值") + 发券奖励积分值: int = Field(10, description="添加通知好友积分") + 每日积分积分值: int = Field(50, description="发券奖励积分值") + 小程序分享积分值: int = Field(10, description="小程序分享积分值") + + +class miniUser积分(BaseModel): + share分享者unionidID: str = Field(..., description="分享者的unionid") + click点击者unionidID: str = Field(..., description="点击者的的openid") + bind绑定的企微unionidID: str = Field("", description="click绑定的企微unionidID") + + def update更新用户头像(self): + pass + + def add添加每日积分(self, share积分类型: Literal["每日签到"], share分享者积分值: int, ): + pass + # 注意,这里的每日签到: 分享者 同时 也是点击者 + share分享者对象 = weiuser.objects.get(unionid=self.share分享者unionidID) + click点击都对象 = weiuser.objects.get(unionid=self.click点击者unionidID) + today当天的日期 = datetime.now(tz=ZoneInfo("Asia/Shanghai")).date() + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=self.share分享者unionidID, share分享者openid=share分享者对象.mini_openid, share点击者openid=click点击都对象.mini_openid, share点击者unionid=self.click点击者unionidID, + share分享者积分值=share分享者积分值, share分享类型=share积分类型, share日期=today当天的日期, share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + + def add添加通知好友积分(self, share积分类型: Literal["通知好友", "发券奖励"], share分享者积分值: int = miniUser用户角色().发券奖励积分值, ): + pass + """这个积分对应的是 小程序主页面 分享3元券的图片 """ + share分享者对象 = weiuser.objects.get(unionid=self.share分享者unionidID) + click点击都对象 = weiuser.objects.get(unionid=self.click点击者unionidID) + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=self.share分享者unionidID, share分享者openid=share分享者对象.mini_openid, + share点击者openid=click点击都对象.mini_openid, share点击者unionid=self.click点击者unionidID, + share分享者积分值=share分享者积分值, share分享类型=share积分类型, share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + if share布尔值: + print("发券奖励积分 添加成功") + else: + print("发券奖励积分 已经存在领过的") + + def add添加用户分享商品推荐的积分(self, share积分类型: Literal["好物推荐"], share分享者积分值: int, share分享的商品ID: str): + pass + print("add添加用户商品详情页面分享积分调用了") + share分享者对象 = weiuser.objects.get(unionid=self.share分享者unionidID) + click点击都对象 = weiuser.objects.get(unionid=self.click点击者unionidID) + six六果对象, sixBool = weiuser.objects.get_or_create(unionid="六果") + if share分享者对象.parent == six六果对象 or share分享者对象.unionid == click点击都对象.unionid: + pass + else: + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=self.share分享者unionidID, share分享者openid=share分享者对象.mini_openid, + share点击者openid=click点击都对象.mini_openid, share点击者unionid=self.click点击者unionidID, + share分享者积分值=share分享者积分值, share分享类型=share积分类型, share分享的商品ID=share分享的商品ID, + share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + # 。更新需要的数据 + + def add添加小程序推荐积分(self, share积分类型: Literal["小程序推荐"], share分享者积分值: int = miniUser用户角色().小程序分享积分值, ): + pass + share分享者对象 = weiuser.objects.get(unionid=self.share分享者unionidID) + click点击都对象 = weiuser.objects.get(unionid=self.click点击者unionidID) + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=share分享者对象.unionid, share分享者openid=share分享者对象.mini_openid, + share点击者openid=click点击都对象.mini_openid, share点击者unionid=self.click点击者unionidID, + share分享者积分值=share分享者积分值, share分享类型=share积分类型, share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + + def add添加好友助力下单返利积分(self, share积分类型: Literal["好友下单"], order支付商家侧订单号): + pass + # 方法被调用的时候 第一步,需要更新当前点击的状态, + # 将字符串转为换字典 + order对象 = order订单.objects.get(order支付商家侧订单号=order支付商家侧订单号) # 拿到当前订单的对象数据 + + share分享者unionidID = order对象.order分享者unionid + click点击者unionidID = order对象.order支付者unionid + share分享者对象 = weiuser.objects.get(unionid=share分享者unionidID) + click点击都对象 = weiuser.objects.get(unionid=click点击者unionidID) + six六果对象, sixBool = weiuser.objects.get_or_create(unionid="六果") + # 通过订单号,拿到 第一个值: + order购物车商品好友下单助力的推广员的积分值 = pydash.get(obj=pydash.head(order对象.order购物车商品数据), path="推荐积分.推广员") # 当前角色,对应的推广积分值 + order购物车商品好友下单助力的企微员工的的积分值 = pydash.get(obj=pydash.head(order对象.order购物车商品数据), path="推荐积分.企微员工") # 当前角色,对应的推广积分值 + order好友下单商品数量 = pydash.get(obj=pydash.head(order对象.order购物车商品数据), path="单个商品订单数量") + order好友下单助力计算后的积分值 = int(order好友下单商品数量) * int(order购物车商品好友下单助力的推广员的积分值) + order好友下单企微员工需要添加的积分值 = int(order好友下单商品数量) * int(order购物车商品好友下单助力的企微员工的的积分值) + if share分享者unionidID == click点击者unionidID or share分享者对象.parent == six六果对象: + print("自己点了自己,不需要添加积分了") + if share分享者对象.user_角色权限 == miniUser用户角色().推广员: + pass # 如果是推广员则添加 + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=share分享者unionidID, share分享者openid=share分享者对象.mini_openid, + share点击者unionid=click点击者unionidID, share点击者openid=click点击都对象.mini_openid, + share分享者积分值=order好友下单助力计算后的积分值, share支付订单商家侧的订单号=order支付商家侧订单号, + share分享类型=share积分类型, share积分是否可以提现的状态=miniUser提现状态().可提现, + + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + print("如果是推广员则添加如果是推广员则添加如果是推广员则添加如果是推广员则添加", share布尔值, share对象) + else: + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=share分享者unionidID, share分享者openid=share分享者对象.mini_openid, + share点击者unionid=click点击者unionidID, share点击者openid=click点击都对象.mini_openid, + share分享者积分值=order好友下单助力计算后的积分值, share支付订单商家侧的订单号=order支付商家侧订单号, + share分享类型=share积分类型, share积分是否可以提现的状态=miniUser提现状态().不可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + print("如果是推广员则添加如果是推广员则添加如果是推广员则添加如果是推广员则添加", share布尔值, share对象) + if share分享者对象.user_企微角色权限 == miniUser用户角色().企微员工: + print("给企微员工添加了积分了") + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=share分享者unionidID, share分享者openid=share分享者对象.mini_openid, + share点击者unionid=click点击者unionidID, share点击者openid=click点击都对象.mini_openid, + share分享者积分值=order好友下单企微员工需要添加的积分值, share支付订单商家侧的订单号=order支付商家侧订单号, + share分享类型=share积分类型, share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + + def add添加点击者添加企微员工双向红包积分(self, share积分类型: Literal["新人红包"], share分享者二维码state: str): + pass + # 必须要先处理一下当前用户的状态,有一种可能性: 就是当前用户直接进入了小程序,所以当前用户的上级用户就是six对象; + six六果对象, sixBool = weiuser.objects.get_or_create(unionid="六果") + # 添加逻辑为: 能调用则说明用户是首次,还可以再添加一个判断条件 + share分享者对象 = weiuser.objects.get(unionid=self.share分享者unionidID) # 这里传递的是分享者,绑定的企微二维码state + click点击都对象 = weiuser.objects.get(unionid=self.click点击者unionidID) + bindRwecom企微员工对象 = weiuser.objects.get(unionid=self.bind绑定的企微unionidID) + click点击者父元素 = click点击都对象.parent + print("当前点击者的父元素是谁", click点击者父元素.unionid) + print("添加企微客户的积分功能调用了啦") + if click点击都对象.parent == six六果对象: + print("===========这里判断生成了就需要更新当前用户的新状态了====处理的当前用户,进来的时候不是好友分享的状态,所以得更新,将当前用户的状态更到当前的企微用户名下============") + click点击都对象.parent = bindRwecom企微员工对象 + click点击都对象.user_绑定企微UNIONID = bindRwecom企微员工对象.user_绑定企微UNIONID + click点击都对象.user_用户当前的等级 = bindRwecom企微员工对象.user_用户当前的等级 + 1 + click点击都对象.codeRemark = bindRwecom企微员工对象.codeRemark + click点击都对象.codeQrCode = bindRwecom企微员工对象.codeQrCode + click点击都对象.codeConfigId = bindRwecom企微员工对象.codeConfigId + click点击都对象.user_绑定企微usrID账号 = bindRwecom企微员工对象.user_绑定企微usrID账号 + click点击都对象.save() + # 第一个逻辑,先判断,当前这个添加企微的 用户,是否已经领过红包了,如果领了过了就直接返回了 + is是否领过红包 = share积分表.objects.filter(share分享者unionid=click点击都对象.unionid, share分享类型="新人红包", share分享者积分值=100).exists() + print("打印一下这里的值是不是已经存在了", is是否领过红包) + if is是否领过红包: + print("当前添加者已经领过新人红包了,直接return") + return + # 添加条件,分享者必须是推广员: + # 添加 积分的条件一: 必须要满足,跟绑定的企微是同城的用户,如果不是同城用户,则不给任何的奖励 + if bindRwecom企微员工对象.user_区县 == click点击都对象.user_区县: + # 这里是:给当前添加企微的用户 添加积分 + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=click点击都对象.unionid, share分享者openid=click点击都对象.mini_openid, + share点击者openid=click点击都对象.mini_openid, share点击者unionid=click点击都对象.unionid, + share分享者积分值=100, share分享类型="新人红包", share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + print("添加企微者,并且是同城的情况下,可提现状态,", share布尔值) + # 接着还需要处理,推广员, 并且还得是同城的情况下, 才可以给推广员添加积分了 + if click点击者父元素.user_角色权限 == miniUser用户角色().推广员 and bindRwecom企微员工对象.user_区县 == click点击者父元素.user_区县 == click点击都对象.user_区县: + # 这里的状态为可以提现 + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=click点击者父元素.unionid, share分享者openid=click点击者父元素.mini_openid, + share点击者openid=click点击都对象.mini_openid, share点击者unionid=self.click点击者unionidID, + share分享者积分值=300, share分享类型="荐客积分", share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + print("分享者,可提现状态", share布尔值) + return + # 在这里判断的是 给当前公司的企微推广员, 添加积分 + if bindRwecom企微员工对象.user_企微角色权限 == miniUser用户角色().企微员工 and bindRwecom企微员工对象.user_区县 == click点击都对象.user_区县: + # 这里的状态为可以提现 这里的积分是给企微员工添加的, + share对象, share布尔值 = share积分表.objects.update_or_create( + share分享者unionid=bindRwecom企微员工对象.unionid, share分享者openid=bindRwecom企微员工对象.mini_openid, + share点击者openid=click点击都对象.mini_openid, share点击者unionid=self.click点击者unionidID, + share分享者积分值=300, share分享类型="荐客积分", share积分是否可以提现的状态=miniUser提现状态().可提现, + defaults={"share分享者头像": share分享者对象.user_头像, "share分享者昵称": share分享者对象.user_昵称, + "share点击者头像": click点击都对象.user_头像, "share点击者昵称": click点击都对象.user_昵称 + }, + ) + print("企微", share布尔值) + return + + +if __name__ == "__main__": + pass + # (miniUser积分(share分享者unionidID="", click点击者unionidID="") + # .add添加好友助力下单返利积分(order支付商家侧订单号="OAT01KYDESHM9ADEXGY7BW0AVHFSG", share积分类型="好友下单", )) + (miniUser积分(share分享者unionidID="oy4Jw6A1T3WkKOOhMxcbQTDSM8rs", click点击者unionidID="oy4Jw6P1FnuTNF-hSoJHNztSAoQ0", bind绑定的企微unionidID="oy4Jw6A1T3WkKOOhMxcbQTDSM8rs") + .add添加点击者添加企微员工双向红包积分(share积分类型="新人红包", share分享者二维码state="oy4Jw6A1T3WkKOOhMxcbQTDSM8rs")) diff --git a/wechat_项目工具包/腾讯地图/腾讯地图工具.py b/wechat_项目工具包/腾讯地图/腾讯地图工具.py new file mode 100644 index 0000000..bc068bd --- /dev/null +++ b/wechat_项目工具包/腾讯地图/腾讯地图工具.py @@ -0,0 +1,195 @@ +"""功能模块""" +import math +from typing import TypedDict, Union + +import jmespath +import pydash +import requests + + +# WechatMapClass.haversine(lat1=32. +# 474664, lon1=119.893471, lat2=32. +# 471578, lon2=119.917068) +# WechatMapClass.addressToCoordinat +# eConversion(address="江苏省泰州市海陵区济川东路与青年南路交叉口东220米泰州万达广场(2号入口)") +# WechatMapClass.coordinateToAddressConversion(location="32.474664,119.893471") +# WechatMapClass.coordinateToAddressConversion(location="32.471578,119.917068") +class OriginPointOptional(TypedDict): + 经度: Union[float, str] + 纬度: Union[float, str] + + +from pydantic import BaseModel + + +class AdInfo(BaseModel): + city: str + adcode: int + nation: str + district: str + province: str + nation_code: int + + +class Location(BaseModel): + lat: float + lng: float + + +class Result(BaseModel): + ip: str + ad_info: AdInfo + location: Location + + +class IP解析地址模型Response(BaseModel): + result: Result + status: int + message: str + + +class wei地图工具: + """注释""" + + key = "7SNBZ-FLN63-LRA3S-YJBAK-XSHQ3-TGF5E" # 腾讯地图的key + + # key = "LREBZ-PH5R7-2NIXW-H7JDB-CVHTK-4YFUJ" # 莫大帅注册地地图的腾讯地图的key + + @classmethod + def 公式计算二点之间的距离(cls, orgin原点: OriginPointOptional, user原点: OriginPointOptional) -> float: + """""" + # 地球半径,单位为公里 + R = 6371.0 + # orgin原点: OriginPointOptional = {"纬度": 30.80377, "经度": 104.151812} + # user原点: OriginPointOptional = {"纬度": 30.80377, "经度": 104.151812} + # 将角度转换为弧度 + orgin纬度 = math.radians(orgin原点.get("纬度")) + orgin经度 = math.radians(orgin原点.get("经度")) + user纬度 = math.radians(user原点.get("纬度")) + user经度 = math.radians(user原点.get("纬度")) + + # 经纬度差值 + 经度差 = user经度 - orgin经度 + 纬度差 = user纬度 - orgin纬度 + print(经度差, 纬度差) + + # Haversine公式 + a = math.sin(纬度差 / 2) ** 2 + math.cos(orgin纬度) * math.cos(user纬度) * math.sin(经度差 / 2) ** 2 + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + # 计算两点间的距离 + distance = R * c + print(f"The distance between two points is {distance} km.") + return distance + + @classmethod + def 腾讯地图计算二点之间的距离(cls, toData终点: OriginPointOptional, fromData起点: OriginPointOptional): + """""" + fromStrDat = dict(sorted(fromData起点.items(), reverse=False)) + fromStr = ",".join(fromStrDat.values()) + toStrDat = dict(sorted(toData终点.items(), reverse=False)) + toStr = ",".join(toStrDat.values()) + print("排序后的值为", fromStr, toStr) + data = {"key": cls.key, "from": fromStr, "to": toStr} + url = f"https://apis.map.qq.com/ws/distance/v1/matrix?mode=driving" + res_data = requests.post(url=url, data=data) + 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, # 表示从起点到终点的结合路况的时间,秒为单位注:步行/骑行方式(不计算耗时)以及起终点附近没有道路造成无法计算时,不返回本此节点 + }], + }], + }, + } + distance = jmespath.search(data=res_data.json(), expression="result.rows[0].elements[0].distance") + return distance + + @classmethod + def 地址转换为坐标(cls, address: str): + """""" + 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, # 纬度 + }, + 'ad_info': { # 行政区划信息 object 是 + 'adcode': '321202', # string 是 行政区划代码,规则详见:行政区划代码说明 + }, + 'address_components': { + 'province': '江苏省', + 'city': '泰州市', + 'district': '海陵区', + 'street': '济川东路', + 'street_number': '', + }, + 'similarity': 0.99, + 'deviation': 1000, + 'reliability': 7, # 可信度参考:值范围 1 <低可信> - 10 <高可信> + 'level': 11, # 解析精度级别,分为11个级别,一般>=9即可采用(定位到点,精度较高) 也可根据实际业务需求自行调整,完整取值表见下文。 + }, + } + + @classmethod + def 经纬度转换为地址(cls, location): + """""" + pass + url = f'https://apis.map.qq.com/ws/geocoder/v1/?location={location}' + res = requests.get(url=url, params={"key": cls.key}, ) + return res.json() + + @classmethod + def ip地址转为地址(cls, x_forwarded_for: str | bool, ): + """""" + url = "https://apis.map.qq.com/ws/location/v1/ip" + response_data = requests.get(url=url, params={"key": cls.key, "ip": x_forwarded_for}, ) + data = response_data.json() # type: dict + 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, + }, + 'ad_info': { + 'nation': '中国', + 'province': '江苏省', + 'city': '泰州市', + 'district': '海陵区', + 'adcode': 321202, + 'nation_code': 156, + }, + }, + } + # nation = jmespath.search(data=data, expression="result.ad_info.nation", ) # 国家 + # province = jmespath.search(data=data, expression="result.ad_info.province", ) # 省份 + # city = jmespath.search(data=data, expression="result.ad_info.city", ) + # district = jmespath.search(data=data, expression="result.ad_info.district", ) # 区 + # adcode = jmespath.search(data=data, expression="result.ad_info.adcode", ) # 区号 + # ip = jmespath.search(data=data, expression="result.ip", ) + # lat = jmespath.search(data=data, expression="result.location.lat", ) + # lng = jmespath.search(data=data, expression="result.location.lng", ) + + return resData + + +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 new file mode 100644 index 0000000..a999980 --- /dev/null +++ b/wechat_项目工具包/项目其它工具/单例模式.py @@ -0,0 +1,67 @@ +import threading +from dataclasses import dataclass + + +class ParameterizedSingletonMeta(type): + """ + 参数化单例元类 + 行为: + - 相同 (类, args, kwargs) → 同一实例 + - 不同参数 → 不同实例 + """ + + _instances: dict = {} + _lock = threading.RLock() + + def __call__(cls, *args, **kwargs): + # 1. kwargs 排序,保证顺序无关 + kwargs_key = tuple(sorted(kwargs.items())) + + # 2. 构造不可变的 key + key = (cls, args, kwargs_key) + + # 3. 防御:确保所有参数都可 hash + try: + hash(key) + except TypeError as e: + raise ValueError( + f"{cls.__name__} 的单例参数必须全部可 hash" + ) from e + + with cls._lock: + if key not in cls._instances: + cls._instances[key] = super().__call__(*args, **kwargs) + else: + print(f"[HIT] 命中缓存实例: {key}") + + return cls._instances[key] + + @classmethod + def get_all_instances(cls): + """调试用:返回当前已创建的所有实例""" + return list(cls._instances.values()) + + +@dataclass +class Demo(metaclass=ParameterizedSingletonMeta): + """ + 示例:参数化单例对象 + """ + + name: str + + def __post_init__(self): + print(f"正在初始化 Demo(name={self.name})") + + def __str__(self): + return f"" + + +if __name__ == "__main__": + print("=== 测试 1:相同参数 ===") + d1 = Demo(name="config_A") + d2 = Demo(name="config_A") + print(d1) + print(d2) + print("是否同一实例:", d1 is d2) + print(ParameterizedSingletonMeta.get_all_instances()) \ No newline at end of file diff --git a/wechat_项目授权/企业微信消息服务器授权接口.py b/wechat_项目授权/企业微信消息服务器授权接口.py new file mode 100644 index 0000000..fc014ff --- /dev/null +++ b/wechat_项目授权/企业微信消息服务器授权接口.py @@ -0,0 +1,524 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:39 +FilePath: django_公共认证接口/企业微信认证接口.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" +import dataclasses +import io +import os +from typing import Literal + +import django +import requests +from rest_framework.viewsets import ViewSet + +from sixGuoDjango.settings import BASE_DIR +from wechat_token.token工具包 import sixToken +from wechat_数据库.企业微信数据库.企微用户表 import wecom企微用户 +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_项目工具包.企业微信工具包.消息推送工具 import wecom消息推送 +from wechat_项目工具包.数据库的工具包.更新用户积分 import miniUser积分 +from 第三方工具目录.腾讯云 import oss上传腾讯云图片 + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() + +import pydash + +import base64 +import hashlib +from pathlib import Path + +import jmespath +import xmltodict +from Crypto.Cipher import AES +from django.conf import settings +from django.core.handlers.wsgi import WSGIRequest +from django.http import HttpResponse +from rest_framework import status +from rest_framework.request import Request +from rest_framework.response import Response + + +@dataclasses.dataclass +class wecomData: + """ + 微信企业服务器推送事件的数据类 + 映射XML中的字段 + """ + # 基本消息头 + as_data: dict + + def __post_init__(self): + self.ToUserName = pydash.get(obj=self.as_data, path="xml.ToUserName") # toUser 企业微信CorpID + self.FromUserName = pydash.get(obj=self.as_data, path="xml.FromUserName") # sys 此事件该值固定为sys,表示该消息由系统生成 + self.CreateTime = pydash.get(obj=self.as_data, path="xml.CreateTime") # 1403610513 消息创建时间 (整型) + self.MsgType = pydash.get(obj=self.as_data, path="xml.MsgType") # event 消息的类型,此时固定为event + self.Event = pydash.get(obj=self.as_data, path="xml.Event", ) # change_external_contact 事件的类型,此时固定为change_external_contact + self.ChangeType = pydash.get(obj=self.as_data, path="xml.ChangeType", ) # add_external_contact 此时固定为add_external_contact + self.UserID = pydash.get(obj=self.as_data, path="xml.UserID") # UserID 企业服务人员的UserID + self.ExternalUserID = pydash.get(obj=self.as_data, path="xml.ExternalUserID", ) # woAJ2GCAAAXtWyujaWJHDDGi0mAAAA 外部联系人的userid,注意不是企业成员的账号 + self.State = pydash.get(obj=self.as_data, path="xml.State", default="六果", ) # teststate 添加此用户的「联系我」方式配置的state参数,或在获客链接中指定的customer_channel参数,可用于识别添加此用户的渠道 + self.WelcomeCode = pydash.get(obj=self.as_data, path="xml.WelcomeCode") # WELCOMECODE 欢迎语code,可用于发送欢迎语 + self.Source = pydash.get(obj=self.as_data, path="xml.Source", ) # 删除客户的操作来源,DELETE_BY_TRANSFER表示此客户是因在职继承自动被转接成员删除 + self.FailReason = pydash.get(obj=self.as_data, path="xml.FailReason", ) # 接替失败的原因, customer_refused-客户拒绝, customer_limit_exceed-接替成员的客户数达到上限 + self.ChatId = pydash.get(obj=self.as_data, path="xml.ChatId") # 群🆔 + self.UpdateDetail = pydash.get(obj=self.as_data, path="xml.UpdateDetail", ) # 群:变更详情。目前有以下几种: add_member : 成员入群 del_member : 成员退群 change_owner : 群主变更 change_name : 群名变更 change_notice : 群公告变更 + self.JoinScene: Literal[0, 1] = pydash.get(obj=self.as_data, path="xml.JoinScene", ) # 当是成员入群时有值。表示成员的入群方式 # 0 - 由成员邀请入群(包括直接邀请入群和通过邀请链接入群) # 3 - 通过扫描群二维码入群 + self.QuitScene = pydash.get(obj=self.as_data, path="xml.QuitScene") # 是用户自已退群了还是群主踢出群, 0 - 自己退群 1 - 群主/群管理员移出 + self.MemChangeCnt = pydash.get(obj=self.as_data, path="xml.MemChangeCnt") # 当当是成员入群或退群时有值。表示成员变更数量 + self.MemChangeList = pydash.get(obj=self.as_data, path="xml.MemChangeList") # 当是成员入群或退群时有值。变更的成员列表 + self.LastMemVer = pydash.get(obj=self.as_data, path="xml.LastMemVer") # 当是成员入群或退群时有值。 变更前的群成员版本号 + self.CurMemVer = pydash.get(obj=self.as_data, path="xml.CurMemVer") # 当是成员入群或退群时有值。变更后的群成员版本号 + + +class sixwecom(ViewSet): + """https://work.weixin.qq.com/wework_admin/frame#apps/contactsApi""" + token = "bVWt1PEUCG" # url验证的token(江苏六果科技有限公司, 元宝零售 的应用) + EncodingAESKey = "LS6VsiJA6Vpb3nJlt34vMZFAbuKDJkFuH2KxuEXYuUR" # 配置的解密(江苏六果科技有限公司 的 元宝零售应用) + corp_id = "wwbe6369dc26a9d83a" # 企业微信🆔(当前账号是,江苏六果科技有限公司的账号) + corpsecret = "SIRyum7vQh-Bt36AxnqKMX0HIiE-zkYbjYgSat7reZw" # 江苏六果科技有限公司账号 企业微信 secret + phone_secret = "WNxZZdcU3FRS5msq_kHZaaZOBauBEjJZdQV3VrAxu0c" # 通讯录 secret + + def 单独处理新添加用户的数据存储(self, UserID, ChangeType, State, ExternalUserID): + """ + :param State: + :param ChangeType: 此时好友的状态 + :param ExternalUserID: + :param UserID: + """ + 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() + # 创建数据库数据表 + unionid = pydash.get(obj=data, path="external_contact.unionid") # 外部联系人在微信开放平台的唯一身份标识(微信unionid) + name = pydash.get(obj=data, path="external_contact.name") # 外部联系人的名称[注1]如果是微信用户,则返回其微信昵称。如果是企业微信联系人,则返回其设置对外展示的别名或实名 + external_userid = pydash.get(obj=data, path="external_contact.external_userid") # 外部联系人的userid + 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") + for wecom in follow_user: + userid = pydash.get(obj=wecom, path="userid") # 添加了此外部联系人的企业成员userid (企微员工的userid) + userid = pydash.get(obj=wecom, path="userid") # 添加了此外部联系人的企业成员userid (企微员工的userid) + tags = pydash.get(obj=wecom, path="tags") + add_way = pydash.get(obj=wecom, path="add_way") + oper_userid = pydash.get(obj=wecom, path="oper_userid") + remark = pydash.get(obj=wecom, path="remark") + createtime = pydash.get(obj=wecom, path="createtime") + remark_mobiles = pydash.get(obj=wecom, path="remark_mobiles") + img_file = requests.get(url=avatar).content + src = oss上传腾讯云图片.上传图片(key=f"{userid}/{name}.png", file=io.BytesIO(img_file), ) + avatar = src + 企微用户关系对象, 企微用户是否为首次 = wecom企微用户.objects.update_or_create(wecom企微ID=UserID, ) + 企微用户关系对象.wecom企微状态State = State + 企微用户关系对象.wecom好友的ID = external_userid + 企微用户关系对象.wecom好友UNIONID = unionid + 企微用户关系对象.wecom好友性别 = gender + 企微用户关系对象.wecom对好友的备注信息 = remark + 企微用户关系对象.wecom企微对好友添加的手机号码 = remark_mobiles + 企微用户关系对象.wecom好友关系状态 = ChangeType + 企微用户关系对象.wecom企微好友添加方式 = oper_userid + 企微用户关系对象.wecom好友头像 = src + 企微用户关系对象.wecom好友昵称 = name + 企微用户关系对象.wecom对好友的添加时间 = createtime + 企微用户关系对象.wecom对好友打的标签 = tags + 企微用户关系对象.wecom对好友的备注名称 = remark + 企微用户关系对象.save() + six六果对象, sixBool = weiuser.objects.get_or_create(unionid="六果") + six上级对象, six上级Bool = weiuser.objects.get_or_create(unionid=State) # 在这里的state是企微号绑定的 unionid + print("在这里打印一下上级的对象是否已经存丰了", six上级对象) + self自生对象, self对象是首次创建 = weiuser.objects.get_or_create(unionid=unionid, ) + print("点击者对象是哪个", self自生对象, "再看看是不是首次创建的啦") + if self对象是首次创建: + print("点击者对象是哪个", self自生对象, "再看看是不是首次创建的啦再看看是不是首次创建的啦再看看是不是首次创建的啦再看看是不是首次创建的啦再看看是不是首次创建的啦再看看是不是首次创建的啦再看看是不是首次创建的啦") + weiuser.objects.update_or_create(unionid=unionid, + defaults={ + "user_头像": src, "user_昵称": name, "codeQrCode": six上级对象.codeQrCode, + "codeRemark": six上级对象.codeRemark, "codeConfigId": six上级对象.codeConfigId, + "external_userid": external_userid, "user_用户当前的等级": six上级对象.user_用户当前的等级 + 1, + "parent": six上级对象, "user_绑定企微UNIONID": six上级对象.user_绑定企微UNIONID, "user_绑定企微usrID账号": six上级对象.user_绑定企微usrID账号 + }) + (miniUser积分(share分享者unionidID=six上级对象.unionid, click点击者unionidID=self自生对象.unionid, bind绑定的企微unionidID=State) + .add添加点击者添加企微员工双向红包积分(share积分类型="新人红包", share分享者二维码state=State)) + else: + if self自生对象.parent == six六果对象: + print("判断父元素为六果公司对象的时候,进行了数据的更新") + weiuser.objects.update_or_create(unionid=unionid, + defaults={ + "user_头像": src, "user_昵称": name, "codeQrCode": six上级对象.codeQrCode, + "codeRemark": six上级对象.codeRemark, "codeConfigId": six上级对象.codeConfigId, + "external_userid": external_userid, "user_用户当前的等级": six上级对象.user_用户当前的等级 + 1, + "parent": six上级对象, "user_绑定企微UNIONID": six上级对象.user_绑定企微UNIONID, "user_绑定企微usrID账号": six上级对象.user_绑定企微usrID账号 + }) + # 数据更新完成后: 需要调用添加积分的方法, 对新添加企微的用户,添加积分; + (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): + pass + + 企微用户关系对象, 企微用户是否为首次 = wecom企微用户.objects.get_or_create(wecom企微ID=UserID, wecom好友的ID=ExternalUserID) + print(企微用户关系对象, 企微用户是否为首次, "============================") + if 企微用户是否为首次: + pass + else: + 企微用户关系对象.wecom好友关系状态 = ChangeType + 企微用户关系对象.save() + + def 好友主动删除企微事件(self, UserID, ChangeType, State, ExternalUserID): + print("\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", UserID, State, ChangeType, ExternalUserID, + "\n🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 \n", + ) + print("到底哪里报错了呀为什么啊") + 企微用户关系对象, 企微用户是否为首次 = wecom企微用户.objects.get_or_create(wecom企微ID=UserID, wecom好友的ID=ExternalUserID) + print(企微用户关系对象, 企微用户是否为首次, "==========到底哪里报错了呀为什么啊到底哪里报错了呀为什么啊==================") + if 企微用户是否为首次: + pass + else: + 企微用户关系对象.wecom好友关系状态 = ChangeType + 企微用户关系对象.save() + + def 解密POST消息(self, msg_content: bytes): + """ + 微信回调消息解密;(这里是用于解决url回调认证,和用户之间推送消息的) + :param msg_content: 回调消息中的body体内容 + :type msg_content: bytes 这里响应的body数据,不要序列化 + :return: 返回解密后的字典对象; + :rtype: dict + """ + # 从XML中找到Encrypt标签的内容,即加密数据 + xmldict = xmltodict.parse(msg_content.decode()) + Encrypt = jmespath.search(data=xmldict, expression="xml.Encrypt", ) + # 将EncodingAESKey进行Base64解码,并补足填充字符"=" + AESKey = base64.b64decode(self.EncodingAESKey + "=") + # 创建一个AES加密器对象,使用CBC模式和指定的初始化向量(IV) + cipher = AES.new(key=AESKey, mode=AES.MODE_CBC, iv=AESKey[:16]) + # 对加密数据进行Base64解码 + aes_msg = base64.b64decode(Encrypt) + # 使用解密器对象解密数据 + de_text = cipher.decrypt(aes_msg) + # 去除解密数据地前16个字节的随机字符串 + content = de_text[16:] + # 解析前4个字节以获取XML内容的实际长度,并将其从网络字节序转换为主机字节序 + # xml_len = socket.ntohl(struct.unpack("I", content[:4])[0]) + xml_len = int.from_bytes(content[:4], byteorder='big') + # 根据解析出的长度提取实际的XML内容 + xml_content = content[4: xml_len + 4] + # 将XML内容解析为字典格式 + as_dict = xmltodict.parse(xml_input=xml_content) + # 打印解析后的字典 + return as_dict + + def 解密GET消息(self, echostr): + """ + :param echostr: + :type echostr: + :return: + :rtype: + """ + AESKey = base64.b64decode(self.EncodingAESKey + "=") + aes_msg = base64.b64decode(echostr) + aes = AES.new(key=AESKey, mode=AES.MODE_CBC, iv=aes_msg[:16]) + de_text = aes.decrypt(aes_msg) + # rand_msg = cls.aes_decrypt(AESKey, aes_msg) + content = de_text[16:] # 去掉前16随机字节 + + # 取出4字节的msg_len + # xml_len = socket.ntohl(struct.unpack("I", content[:4])[0]) + xml_len = int.from_bytes(content[:4], byteorder='big') + xml_content = content[4: xml_len + 4] + print("xml_content", xml_content) + + return xml_content + + def api_text(self, request: WSGIRequest | Request, *args, **kwargs): + """ + :param request: + :param args: + :param kwargs: + :return: + """ + print("============") + file_path = f"{settings.BASE_DIR}/django_公共认证接口/WW_verify_EhbJf3fcwi8bNijV.txt" + file_text = Path(file_path).read_text() + return HttpResponse(content=file_text) + + def api_get(self, request: Request): + """接受微信发过来的get请求,拿到参数后解决,并且回复值,结果为验证成功""" + GET_OBJ = request.query_params + signature = jmespath.search(data=GET_OBJ, expression="msg_signature", ) + timestamp = jmespath.search(data=GET_OBJ, expression="timestamp", ) + nonce = jmespath.search(data=GET_OBJ, expression="nonce", ) + echostr = jmespath.search(data=GET_OBJ, expression="echostr", ) + # TODO:sorted([token, timestamp, nonce])这是就是对三个参数进行字典排序 + hashstr = "".join(sorted([self.token, timestamp, nonce, echostr])) # 这是就是对三个参数进行字典排序 + sig = hashlib.sha1(string=hashstr.encode()).hexdigest() + if sig == signature: + ret = self.解密GET消息(echostr=echostr) # 调用算法,返回解密后的数值 + s = ret.decode().strip() + print("成功回调") + return HttpResponse(content=s) + else: + print("没有验yghd成功") + return None + + def 添加企业客户事件(self, as_data): + """https://developer.work.weixin.qq.com/document/path/92130#%E6%B7%BB%E5%8A%A0%E4%BC%81%E4%B8%9A%E5%AE%A2%E6%88%B7%E4%BA%8B%E4%BB%B6""" + pass + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 添加企业客户事件") + wecom_data = wecomData(as_data=as_data) # 解析返回的数据,拿到对应的值 + + res_welcom_code = wecom消息推送.发送新客户欢迎语(CALLBACK_CODE=wecom_data.WelcomeCode) + + # 这里还需要判断, 是否要给上一级的对象添加 积分(得从用户中查看是否为推广员) + self.单独处理新添加用户的数据存储(UserID=wecom_data.UserID, ChangeType=wecom_data.ChangeType, + State=wecom_data.State, ExternalUserID=wecom_data.ExternalUserID, + ) + + def 外部联系人免验证添加成员事件(self, as_data): + """https://developer.work.weixin.qq.com/document/path/92130#%E5%A4%96%E9%83%A8%E8%81%94%E7%B3%BB%E4%BA%BA%E5%85%8D%E9%AA%8C%E8%AF%81%E6%B7%BB%E5%8A%A0%E6%88%90%E5%91%98%E4%BA%8B%E4%BB%B6""" + pass + # 外部联系人添加了配置了客户联系功能且开启了免验证的成员时(此时成员尚未确认添加对方为好友),回调该事件 + wecom_data = wecomData(as_data=as_data) # 解析返回的数据,拿到对应的值 + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 外部联系人免验证添加成员事件") + # print(res_welcom_code) + + def 删除企业客户事件(self, as_data): + """https://developer.work.weixin.qq.com/document/path/92130#%E5%88%A0%E9%99%A4%E4%BC%81%E4%B8%9A%E5%AE%A2%E6%88%B7%E4%BA%8B%E4%BB%B6""" + pass + + def 好友主动删除企微(self, as_data): + """""" + wecom_data = wecomData(as_data=as_data) + pass + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 删除跟进成员事件") + + def 删除跟进成员事件(self, as_data): + """https://developer.work.weixin.qq.com/document/path/92130#%E5%88%A0%E9%99%A4%E8%B7%9F%E8%BF%9B%E6%88%90%E5%91%98%E4%BA%8B%E4%BB%B6""" + pass + # 配置了客户联系功能的成员被外部联系人删除时,回调该事件 + wecom_data = wecomData(as_data=as_data) # 解析返回的数据,拿到对应的值 + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 删除跟进成员事件") + + def 客户接替失败事件(self, as_data): + """https://developer.work.weixin.qq.com/document/path/92130#%E5%AE%A2%E6%88%B7%E6%8E%A5%E6%9B%BF%E5%A4%B1%E8%B4%A5%E4%BA%8B%E4%BB%B6""" + pass + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 客户接替失败事件") + # 企业将客户分配给新的成员接替后,客户添加失败时回调该事件 + + def 客户群创建事件(self, as_data): + """""" + # 有新增客户群时,回调该事件。收到该事件后,企业可以调用获取客户群详情接口获取客户群详情。 + pass + + def 客户群变更事件(self, as_data): + """""" + pass + wecom_data = wecomData(as_data=as_data) + print(wecom_data.UpdateDetail, "🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 这里的值是多少的呢?") + # https://developer.work.weixin.qq.com/document/path/92130#%E5%AE%A2%E6%88%B7%E7%BE%A4%E5%8F%98%E6%9B%B4%E4%BA%8B%E4%BB%B6 + # 客户群被修改后(群名变更,群成员增加或移除,群主变更,群公告变更),回调该事件。收到该事件后,企业需要再调用获取客户群详情接口,以获取最新的群详情。 + + def 客户群解散事件(self, as_data): + """ + https://developer.work.weixin.qq.com/document/path/92130#%E5%AE%A2%E6%88%B7%E7%BE%A4%E8%A7%A3%E6%95%A3%E4%BA%8B%E4%BB%B6 + """ + pass + # 当客户群被群主解散后,回调该事件。 + wecom_data = wecomData(as_data=as_data) # 解析回调的数据 + + def 编辑企业客户事件(self, as_data): + """https://developer.work.weixin.qq.com/document/path/92130#%E7%BC%96%E8%BE%91%E4%BC%81%E4%B8%9A%E5%AE%A2%E6%88%B7%E4%BA%8B%E4%BB%B6""" + pass + + # 配置了客户联系功能的成员修改外部联系人的备注、手机号或标签时,回调该事件 + print("编辑企业客户事件编辑企业客户事件编辑企业客户事件", as_data) + + def 获客链接_企业使用量即将耗尽事件(self, as_data): + """""" + pass + + def 获客链接_使用量已经耗尽事件(self, as_data): + """""" + pass + + def 获客链接_使用量增加事件事件(self, as_data): + """""" + pass + + def 获客链接_获客链接异常事件(self, as_data): + """""" + pass + + def 获客链接_删除获客链接事件(self, as_data): + """""" + pass + + def 获客链接_获客使用量即将过期事件(self, as_data): + """""" + pass + + def 获客链接_微信客户打开获客链接事件(self, as_data): + """""" + pass + + def 获客链接_通过获客链接发起好友请求事件(self, as_data): + """""" + pass + + def 获客链接_成员首次收消息事件(self, as_data): + """""" + pass + + def 获客链接_成员多次收消息事件(self, as_data): + """ + 参数 说明 + ToUserName 企业微信CorpID + FromUserName 此事件该值固定为sys,表示该消息由系统生成 + CreateTime 消息创建时间 (整型) + MsgType 消息的类型,此时固定为event + Event 固定为customer_acquisition + ChangeType 此时固定为message_from_customer + UserID 企业服务人员的UserID(2024年12月19号0点开始将不再回调该字段,请根据ChatKey参数查询收消息数据) + ExternalUserID 外部联系人的userid,注意不是企业成员的账号(2024年12月19号0点开始将不再回调该字段,请根据ChatKey参数查询收消息数据) + LinkId 获客链接ID + ChatSeq 成员收到消息的次数(2024年12月19号0点开始将不再回调该字段,请根据ChatKey参数查询收消息数据) + ChatKey 成员收消息的会话信息凭据,可通过调用获取获客链接使用成员接受消息数据接口获取详细的收消息信息,回调后30分钟内有效 + 应用可以根据ExternalUserID调用“获取客户详情”读取详情。 + 目前仅对微信客户支持此事件 + """ + pass + + def api_post(self, request: WSGIRequest | Request, *args, **kwargs): + """""" + as_dict = self.解密POST消息(msg_content=request.body) + wecom_data = wecomData(as_data=as_dict) # 创建了对象 + print(as_dict, "回调接口回调成功了啦:sixwecom测试") + Event = pydash.get(obj=as_dict, path="xml.Event") # change_external_contact 事件的类型,此时固定为change_external_contact + print(Event) + ChangeType = pydash.get(obj=as_dict, path="xml.ChangeType") # add_external_contact 此时固定为add_external_contact + # TODO 以下为添加好友相关的接口调用事件 + if Event == "change_external_contact" and ChangeType == "add_external_contact": # 好友主动添加企微回调 + self.添加企业客户事件(as_data=as_dict) + # six企微回调业务处理方法().添加企业客户事件(as_data=as_dict) + # TODO 以下为删除好友 + if Event == "change_external_contact" and ChangeType == "del_external_contact": + print("企微主动删除好友") # 企微主动删除好友 + self.企微主动删除好友事件(UserID=wecom_data.UserID, ExternalUserID=wecom_data.ExternalUserID, + State=wecom_data.State, ChangeType=wecom_data.ChangeType, + ) + if Event == "change_external_contact" and ChangeType == "del_follow_user": + print("好友主动删除企微", wecom_data) # 好友主动删除 + self.好友主动删除企微事件(UserID=wecom_data.UserID, ExternalUserID=wecom_data.ExternalUserID, + State=wecom_data.State, ChangeType=wecom_data.ChangeType, + ) + # TODO 编辑外部联系人好友回调事件 + if Event == "change_external_contact" and ChangeType == "edit_external_contact": + self.编辑企业客户事件(as_data=as_dict) + # TODO 外部联系人免验证添加成员事件 外部联系人添加了配置了客户联系功能且开启了免验证的成员时(此时成员尚未确认添加对方为好友),回调该事件 + if Event == "change_external_contact" and ChangeType == "add_half_external_contact": + self.外部联系人免验证添加成员事件(as_data=as_dict) + # TODO 以下为群相关的接口调用事件 + # 客户群创建事件 有新增客户群时,回调该事件。收到该事件后,企业可以调用获取客户群详情接口获取客户群详情。 + if Event == "change_external_chat" and ChangeType == "create": + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "客户群创建事件") + self.客户群创建事件(as_data=as_dict) + # 客户群被修改后(群名变更,群成员增加或移除,群主变更,群公告变更),回调该事件。收到该事件后,企业需要再调用获取客户群详情接口,以获取最新的群详情。 + if Event == "change_external_chat" and ChangeType == "update": + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "客户群变更事件") + self.客户群变更事件(as_data=as_dict) + # 群解散事件 + if Event == "change_external_chat" and ChangeType == "dismiss": + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "客户群解散事件") + self.客户群解散事件(as_data=as_dict) + # TODO 以下为标签相关的接口调用事件 + # 企业客户标签创建事件 + if Event == "change_external_tag" and ChangeType == "create": + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "企业客户标签创建事件") + # 企业客户标签变更事件当企业客户标签/标签组(包括规则组的标签)被修改时,回调此事件。收到该事件后,企业需要调用获取企业标签库来获取标签/标签组的详细信息。 + if Event == "change_external_tag" and ChangeType == "update": + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "企业客户标签变更事件") + self.客户群变更事件(as_data=as_dict) + # 企业客户标签删除事件 当企业客户标签/标签组被删除时,回调此事件。删除标签组时,该标签组下的所有标签将被同时删除,但不会进行回调。 + if Event == "change_external_tag" and ChangeType == "delete": + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "企业客户标签删除事件") + if Event == "change_external_tag" and ChangeType == "shuffle": + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "企业客户标签重排事件") + # 企业使用量即将耗尽事件 + if Event == "customer_acquisition" and ChangeType == "balance_low": + pass + print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", "获客链接_企业使用量即将耗尽事件") + self.获客链接_企业使用量即将耗尽事件(as_data=as_dict) + + # 当获客助手的使用量已经消耗完时,回调此事件 + if Event == "customer_acquisition" and ChangeType == "balance_exhausted": + pass + self.获客链接_使用量已经耗尽事件(as_data=as_dict) + + # 当获客助手的使用量从0变到非0时,回调此事件。 + if Event == "customer_acquisition" and ChangeType == "balance_increased": + pass + self.获客链接_使用量增加事件事件(as_data=as_dict) + + # 获客链接异常事件 + if Event == "customer_acquisition" and ChangeType == "link_unavailable": + # 若链接中的成员暂时无法添加客户时,会在分配时自动跳过该成员。当链接中配置的全部成员账号异常,暂时无法继续添加客户时,回调此事件到创建相应链接的应用,可及时调整链接配置或流量曝光策略,避免流量浪费。 + pass + self.获客链接_获客链接异常事件(as_data=as_dict) + + if Event == "customer_acquisition" and ChangeType == "delete_link": + # 当API创建的获客链接在管理端或终端被删除时,回调此事件到创建相应链接的应用。 + pass + self.获客链接_删除获客链接事件(as_data=as_dict) + + # 获客使用量即将过期事件 当企业购买的获客助手使用量即将过期时,将在过期前的14天、7天、3天、2天及1天回调此事件。 + if Event == "customer_acquisition" and ChangeType == "quota_expire_soon": + pass + self.获客链接_获客使用量即将过期事件(as_data=as_dict) + + # 微信客户打开获客链接事件 当微信客户通过获客链接进入成员的profile页时,回调此事件。仅部分经营类目企业支持,当前企业是否支持可在「高级功能-获客助手」中查看该类目对应的功能是否包含「链接打开回调」 + if Event == "customer_acquisition" and ChangeType == "open_profile": + pass + self.获客链接_微信客户打开获客链接事件(as_data=as_dict) + + # 通过获客链接发起好友请求事件 当微信用户通过获客链接点击添加到通讯录,成功发起好友请求,回调此事件到创建该链接的应用。 + if Event == "customer_acquisition" and ChangeType == "friend_request": + pass + self.获客链接_通过获客链接发起好友请求事件(as_data=as_dict) + + # 成员首次收消息事件 授权企业中配置了客户联系功能的成员通过获客链接添加微信客户后,当成员首次收到客户消息时,回调此事件到创建相应链接的应用。 + if Event == "customer_acquisition" and ChangeType == "customer_start_chat": + pass + self.获客链接_成员首次收消息事件(as_data=as_dict) + # 成员多次收消息事件授权企业中配置了客户联系功能的成员通过获客链接添加微信客户后,当成员第3、5、10次收到客户消息时,回调此事件到创建相应链接的应用。该事件仅在获客助手内测期限时免费提供。 + # 注:3次、5次、10次为近期新增统计,仅能针对上线后才第1次收到消息的客户生效。 + if Event == "customer_acquisition" and ChangeType == "message_from_customer": + pass + self.获客链接_通过获客链接发起好友请求事件(as_data=as_dict) + return Response(data={"message": "xiao方法被调用了"}, status=status.HTTP_200_OK) diff --git a/wechat_项目授权/企业微信网页授权.py b/wechat_项目授权/企业微信网页授权.py new file mode 100644 index 0000000..6096e9a --- /dev/null +++ b/wechat_项目授权/企业微信网页授权.py @@ -0,0 +1,64 @@ +import datetime +import hashlib + +import requests +from django.core.handlers.wsgi import WSGIRequest +from django.utils.crypto import get_random_string +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 wechat_token.token工具包 import sixToken + + +class wecom网页开发接口(ViewSet): + AppID = "wwbe6369dc26a9d83a" # 企微appid + AppSecret = "SIRyum7vQh-Bt36AxnqKMX0HIiE-zkYbjYgSat7reZw" # 企微secret + AgentId = "1000008" # 企微agentid + """这个接口,是在微信开发者工具, 打开时请求的接口,进行授权状态""" + """官网文档:https://developer.work.weixin.qq.com/document/path/91023""" + + @action(detail=False, methods=["get"], url_path="web_auth") + def 企微网页授权(self, request: WSGIRequest | Request, *args, **kwargs): + """""" + code = request.data.get("code", False) # + print("code的值", code) + wecom_token = sixToken.get_wecom_token() + code_access_token = f"https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token={wecom_token}&code={code}" + json_data = requests.get(url=code_access_token, ) + print("打印一下企微网页授权", json_data.json()) + 当用户为企业成员时在企微中打开链接返回示例如下 = {"errcode": 0, "errmsg": "ok", "userid": "USERID", "user_ticket": "USER_TICKET"} + 用户不是企微的成员同时是在个微中打开的链接 = {'errcode': 0, 'errmsg': 'ok', 'openid': 'oan8ExL4vgmQwhh0B3-MBKhqrXko'} # 元宝的号 服务号的:o28bf6x8TjmK6DZlInbC1ieAowGE + 用户是企微的成员是在个微中打开链接的 = {'userid': 'YuanBao1975', 'errcode': 0, 'errmsg': 'ok'} + 双方都是好友同时个微不企微成员时 = { + 'errcode': 0, 'errmsg': 'ok', 'openid': 'oan8ExL4vgmQwhh0B3-MBKhqrXko', + 'external_userid': 'wmj4zANAAA86UQT22hrqS4izuR_iNjKw' + } + return Response(data="", status=status.HTTP_200_OK) + + @action(detail=False, methods=["get", "post", "put", "delete"], url_path="sdk_auth") + def 企微号SDK授权(self, request: Request, *args, **kwargs): + """ + :param request: + :param args: + :param kwargs: + :return: + """ + url = request.data.get("url", False) # + random_string = get_random_string(length=16) + timestamp = int(datetime.datetime.now().strftime('%s')) + wecom_tick = sixToken.get_wecom_tick() + d = {"noncestr": random_string, "jsapi_ticket": wecom_tick, "timestamp": timestamp, "url": url} + # TODO 这里数据就是根据文档中,自己组装的,并没有返回值可以获取 + sorted_by_key_rise = dict(sorted(d.items())) + str_list = "&".join([f"{key}={value}" for key, value in sorted_by_key_rise.items()]) + sig = hashlib.new(name="sha1", data=str_list.encode("utf-8")).hexdigest() + res_data = {"nonceStr": random_string, "timestamp": timestamp, "signature": sig} + return Response(data=res_data, status=status.HTTP_200_OK) + + +wecom网页开发接口Router = DefaultRouter() +wecom网页开发接口Router.register(prefix="", viewset=wecom网页开发接口, basename="") diff --git a/wechat_项目授权/小程序授权接口.py b/wechat_项目授权/小程序授权接口.py new file mode 100644 index 0000000..a0eb007 --- /dev/null +++ b/wechat_项目授权/小程序授权接口.py @@ -0,0 +1,268 @@ +""" +Author: xiao 792282@qq.com +Date: 2025-08-10 11:36:05 +LastEditors: xiao 792282@qq.com +LastEditTime: 2025-08-17 13:38:40 +FilePath: django_公共认证接口/小程序认证接口.py +Description: 这是默认设置,可以在设置》工具》File Description中进行配置 +""" +import os + +import django + +from sixGuoDjango.settings import BASE_DIR +from wechat_token.token工具包 import sixToken +from wechat_项目工具包.EMS中国邮政.ems邮政 import ems邮政物流工具 + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() + +import jmespath + +from rest_framework.viewsets import ViewSet + +import base64 +import hashlib +import os +from pathlib import Path + +import orjson +import pydash +from Crypto.Cipher import AES +from Crypto.Util.Padding import pad +from django.conf import settings +from django.core.handlers.wsgi import WSGIRequest +from django.http import HttpResponse +from requests import post +from rest_framework import status +from rest_framework.request import Request +from rest_framework.response import Response + + +# async def async_function(FromUserName: str, result_data_list, channelID): +# """ 异步调用:协程""" +# pass +# print("在这里打印值", result_data_list) +# result_data = pydash.get(obj=result_data_list, path="0") +# +# data = {'type': 'chat_messages', 'message': {"xiao": "zizi", "result_data": result_data}, } +# await channel_layer.send(channel=channelID, message=data, ) +# + +class sixmini(ViewSet): + """小程序消息的认和回调接口""" + token = "xiaozizi" + EncodingAESKey = "sdnUVuOoDCzMqFJZ9uECMXSYEbVAYnQTqQIWSkI1KfP" # EncodingAESKey(消息加密密钥)(不程序的) + """ + 消息推送启用并设置消息推送配置后,用户发给小程序的消息以及开发者需要的事件推送,都将被微信转发至该服务器地址中。 + 开发者也可使用云函数或微信云托管免鉴权接收消息推送,立即开通 认证 + https://mp.weixin.qq.com/wxamp/devprofile/get_profile?token=2052988734&lang=zh_CN + """ + + def sendCustomMessage(self, FromUserName: str, post_data_type): + """""" + # 回复消息的请求 + uri = f"https://api.weixin.qq.com/cgi-bin/message/custom/send" + post_data_text = { + "touser": FromUserName, # string 是 用户的 OpenID + "msgtype": "text", # string 是消息类型。text表示文本消息;image表示图片消息;link表示图文链接;miniprogrampage表示小程序卡片。 + "text": {"content": "你好"}, + } + post_data_image = { + "touser": FromUserName, # string 是 用户的 OpenID + "msgtype": "image", # object 否 图片消息,msgtype="image" 时必填。 + "image": {"media_id": "g_2HeEUOFmcJoWEic-ex4rj9BPVQYvkXAdTFWOMifCkxreYQhiJxxbaN8bDNfHuR"}, + # 发送的图片的媒体ID,通过 uploadTempMedia上传图片文件获得。 + } + post_data_link = { + "touser": FromUserName, # string 是 用户的 OpenID + "msgtype": "link", # object 否 图文链接,msgtype="link" 时必填 + "link": { + "title": "Happy Day", # string 否 消息标题 + "description": "Is Really A Happy Day", # string 否 图文链接消息 + "url": "URL", # string 否 图文链接消息被点击后跳转的链接 + "thumb_url": "THUMB_URL", # 图文链接消息的图片链接,支持 JPG、PNG 格式,较好的效果为大图 640 X 320,小图 80 X 80 + }, + } + post_data_miniprogrampage = { + "touser": FromUserName, # string 是 用户的 OpenID + "msgtype": "miniprogrampage", + # string 是消息类型。text表示文本消息;image表示图片消息;link表示图文链接;miniprogrampage表示小程序卡片。 + "miniprogrampage": { + "title": "title", # string 否 消息标题 + "pagepath": "pagepath", + # 小程序的页面路径,跟app.json对齐,支持参数,比如pages/index/index?foo=bar + "thumb_media_id": "thumb_media_id", + # 小程序消息卡片的封面, image 类型的 media_id,通过 uploadTempMedia接口上传图片文件获得,建议大小为 520*416 + }, + } + wecom_token = sixToken.get_wecom_token() + mini_token = sixToken.get_mini_token() + result_data = post( + url=uri, params={"access_token": mini_token}, + data=orjson.dumps(post_data_text).decode("utf-8"), + ) + + def uploadTempMedia(self, request: WSGIRequest | Request, *args, **kwargs): + """ + + :param request: + :type request: + :param args: + :type args: + :param kwargs: + :type kwargs: + """ + # 上传图片的接口 + uri = f"https://api.weixin.qq.com/cgi-bin/media/upload" + wecom_token = sixToken.get_wecom_token() + file_path = Path(settings.BASE_DIR).joinpath("django_环境/常用类/xiao小程序项目图片/ico运力管理系统.png") + 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: + """""" + # 1. 生成 AESKey(Base64 解码 EncodingAESKey + "=") + aes_key = base64.b64decode(encoding_aes_key + "=") + # 2. 构造 FullStr = random(16B) + msg_len(4B) + msg + appid + random_16b = os.urandom(16) # 16 字节随机字符串 + # msg_len = struct.pack( ">I", len( msg_bytes ) ) # 4 字节网络字节序 学习理解 + msg_bytes_1 = msg.encode("utf-8") + msg_len_1 = len(msg_bytes_1).to_bytes(length=4, byteorder="big") # 大端序 + # 结果是一样的 + # print( msg_len_1, msg_len_1, "这二个一是一样的吗" ) + appid_bytes = appid.encode("utf-8") + full_str = random_16b + msg_len_1 + msg_bytes_1 + appid_bytes + # 3. AES-256-CBC 加密(PKCS#7 填充) + iv = aes_key[:16] # IV 取 AESKey 前 16 字节( 自定义的随机密钥字符串的base64 前16位) + cipher = AES.new(key=aes_key, mode=AES.MODE_CBC, iv=iv) + encrypted = cipher.encrypt(pad(data_to_pad=full_str, block_size=AES.block_size)) + # 4. Base64 编码得到 Encrypt + encrypt = base64.b64encode(encrypted).decode("utf-8") + # 5. 生成 MsgSignature(sha1(token + timestamp + nonce + encrypt)) + params = sorted([str(timestamp), nonce, token, encrypt]) + 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 + 编码数据 组成的 + :param encrypt: + :type encrypt: + :return: + :rtype: + """ + aes_key = base64.b64decode(self.EncodingAESKey + "=") # 补 全 Base64 编码缺失的 '=' + # Step 2: Base64 解码加密数据 + encrypted_data = base64.b64decode(encrypt) + # Step 3: 提取 IV 和密文 + try: + # 获取初始向量(IV取AES Key的前16字节) + iv = aes_key[:16] + # 创建AES-CBC解密器 + cipher = AES.new(key=aes_key, mode=AES.MODE_CBC, iv=iv) + # 执行AES解密 + decrypted = cipher.decrypt(encrypted_data) + # 解析解密后的数据:# 1. 去除前 16 字节的随机字符串 + content_start = decrypted[16:] + # 使用int.from_bytes提取消息长度(大端序)这里的 content_start 是去除掉了解密后面的前16位字符串的长度 # 2. 读取4字节的消息长度(大端序) + xml_len = int.from_bytes(content_start[:4], byteorder='big') + # 提取XML消息内容 + xml_content = content_start[4:4 + xml_len].decode('utf-8') + 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) + + def 确认收货(self, data): + print("确认订单请求接口进来了", data) + 确认收货的方法 = pydash.get(obj=data, path="confirm_receive_method", default=None) + order支付微信侧订单号 = pydash.get(obj=data, path="transaction_id") + if 确认收货的方法: + print("确认收货的回请求进来了") + ems邮政物流工具().确认收货(order支付微信侧订单号=order支付微信侧订单号) + 确认收货的时候数据 = { + 'ToUserName': 'gh_f754c53eb962', + 'FromUserName': 'ohQkD7HmLYEYrFjFau6juOhduRU8', + 'CreateTime': 1784839115, + 'MsgType': 'event', # 类型,微信官方默认的 + 'Event': 'trade_manage_order_settlement', # 接收到消息的类型, 可以判断是不是当前用户 确认收货 + 'transaction_id': '4200003120202607191690098150', # 微信官方生成的支付订单号 + 'merchant_id': '1700383419', # 微信官方的商户号 + 'sub_merchant_id': '', # 子商户有的商户ID + 'merchant_trade_no': '548663656512', + 'pay_time': 1784410374, # 接收到消息的时间戳 + 'shipped_time': 1784666314, # 商家发货的时间 + 'confirm_receive_method': 2, # 当前用户 确认收货的方式 2:表示是自动确认收货 1:表示用户主动点击收货 + '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: + :param args: + :param kwargs: + :return: + """ + print("认证请求进来了") + signature = request.query_params.get("signature", "") + timestamp = request.query_params.get("timestamp", "") + nonce = request.query_params.get("nonce", "") + echostr = request.query_params.get("echostr", False) + # TODO:sorted([token, timestamp, nonce])这是就是对三个参数进行字典排序 + hashstr = "".join(sorted([self.token, timestamp, nonce])) # 这是就是对三个参数进行字典排序 + sig = hashlib.new(name="sha1", data=hashstr.encode("utf-8")).hexdigest() + if sig == signature: + # 当上面的值判断正确后 官方要求原样返回 echostr ; + return HttpResponse(content=echostr, content_type="text/plan") + else: + return Response(data="不对", ) + + def api_post(self, request: Request, *args, **kwargs): + """ + 调用本接口: 就可以向已经订阅消息的用户发送消息,(同时需要注意的是:消息模板需要在小程序的管理后台订阅好) + :param request: + :param args: + :param kwargs: + :return: + """ + Encrypt = request.data.get("Encrypt", False) # + xml_content = self.消息解密(encrypt=Encrypt) + Event = pydash.get(obj=xml_content, path="Event") + FromUserName = pydash.get(obj=xml_content, path="FromUserName") + MsgType = pydash.get(obj=xml_content, path="MsgType") + print("微信官方到底推送了啥信息啊...........为什么", ) + print(xml_content) + print("微信官方到底推送了啥信息啊...........为什么", ) + if Event == "trade_manage_order_settlement": + # 这里的通知是微信官方发过来的, 同时,是用户没有确认收货时 达到时间后自动触发的 + self.确认收货(data=xml_content) + if Event == "subscribe_msg_popup_event": + print("----此接口是记录的用户点击订阅消息的次数!", xml_content) + # subMsgObj = weiuser.objects.get(mini_openid=FromUserName) + if Event == "add_express_path": + # 这里发生回调,是说明物流的快递信息有推送 + pass + self.更新物流信息(data=xml_content) + if MsgType == "text": + pass + # 客服收到的文字消息(此时只是测试,直接返回了文本本身) + # self.sendCustomMessage(FromUserName=FromUserName, post_data_type="text") + if MsgType == "image": + pass # 客服收到了图片消息(只是测试,收到消息后,并没有做任何的处理) + return Response(data={"message": "xiao方法被调用了"}, status=status.HTTP_200_OK) diff --git a/wechat_项目授权/服务号认证接口.py b/wechat_项目授权/服务号认证接口.py new file mode 100644 index 0000000..5c5d43a --- /dev/null +++ b/wechat_项目授权/服务号认证接口.py @@ -0,0 +1,53 @@ +import hashlib + +import xmltodict +from django.core.handlers.wsgi import WSGIRequest +from django.http import HttpResponse +from rest_framework import status +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.viewsets import ViewSet + + + + + +class sixwechat( ViewSet ): + token = "xiaozizi" # 配置时填写的token的值(随机字符串) + EncodingAESKey = "RWxYCl7lGDilyJ5BumHDCksnU07EpQLlo87876uUOCq" # 消息加解密密钥 (EncodingAESKey)(服务号) + + + + def api_get( self, request: Request, ): + """""" + signature = request.query_params.get( key="signature", default="" ) + timestamp = request.query_params.get( key="timestamp", default="" ) + nonce = request.query_params.get( key="nonce", default="" ) + echostr = request.query_params.get( "echostr", False ) + # TODO:sorted([token, timestamp, nonce])这是就是对三个参数进行字典排序 + hashstr = "".join( sorted( [ self.token, timestamp, nonce ] ) ) # 这是就是对三个参数进行字典排序 + # hashstr = f"{}" # 这是就是对三个参数进行字典排序 + print( hashstr ) + sig = hashlib.new( name="sha1", data=hashstr.encode( "utf-8" ) ).hexdigest( ) + if sig == signature: + # 当上面的值判断正确后 官方要求原样返回 echostr; + print( "服务号消息推送授权成功了" ) + return HttpResponse( content=echostr, content_type="text/plan" ) + else: + return Response( data="不对", ) + + + + def api_text( self, request: WSGIRequest | Request, ): + """ 这个接口是的配置路径为 服务号官网 ---> 功能设置 ---> 网页授权配置 """ + print( "============" ) + return HttpResponse( content="kMmcLX8ZO79apUxA" ) + + + + def api_post( self, request: WSGIRequest | Request, ): + """""" + xml_data = request.body # 微信会以 XML 格式推送消息 + xml_str = xml_data.decode( "utf-8" ) + xml_dict = xmltodict.parse( xml_input=xml_str.encode( "utf-8" ) ) + return Response( data={ "message": "xiao方法被调用了" }, status=status.HTTP_200_OK ) diff --git a/数据库初始化.py b/数据库初始化.py new file mode 100644 index 0000000..e69de29 diff --git a/测试数据库.py b/测试数据库.py new file mode 100644 index 0000000..8f5adbd --- /dev/null +++ b/测试数据库.py @@ -0,0 +1,32 @@ +import os + +import django + +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/测试目录最后删除/xiaodemo.py b/测试目录最后删除/xiaodemo.py new file mode 100644 index 0000000..df70e12 --- /dev/null +++ b/测试目录最后删除/xiaodemo.py @@ -0,0 +1,37 @@ +import os +import time + +import django +from sixGuoDjango.settings import base_dir_name, 项目名称 + + + +os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{项目名称}.settings" ) +django.setup( ) + +import os +from datetime import datetime, timedelta +from pathlib import Path +from urllib.parse import urlencode +from zoneinfo import ZoneInfo + +import django +import pydash +from Crypto.PublicKey import RSA +from django.conf import settings +from jwt import JWT, jwk_from_pem + +from sixGuoDjango.settings import 项目名称 + + + +os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{项目名称}.settings" ) +django.setup( ) +from wechat_数据库.测试数据库.测试数据表 import xiaozizi + +from jwt.utils import get_int_from_datetime, get_time_from_int + + + +print( get_int_from_datetime( value=datetime.now( ) ) ) +print(time.time()) \ No newline at end of file diff --git a/测试目录最后删除/线程池测试.py b/测试目录最后删除/线程池测试.py new file mode 100644 index 0000000..d74a250 --- /dev/null +++ b/测试目录最后删除/线程池测试.py @@ -0,0 +1,15 @@ +import os + +import django + +from sixGuoDjango.settings import 项目名称 + + + +os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{项目名称}.settings" ) +django.setup( ) + +if __name__ == "__main__": + # 示例1:秒级时间戳 + pass + \ No newline at end of file diff --git a/清除数据.py b/清除数据.py new file mode 100644 index 0000000..d1c088e --- /dev/null +++ b/清除数据.py @@ -0,0 +1,28 @@ +import os + +import django + +from sixGuoDjango.settings import BASE_DIR + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() +from wechat_数据库.用户数据库.小程序登陆用户 import weiuser +from wechat_数据库.企业微信数据库.企微用户表 import wecom企微用户 +from wechat_数据库.支付订单数据库.商品订单数据 import order订单, order订单商品数据 + + +def delete清除所有的订单(): + order订单商品数据.objects.all().delete() + order订单.objects.all().delete() + + +def delete清除用户表(): + weiuser.objects.all().delete() + # wecom企微用户.objects.all().delete() + + +if __name__ == "__main__": + # 这里写你的主程序代码 + pass + # delete清除所有的订单( ) + delete清除用户表() diff --git a/第三方工具目录/腾讯云.py b/第三方工具目录/腾讯云.py new file mode 100644 index 0000000..43b117c --- /dev/null +++ b/第三方工具目录/腾讯云.py @@ -0,0 +1,129 @@ +# 预先定义共享的 CosConfig 实例 需要安装的包为 pip install cos-python-sdk-v5 +import os + +import django + +from sixGuoDjango.settings import BASE_DIR + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings") +django.setup() + +import io +from pathlib import Path + +import jmespath +import pydash +from qcloud_cos import CosConfig, CosS3Client + +default_config = CosS3Client( + CosConfig( + Region="ap-nanjing", SecretId="AKID5FE1e4SjPvFLvLNEvRm8KJ5h86sRXR9e", + SecretKey="NWTFoDUaWHvOhrriMo4FG7pOmxwxpY7V", Token=None, Scheme="https", Domain="hudie.xiao.band", ), + ) + + +class oss上传腾讯云图片: + """ + from qcloud_cos import CosConfig + from qcloud_cos import CosS3Client + """ + # key: str + # Bucket: str = "sixgou-1320557642" # 腾讯云配置(元宝) + Bucket: str = "six-1407732583" # 蝴蝶云配置 + + client: CosS3Client = default_config + + @classmethod + def 上传图片(cls, key: str, file, ): + """ + :param key: 目录名称 + :param file: 文件的bytes类型文件 + """ + response = cls.client.upload_file_from_buffer(Bucket=cls.Bucket, Key=key, + Body=file, ) # Body: 文件的 bytes 类型数据 必须要是一个可以调用read()方法的对象 + data = cls.批量查询图片链接(Key=key) + src = pydash.get(obj=data, path="src") + # print( src ) + return src + + @classmethod + def update本地图片文件(cls, key: str, filename: str, path_name: Path): + """ + :return: + """ + Key = f"six/{key}" + response = cls.client.upload_file( + Bucket=cls.Bucket, # Bucket: 指定存储桶的名称,这里是 "six-1320557642" + Key=Key, # Key: 指定文件在存储桶中的路径和名称,这里是 'six/img.jpg' + LocalFilePath=path_name, # LocalFilePath: 指定本地要上传的文件路径,这里是 "img.jpg" + EnableMD5=False, # EnableMD5: 是否启用 MD5 校验,False 表示不启用 + progress_callback=None, # progress_callback: 上传进度回调函数,None 表示不使用回调函数 + ) + cls.批量查询图片链接(Key=Key) + + @classmethod + def 批量查询图片链接(cls, Key): + """ + :return: + """ + url = cls.client.get_object_url(Bucket=cls.Bucket, Key=Key, ) + data = {"type": "image", "src": url, } + return data + + @classmethod + def 处理用户头像(cls, content: bytes, name: str): + """""" + image = io.BytesIO(content) + Key = f"six/app应用/用户头像/{name}.png" + print(Key) + response = cls.client.upload_file_from_buffer(Bucket=cls.Bucket, Key=Key, + Body=image, ) # Body: 文件的 bytes 类型数据 必须要是一个可以调用read()方法的对象 + img_response = cls.批量查询图片链接(Key=Key) + src = jmespath.search(data=img_response, expression="src", ) + return src + + @classmethod + def 删除图片(cls): + data = cls.client.delete_object(Bucket=cls.Bucket, Key="六果项目/app/加.png") + print(data) + + @classmethod + def xiaozizi(cls): + data = cls.client.delete_object(Bucket=cls.Bucket, Key="zizi/") + print(data) + + @classmethod + def 删除目录(cls): + pass + data_img_list = cls.client.list_objects(Bucket=cls.Bucket, Prefix="zizi", ) + # 从icon这个目录中, 获取所有的 子元素(图片) 信息 + Contents = jmespath.search(data=data_img_list, expression="Contents") + # 取出所有的图片 信息 + for img in Contents: + # 循环, 操作 + Key = jmespath.search(data=img, expression="Key") + print(Key) + # 删除 + res = cls.client.delete_object(Bucket=cls.Bucket, Key=Key) + print(res) + + @classmethod + def 查询所有的图片(cls): + pass + data = cls.client.list_objects(Bucket=cls.Bucket, Prefix="元宝零售", ) + print(data) + Contents = jmespath.search(data=data, expression="Contents") + for img in Contents: + Key = jmespath.search(data=img, expression="Key") + print(Key) + + +if __name__ == "__main__": + pass + fileImg = Path("../django_static_directory/media/yanhua.jpg").resolve() + 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上传腾讯云图片.删除图片() diff --git a/请求接口示例.py b/请求接口示例.py new file mode 100644 index 0000000..68081ad --- /dev/null +++ b/请求接口示例.py @@ -0,0 +1,12 @@ +import os +import django + +from sixGuoDjango.settings import 项目名称 +import os + +import django + +from sixGuoDjango.settings import 项目名称 + +os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{项目名称}.settings") +django.setup()