kdn-sdk 0.2.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kdn/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/python3
2
+ # @Time : 2020-03-25
3
+ # @Author : Kevin Kong (kfx2007@163.com)
4
+
5
+
6
+ __author__ = "Kevin Kong"
7
+ __version__ = "0.2.9"
kdn/api/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/python3
2
+ # @Time : 2020-04-17
3
+ # @Author : Kevin Kong (kfx2007@163.com)
kdn/api/comm.py ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/python3
2
+ # @Time : 2020-03-25
3
+ # @Author : Kevin Kong (kfx2007@163.com)
4
+
5
+ # 接口调用公共类
6
+
7
+ import json
8
+ from hashlib import md5
9
+ import base64
10
+ from urllib.parse import urlencode, quote_plus, quote
11
+ import requests
12
+ import csv
13
+ from copy import deepcopy
14
+ import logging
15
+
16
+ _logger = logging.getLogger(__name__)
17
+
18
+
19
+ class Comm(object):
20
+
21
+ def __get__(self, instance, owner):
22
+ self.client_id = instance.client_id
23
+ self.api_key = instance.api_key
24
+ self.sandbox = instance.sandbox
25
+ self.timeout = instance.timeout
26
+ self.url = instance.url
27
+ return self
28
+
29
+ def _get_request_header(self):
30
+ """
31
+ 获取固定的header
32
+ """
33
+ header = {
34
+ "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
35
+ }
36
+ return header
37
+
38
+ def _mask_identifier(self, value):
39
+ value = str(value or "")
40
+ if len(value) <= 4:
41
+ return "*" * len(value)
42
+ return f"{value[:2]}***{value[-2:]}"
43
+
44
+ def _sign(self, data):
45
+ """
46
+ 签名逻辑
47
+ """
48
+ to_sign = f"{data}{self.api_key}".encode(
49
+ "utf-8")
50
+ sign = base64.b64encode(
51
+ md5(to_sign).hexdigest().encode("utf-8")).decode("utf-8")
52
+ return sign
53
+
54
+ def _remove_none(self, d):
55
+ dx = deepcopy(d)
56
+ for k, v in d.items():
57
+ if v and type(v) is dict:
58
+ r = self._remove_none(v)
59
+ if r:
60
+ dx[k] = r
61
+ else:
62
+ dx[k] = ''
63
+ if v and type(v) is list:
64
+ for i in range(len(v)):
65
+ dx[k][i] = self._remove_none(v[i])
66
+ if not v:
67
+ dx[k] = ''
68
+ return dx
69
+
70
+ def post(self, request_type, data, url=None, timeout=None):
71
+ """
72
+ 提交请求
73
+ params:
74
+ data: 提交的数据
75
+ """
76
+ payload = json.dumps(self._remove_none(
77
+ data), separators=(',', ':'), ensure_ascii=False)
78
+ request_data = {
79
+ "RequestType": request_type,
80
+ "EBusinessID": self.client_id,
81
+ "RequestData": quote_plus(payload),
82
+ "DataSign": self._sign(payload),
83
+ "DataType": 2
84
+ }
85
+ endpoint = url or self.url
86
+ request_timeout = self.timeout if timeout is None else timeout
87
+ _logger.debug(
88
+ "KDN-SDK POST request_type=%s ebusiness_id=%s endpoint=%s payload_bytes=%s",
89
+ request_type,
90
+ self._mask_identifier(self.client_id),
91
+ endpoint,
92
+ len(payload.encode("utf-8")),
93
+ )
94
+ response = requests.post(
95
+ endpoint,
96
+ data=request_data,
97
+ headers=self._get_request_header(),
98
+ timeout=request_timeout,
99
+ )
100
+ return response.json()
kdn/api/kdn.py ADDED
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/python3
2
+ # @Time : 2020-03-25
3
+ # @Author : Kevin Kong (kfx2007@163.com)
4
+
5
+ from .comm import Comm
6
+ from .query import Query
7
+ from .order import Order
8
+ from .service import Service
9
+ from .logistic import Logistic
10
+ import csv
11
+ import os
12
+
13
+
14
+ SANDBOXURL = "http://sandboxapi.kdniao.com:8080/kdniaosandbox/gateway/exterfaceInvoke.json"
15
+ URL = "http://api.kdniao.com"
16
+ DEFAULT_TIMEOUT = 15
17
+
18
+
19
+ class KDN(object):
20
+
21
+ def __init__(self, client_id, api_key, sandbox=False, timeout=DEFAULT_TIMEOUT):
22
+ """
23
+ params:
24
+ client_id: 商户ID,
25
+ api_key: API KEY,
26
+ sandbox: 是否沙箱测试环境
27
+ timeout: 请求超时时间,单位秒
28
+ """
29
+ self.client_id = client_id
30
+ self.api_key = api_key
31
+ self.sandbox = sandbox
32
+ self.timeout = timeout
33
+ self.url = SANDBOXURL if self.sandbox else URL
34
+
35
+ @classmethod
36
+ def get_express_list(cls):
37
+ """
38
+ 获取支持的公司列表
39
+ 返回包含代码和名称的字典
40
+ """
41
+ express = {}
42
+ csv_path = os.path.dirname(os.path.dirname(__file__))
43
+ with open(os.path.join(csv_path, "data/express.csv"),encoding='UTF-8') as f:
44
+ for row in csv.reader(f):
45
+ express[row[1].strip()] = row[0].strip()
46
+ return express
47
+
48
+ @classmethod
49
+ def get_eorder_express(cls):
50
+ """
51
+ 获取支持电子面单的物流公司
52
+ """
53
+ codes = []
54
+ filelist = ('direct.csv', 'eorder.csv',
55
+ 'kdn.csv', 'month.csv', 'offline.csv')
56
+ csv_path = os.path.dirname(os.path.dirname(__file__))
57
+ for file in filelist:
58
+ with open(os.path.join(csv_path, f"data/{file}"),encoding='UTF-8') as f:
59
+ for row in csv.reader(f):
60
+ codes.append(row[0])
61
+ return set(list(codes))
62
+
63
+ @classmethod
64
+ def get_templates(cls):
65
+ """
66
+ 获取电子面单模板
67
+ """
68
+ templates = []
69
+ csv_path = os.path.dirname(os.path.dirname(__file__))
70
+ with open(os.path.join(csv_path, "data/templates.csv"),encoding='UTF-8') as f:
71
+ for row in csv.reader(f):
72
+ templates.append(tuple(row))
73
+ return templates
74
+
75
+ @classmethod
76
+ def get_express_types(self):
77
+ """获取快递公司业务类型"""
78
+ types = []
79
+ csv_path = os.path.dirname(os.path.dirname(__file__))
80
+ with open(os.path.join(csv_path, "data/exptype.csv"),encoding='UTF-8') as f:
81
+ for row in csv.reader(f):
82
+ types.append(tuple(row))
83
+ return types
84
+
85
+ @classmethod
86
+ def get_preorder_express(self):
87
+ """get express list which supported preordering"""
88
+ expresses =[]
89
+ csv_path = os.path.dirname(os.path.dirname(__file__))
90
+ with open(os.path.join(csv_path, "data/preorder.csv"),encoding='UTF-8') as f:
91
+ for row in csv.reader(f):
92
+ expresses.append(row[0])
93
+ return expresses
94
+
95
+
96
+ @classmethod
97
+ def get_trans_types(self):
98
+ """get express trans types"""
99
+ transtypes =[]
100
+ csv_path = os.path.dirname(os.path.dirname(__file__))
101
+ with open(os.path.join(csv_path, "data/trans.csv"),encoding='UTF-8') as f:
102
+ for row in csv.reader(f):
103
+ transtypes.append(row)
104
+ return transtypes
105
+
106
+ comm = Comm()
107
+ query = Query()
108
+ order = Order()
109
+ service = Service()
110
+ logistic = Logistic()
kdn/api/logistic.py ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/python3
2
+ # @Time : 2021-11-29
3
+ # @Author : Kevin Kong (kfx2007@163.com)
4
+
5
+ # 物流跟踪 API
6
+
7
+ from requests.api import get
8
+ from .query import Query
9
+ # from .comm import Comm
10
+ # UPGRADE = {
11
+ # 1002: 8001,
12
+ # }
13
+
14
+
15
+ # def logistic(func):
16
+ # def wrapper(*args, **kwargs):
17
+ # print(getattr(func,'request_type'))
18
+ # func.request_type = UPGRADE[func.request_type]
19
+ # return func(*args, **kwargs)
20
+ # return wrapper
21
+
22
+
23
+ class Logistic(Query):
24
+
25
+ def __init__(self, *args, **kwargs):
26
+ self.express_code = 8001
27
+ self.subsribe_code = 8008
28
+
29
+ # def get_express_routes(self, *args, **kwargs):
30
+ # """
31
+ # 获取即时物流轨迹
32
+ # params:
33
+ # shipper_code: 快递公司编码
34
+ # logistic_code: 快递单号
35
+ # order_code: 订单编号
36
+ # customer_name: ShipperCode 为 JD,必填,对应京东的青龙配送编码,也叫商家编码.
37
+ # """
38
+ # func = Query.get_express_routes
39
+ # func.request_type = 8001
40
+ # return func(self, *args, **kwargs)
41
+
42
+ # def subscribe_express_routes(self, *args, **kwargs):
43
+ # """
44
+ # 轨迹订阅接口
45
+ # params:
46
+ # shipper_code: 快递公司编码
47
+ # logistic_code: 快递单号
48
+ # recevier_name: 收件人姓名
49
+ # province_name: 收件人省份
50
+ # city_name: 收件人城市
51
+ # district_name: 收件人区域
52
+ # address: 收件人详细地址
53
+ # sender_name: 发件人姓名
54
+ # sender_tel: 发件人电话
55
+ # sender_mobile: 发件人手机 (电话或手机必填一个)
56
+ # sender_province: 发件人省份
57
+ # sender_city:发件人城市
58
+ # sender_district: 发件人区域
59
+ # sender_address: 发件人详细地址
60
+ # recevier_tel: 收件人电话
61
+ # receiver_mobile: 收件人手机 (电话或手机必填一个)
62
+ # member_id: ERP 系统、电商平台等系统或平台类型用户的会员ID或店铺账号等唯一性标识,用于区分其用户
63
+ # warehouse_id: 仓库标志
64
+ # customer_name: ShipperCode 为 JD,必填,对应京东的青龙配送编码,也叫商家编码
65
+ # order_code: 订单编号
66
+ # month_code: 月结单号
67
+ # pay_type: 运费支付方式:1-现付,2-到付,3-月结,4- 第三方付(仅 SF、KYSY 支持)
68
+ # exp_type:详细快递类型
69
+ # cost: 快递运费
70
+ # other_cost: 其他费用
71
+ # receiver_company: 收件人公司
72
+ # receiver_post_code:收件人邮编
73
+ # sender_company: 发件人公司
74
+ # sender_post_code: 发件人邮编
75
+ # is_notice:是否通知快递员上门揽件 0-通知,1-不通知,不填则 默认为 1
76
+ # start_date: 上门揽件时间段,格式:YYYY-MM-DD HH24:MM:SS
77
+ # end_date: 上门揽件时间段
78
+ # weight: 重量
79
+ # quantity: 包裹数量
80
+ # volume: 体积
81
+ # remark: 备注
82
+ # is_sender_message: 是否订阅短信 0-不需要,1-需要
83
+ # service_name:增值服务名称
84
+ # service_value: 增值服务值
85
+ # service_customer_id: 增值服务客户id
86
+ # goods_name: 商品名称
87
+ # goods_code: 商品编码
88
+ # goods_quantity:商品数量
89
+ # goods_price: 商品价格
90
+ # goods_weight:商品重量
91
+ # goods_desc:商品描述
92
+ # goods_vol: 商品体积
93
+ # """
94
+ # func = Query.subscribe_express_routes
95
+ # func.request_type = 8008
96
+ # return func(self, *args, **kwargs)