Explorar o código

韵达包裹信息同步

ANG YU %!s(int64=4) %!d(string=hai) anos
pai
achega
be26477ab2

+ 2 - 1
app/Http/Controllers/TestController.php

@@ -958,8 +958,9 @@ class TestController extends Controller
         dump($orderPackage);
     }
 
-    public function logistic_route_sync_SF()
+    public function logistic_route_sync()
     {
+        ini_set('max_execution_time', 60*10);
         $orderPackageReceivedSyncService = new OrderPackageReceivedSyncService();
         $orderPackageReceivedSyncService->syncLogisticRoute();
     }

+ 50 - 0
app/Jobs/LogisticYDSync.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Services\LogisticYDService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class LogisticYDSync implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+
+    protected $logistic_number;
+    /**
+     * @var $logisticYDService LogisticYDService
+     */
+    protected $logisticYDService;
+    protected $orderPackageReceivedSyncService;
+
+    /**
+     * LogisticYDSync constructor.
+     * @param $logistic_number
+     */
+    public function __construct($logistic_number)
+    {
+        $this->logistic_number = $logistic_number;
+    }
+
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        //
+        ini_set('max_execution_time', 10);
+        $this->logisticYDService = app('LogisticYDService');
+        $this->logisticYDService->registerApi($this->logistic_number);
+        $nativeResponse = $this->logisticYDService->query($this->logistic_number);
+        $formattedData = $this->logisticYDService->format($nativeResponse);
+        $this->orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+        $this->orderPackageReceivedSyncService->update($formattedData);
+    }
+}

+ 255 - 19
app/Services/LogisticYDService.php

@@ -4,13 +4,13 @@ namespace App\Services;
 
 use App\OrderPackage;
 use App\Traits\ServiceAppAop;
+use Carbon\Carbon;
 use Illuminate\Support\Facades\Http;
 
 class LogisticYDService
 {
     use ServiceAppAop;
 
-//    protected $modelClass=LogisticYD::class;
     private $app_key;
     private $app_secret;
     private $url;
@@ -19,12 +19,13 @@ class LogisticYDService
     /**
      * 批量订阅接口
      * @param $logistic_numbers array
+     * @return mixed
      */
     public function registerApi(array $logistic_numbers)
     {
-        $this->app_key = config('api_logistic.YD.test.app-key', '999999');
-        $this->app_secret = config('api_logistic.YD.test.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d');
-        $this->url = config('api_logistic.YD.test.register.url');
+        $this->app_key = config('api_logistic.YD.prod.app-key', '999999');
+        $this->app_secret = config('api_logistic.YD.prod.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d');
+        $this->url = config('api_logistic.YD.prod.register.url');
         $sender = [
             "address" => "上海市松江区泗泾镇泗砖公路351号",
             "city" => "上海市",
@@ -64,19 +65,14 @@ class LogisticYDService
             "Content-Type" => "application/json"
         ];
         $response = Http::withHeaders($headers)->withBody($json_body, 'application/json')->post($this->url);
-        dump([
-            'url' => $this->url,
-            'headers' => $headers,
-            'body' => $body,
-            'response' => $response->body(),
-        ]);
+        return json_decode($response);
     }
 
     public function query($logistic_number)
     {
-        $this->app_key = config('api_logistic.YD.test.app-key', '999999');
-        $this->app_secret = config('api_logistic.YD.test.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d');
-        $this->url = config('api_logistic.YD.test.search.url');
+        $this->app_key = config('api_logistic.YD.prod.app-key', '999999');
+        $this->app_secret = config('api_logistic.YD.prod.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d');
+        $this->url = config('api_logistic.YD.prod.search.url');
         $body = [
             "mailno" => $logistic_number
         ];
@@ -88,11 +84,251 @@ class LogisticYDService
             "Content-Type" => "application/json"
         ];
         $response = Http::withHeaders($headers)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json')->post($this->url);
-        dump([
-            'url' => $this->url,
-            'headers' => $headers,
-            'body' => $body,
-            'response' => $response->body(),
-        ]);
+        return json_decode($response->body());
+    }
+
+    public function format($nativeResponse)
+    {
+        $result = [];
+        if ($nativeResponse->code != '0000') {
+            return [];
+        } else {
+            $nativeData = $nativeResponse->data;
+            $result['logistic_number'] = $nativeData->mailno;
+            $nativeRoutes = $nativeData->steps;
+            if (!empty($nativeRoutes)) {
+                $lastNativeRoute = $nativeRoutes[count($nativeRoutes) - 1];
+                $result['status'] = $this->getStatus($nativeData);
+                if ($result['status'] == '已收件') {
+                    $result['received_at'] = $lastNativeRoute->time;
+                }
+                $result['transfer_status'] = $this->getTransferStatus($nativeRoutes);
+                $exceptionData = $this->setExceptionType($result, $lastNativeRoute ? $lastNativeRoute->time : null);
+                $result['exception_type'] = $exceptionData['exception_type'];
+                $result['exception'] = $exceptionData['exception'];
+
+            } else {
+                $result['status'] = null;
+                $result['transfer_status'] = [];
+            }
+
+            if (!array_key_exists('status', $result)) {
+                $result['status'] = null;
+                $result['transfer_status'] = [];
+            }
+            //如果没有发现额外的异常,且查询到物流轨迹,将异常置为无
+            if (!array_key_exists('exception', $result)
+                && !array_key_exists('exception_type', $result)
+                && array_key_exists('transfer_status', $result)
+            ) {
+                $result['exception_type'] = '无';
+                $result['exception'] = '否';
+            }
+            return $result;
+        }
+    }
+
+    /**
+     * @param array $data
+     * @param $lastRouteDate
+     * @return array
+     */
+    private function setExceptionType(array $data, $lastRouteDate): array
+    {
+        $logistic_number = $data['logistic_number'];
+        /** @var OrderPackage $orderPackage */
+        $orderPackage = OrderPackage::query()->with('order')->where('logistic_number', $logistic_number)->first();
+        $delivered_duration = now()->diffInHours(Carbon::parse($orderPackage['sent_at']));
+        $last_routed_duration = now()->diffInHours(Carbon::parse($lastRouteDate));
+        $VALID_HOURS = 4;
+        $SHORT_RESPONSE_HOURS = (function ($province) {
+            switch ($province) {
+                case '浙江省':
+                case '江苏省':
+                case '上海':
+                case '安徽省':
+                    return 24;
+                case '北京':
+                case '天津':
+                case '江西省':
+                case '湖北省':
+                case '湖南省':
+                case '广东省':
+                case '福建省':
+                case '山东省':
+                case '河北省':
+                case '河南省':
+                case '山西省':
+                case '四川省':
+                case '陕西省':
+                case '重庆':
+                case '广西壮族自治区':
+                case '贵州省':
+                case '云南省':
+                case '海南省':
+                case '吉林省':
+                case '黑龙江省':
+                case '辽宁省':
+                    return 72;
+                case '青海省':
+                case '宁夏回族自治区':
+                case '甘肃省':
+                case '内蒙古自治区':
+                case '新疆维吾尔自治区':
+                case '西藏自治区':
+                    return 120;
+                default:
+                    return 24;
+            }
+        })($orderPackage->order->province);
+        $LONG_RESPONSE_HOURS = (function ($province) {
+            switch ($province) {
+                case '浙江省':
+                case '江苏省':
+                case '上海':
+                case '安徽省':
+                    return 72;
+                case '北京':
+                case '天津':
+                case '江西省':
+                case '湖北省':
+                case '湖南省':
+                case '广东省':
+                case '福建省':
+                case '山东省':
+                case '河北省':
+                case '河南省':
+                case '山西省':
+                case '四川省':
+                case '陕西省':
+                case '重庆':
+                case '广西壮族自治区':
+                case '贵州省':
+                case '云南省':
+                case '海南省':
+                case '吉林省':
+                case '黑龙江省':
+                case '辽宁省':
+                    return 120;
+                case '青海省':
+                case '宁夏回族自治区':
+                case '甘肃省':
+                case '内蒙古自治区':
+                case '新疆维吾尔自治区':
+                case '西藏自治区':
+                    return 168;
+                default:
+                    return 72;
+            }
+        })($orderPackage->order->province);
+        $SENDING_RESPONSE_HOURS = 48;
+        $IS_ROUTED = 1;               //0000 0001 有路由信息
+        $IS_IN_VALID_TIME = 2;        //0000 0010 大于4小时
+        $IS_WEIGHED = 4;              //0000 0100 称重过
+        $IS_RECEIVED = 8;          //0000 1000 已经收货
+        $IS_SENDING = 16;             //0001 0000 正在派送
+        $IS_SHORT_NO_RESPONSE = 32;     //0010 0000 中转异常
+        $IS_LONG_NO_RESPONSE = 64;     //0010 0000 疑似丢件
+        $IS_SENDING_NO_RESPONSE = 128;     //0010 0000 派送异常
+        $conclusion = (function () use (
+            $data, $delivered_duration, $last_routed_duration,
+            $VALID_HOURS, $IS_ROUTED, $IS_IN_VALID_TIME, $IS_WEIGHED, $IS_RECEIVED, $IS_SENDING, $IS_SHORT_NO_RESPONSE, $IS_LONG_NO_RESPONSE, $IS_SENDING_NO_RESPONSE,
+            $SHORT_RESPONSE_HOURS, $LONG_RESPONSE_HOURS, $SENDING_RESPONSE_HOURS,
+            $orderPackage
+        ) {
+            $conclusion = 0;
+            $conclusion |= !empty($data['transfer_status']) ? $IS_ROUTED : 0;
+            $conclusion |= ($delivered_duration > $VALID_HOURS) ? $IS_IN_VALID_TIME : 0;
+            $conclusion |= ($orderPackage->weighed_at) ? $IS_WEIGHED : 0;
+            $conclusion |= ($data['status'] == '已收件') ? $IS_RECEIVED : 0;
+            $conclusion |= ($data['status'] == '派送中') ? $IS_SENDING : 0;//
+            $conclusion |= ($last_routed_duration > $SHORT_RESPONSE_HOURS && $last_routed_duration < $LONG_RESPONSE_HOURS) ? $IS_SHORT_NO_RESPONSE : 0;
+            $conclusion |= ($last_routed_duration > $LONG_RESPONSE_HOURS) ? $IS_LONG_NO_RESPONSE : 0;
+            $conclusion |= ($last_routed_duration > $SENDING_RESPONSE_HOURS && $data['status'] == '派送中') ? $IS_SENDING_NO_RESPONSE : 0;
+            return $conclusion;
+        })();
+        switch ($conclusion) {
+            case $IS_IN_VALID_TIME:
+                $data['exception_type'] = '疑似库内丢件';
+                break;
+            case $IS_IN_VALID_TIME | $IS_WEIGHED:
+                $data['exception_type'] = '揽件异常';
+                break;
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE:
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE | $IS_WEIGHED:
+                $data['exception_type'] = '中转异常';
+                break;
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE:
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE | $IS_WEIGHED:
+                $data['exception_type'] = '疑似丢件';
+                break;
+            default:
+                break;
+        }
+        if ($conclusion
+            == ($conclusion | $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SENDING | $IS_SENDING_NO_RESPONSE)) {
+            $data['exception_type'] = '派件异常';
+        }
+        switch ($conclusion) {
+            case $IS_IN_VALID_TIME:
+            case $IS_IN_VALID_TIME | $IS_WEIGHED:
+            case $IS_ROUTED | $IS_SHORT_NO_RESPONSE:
+            case $IS_LONG_NO_RESPONSE:
+                $data['exception'] = '是';
+                break;
+            default:
+                break;
+        }
+        return [
+            'exception_type' => array_key_exists('exception_type', $data) ? $data['exception_type'] : null,
+            'exception' => array_key_exists('exception', $data) ? $data['exception'] : null,
+        ];
+    }
+
+
+    /**
+     * @param $nativeData
+     * @return string
+     */
+    private function getStatus($nativeData): string
+    {
+        $status = null;
+        switch ($nativeData->status) {
+            case 'GOT':
+                $status = '已揽收';
+                break;
+            case 'TRANSIT':
+                $status = '在途';
+                break;
+            case 'SIGNED':
+                $status = '已收件';
+                break;
+            case 'RETURN':
+                $status = '返回中';
+                break;
+            case 'SIGNFAIL':
+                $status = '无';
+                break;
+            default:
+                $status = '无';
+        }
+        return $status;
+    }
+
+    /**
+     * @param $nativeRoutes
+     * @return array
+     */
+    private function getTransferStatus($nativeRoutes): array
+    {
+        $transferStatus = [];
+        foreach ($nativeRoutes as $nativeRoute) {
+            $item = [];
+            $item['accept_time'] = $nativeRoute->time;
+            $item['accept_address'] = $nativeRoute->description;
+            $item['remark'] = "";
+            $transferStatus[] = $item;
+        }
+        return $transferStatus;
     }
 }

+ 15 - 8
app/Services/OrderPackageReceivedSyncService.php

@@ -4,6 +4,7 @@
 namespace App\Services;
 
 
+use App\Jobs\LogisticYDSync;
 use App\Jobs\LogisticZopSync;
 use App\OrderPackage;
 use Carbon\Carbon;
@@ -30,6 +31,11 @@ class OrderPackageReceivedSyncService
         foreach ($ZTOLogisticNumbers as $logisticNumber) {
             LogisticZopSync::dispatch($logisticNumber);
         }
+        //更新韵达
+        $YDLogisticNumbers = $logisticNumbers['YUNDA'];
+        foreach ($YDLogisticNumbers as $logistic_number) {
+            LogisticYDSync::dispatch($logistic_number);
+        }
     }
 
     /**
@@ -102,32 +108,33 @@ class OrderPackageReceivedSyncService
     {
         //初始化时间 2020-12-31 23:59:59
         $initDate = Carbon::parse(config('api_logistic.init_date'));
-        $data = [];
         $query = OrderPackage::query()
             ->with(['order' => function ($query) {
                 return $query->with('logistic');
             }]);
         if (Carbon::now()->lte($initDate)) {//当前时间小于等于初始化时间
             //初始化查询一个月的数据,exception为否
-            $query = $query->where('created_at', '>=', $initDate->subDays((int)config('api_logistic.days'))->toDateTimeString())
-//                ->where('exception', '否')
+            $query = $query->where('sent_at', '>=', $initDate->subDays((int)config('api_logistic.days'))->toDateTimeString())
                 ->whereNull('received_at');
         } else {//当前时间大于初始化时间,exception为否且未收货
-            $query = $query->where('created_at', '>=', $initDate->toDateTimeString())
-//                ->where('exception', '否')
+            $query = $query->where('sent_at', '>=', $initDate->toDateTimeString())
                 ->whereNull('received_at');
         }
-        return $this->buildData($query->get(), $data);
+        $result = [];
+        $query->chunk(200, function ($orderPackages) use (&$result) {
+            return $result = array_merge($result, $this->buildData($orderPackages));
+        });
+        return $result;
     }
 
     /**
      * 将orderPackage集合分类并摘取指定数据
      * @param Collection $orderPackages
-     * @param array $data
      * @return array
      */
-    private function buildData(Collection $orderPackages, array $data): array
+    private function buildData(Collection $orderPackages): array
     {
+        $data = [];
         foreach ($orderPackages as $orderPackage) {
             try {
                 $logisticCode = $orderPackage->order->logistic->code;

+ 12 - 2
config/api_logistic.php

@@ -116,8 +116,18 @@ return [
             'register' => [
                 'url' => 'https://u-openapi.yundasys.com/openapi/outer/logictis/subscribe',
             ],
+        ],
+        'prod'=>[
+            'app-key' => '000638',
+            'app-secret' => '0b941e746e3e4a5687c11f11f32ef9a3',
+            'search' => [
+                'url' => 'https://openapi.yundaex.com/openapi/outer/logictis/query',
+            ],
+            'register' => [
+                'url' => 'https://openapi.yundaex.com/openapi/outer/logictis/subscribe',
+            ],
         ]
     ],
-    'init_date' => '2021-04-14 23:59:59',
-    'days' => 4,
+    'init_date' => '2021-05-17 23:59:59',
+    'days' => 2,
 ];

+ 43 - 0
tests/Services/LogisticYDService/FormatTest.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace Tests\Services\LogisticYDService;
+
+use App\Services\LogisticYDService;
+use Tests\TestCase;
+use App\LogisticYD;
+use App\Traits\TestMockSubServices;
+
+class FormatTest extends TestCase
+{
+    use TestMockSubServices;
+
+    /** @var LogisticYDService $service */
+    public $service;
+    private $data;
+    private $amount = 2;
+
+    function setUp(): void
+    {
+        parent::setUp();
+        $this->service = app('LogisticYDService');
+    }
+
+    public function testReturned()
+    {
+        $this->assertTrue(true);
+    }
+
+    function tearDown(): void
+    {
+        parent::tearDown();
+    }
+
+    /**
+     * @test
+     */
+    public function format_test()
+    {
+       $result =$this->service->format($this->service->query('4314519335027'));
+       dd($result);
+    }
+}

+ 11 - 0
tests/Services/LogisticYDService/QueryTest.php

@@ -30,4 +30,15 @@ class QueryTest extends TestCase
     {
         $this->service->query('340987657890876');
     }
+
+
+    /**
+     * @test
+     */
+    public function prod_test()
+    {
+       $response = $this->service->query('4314519335027');
+        dump($response);
+        $this->assertEquals('0000', $response->code);
+    }
 }

+ 9 - 0
tests/Services/LogisticYDService/RegisterApiTest.php

@@ -80,4 +80,13 @@ class RegisterApiTest extends TestCase
     {
         $this->service->registerApi(['75464485214976','75464484634676']);
     }
+
+    /**
+     * @test
+     */
+    public function prod_test()
+    {
+        $result = $this->service->registerApi(['4314519335027']);
+        $this->assertEquals('0000', $result->code);
+    }
 }