| @@ -2,15 +2,18 @@ | ||
| 2 | 2 |  | 
| 3 | 3 | from __future__ import division | 
| 4 | 4 |  | 
| 5 | +import json | |
| 6 | + | |
| 5 | 7 | from django.conf import settings | 
| 6 | 8 | from django_logit import logit | 
| 7 | 9 | from django_response import response | 
| 8 | 10 | from paginator import pagination | 
| 9 | 11 | from TimeConvert import TimeConvert as tc | 
| 10 | 12 |  | 
| 11 | -from maintenance.models import MaintenaceInfo | |
| 13 | +from maintenance.models import ExpressCompanyInfo, MaintenaceInfo | |
| 12 | 14 | from utils.admin_utils import is_admin, is_maintenanceman | 
| 13 | 15 | from utils.error.errno_utils import MaintenanceStatusCode | 
| 16 | +from utils.kuaidi.synquery import KuaiDi100 | |
| 14 | 17 |  | 
| 15 | 18 |  | 
| 16 | 19 | @logit | 
| @@ -29,6 +32,11 @@ def maintenance_add(request): | ||
| 29 | 32 |      tracking_number = request.POST.get('tracking_number', '') | 
| 30 | 33 |      maintenance_status = request.POST.get('maintenance_status', u'寄出运送中') | 
| 31 | 34 |  | 
| 35 | + try: | |
| 36 | + company = ExpressCompanyInfo.objects.get(name=express_name, status=True) | |
| 37 | + except ExpressCompanyInfo.DoesNotExist: | |
| 38 | + company = None | |
| 39 | + | |
| 32 | 40 | maintenance = MaintenaceInfo.objects.create( | 
| 33 | 41 | user_id=user_id, | 
| 34 | 42 | name=name, | 
| @@ -41,6 +49,7 @@ def maintenance_add(request): | ||
| 41 | 49 | point_id=point_id, | 
| 42 | 50 | point_name=point_name, | 
| 43 | 51 | express_name=express_name, | 
| 52 | + express_com=company.com if company else '', | |
| 44 | 53 | tracking_number=tracking_number, | 
| 45 | 54 | maintenance_status=maintenance_status, | 
| 46 | 55 |          maintenance_status_at={maintenance_status: tc.utc_datetime()} | 
| @@ -113,11 +122,21 @@ def maintenance_update(request): | ||
| 113 | 122 | if point_name: | 
| 114 | 123 | maintenance.point_name = point_name | 
| 115 | 124 | if express_name: | 
| 125 | + try: | |
| 126 | + company = ExpressCompanyInfo.objects.get(name=express_name, status=True) | |
| 127 | + except ExpressCompanyInfo.DoesNotExist: | |
| 128 | + company = None | |
| 116 | 129 | maintenance.express_name = express_name | 
| 130 | + maintenance.express_com = company.com if company else '' | |
| 117 | 131 | if tracking_number: | 
| 118 | 132 | maintenance.tracking_number = tracking_number | 
| 119 | 133 | if back_express_name: | 
| 134 | + try: | |
| 135 | + company = ExpressCompanyInfo.objects.get(name=back_express_name, status=True) | |
| 136 | + except ExpressCompanyInfo.DoesNotExist: | |
| 137 | + company = None | |
| 120 | 138 | maintenance.back_express_name = back_express_name | 
| 139 | + maintenance.back_express_com = company.com if company else '' | |
| 121 | 140 | if back_tracking_number: | 
| 122 | 141 | maintenance.back_tracking_number = back_tracking_number | 
| 123 | 142 | if maintenance_status: | 
| @@ -165,3 +184,51 @@ def maintenance_detail(request): | ||
| 165 | 184 |      return response(data={ | 
| 166 | 185 | 'maintenace': maintenance.data, | 
| 167 | 186 | }) | 
| 187 | + | |
| 188 | + | |
| 189 | +def is_tracking_signed(tracking_info): | |
| 190 | + if not tracking_info: | |
| 191 | + return False | |
| 192 | +    items = tracking_info.get('data', []) | |
| 193 | + if not items: | |
| 194 | + return False | |
| 195 | +    return items[0].get('status') == u'签收' | |
| 196 | + | |
| 197 | + | |
| 198 | +@logit | |
| 199 | +def maintenance_tracking_info(request): | |
| 200 | +    maintenance_id = request.POST.get('maintenance_id', '') | |
| 201 | +    type_ = request.POST.get('type', 'tracking')  # tracking / back_tracking | |
| 202 | + | |
| 203 | + try: | |
| 204 | + maintenance = MaintenaceInfo.objects.get(id=maintenance_id, status=True) | |
| 205 | + except MaintenaceInfo.DoesNotExist: | |
| 206 | + return response(MaintenanceStatusCode.MAINTENACE_NOT_FOUND) | |
| 207 | + | |
| 208 | +    tracking_info = {} | |
| 209 | + if type_ == 'tracking': | |
| 210 | + if maintenance.express_com and maintenance.tracking_number: | |
| 211 | + tracking_info = KuaiDi100().track(maintenance.express_com, maintenance.tracking_number) | |
| 212 | + else: | |
| 213 | + if maintenance.back_express_com and maintenance.back_tracking_number: | |
| 214 | + tracking_info = KuaiDi100().track(maintenance.back_express_com, maintenance.back_tracking_number) | |
| 215 | + | |
| 216 | + if tracking_info: | |
| 217 | + try: | |
| 218 | + tracking_info = json.loads(tracking_info) | |
| 219 | + except Exception: | |
| 220 | +            tracking_info = {} | |
| 221 | + | |
| 222 | + if tracking_info: | |
| 223 | + if type_ == 'tracking': | |
| 224 | + maintenance.tracking_info = tracking_info | |
| 225 | + maintenance.tracking_signed = is_tracking_signed(tracking_info) | |
| 226 | + else: | |
| 227 | + maintenance.back_tracking_info = tracking_info | |
| 228 | + maintenance.back_tracking_signed = is_tracking_signed(tracking_info) | |
| 229 | + maintenance.save() | |
| 230 | + | |
| 231 | +    return response(data={ | |
| 232 | + 'type': type_, | |
| 233 | + 'tracking_info': tracking_info, | |
| 234 | + }) | 
| @@ -277,4 +277,6 @@ urlpatterns += [ | ||
| 277 | 277 |  | 
| 278 | 278 | url(r'^admin/maintenance/update$', maintenance_views.maintenance_update, name='maintenance_update'), | 
| 279 | 279 | url(r'^admin/maintenance/list$', maintenance_views.maintenance_list, name='maintenance_list'), | 
| 280 | + | |
| 281 | + url(r'^maintenance/tracking/info$', maintenance_views.maintenance_tracking_info, name='maintenance_tracking_info'), | |
| 280 | 282 | ] | 
| @@ -419,6 +419,12 @@ KODO_DEFAULT_BRAND_DOMAIN = '' | ||
| 419 | 419 |  GIS_2_ADMINISTRATIVE_DIVISION = 'https://apis.map.qq.com/ws/geocoder/v1/?key=4FNBZ-TIIKW-MWJRQ-RHZJN-W6F7Q-BFBKX&location={0},{1}' | 
| 420 | 420 |  PHONE_2_ADMINISTRATIVE_DIVISION = 'https://www.baifubao.com/callback?cmd=1059&callback=phone&phone={0}' | 
| 421 | 421 |  | 
| 422 | +# 快递100 | |
| 423 | +KUAIDI00 = { | |
| 424 | + 'key': '', | |
| 425 | + 'customer': '', | |
| 426 | +} | |
| 427 | + | |
| 422 | 428 | TESTING_SNS = ['000000'] | 
| 423 | 429 |  | 
| 424 | 430 |  COMPONENT_CALLBACK_CONFIG = { | 
| @@ -10,11 +10,11 @@ class MaintenancePointInfoAdmin(admin.ModelAdmin): | ||
| 10 | 10 |  | 
| 11 | 11 |  | 
| 12 | 12 | class ExpressCompanyInfoAdmin(admin.ModelAdmin): | 
| 13 | -    list_display = ('name', 'status', 'created_at', 'updated_at') | |
| 13 | +    list_display = ('name', 'com', 'status', 'created_at', 'updated_at') | |
| 14 | 14 |  | 
| 15 | 15 |  | 
| 16 | 16 | class MaintenanceInfoAdmin(admin.ModelAdmin): | 
| 17 | -    list_display = ('user_id', 'name', 'phone', 'address', 'sn', 'desc', 'point_id', 'point_name', 'express_name', 'tracking_number', 'back_express_name', 'back_tracking_number', 'maintenance_status', 'status', 'created_at', 'updated_at') | |
| 17 | +    list_display = ('user_id', 'name', 'phone', 'address', 'sn', 'desc', 'point_id', 'point_name', 'express_name', 'express_com', 'tracking_number', 'tracking_signed', 'back_express_name', 'back_express_com', 'back_tracking_number', 'back_tracking_signed', 'maintenance_status', 'status', 'created_at', 'updated_at') | |
| 18 | 18 |  | 
| 19 | 19 |  | 
| 20 | 20 | admin.site.register(MaintenacePointInfo, MaintenancePointInfoAdmin) | 
| @@ -0,0 +1,26 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.29 on 2021-09-22 08:46 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations | |
| 6 | +import jsonfield.fields | |
| 7 | + | |
| 8 | + | |
| 9 | +class Migration(migrations.Migration): | |
| 10 | + | |
| 11 | + dependencies = [ | |
| 12 | +        ('maintenance', '0007_auto_20210922_1522'), | |
| 13 | + ] | |
| 14 | + | |
| 15 | + operations = [ | |
| 16 | + migrations.AddField( | |
| 17 | + model_name='maintenaceinfo', | |
| 18 | + name='back_tracking_info', | |
| 19 | +            field=jsonfield.fields.JSONField(default={}, help_text='\u5bc4\u56de\u5feb\u9012\u4fe1\u606f', verbose_name='back_tracking_info'), | |
| 20 | + ), | |
| 21 | + migrations.AddField( | |
| 22 | + model_name='maintenaceinfo', | |
| 23 | + name='tracking_info', | |
| 24 | +            field=jsonfield.fields.JSONField(default={}, help_text='\u5feb\u9012\u4fe1\u606f', verbose_name='tracking_info'), | |
| 25 | + ), | |
| 26 | + ] | 
| @@ -0,0 +1,20 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.29 on 2021-09-22 09:00 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | + | |
| 7 | + | |
| 8 | +class Migration(migrations.Migration): | |
| 9 | + | |
| 10 | + dependencies = [ | |
| 11 | +        ('maintenance', '0008_auto_20210922_1646'), | |
| 12 | + ] | |
| 13 | + | |
| 14 | + operations = [ | |
| 15 | + migrations.AddField( | |
| 16 | + model_name='expresscompanyinfo', | |
| 17 | + name='com', | |
| 18 | + field=models.CharField(blank=True, help_text='\u7f16\u7801', max_length=255, null=True, verbose_name='com'), | |
| 19 | + ), | |
| 20 | + ] | 
| @@ -0,0 +1,25 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.29 on 2021-09-22 09:04 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | + | |
| 7 | + | |
| 8 | +class Migration(migrations.Migration): | |
| 9 | + | |
| 10 | + dependencies = [ | |
| 11 | +        ('maintenance', '0009_expresscompanyinfo_com'), | |
| 12 | + ] | |
| 13 | + | |
| 14 | + operations = [ | |
| 15 | + migrations.AddField( | |
| 16 | + model_name='maintenaceinfo', | |
| 17 | + name='back_express_com', | |
| 18 | + field=models.CharField(blank=True, help_text='\u5bc4\u56de\u5feb\u9012\u7f16\u7801', max_length=255, null=True, verbose_name='back_express_com'), | |
| 19 | + ), | |
| 20 | + migrations.AddField( | |
| 21 | + model_name='maintenaceinfo', | |
| 22 | + name='express_com', | |
| 23 | + field=models.CharField(blank=True, help_text='\u5feb\u9012\u7f16\u7801', max_length=255, null=True, verbose_name='express_com'), | |
| 24 | + ), | |
| 25 | + ] | 
| @@ -0,0 +1,41 @@ | ||
| 1 | +# -*- coding: utf-8 -*- | |
| 2 | +# Generated by Django 1.11.29 on 2021-09-22 09:27 | |
| 3 | +from __future__ import unicode_literals | |
| 4 | + | |
| 5 | +from django.db import migrations, models | |
| 6 | +import jsonfield.fields | |
| 7 | + | |
| 8 | + | |
| 9 | +class Migration(migrations.Migration): | |
| 10 | + | |
| 11 | + dependencies = [ | |
| 12 | +        ('maintenance', '0010_auto_20210922_1704'), | |
| 13 | + ] | |
| 14 | + | |
| 15 | + operations = [ | |
| 16 | + migrations.AddField( | |
| 17 | + model_name='maintenaceinfo', | |
| 18 | + name='back_tracking_signed', | |
| 19 | + field=models.BooleanField(default=False, help_text='\u5bc4\u56de\u5feb\u9012\u662f\u5426\u5df2\u7b7e\u6536', verbose_name='back_tracking_signed'), | |
| 20 | + ), | |
| 21 | + migrations.AddField( | |
| 22 | + model_name='maintenaceinfo', | |
| 23 | + name='tracking_signed', | |
| 24 | + field=models.BooleanField(default=False, help_text='\u5feb\u9012\u662f\u5426\u5df2\u7b7e\u6536', verbose_name='tracking_signed'), | |
| 25 | + ), | |
| 26 | + migrations.AlterField( | |
| 27 | + model_name='maintenaceinfo', | |
| 28 | + name='back_tracking_info', | |
| 29 | +            field=jsonfield.fields.JSONField(blank=True, default={}, help_text='\u5bc4\u56de\u5feb\u9012\u4fe1\u606f', null=True, verbose_name='back_tracking_info'), | |
| 30 | + ), | |
| 31 | + migrations.AlterField( | |
| 32 | + model_name='maintenaceinfo', | |
| 33 | + name='maintenance_status_at', | |
| 34 | +            field=jsonfield.fields.JSONField(blank=True, default={}, help_text='\u7ef4\u4fee\u72b6\u6001\u53d8\u66f4\u65f6\u95f4', null=True, verbose_name='maintenance_status_at'), | |
| 35 | + ), | |
| 36 | + migrations.AlterField( | |
| 37 | + model_name='maintenaceinfo', | |
| 38 | + name='tracking_info', | |
| 39 | +            field=jsonfield.fields.JSONField(blank=True, default={}, help_text='\u5feb\u9012\u4fe1\u606f', null=True, verbose_name='tracking_info'), | |
| 40 | + ), | |
| 41 | + ] | 
| @@ -35,6 +35,7 @@ class MaintenacePointInfo(BaseModelMixin): | ||
| 35 | 35 |  | 
| 36 | 36 | class ExpressCompanyInfo(BaseModelMixin): | 
| 37 | 37 | name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'名称') | 
| 38 | + com = models.CharField(_(u'com'), max_length=255, blank=True, null=True, help_text=u'编码') | |
| 38 | 39 |  | 
| 39 | 40 | class Meta: | 
| 40 | 41 | verbose_name = _(u'快递公司信息') | 
| @@ -48,6 +49,7 @@ class ExpressCompanyInfo(BaseModelMixin): | ||
| 48 | 49 |          return { | 
| 49 | 50 | 'id': self.pk, | 
| 50 | 51 | 'name': self.name, | 
| 52 | + 'com': self.com, | |
| 51 | 53 | } | 
| 52 | 54 |  | 
| 53 | 55 |  | 
| @@ -67,14 +69,20 @@ class MaintenaceInfo(BaseModelMixin): | ||
| 67 | 69 | point_name = models.CharField(_(u'point_name'), max_length=255, blank=True, null=True, help_text=u'维修点名称') | 
| 68 | 70 |  | 
| 69 | 71 | express_name = models.CharField(_(u'express_name'), max_length=255, blank=True, null=True, help_text=u'快递公司') | 
| 72 | + express_com = models.CharField(_(u'express_com'), max_length=255, blank=True, null=True, help_text=u'快递编码') | |
| 70 | 73 | tracking_number = models.CharField(_(u'tracking_number'), max_length=255, blank=True, null=True, help_text=u'快递单号') | 
| 74 | +    tracking_info = JSONField(_(u'tracking_info'), blank=True, null=True, default={}, help_text=u'快递信息') | |
| 75 | + tracking_signed = models.BooleanField(_(u'tracking_signed'), default=False, help_text=u'快递是否已签收') | |
| 71 | 76 |  | 
| 72 | 77 | back_express_name = models.CharField(_(u'back_express_name'), max_length=255, blank=True, null=True, help_text=u'寄回快递公司') | 
| 78 | + back_express_com = models.CharField(_(u'back_express_com'), max_length=255, blank=True, null=True, help_text=u'寄回快递编码') | |
| 73 | 79 | back_tracking_number = models.CharField(_(u'back_tracking_number'), max_length=255, blank=True, null=True, help_text=u'寄回快递单号') | 
| 80 | +    back_tracking_info = JSONField(_(u'back_tracking_info'), blank=True, null=True, default={}, help_text=u'寄回快递信息') | |
| 81 | + back_tracking_signed = models.BooleanField(_(u'back_tracking_signed'), default=False, help_text=u'寄回快递是否已签收') | |
| 74 | 82 |  | 
| 75 | 83 | # 寄出运送中、已签收修理中、已修复寄回、寄回签收 | 
| 76 | 84 | maintenance_status = models.CharField(_(u'maintenance_status'), max_length=8, default=u'寄出运送中', help_text=u'维修状态') | 
| 77 | -    maintenance_status_at = JSONField(_(u'maintenance_status_at'), default={}, help_text=u'维修状态变更时间') | |
| 85 | +    maintenance_status_at = JSONField(_(u'maintenance_status_at'), blank=True, null=True, default={}, help_text=u'维修状态变更时间') | |
| 78 | 86 |  | 
| 79 | 87 | class Meta: | 
| 80 | 88 | verbose_name = _(u'维修信息') | 
| @@ -104,9 +112,15 @@ class MaintenaceInfo(BaseModelMixin): | ||
| 104 | 112 | 'point_id': self.point_id, | 
| 105 | 113 | 'point_name': self.point_name, | 
| 106 | 114 | 'express_name': self.express_name, | 
| 115 | + 'express_com': self.express_com, | |
| 107 | 116 | 'tracking_number': self.tracking_number, | 
| 117 | + 'tracking_info': self.tracking_info, | |
| 118 | + 'tracking_signed': self.tracking_signed, | |
| 108 | 119 | 'back_express_name': self.back_express_name, | 
| 120 | + 'back_express_com': self.back_express_com, | |
| 109 | 121 | 'back_tracking_number': self.back_tracking_number, | 
| 122 | + 'back_tracking_info': self.back_tracking_info, | |
| 123 | + 'back_tracking_signed': self.back_tracking_signed, | |
| 110 | 124 | 'maintenance_status': self.maintenance_status, | 
| 111 | 125 |              'maintenance_status_at': {k: tc.local_string(utc_dt=tc.string_to_utc_datetime(v, format='%Y-%m-%dT%H:%M:%S.%fZ')) for k, v in self.maintenance_status_at.items()}, | 
| 112 | 126 | 'created_at': tc.local_string(utc_dt=self.created_at), | 
| @@ -0,0 +1,22 @@ | ||
| 1 | +# -*- coding: utf-8 -*-' | |
| 2 | + | |
| 3 | +import requests | |
| 4 | + | |
| 5 | + | |
| 6 | +class KuaiDi100: | |
| 7 | + def __init__(self): | |
| 8 | + self.key = '' # TODO 客户授权key | |
| 9 | + self.url = 'https://www.kuaidi100.com/autonumber/auto' # 请求地址 | |
| 10 | + | |
| 11 | + def auto_number(self, num): | |
| 12 | + """ | |
| 13 | + 智能单号识别 | |
| 14 | + :param num: 快递单号 | |
| 15 | + :return: requests.Response.text | |
| 16 | + """ | |
| 17 | +        req_params = {'key': self.key, 'num': num} | |
| 18 | + return requests.post(self.url, req_params).text # 发送请求 | |
| 19 | + | |
| 20 | + | |
| 21 | +result = KuaiDi100().auto_number('YT9693083639795') | |
| 22 | +print(result) | 
| @@ -0,0 +1,103 @@ | ||
| 1 | +# -*- coding: utf-8 -*-' | |
| 2 | + | |
| 3 | +import hashlib | |
| 4 | +import json | |
| 5 | +import time | |
| 6 | + | |
| 7 | +import requests | |
| 8 | + | |
| 9 | + | |
| 10 | +class KuaiDi100: | |
| 11 | + def __init__(self): | |
| 12 | + self.key = '' # TODO 客户授权key | |
| 13 | + self.secret = '' # TODO 电子面单secret | |
| 14 | + self.url = 'https://poll.kuaidi100.com/print/billparcels.do' # 请求地址 | |
| 15 | + | |
| 16 | + def submit(self, param, settings): | |
| 17 | + """ | |
| 18 | + 发货单打印 | |
| 19 | + :param param: 模板配置信息和自定义参数信息 | |
| 20 | + :param settings: 纸张配置信息 | |
| 21 | + :return: requests.Response.text | |
| 22 | + """ | |
| 23 | + timestamp = str(time.time()) | |
| 24 | + md = hashlib.md5() | |
| 25 | + param_str = json.dumps(param) | |
| 26 | + temp_sign = param_str + timestamp + self.key + self.secret | |
| 27 | + md.update(temp_sign.encode()) | |
| 28 | + sign = md.hexdigest().upper() | |
| 29 | +        req_params = { | |
| 30 | + 'method': 'billparcels', | |
| 31 | + 'key': self.key, | |
| 32 | + 't': timestamp, | |
| 33 | + 'sign': sign, | |
| 34 | + 'param': param_str, | |
| 35 | + 'settings': json.dumps(settings) | |
| 36 | + } | |
| 37 | + return requests.post(self.url, req_params).text # 发送请求 | |
| 38 | + | |
| 39 | + | |
| 40 | +param = { | |
| 41 | + "tempid": "xxxx", # 模板编码,通过管理后台的打印发货单模板配置信息获取 | |
| 42 | + "siid": "xxxx", # 打印设备码,通过打印机输出的设备码进行获取 | |
| 43 | + "callBackUrl": "https://www.baidu.com/fhd/callback", # 打印状态对调地址 | |
| 44 | + "petName": "kd100", # 自定义参数 | |
| 45 | + "recName": "小百", # 自定义参数 | |
| 46 | + "recPhone": "10086", # 自定义参数 | |
| 47 | + "payTime": "2021-01-15 15:40:55", # 自定义参数 | |
| 48 | + "expressName": "德邦快递", # 自定义参数 | |
| 49 | + "printTime": "2021-01-15 15:41:30", # 自定义参数 | |
| 50 | + "printCount": "1", # 自定义参数 | |
| 51 | + "address": "广东省深圳市南山区金蝶软件园", # 自定义参数 | |
| 52 | + "total": "21", "remark": "购物小票作为购物凭证,请妥善保管,您有任何疑问,请咨询服务热线 123456798", # 自定义参数 | |
| 53 | +    "img0": {  # 图片参数,多图片时用img0,img1,img2等追加 | |
| 54 | + "type": "code_128", | |
| 55 | + "content": "887921256577", | |
| 56 | + "width": 350, | |
| 57 | + "height": 100 | |
| 58 | + }, | |
| 59 | + "tab0": [ # 表格参数,多表格时用tab0,tab1,tab2等追加对象 | |
| 60 | +        { | |
| 61 | + "prodName": "热敏纸", | |
| 62 | + "count": "5", | |
| 63 | + "specs": "76*130", | |
| 64 | + "unitPrice": "30", | |
| 65 | + "price": "150" | |
| 66 | + }, | |
| 67 | +        { | |
| 68 | + "prodName": "热敏纸", | |
| 69 | + "count": "10", | |
| 70 | + "specs": "100*180", | |
| 71 | + "unitPrice": "50", | |
| 72 | + "price": "500" | |
| 73 | + }, | |
| 74 | +        { | |
| 75 | + "prodName": "续打纸", | |
| 76 | + "count": "5", | |
| 77 | + "specs": "", | |
| 78 | + "unitPrice": "40", | |
| 79 | + "price": "200" | |
| 80 | + }, | |
| 81 | +        { | |
| 82 | + "prodName": "云打印机", | |
| 83 | + "count": "1", | |
| 84 | + "specs": "二代", | |
| 85 | + "unitPrice": "499", | |
| 86 | + "price": "499" | |
| 87 | + } | |
| 88 | + ] | |
| 89 | +} | |
| 90 | + | |
| 91 | +settings = { | |
| 92 | + "pageWidth": 100, # 纸张宽,单位mm,默认值:100 | |
| 93 | + "pageHeight": 180, # 纸张高,单位mm ,续打纸张时,该字段设置为null或空串 | |
| 94 | +    "margins": {  # 边距 | |
| 95 | + "top": 5, # 上边距,单位:mm,默认:0 | |
| 96 | + "bottom": 5, # 下边距,单位:mm,默认:0 | |
| 97 | + "left": 5, # 左边距,单位:mm,默认:0 | |
| 98 | + "right": 5 # 右边距,单位:mm,默认:0 | |
| 99 | + } | |
| 100 | +} | |
| 101 | + | |
| 102 | +result = KuaiDi100().submit(param, settings) | |
| 103 | +print(result) | 
| @@ -0,0 +1,48 @@ | ||
| 1 | +# -*- coding: utf-8 -*-' | |
| 2 | + | |
| 3 | +import hashlib | |
| 4 | +import json | |
| 5 | + | |
| 6 | +import requests | |
| 7 | + | |
| 8 | + | |
| 9 | +class KuaiDi100: | |
| 10 | + def __init__(self): | |
| 11 | + self.key = '' # TODO 客户授权key | |
| 12 | + self.customer = '' # TODO 查询公司编号 | |
| 13 | + self.url = 'https://poll.kuaidi100.com/poll/maptrack.do' # 请求地址 | |
| 14 | + | |
| 15 | + def map_track(self, com, num, phone, ship_from, ship_to, orderTime): | |
| 16 | + """ | |
| 17 | + 快递查询地图轨迹 | |
| 18 | + :param com: 查询的快递公司的编码,一律用小写字母 | |
| 19 | + :param num: 查询的快递单号,单号的最大长度是32个字符 | |
| 20 | + :param phone: 收件人或寄件人的手机号或固话(也可以填写后四位,如果是固话,请不要上传分机号) | |
| 21 | + :param ship_from: 出发地城市,省-市-区,非必填,填了有助于提升签收状态的判断的准确率,请尽量提供 | |
| 22 | + :param ship_to: 目的地城市,省-市-区,非必填,填了有助于提升签收状态的判断的准确率,且到达目的地后会加大监控频率,请尽量提供 | |
| 23 | + :param orderTime: 订单下单时间,格式为(yyyy-MM-dd HH:mm:ss)如:2020-12-16 12:59:59 | |
| 24 | + :return: requests.Response.text | |
| 25 | + """ | |
| 26 | +        param = { | |
| 27 | + 'com': com, | |
| 28 | + 'num': num, | |
| 29 | + 'phone': phone, | |
| 30 | + 'from': ship_from, | |
| 31 | + 'to': ship_to, | |
| 32 | + 'show': '0', # 返回数据格式。0:json(默认),1:xml,2:html,3:text | |
| 33 | + 'order': 'desc', # 返回结果排序方式。desc:降序(默认),asc:升序 | |
| 34 | + 'orderTime': orderTime | |
| 35 | + } | |
| 36 | + param_str = json.dumps(param) # 转json字符串 | |
| 37 | + | |
| 38 | + # 签名加密, 用于验证身份, 按param + key + customer 的顺序进行MD5加密(注意加密后字符串要转大写), 不需要“+”号 | |
| 39 | + temp_sign = param_str + self.key + self.customer | |
| 40 | + md = hashlib.md5() | |
| 41 | + md.update(temp_sign.encode()) | |
| 42 | + sign = md.hexdigest().upper() | |
| 43 | +        request_data = {'customer': self.customer, 'param': param_str, 'sign': sign} | |
| 44 | + return requests.post(self.url, request_data).text # 发送请求 | |
| 45 | + | |
| 46 | + | |
| 47 | +result = KuaiDi100().map_track('yuantong', 'YT9693083639795', '', '广东省江门市', '广东省深圳市', '2021-08-01 20:04:44') | |
| 48 | +print(result) | 
| @@ -0,0 +1,48 @@ | ||
| 1 | +# -*- coding: utf-8 -*-' | |
| 2 | + | |
| 3 | +import hashlib | |
| 4 | + | |
| 5 | +import requests | |
| 6 | + | |
| 7 | + | |
| 8 | +class KuaiDi100: | |
| 9 | + def __init__(self): | |
| 10 | + self.key = '' # TODO 客户授权key | |
| 11 | + self.userid = '' # TODO 查询公司编号 | |
| 12 | + md = hashlib.md5() | |
| 13 | + md.update((self.key + self.userid).encode()) | |
| 14 | + self.sign = md.hexdigest().upper() | |
| 15 | + self.url = 'https://apisms.kuaidi100.com/sms/send.do' # 接口地址,或者 http://apisms.kuaidi100.com:9502/sms/send.do | |
| 16 | + | |
| 17 | + def send_sms(self, seller, phone, tid, sms_content, order_id): | |
| 18 | + """ | |
| 19 | + 短信发送 | |
| 20 | + :param seller: 商户名称签名;最好用简称,该字段信息会在短信标签处显示。不要超过5个字符 | |
| 21 | + :param phone: 接收短信手机号 | |
| 22 | + :param tid: 短信模板ID | |
| 23 | + :param sms_content: 短信模板替换内容 | |
| 24 | + :param order_id: 外部订单号:当该短信发送模板有回调地址时,外部订单号会返回给调用者,方便用户更新数据 | |
| 25 | + :return: requests.Response.text | |
| 26 | + """ | |
| 27 | +        req_params = { | |
| 28 | + 'sign': self.sign, # 加密签名信息:MD5(key + userid);加密后字符串转大写 | |
| 29 | + 'userid': self.userid, # 我方分配给贵司的的短信接口用户ID,点击查看账号信息 | |
| 30 | + 'seller': seller, # 商户名称签名;最好用简称,该字段信息会在短信标签处显示。不要超过5个字符 | |
| 31 | + 'phone': phone, # 接收短信手机号 | |
| 32 | + 'tid': tid, # 短信模板ID | |
| 33 | + 'content': sms_content, # 短信模板替换内容 | |
| 34 | + 'outorder': order_id, # 外部订单号:当该短信发送模板有回调地址时,外部订单号会返回给调用者,方便用户更新数据 | |
| 35 | + # 'callback': 'https//www.baidu.com/kd100/callback' # 回调地址:如果客户在发送短信时填写该参数,将按照这个参数回调短信发送状态;如果为空,将按照模板配置的地址回调短信发送状态;如果两个参数都不填写,将不会回调通知状态 | |
| 36 | + } | |
| 37 | + | |
| 38 | + return requests.post(self.url, req_params).text # 发送请求 | |
| 39 | + | |
| 40 | + | |
| 41 | +content = {  # 短信模板替换内容 | |
| 42 | + "接收人姓名": "小百", | |
| 43 | + "公司名": "快递100", | |
| 44 | + "快递单号": "154893238584", | |
| 45 | + "url": "https://www.kuaidi100.com" | |
| 46 | +} | |
| 47 | +result = KuaiDi100().send_sms('快递100', '13800138000', '11', content, '123456789') | |
| 48 | +print(result) | 
| @@ -0,0 +1,52 @@ | ||
| 1 | +# -*- coding: utf-8 -*-' | |
| 2 | + | |
| 3 | +import json | |
| 4 | + | |
| 5 | +import requests | |
| 6 | + | |
| 7 | + | |
| 8 | +class KuaiDi100: | |
| 9 | + def __init__(self): | |
| 10 | + self.key = '' # TODO 客户授权key | |
| 11 | + self.url = 'https://poll.kuaidi100.com/poll' # 请求地址 | |
| 12 | + | |
| 13 | + def submit(self, com, num, phone, ship_from, ship_to): | |
| 14 | + """ | |
| 15 | + 物流轨迹订阅 | |
| 16 | + :param com: 快递公司编码 | |
| 17 | + :param num: 快递单号 | |
| 18 | + :param phone: 收件人或寄件人的手机号或固话(也可以填写后四位,如果是固话,请不要上传分机号) | |
| 19 | + :param ship_from: 出发地城市,省-市-区,非必填,填了有助于提升签收状态的判断的准确率,请尽量提供 | |
| 20 | + :param ship_to: 目的地城市,省-市-区,非必填,填了有助于提升签收状态的判断的准确率,且到达目的地后会加大监控频率,请尽量提供 | |
| 21 | + :return: requests.Response.text | |
| 22 | + """ | |
| 23 | +        param = { | |
| 24 | + 'company': com, | |
| 25 | + 'number': num, | |
| 26 | + 'from': ship_from, | |
| 27 | + 'to': ship_to, | |
| 28 | + 'key': self.key, | |
| 29 | +            'parameters': { | |
| 30 | + 'callbackurl': 'https://www.baidu.com/kd100/callback', # 回调接口的地址。如果需要在推送信息回传自己业务参数,可以在回调地址URL后面拼接上去,例如:https://www.baidu.com/kd100/callback?orderId=123 | |
| 31 | + 'salt': None, # 签名用随机字符串。32位自定义字符串。添加该参数,则推送的时候会增加sign给贵司校验消息的可靠性 | |
| 32 | + 'resultv2': '1', # 添加此字段表示开通行政区域解析功能。0:关闭(默认),1:开通行政区域解析功能 | |
| 33 | + 'autoCom': '0', # 添加此字段且将此值设为1,则表示开始智能判断单号所属公司的功能,开启后,company字段可为空,即只传运单号(number字段),我方收到后会根据单号判断出其所属的快递公司(即company字段)。建议只有在无法知道单号对应的快递公司(即company的值)的情况下才开启此功能 | |
| 34 | + 'interCom': '0', # 添加此字段且将此值设为1,则表示开启国际版,开启后,若订阅的单号(即number字段)属于国际单号,会返回出发国与目的国两个国家的跟踪信息,本功能暂时只支持邮政体系(国际类的邮政小包、EMS)内的快递公司,若单号我方识别为非国际单,即使添加本字段,也不会返回destResult元素组 | |
| 35 | + 'departureCountry': '', # 出发国家编码,interCom=1的国际单号最好提供该值 | |
| 36 | + 'departureCom': '', # 出发国家快递公司的编码,interCom=1的国际单号最好提供该值 | |
| 37 | + 'destinationCountry': '', # 目的国家编码,interCom=1的国际单号最好提供该值 | |
| 38 | + 'destinationCom': '', # 目的国家快递公司的编码,interCom=1的国际单号最好提供该值 | |
| 39 | + 'phone': phone | |
| 40 | + } | |
| 41 | + } | |
| 42 | + | |
| 43 | +        req_params = { | |
| 44 | + 'schema': 'json', # 查询公司编号 | |
| 45 | + 'param': json.dumps(param) # 参数数据 | |
| 46 | + } | |
| 47 | + | |
| 48 | + return requests.post(self.url, req_params).text # 发送请求 | |
| 49 | + | |
| 50 | + | |
| 51 | +result = KuaiDi100().submit('yuantong', 'YT9693083639795', '', '江门市', '深圳市') | |
| 52 | +print(result) | 
| @@ -0,0 +1,48 @@ | ||
| 1 | +# -*- coding: utf-8 -*-' | |
| 2 | + | |
| 3 | +import hashlib | |
| 4 | +import json | |
| 5 | + | |
| 6 | +import requests | |
| 7 | +from django.conf import settings | |
| 8 | + | |
| 9 | + | |
| 10 | +class KuaiDi100: | |
| 11 | + def __init__(self): | |
| 12 | +        self.key = settings.KUAIDI00.get('key', '')  # TODO 客户授权key | |
| 13 | +        self.customer = settings.KUAIDI00.get('customer', '')  # TODO 查询公司编号 | |
| 14 | + self.url = 'https://poll.kuaidi100.com/poll/query.do' # 请求地址 | |
| 15 | + | |
| 16 | + def track(self, com, num, phone=None, ship_from=None, ship_to=None): | |
| 17 | + """ | |
| 18 | + 物流轨迹实时查询: https://api.kuaidi100.com/document/5f0ffb5ebc8da837cbd8aefc.html | |
| 19 | + :param com: 查询的快递公司的编码,一律用小写字母 | |
| 20 | + :param num: 查询的快递单号,单号的最大长度是32个字符 | |
| 21 | + :param phone: 收件人或寄件人的手机号或固话(也可以填写后四位,如果是固话,请不要上传分机号) | |
| 22 | + :param ship_from: 出发地城市,省-市-区,非必填,填了有助于提升签收状态的判断的准确率,请尽量提供 | |
| 23 | + :param ship_to: 目的地城市,省-市-区,非必填,填了有助于提升签收状态的判断的准确率,且到达目的地后会加大监控频率,请尽量提供 | |
| 24 | + :return: requests.Response.text | |
| 25 | + """ | |
| 26 | +        param = { | |
| 27 | + 'com': com, | |
| 28 | + 'num': num, | |
| 29 | + 'phone': phone, | |
| 30 | + 'from': ship_from, | |
| 31 | + 'to': ship_to, | |
| 32 | + 'resultv2': '1', # 添加此字段表示开通行政区域解析功能。0:关闭(默认),1:开通行政区域解析功能,2:开通行政解析功能并且返回出发、目的及当前城市信息 | |
| 33 | + 'show': '0', # 返回数据格式。0:json(默认),1:xml,2:html,3:text | |
| 34 | + 'order': 'desc' # 返回结果排序方式。desc:降序(默认),asc:升序 | |
| 35 | + } | |
| 36 | + param_str = json.dumps(param) # 转json字符串 | |
| 37 | + | |
| 38 | + # 签名加密, 用于验证身份, 按param + key + customer 的顺序进行MD5加密(注意加密后字符串要转大写), 不需要“+”号 | |
| 39 | + temp_sign = param_str + self.key + self.customer | |
| 40 | + md = hashlib.md5() | |
| 41 | + md.update(temp_sign.encode()) | |
| 42 | + sign = md.hexdigest().upper() | |
| 43 | +        request_data = {'customer': self.customer, 'param': param_str, 'sign': sign} | |
| 44 | + return requests.post(self.url, request_data).text # 发送请求 | |
| 45 | + | |
| 46 | + | |
| 47 | +# result = KuaiDi100().track('yuantong', 'YT9693083639795', '', '广东省江门市', '广东省深圳市') | |
| 48 | +# print(result) |