Files
sixGuoDjango/wechat_mini_服务端接口目录/物流账号邮政/物流账号接口.py
T

362 lines
22 KiB
Python
Raw Normal View History

2026-08-02 14:07:04 +08:00
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)