@@ -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)  |