This commit is contained in:
doudou201703
2026-08-06 20:39:45 +08:00
parent 046fac6dc1
commit 3ff0faebb9
38 changed files with 1029 additions and 611 deletions
@@ -1,4 +1,7 @@
import time
from datetime import datetime
from typing import Literal, Optional
from zoneinfo import ZoneInfo
import emoji
import orjson
@@ -6,7 +9,6 @@ import pydash
import requests
from django.forms import model_to_dict
from pydantic import BaseModel, Field
from ulid import ULID
from django_celery.message.tasks import mini调用微信小程序交易管理服务录入订单接口
from wechat_token.token工具包 import sixToken
@@ -192,43 +194,43 @@ class ems邮政物流工具(BaseModel):
order当前订单对象.order物流订单号 = order订单对象.order物流订单号
order当前订单对象.order物流公司订单编号 = waybill_id
order当前订单对象.save()
print(data.json())
print("生成运单成功时的打印", data.json())
# 这里的作用是, 当订单生成了 就调用 小程序交易管理的发货管理接口, 自动录入订单号
mini调用微信小程序交易管理服务录入订单接口.apply_async(kwargs={"order支付商家侧订单号": order当前订单对象.order支付商家侧订单号}, countdown=30)
def 模拟更新订单状态(self, order物流商家侧订单号):
def 模拟更新订单状态(self, order物流公司订单编号, action_type, action_msg):
""""""
order物流对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号)
mini_token = sixToken.get_mini_token()
milliseconds_int = ULID().milliseconds
模拟更新物流状态 = f"https://api.weixin.qq.com/cgi-bin/express/business/test_update_order?access_token={mini_token}"
utc_unix_timestamp = int(datetime.now(tz=ZoneInfo("utc")).timestamp())
模拟数据 = {
"biz_id": self.ems_biz_id,
"order_id": order物流商家侧订单号, # 商家生成的订单号
"order_id": order物流对象.order物流订单号, # 商家生成的订单号
"delivery_id": self.ems_delivery_id, #
"waybill_id": "", # 物流订单号
"action_time": milliseconds_int, # 这里是更新发的时间戳
"action_type": 100001,
"action_msg": "揽件成功",
"waybill_id": order物流公司订单编号, # 物流订单号
"action_time": utc_unix_timestamp, # 这里是更新发的时间戳
"action_type": action_type,
"action_msg": action_msg,
}
print("打印 一下模拟的数据,主要就是看一下时间戳的问题", 模拟数据)
data = requests.post(url=模拟更新物流状态,
data=orjson.dumps(模拟数据, option=orjson.OPT_SORT_KEYS, ).decode(encoding="utf-8"))
print("🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 🍊 🍎 🍏 ", data.json())
def 查询运单轨迹(self, order物流商家侧订单号):
""""""
查询对象 = order订单.objects.get(order物流订单号=order物流商家侧订单号, )
print(查询对象)
mini_token = sixToken.get_mini_token()
def 更新物流快递数据(self, order物流公司订单编号, order物流订单号):
def 更新物流快递数据(self, order物流公司订单编号, ):
""""""
查询对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号, order物流订单号=order物流订单号)
查询对象 = order订单.objects.get(order物流公司订单编号=order物流公司订单编号, )
mini_token = sixToken.get_mini_token()
emsGetPathData = requests.post(url="https://api.weixin.qq.com/cgi-bin/express/business/path/get",
params={"access_token": mini_token, },
json={
"openid": 查询对象.order支付者openid,
"delivery_id": self.ems_delivery_id, "waybill_id": 查询对象.order物流公司订单编号,
"delivery_id": self.ems_delivery_id, "waybill_id": order物流公司订单编号,
},
)
resData = orjson.loads(emsGetPathData.content.decode(encoding="utf-8"))
@@ -299,4 +301,11 @@ class ems邮政物流工具(BaseModel):
if __name__ == "__main__":
# 当脚本直接运行时执行的代码
ems邮政物流工具().生成运单(out_trade_no商家侧支付订单号="")
# ems邮政物流工具().生成运单(out_trade_no商家侧支付订单号="")
ems邮政物流工具().模拟更新订单状态(order物流公司订单编号="EMS01KZAH47JZA3HCY2R5NS0WD3VN_waybill_id", action_type=100001, action_msg="揽件成功")
time.sleep(30)
ems邮政物流工具().模拟更新订单状态(order物流公司订单编号="EMS01KZAH47JZA3HCY2R5NS0WD3VN_waybill_id", action_type=300002, action_msg="开始派送")
time.sleep(30)
ems邮政物流工具().模拟更新订单状态(order物流公司订单编号="EMS01KZAH47JZA3HCY2R5NS0WD3VN_waybill_id", action_type=300003, action_msg="签收成功")
# ems邮政物流工具().更新物流快递数据(order物流公司订单编号="EMS01KZAD94RDQFQBVVX705YNH6SE_waybill_id")
@@ -5,9 +5,8 @@ import django
from sixGuoDjango.settings import BASE_DIR
from wechat_token.token工具包 import sixToken
os.environ.setdefault( key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings" )
django.setup( )
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{BASE_DIR.name}.settings")
django.setup()
from pathlib import Path
@@ -15,23 +14,18 @@ import pydash
import requests
from django.conf import settings
from requests import post
class wecom消息推送:
pass
@classmethod
def 上传图片文件( cls ):
def 上传图片文件(cls):
uri = ''
filePath = Path( settings.BASE_DIR ).joinpath( "django_static_directory/media/app.png" )
data = requests.post( url=uri, files={ "media": open( file="文件路径", mode="rb", ) } )
filePath = Path(settings.BASE_DIR).joinpath("django_static_directory/media/app.png")
data = requests.post(url=uri, files={"media": open(file="文件路径", mode="rb", )})
@classmethod
def 欢迎语类型IMG( cls ):
def 欢迎语类型IMG(cls):
pass
IMG = {
"msgtype": "link",
@@ -45,7 +39,7 @@ class wecom消息推送:
return IMG
@classmethod
def 欢迎语类型小程序( cls ):
def 欢迎语类型小程序(cls):
pass
miniprogram = {
"msgtype": "miniprogram", # 附件类型,可选image、link、miniprogram或者video
@@ -60,7 +54,7 @@ class wecom消息推送:
return miniprogram
@classmethod
def 欢迎语类型LINK( cls ):
def 欢迎语类型LINK(cls):
"""
欢迎语类型LINK
"""
@@ -73,7 +67,7 @@ class wecom消息推送:
}
@classmethod
def 欢迎语类型VIDEO( cls ):
def 欢迎语类型VIDEO(cls):
pass
VIDEO = {
"msgtype": "video",
@@ -84,9 +78,9 @@ class wecom消息推送:
return VIDEO
@classmethod
def 创建企业群发( cls ):
def 创建企业群发(cls):
pass
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_msg_template"
json_data = {
"chat_type": "single",
@@ -106,30 +100,26 @@ class wecom消息推送:
},
],
}
data = post(
url=url, json=json_data, params={
"access_token": wecom_token,
},
)
print( data.json( ) )
data = requests.post(url=url, json=json_data, params={"access_token": wecom_token, }, )
print(data.json())
@classmethod
def 提醒成员群发( cls ):
def 提醒成员群发(cls):
"""
提醒成员群发
"""
pass
@classmethod
def 停止企业群发( cls ):
def 停止企业群发(cls):
pass
@classmethod
def 发送新客户欢迎语( cls, CALLBACK_CODE: str ):
""""""
wecom_token = sixToken.get_wecom_token( )
def 发送新客户欢迎语(cls, CALLBACK_CODE: str):
"""发送客户添加好友时的 欢迎语 """
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/send_welcome_msg?access_token={wecom_token}"
miniprogram = cls.欢迎语类型小程序( )
miniprogram = cls.欢迎语类型小程序()
json_data = {
"welcome_code": CALLBACK_CODE,
"text": {
@@ -150,15 +140,12 @@ class wecom消息推送:
""",
},
}
data = post( url=url, json=json_data )
print( "客户欢迎语发送成功了:", data.json( ) )
errcode = pydash.get( obj=data.json( ), path="errcode" )
data = requests.post(url=url, json=json_data)
print("客户欢迎语发送成功了:", data.json())
errcode = pydash.get(obj=data.json(), path="errcode")
if errcode == 41051:
pass
return data.json( ).get( "errmsg" )
return data.json().get("errmsg")
class wecom获取企业的全部群发记录:
@@ -174,13 +161,13 @@ class wecom获取企业的全部群发记录:
"""
@classmethod
def 获取群发记录列表( cls ):
def 获取群发记录列表(cls):
"""
企业和第三方应用可通过此接口获取企业与成员的群发记录。
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_list_v2?access_token={wecom_token}"
请求数据示例 = {
"chat_type": "single",
@@ -191,29 +178,28 @@ class wecom获取企业的全部群发记录:
"limit": 50,
"cursor": "CURSOR"
}
data = post( url=url, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=url, json=请求数据示例).json()
print(data)
@classmethod
def 获取群发成员发送任务列表( cls ):
def 获取群发成员发送任务列表(cls):
"""
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_task?access_token={wecom_token}"
请求数据示例 = { "msgid": "msgGCAAAXtWyujaWJHDDGi0mACAAAA", "limit": 50, "cursor": "CURSOR" }
data = post( url=url, json=请求数据示例 ).json( )
print( data )
请求数据示例 = {"msgid": "msgGCAAAXtWyujaWJHDDGi0mACAAAA", "limit": 50, "cursor": "CURSOR"}
data = requests.post(url=url, json=请求数据示例).json()
print(data)
@classmethod
def 获取企业群发成员执行结果( cls ):
def 获取企业群发成员执行结果(cls):
"""
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_send_result?access_token={wecom_token}"
请求数据示例 = {
"msgid": "msgGCAAAXtWyujaWJHDDGi0mACAAAA",
@@ -221,11 +207,8 @@ class wecom获取企业的全部群发记录:
"limit": 50,
"cursor": "CURSOR"
}
data = post( url=url, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=url, json=请求数据示例).json()
print(data)
class wecom入群欢迎语素材管理:
@@ -235,8 +218,8 @@ class wecom入群欢迎语素材管理:
"""
@classmethod
def 添加入群欢迎语素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 添加入群欢迎语素材(cls):
wecom_token = sixToken.get_wecom_token()
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/add?access_token={wecom_token}"
请求数据示例 = {
"text": {
@@ -267,12 +250,12 @@ class wecom入群欢迎语素材管理:
"agentid": 1000014,
"notify": 1
}
data = post( url=url, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=url, json=请求数据示例).json()
print(data)
@classmethod
def 编辑入群欢迎语素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 编辑入群欢迎语素材(cls):
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/edit?access_token={wecom_token}"
请求数据示例 = {
"template_id": "msgXXXXXXX",
@@ -303,41 +286,38 @@ class wecom入群欢迎语素材管理:
},
"agentid": 1000014
}
data = post( url=uri, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=uri, json=请求数据示例).json()
print(data)
@classmethod
def 获取入群欢迎语素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 获取入群欢迎语素材(cls):
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/get?access_token={wecom_token}"
请求数据示例 = {
"template_id": "msgXXXXXXX"
}
data = post( url=uri, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=uri, json=请求数据示例).json()
print(data)
@classmethod
def 删除入群欢迎语素材( cls ):
def 删除入群欢迎语素材(cls):
"""
删除入群欢迎语素材
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/group_welcome_template/del?access_token={wecom_token}"
请求数据示例 = {
"template_id": "msgXXXXXXX",
"agentid": 1000014
}
data = post( url=uri, json=请求数据示例 ).json( )
print( data )
data = requests.post(url=uri, json=请求数据示例).json()
print(data)
class uploadTempMedia上传附件资源:
@classmethod
def upload_file( cls ):
def upload_file(cls):
"""
参数 必须 说明
access_token 是 调用接口凭证
@@ -346,35 +326,29 @@ class uploadTempMedia上传附件资源:
:return:
:rtype:
"""
wecom_token = sixToken.get_wecom_token( )
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload_attachment?access_token={wecom_token}&media_type=image&attachment_type=1"
params = { "access_token": wecom_token, "media_type": "image", "attachment_type": "1" }
file_path = Path( settings.BASE_DIR ).joinpath( "django_环境/常用类/xiao小程序项目图片/ico运力管理系统.png" )
print( file_path )
file = { "media": open( file=file_path, mode="rb", ) }
params = {"access_token": wecom_token, "media_type": "image", "attachment_type": "1"}
file_path = Path(settings.BASE_DIR).joinpath("django_环境/常用类/xiao小程序项目图片/ico运力管理系统.png")
print(file_path)
file = {"media": open(file=file_path, mode="rb", )}
data = post( url=uri, files=file )
media_id = pydash.get( obj=data.json( ), path="media_id" )
print( media_id )
data = requests.post(url=uri, files=file)
media_id = pydash.get(obj=data.json(), path="media_id")
print(media_id)
@classmethod
def 上传临时素材( cls ):
wecom_token = sixToken.get_wecom_token( )
def 上传临时素材(cls):
wecom_token = sixToken.get_wecom_token()
uri = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={wecom_token}&type=image"
# file_path = Path(settings.BASE_DIR).joinpath("django_环境/常用类/xiao小程序项目图片/ico运力管理系统.png")
file_path = Path( settings.BASE_DIR ).joinpath( "django_环境//常用类/xiao小程序项目图片/莫大帅分享主图.png" )
print( file_path )
file = { "media": open( file=file_path, mode="rb", ) }
data = post( url=uri, files=file )
media_id = pydash.get( obj=data.json( ), path="media_id" )
print( data.json( ) )
print( media_id )
file_path = Path(settings.BASE_DIR).joinpath("django_环境/常用类/xiao小程序项目图片/莫大帅分享主图.png")
file = {"media": open(file=file_path, mode="rb", )}
data = requests.post(url=uri, files=file)
media_id = pydash.get(obj=data.json(), path="media_id")
print(data.json())
print(media_id)
if __name__ == '__main__':
pass
uploadTempMedia上传附件资源.上传临时素材( )
uploadTempMedia上传附件资源.上传临时素材()
@@ -16,6 +16,13 @@ class miniTransaction交易管理服务工具(BaseModel):
# demo_可选: Optional[int] = None # 可选值
# demo_默认值: int = Field(default=100001, description="描述") # 有默认值
# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述")
def 消息跳转路径设置(self, ):
"""如你已经在小程序内接入平台提供的确认收货组件,可以通过该接口设置发货消息及确认收货消息的跳转动作,
用户点击发货消息时会直接进入你的小程序订单列表页面或详情页面进行确认收货,进一步优化用户体验"""
pass
mini_token = sixToken.get_mini_token()
uri = f"https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path?access_token={mini_token}"
def 发货信息录入(self, order支付商家侧订单号, ):
pass
print("开始调用录入订单信息了")
@@ -73,6 +80,7 @@ class miniTransaction交易管理服务工具(BaseModel):
"""这里的调用的时机为: 目前的业务逻辑是,物流的状态更新用户已签收了 , 我会在此时调用户确认接口 用户会收得到一个 确认收货的提示"""
mini_token = sixToken.get_mini_token()
uri = f"https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive?access_token={mini_token}"
print("发起确认交易调用了")
# 快递签收时间设定为 2026-07-24 04:11:24
action_time_签收时间戳 = pydash.get(obj=pydash.head(order物流数据), path="action_time")
data = {
@@ -80,10 +88,12 @@ class miniTransaction交易管理服务工具(BaseModel):
"received_time": action_time_签收时间戳, # 快递签收时间,时间戳形式,必传
}
postData = requests.post(url=uri, json=data)
print(postData.json())
# 当请求发送后, 因为只能发送一次,所以需要直接更新状态,
更新对象 = order订单.objects.get(order支付微信官方订单号=order支付微信官方订单号)
更新对象.order物流状态 = "待用户确认收货"
更新对象.save()
print("发起确认交易调用成功了")
if __name__ == "__main__":
@@ -11,6 +11,7 @@ import os
import django
from sixGuoDjango.settings import base_dir_name
from wechat_微信支付证书.江苏六果科技服务商支付证书.江苏六果科技有限公司服务商支付参数 import six六果服务商支付参数
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings")
django.setup()
@@ -35,8 +36,8 @@ from typing import Optional, Literal
import pydash
import xmltodict
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Hash import SHA1, SHA256
from Crypto.PublicKey import RSA
from Crypto.PublicKey.RSA import RsaKey
from Crypto.Signature import pkcs1_15
@@ -51,21 +52,13 @@ class paymentCategory(sixpay六果科技公司):
class wechatPay(BaseModel):
payment: type[paymentCategory] | type[sixpay六果科技公司]
payment: type[sixpay六果科技公司] | type[six六果服务商支付参数]
def 构造签名串(self, uri: str, body_data: dict | bytes | str | None = None,
method: Optional[Literal["GET", "POST"]] = "POST",
method: Optional[Literal["GET", "POST", "PATCH"]] = "POST",
):
"""
构造签名串
@param url:
@type url:
@param body:
@type body:
@param method:
@type method:
@return: 返回已经加密后并组装好的请求头;
@rtype:
"""
url_data = re.search(r'/v3.*', string=uri).group()
shi_jian_chou = str(int(time.time())) # 时间戳
@@ -91,7 +84,7 @@ class wechatPay(BaseModel):
# 加载商户私钥
# 调用了 RSA.import_key() 方法,它会从字符串或文件中导入一个 PEM 格式的 RSA 私钥,并返回一个 RsaKey 类型的对象
private_key: RsaKey = RSA.import_key(self.payment.private_key)
# 生成签名
# 生成签名 使用商户的 私钥进行签名
signature = pkcs1_15.new(rsa_key=private_key).sign(msg_hash=hash_obj)
# 对签名进行Base64编码,符合微信支付API要求
encoded_signature = base64.b64encode(s=signature).decode()
@@ -111,24 +104,16 @@ class wechatPay(BaseModel):
headers = {
"Content-Type": "application/json", "Authorization": Authorization,
}
# headers.update({"Wechatpay-Serial": self.payment.微信支付公钥ID})
return headers
def getpay_jsapi(self, uri, body_data: dict | bytes | str | None = None, method: Optional[
Literal["GET", "POST"]] = "POST",
):
"""
@param url: 请求支付的微信官方地址
@type url: str
@param pay_body: 小程序下单接口获取到发起支付的必要参数prepay_id
@type pay_body: str
@return:
@rtype:
"""
headers = self.构造签名串(uri=uri, body_data=body_data, method=method)
# 发送请求
response: Response = requests.post(url=uri, json=body_data, headers=headers)
print(response.json())
prepay_id = pydash.get(obj=response.json(), path="prepay_id", default=None)
# 验证请求后返回的数据是否为微信官方所发送;
验证签名结果 = self.验证签名串(response_data=response.json(), response_headers=response.headers)
@@ -170,6 +155,15 @@ class wechatPay(BaseModel):
回调解密数据: dict = orjson.loads(decrypted_data.decode(encoding="utf-8"))
return 回调解密数据
def modegmc解密电子发票邮箱账号(self, ciphertext):
pass
encrypted_bytes = base64.b64decode(ciphertext)
# 3. 构建 OAEP 解密器(SHA-1)
private_key: RsaKey = RSA.import_key(self.payment.private_key)
cipher = PKCS1_OAEP.new(key=private_key, hashAlgo=SHA1)
plaintext_bytes = cipher.decrypt(encrypted_bytes)
return plaintext_bytes.decode("utf-8")
def getpay_navite(self, navite_body: dict, ):
"""
@param navite_body:
@@ -316,6 +310,7 @@ class wechatPay(BaseModel):
@rtype:
"""
public_key = RSA.import_key(self.payment.wechat_certificate)
# public_key = RSA.import_key(self.payment.pem微信支付公钥)
Wechatpay_Timestamp = pydash.get(response_headers, "Wechatpay-Timestamp")
Wechatpay_Nonce = pydash.get(response_headers, "Wechatpay-Nonce")
Wechatpay_Signa = pydash.get(response_headers, "Wechatpay-Signature")
@@ -331,7 +326,6 @@ class wechatPay(BaseModel):
def v2签名返回XML(self, sign_data: dict):
"""v2版本的签名:将扫码支付的body转换为微信支付所要求的数据类型"""
# sorted_dict = dict(sorted(sign_data.items(), key=lambda item: item[0], reverse=False))
sorted_dict = dict(pydash.sort_by(collection=sign_data.items(), iteratee=0))
# 拼接字符串: (将密钥添加到最末尾)
params_str = "&".join(f"{k}={v}" for k, v in sorted_dict.items()) + '&key=' + self.payment.apiv2
@@ -397,14 +391,6 @@ class wechatPay(BaseModel):
def 解密群号(self, encryptedData, iv, sessionKey):
"""
对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
对称解密的目标密文为 Base64_Decode(encryptedData)。
对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
:param sessionKey:
:param encryptedData:
:param iv:
:return:
"""
try:
session_key_bytes = base64.b64decode(sessionKey)
@@ -447,7 +433,7 @@ class wechatPay(BaseModel):
def 发起退款(self, body):
pass
uri = f"https://api.mch.weixin.qq.com//v3/refund/domestic/refunds"
uri = f"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"
heardes = self.构造签名串(body_data=body, uri=uri, method="POST")
print(heardes)
response_data = requests.post(url=uri, json=body, headers=heardes)
@@ -17,7 +17,7 @@ class stock发送代金券功能(BaseModel):
# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述")
pass
stock_id_代金券批次号: str = Field(..., description="发放代金券是创建的批次号")
def send发券并返回前端需要的数据(self):
"""前端请求:将这个字典对象返回给前端,前端调用小程序原生插件领取券"""
pass
@@ -29,13 +29,13 @@ class stock发送代金券功能(BaseModel):
# 第二步: 创建好需要的数据并验名
params每一张券需要验名的数据格式 = {
"out_request_no0": out_request_no, # 商家侧的发券订单号
"stock_id0": "22512292", # 代金券创建的批次号
"stock_id0": self.stock_id_代金券批次号, # 代金券创建的批次号
"send_coupon_merchant": mchid, # 发券的商家商户号
# 如果是支付券,必须包含此项并参与签名;商家券则去掉
"create_coupon_merchant0": mchid, # 发券的商家商户号
"customize_send_time0": rfc3339, # 当前的领券的时间
}
# iteratee为0是按key iteratee是以value的值来排序 reverse=False(从小到大) reverse=True(从大到小)
sorted_dict = dict(pydash.sort_by(collection=params每一张券需要验名的数据格式.items(), iteratee=0, reverse=False))
print(sorted_dict)
@@ -46,7 +46,7 @@ class stock发送代金券功能(BaseModel):
# 3. 拼接参数串
params = {
"out_request_no": out_request_no,
"stock_id": "22512292",
"stock_id": self.stock_id_代金券批次号,
"create_coupon_merchant": sixpay六果科技公司.mchid,
"customize_send_time": rfc3339,
"send_coupon_merchant": sixpay六果科技公司.mchid,
@@ -0,0 +1,42 @@
import requests
from pydantic import BaseModel
from yarl import URL
from wechat_微信支付证书.江苏六果科技服务商支付证书.江苏六果科技有限公司服务商支付参数 import six六果服务商支付参数
from wechat_项目工具包.微信支付工具包.微信支付类 import wechatPay
class weiPay服务商电子发票(BaseModel):
# demo_必填: int = Field(..., description="描述") # 必传属发生
# demo_可选: Optional[int] = None # 可选值
# demo_默认值: int = Field(default=100001, description="描述") # 有默认值
# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述")
def model_post_init(self, __context):
print("初始化完成,自动调用 model_post_init")
def 获取开通服务商电子发票能力邀请链接(self):
pass
uri = URL.build(
scheme='https',
host="api.mch.weixin.qq.com",
path="/v3/new-tax-control-fapiao/fapiaomerchant/getspinviteurl",
query={
"operation_type": "AUTH_BINDING",
"fapiao_mode": ["TENCENT_DIGITAL_TAX"], # 【开票模式】 邀请商户开通服务商电子发票的可选开票模式
"fapiao_ability_type_list": ["BASE_ABILITY"],
"invite_code": "code_20260805_123", # 必填 【服务商邀请code】 服务商邀请的唯一标识,由服务商生成,可根据邀请code查询邀请开通情况
# "sub_mchid": "1700383419"
"taxpayer_id":"91321202MAE608K31Q"
}
)
print(uri)
headers = wechatPay(payment=six六果服务商支付参数).构造签名串(uri=str(uri), method="GET")
headers.update({"Wechatpay-Serial":"1880A972F4400AF653A108F5F0C7A71585A4338E"})
getData = requests.get(url=uri, headers=headers)
print(getData.text)
if __name__ == "__main__":
pass
weiPay服务商电子发票().获取开通服务商电子发票能力邀请链接()
@@ -0,0 +1,135 @@
import emoji
import pydash
import requests
from pydantic import BaseModel
from ulid import ULID
from wechat_微信支付证书.江苏六果科技有限公司支付证书.江苏六果科技有限公司支付参数 import sixpay六果科技公司
from wechat_数据库.支付订单数据库.商品订单数据 import order订单
from wechat_项目工具包.微信支付工具包.微信支付类 import wechatPay
class weiPay电子发票(BaseModel):
# demo_可选: Optional[int] = None # 可选值
# demo_默认值: int = Field(default=100001, description="描述") # 有默认值
# demo_联合类型: Literal["xiao", "zizi"] = Field(..., description="描述")
def model_post_init(self, __context):
print("")
def 配置开发选项(self):
"""配置,小程序用户申请开票时的回调请求地址URL"""
pass
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/development-config"
http_uri = "https://xiao.sixgou.com/wechat_mini/invoice/callback/"
请求体 = {
"callback_url": http_uri,
"show_fapiao_cell": True
}
header电子发票请求头 = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, body_data=请求体, method="PATCH")
postData = requests.patch(url=uri, json=请求体, headers=header电子发票请求头)
def 获取商户开票基础信息(self):
pass
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/base-information"
heardes_data = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, method="GET")
getData = requests.get(url=uri, headers=heardes_data)
print(getData)
print(getData.text)
@classmethod
def 查询电子发票的数据(cls, fapiao_apply_id: str):
fapiao_apply_id = "4500000249202608055531280227"
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications/{fapiao_apply_id}"
headers = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, method="GET")
postData = requests.get(url=uri, headers=headers)
print(postData)
print(postData.json())
@classmethod
def 开具电子发票(cls, fapiao_apply_id, 用户填写的开票):
pass
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications"
发起开票的数据 = {
"scene": "WITH_WECHATPAY", # 开票场景,固定值 "WITH_WECHATPAY" 表示该开票申请来源于微信支付订单
"fapiao_apply_id": fapiao_apply_id, # 发票申请单号,从"获取用户填写抬头信息"接口返回的 fapiao_apply_id
"fapiao_information": [ # 发票信息列表(本次只开一张票,故只有一个元素)
{
"fapiao_id": "20200701123456", # 商户侧发票单号,由商户自行生成,保证唯一
"total_amount": 1, # 总价税合计,单位为分(整数)
"need_list": False, # 是否需要发票明细清单,false 表示不需要(即只在票面显示总金额)
"remark": "微信电子发票测试备注", # 发票备注(选填)
"items": [ # 发票行项目列表
{
"tax_code": "3010101020203000000", # 税收分类编码(需从"获取商品和服务税收分类对照表"接口获取)
"goods_category": "洗化用品", # 商品类别(选填,用于辅助分类)
"goods_name": "六果洗衣液", # 商品名称(必填,显示在发票明细上)
"goods_id": 1, # 商品编号(商户自定义,选填
"specification": "A4", # 规格型号(选填)
"unit": "根", # 计量单位(选填,如“次”“个”“件”)
"quantity": 1, # 数量(整数,此处数量极大,实际应根据订单合理设置)
"total_amount": 1, # 该行项目的总价税合计,单位为分(应与 total_amount 逻辑一致)
"tax_rate": 1300, # 税率,单位为万分比(如 13% 填 1300)
"tax_prefer_mark": "NO_FAVORABLE", # 税收优惠政策标识:NO_FAVORABLE 表示不享受优惠
"discount": False, # 是否享受折扣,false 表示不折扣
}
]
}
]
}
发起开票的数据.update({"buyer_information": 用户填写的开票})
商家侧生成的发票单号 = f"{ULID()}"
发票对象 = order订单.objects.get(order支付微信官方订单号=fapiao_apply_id)
print(发票对象.order购物车商品总价)
总价税合计 = 发票对象.order购物车商品总价
goods_name = emoji.replace_emoji(pydash.get(obj=pydash.head(发票对象.order购物车商品数据), path="goods_商品标题"))
销售规格 = pydash.get(obj=pydash.head(发票对象.order购物车商品数据), path="销售规格")
单个商品订单数量 = pydash.get(obj=pydash.head(发票对象.order购物车商品数据), path="单个商品订单数量")
fapiao_information = [
{
"fapiao_id": 商家侧生成的发票单号, # 商户侧发票单号,由商户自行生成,保证唯一
"total_amount": 总价税合计, # 总价税合计,单位为分(整数)
"need_list": False, # 是否需要发票明细清单,false 表示不需要(即只在票面显示总金额)
"remark": "微信电子发票", # 发票备注(选填)
"items": [ # 发票行项目列表
{
"tax_code": "3010101020203000000", # 税收分类编码(需从"获取商品和服务税收分类对照表"接口获取)
"goods_category": "洗化用品", # 商品类别(选填,用于辅助分类)
"goods_name": goods_name, # 商品名称(必填,显示在发票明细上)
"goods_id": 1, # 商品编号(商户自定义,选填)
"specification": 销售规格, # 规格型号(选填)
"unit": "根", # 计量单位(选填,如“次”“个”“件”)
"quantity": 单个商品订单数量, # 数量(整数,此处数量极大,实际应根据订单合理设置)
"total_amount": 总价税合计, # 该行项目的总价税合计,单位为分(应与 total_amount 逻辑一致)
"tax_rate": 1300, # 税率,单位为万分比(如 13% 填 1300)
"tax_prefer_mark": "NO_FAVORABLE", # 税收优惠政策标识:NO_FAVORABLE 表示不享受优惠
"discount": False, # 是否享受折扣,false 表示不折扣
}
]
}
]
发起开票的数据.update({"fapiao_information": fapiao_information})
print(发起开票的数据)
headers = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, body_data=发起开票的数据, method="POST")
headers.update({"Wechatpay-Serial": "11D762828E947104028F2D045DE78FA806D0D4F2"})
print("打印一下请求头", headers)
postData = requests.post(url=uri, json=发起开票的数据, headers=headers)
print(postData.text)
@classmethod
def 获取用户填写的开票(cls, fapiao_apply_id):
uri = f"https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/user-title?fapiao_apply_id={fapiao_apply_id}&scene=WITH_WECHATPAY"
headers = wechatPay(payment=sixpay六果科技公司).构造签名串(uri=uri, method="GET")
postData = requests.get(url=uri, headers=headers)
return postData.json()
if __name__ == "__main__":
pass
用户填写的开票 = weiPay电子发票.获取用户填写的开票(fapiao_apply_id="4500000272202608055614870626")
weiPay电子发票.开具电子发票(fapiao_apply_id="4500000272202608055614870626", 用户填写的开票=用户填写的开票)
@@ -137,6 +137,7 @@ class miniUser积分(BaseModel):
order好友下单企微员工需要添加的积分值 = int(order好友下单商品数量) * int(order购物车商品好友下单助力的企微员工的的积分值)
if share分享者unionidID == click点击者unionidID or share分享者对象.parent == six六果对象:
print("自己点了自己,不需要添加积分了")
return
if share分享者对象.user_角色权限 == miniUser用户角色().推广员:
pass # 如果是推广员则添加
share对象, share布尔值 = share积分表.objects.update_or_create(
@@ -95,14 +95,14 @@ class wei地图工具:
print(res_data.json())
res_json = res_data.json() # type: dict
d = {
'status': 0,
'message': 'Success',
'request_id': '9435209f1ee84219ae7826e65f577331',
'result': {
'rows': [{
'elements': [{
'distance': 3550, # 起点到终点的距离,单位:米
'duration': 651, # 表示从起点到终点的结合路况的时间,秒为单位注:步行/骑行方式(不计算耗时)以及起终点附近没有道路造成无法计算时,不返回本此节点
"status": 0,
"message": "Success",
"request_id": "9435209f1ee84219ae7826e65f577331",
"result": {
"rows": [{
"elements": [{
"distance": 3550, # 起点到终点的距离,单位:米
"duration": 651, # 表示从起点到终点的结合路况的时间,秒为单位注:步行/骑行方式(不计算耗时)以及起终点附近没有道路造成无法计算时,不返回本此节点
}],
}],
},
@@ -116,29 +116,29 @@ class wei地图工具:
url = f"https://apis.map.qq.com/ws/geocoder/v1/?address={address}"
res = requests.get(url=url, params={"key": cls.key}, )
d = {
'status': 0,
'message': 'Success',
'request_id': '9b049a3ff13c4ac3bda3bb5a9fe0c0a8',
'result': {
'title': '泰州海陵万达广场',
'location': { # 解析到的坐标(GCJ02坐标系)
'lng': 119.917068, # 经度
'lat': 32.471578, # 纬度
"status": 0,
"message": "Success",
"request_id": "9b049a3ff13c4ac3bda3bb5a9fe0c0a8",
"result": {
"title": "泰州海陵万达广场",
"location": { # 解析到的坐标(GCJ02坐标系)
"lng": 119.917068, # 经度
"lat": 32.471578, # 纬度
},
'ad_info': { # 行政区划信息 object 是
'adcode': '321202', # string 是 行政区划代码,规则详见:行政区划代码说明
"ad_info": { # 行政区划信息 object 是
"adcode": "321202", # string 是 行政区划代码,规则详见:行政区划代码说明
},
'address_components': {
'province': '江苏省',
'city': '泰州市',
'district': '海陵区',
'street': '济川东路',
'street_number': '',
"address_components": {
"province": "江苏省",
"city": "泰州市",
"district": "海陵区",
"street": "济川东路",
"street_number": "",
},
'similarity': 0.99,
'deviation': 1000,
'reliability': 7, # 可信度参考:值范围 1 <低可信> - 10 <高可信>
'level': 11, # 解析精度级别,分为11个级别,一般>=9即可采用(定位到点,精度较高) 也可根据实际业务需求自行调整,完整取值表见下文。
"similarity": 0.99,
"deviation": 1000,
"reliability": 7, # 可信度参考:值范围 1 <低可信> - 10 <高可信>
"level": 11, # 解析精度级别,分为11个级别,一般>=9即可采用(定位到点,精度较高) 也可根据实际业务需求自行调整,完整取值表见下文。
},
}
@@ -146,7 +146,7 @@ class wei地图工具:
def 经纬度转换为地址(cls, location):
""""""
pass
url = f'https://apis.map.qq.com/ws/geocoder/v1/?location={location}'
url = f"https://apis.map.qq.com/ws/geocoder/v1/?location={location}"
res = requests.get(url=url, params={"key": cls.key}, )
return res.json()
@@ -159,22 +159,22 @@ class wei地图工具:
print(data)
resData = pydash.omit(data, "request_id")
d = {
'status': 0,
'message': 'Success',
'request_id': '8805bff3303f42dd8a1cbcca3701cf63',
'result': {
'ip': '240e:3a3:b201:3f10:185c:efdb:c5b0:b95c',
'location': {
'lat': 32.49098,
'lng': 119.91956,
"status": 0,
"message": "Success",
"request_id": "8805bff3303f42dd8a1cbcca3701cf63",
"result": {
"ip": "240e:3a3:b201:3f10:185c:efdb:c5b0:b95c",
"location": {
"lat": 32.49098,
"lng": 119.91956,
},
'ad_info': {
'nation': '中国',
'province': '江苏省',
'city': '泰州市',
'district': '海陵区',
'adcode': 321202,
'nation_code': 156,
"ad_info": {
"nation": "中国",
"province": "江苏省",
"city": "泰州市",
"district": "海陵区",
"adcode": 321202,
"nation_code": 156,
},
},
}
@@ -190,6 +190,6 @@ class wei地图工具:
return resData
if __name__ == '__main__':
if __name__ == "__main__":
# wei地图工具.腾讯地图计算二点之间的距离(toData终点={"纬度": "30.80377", "经度": "104.151812"}, fromData起点={"纬度": "30.80377", "经度": "104.151812"})
print(wei地图工具.ip地址转为地址(x_forwarded_for="119.84.150.100", ))