Ver código fonte

Merge branch 'master' into zzd

dream 5 anos atrás
pai
commit
ffd741318f
100 arquivos alterados com 2932 adições e 691 exclusões
  1. 8 3
      app/Console/Commands/SyncOrderPackageLogisticRouteTask.php
  2. 45 0
      app/Console/Commands/UpdateOrderPackageExceptionTypeCountingRecordTask.php
  3. 3 1
      app/Console/Kernel.php
  4. 41 0
      app/Events/UpdateOrderPackageExceptionListenerEvent.php
  5. 9 1
      app/Filters/OrderPackageFilters.php
  6. 11 2
      app/Http/Controllers/CacheShelfController.php
  7. 15 1
      app/Http/Controllers/ControlPanelController.php
  8. 9 5
      app/Http/Controllers/InventoryAccountController.php
  9. 16 2
      app/Http/Controllers/OwnerController.php
  10. 17 9
      app/Http/Controllers/PackageLogisticController.php
  11. 4 4
      app/Http/Controllers/ProcurementController.php
  12. 8 1
      app/Http/Controllers/RoleController.php
  13. 57 9
      app/Http/Controllers/StationRuleBatchController.php
  14. 80 7
      app/Http/Controllers/TestController.php
  15. 9 2
      app/Http/Controllers/UserController.php
  16. 7 1
      app/Http/Controllers/UserLaborController.php
  17. 17 0
      app/Http/Controllers/WaybillController.php
  18. 76 76
      app/Http/Controllers/api/thirdPart/flux/SortingController.php
  19. 10 7
      app/Http/Controllers/api/thirdPart/haiq/LightController.php
  20. 6 2
      app/Http/Controllers/api/thirdPart/haiq/StorageController.php
  21. 1 1
      app/Http/Controllers/api/thirdPart/weight/WeightBaseController.php
  22. 70 0
      app/Http/Requests/Station/StationRuleBatchRequest.php
  23. 50 0
      app/Jobs/LogisticSFSync.php
  24. 59 0
      app/Jobs/LogisticYDSync.php
  25. 54 0
      app/Jobs/LogisticYTOSync.php
  26. 9 159
      app/Jobs/LogisticZopSync.php
  27. 5 1
      app/Listeners/AddOrUpdateOrderIssuesListener.php
  28. 5 1
      app/Listeners/UpdateOrderPackageExceptionListener.php
  29. 42 0
      app/Listeners/UpdateOrderPackageExceptionTypeCountingRecordListener.php
  30. 30 1
      app/MaterialBox.php
  31. 5 0
      app/OracleDOCOrderHeader.php
  32. 2 2
      app/OracleDOCWaveDetails.php
  33. 1 0
      app/OrderIssueRejectedBill.php
  34. 17 0
      app/OrderPackageExceptionTypeCountingRecord.php
  35. 8 0
      app/Providers/AppServiceProvider.php
  36. 7 4
      app/Providers/EventServiceProvider.php
  37. 151 23
      app/Services/CacheShelfService.php
  38. 1 1
      app/Services/CityService.php
  39. 35 22
      app/Services/ForeignHaiRoboticsService.php
  40. 8 0
      app/Services/LaborReportService.php
  41. 15 122
      app/Services/LogisticSFService.php
  42. 182 0
      app/Services/LogisticYDService.php
  43. 126 0
      app/Services/LogisticYTOService.php
  44. 12 10
      app/Services/OracleDocWaveDetailService.php
  45. 71 0
      app/Services/OrderPackageExceptionTypeCountingRecordService.php
  46. 224 32
      app/Services/OrderPackageReceivedSyncService.php
  47. 3 3
      app/Services/OwnerPriceExpressService.php
  48. 2 2
      app/Services/PackageStatisticsService.php
  49. 1 1
      app/Services/ProvinceService.php
  50. 16 2
      app/Services/StationTaskMaterialBoxService.php
  51. 34 1
      app/Services/WaybillService.php
  52. 5 0
      app/StationRuleBatch.php
  53. 10 11
      app/library/zop/ZopClient.php
  54. 53 7
      config/api_logistic.php
  55. 1 1
      database/factories/OracleBasCustomerFactory.php
  56. 12 0
      database/factories/OrderPackageExceptionTypeCountingRecordFactory.php
  57. 24 1
      database/factories/OrderPackageFactory.php
  58. 1 1
      database/factories/OwnerBillReportFactory.php
  59. 0 1
      database/factories/OwnerReportFactory.php
  60. 13 0
      database/factories/TaxRateFactory.php
  61. 3 1
      database/factories/WarehouseFactory.php
  62. 32 0
      database/migrations/2021_05_07_141019_add_index_exception_type_sent_at_owner_id_order_packages_table.php
  63. 35 0
      database/migrations/2021_05_07_141912_create_order_package_exception_type_counting_records_table.php
  64. 35 0
      database/migrations/2021_05_18_093618_add_authorities_wabill.php
  65. 30 0
      database/migrations/2021_05_18_151348_add_authority_order_package_remark.php
  66. 38 0
      database/migrations/2021_05_19_171047_add_station_rule_batch_author.php
  67. 32 0
      database/migrations/2021_05_19_173442_add_materialBoxes_field_status.php
  68. 16 0
      database/seeds/OrderPackageExceptionTypeCountingRecordSeeder.php
  69. 1 0
      database/seeds/StationRuleBatchSeeder.php
  70. BIN
      public/images/QRCodeIMG/1.png
  71. 25 4
      public/t.php
  72. 3 3
      resources/js/queryForm/queryForm.js
  73. 93 0
      resources/views/control/panel.blade.php
  74. 16 5
      resources/views/inventory/stockInventory/mission.blade.php
  75. 2 2
      resources/views/maintenance/owner/index.blade.php
  76. 2 1
      resources/views/maintenance/role/index.blade.php
  77. 1 1
      resources/views/maintenance/tutorial/create.blade.php
  78. 2 1
      resources/views/maintenance/user/index.blade.php
  79. 1 1
      resources/views/maintenance/userLabor/index.blade.php
  80. 2 2
      resources/views/order/issue/index.blade.php
  81. 56 18
      resources/views/package/logistic/index.blade.php
  82. 1 1
      resources/views/package/measureMonitor/index.blade.php
  83. 1 1
      resources/views/procurement/finance/procurementBill.blade.php
  84. 4 1
      resources/views/station/cachingShelf/list/_fillBox.blade.php
  85. 41 15
      resources/views/station/cachingShelf/list/index.blade.php
  86. 5 0
      resources/views/station/menu.blade.php
  87. 51 0
      resources/views/station/rule/_edit.blade.php
  88. 47 0
      resources/views/station/rule/_table.blade.php
  89. 140 0
      resources/views/station/rule/index.blade.php
  90. 9 0
      resources/views/station/rule/menu.blade.php
  91. 36 0
      resources/views/transport/waybill/_dailyBilling.blade.php
  92. 107 19
      resources/views/transport/waybill/index.blade.php
  93. 11 1
      routes/apiLocal.php
  94. 11 0
      routes/web.php
  95. 1 1
      tests/Feature/LogisticZopSyncTest.php
  96. 5 5
      tests/Services/CacheService/GetOrExecuteTest.php
  97. 114 0
      tests/Services/CacheShelfService/ClearTaskTest.php
  98. 33 25
      tests/Services/CacheShelfService/CreateStationTask.php
  99. 77 0
      tests/Services/CacheShelfService/GetChildStationTest.php
  100. 0 40
      tests/Services/CacheShelfService/GetTasksTest.php

+ 8 - 3
app/Console/Commands/SyncOrderPackageLogisticRouteTask.php

@@ -8,6 +8,10 @@ use Illuminate\Console\Command;
 
 class SyncOrderPackageLogisticRouteTask extends Command
 {
+    /**
+     * @var OrderPackageReceivedSyncService $service
+     */
+    public $service;
     /**
      * The name and signature of the console command.
      *
@@ -39,8 +43,9 @@ class SyncOrderPackageLogisticRouteTask extends Command
      */
     public function handle()
     {
-        LogService::log(__CLASS__,"同步快递信息",'');
-        ini_set('memory_limit','2226M');
-        (new OrderPackageReceivedSyncService)->syncLogisticRoute();
+        LogService::log(SyncOrderPackageLogisticRouteTask::class, "同步快递信息定时任务启动", '');
+        ini_set('memory_limit', '2226M');
+        $this->service = app('OrderPackageReceivedSyncService');
+        $this->service->syncLogisticRoute();
     }
 }

+ 45 - 0
app/Console/Commands/UpdateOrderPackageExceptionTypeCountingRecordTask.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Services\LogService;
+use Illuminate\Console\Command;
+
+class UpdateOrderPackageExceptionTypeCountingRecordTask extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'updateOrderPackageExceptionTypeCountingRecordTask';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '更新order_package_exception_type_counting_records';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        LogService::log(__CLASS__,"更新order_package_exception_type_counting_records",'');
+        ini_set('memory_limit','2226M');
+        app('OrderPackageExceptionTypeCountingRecordService')->updateOrCreate(7);
+    }
+}

+ 3 - 1
app/Console/Kernel.php

@@ -72,8 +72,10 @@ class  Kernel extends ConsoleKernel
         $schedule->command('sync:batch')->everyMinute();
         $schedule->command('sync:order')->everyMinute();
         $schedule->command('syncOrderPackageLogisticRouteTask')->dailyAt('1:20');//同步快递信息到orderPackage
+        $schedule->command('syncOrderPackageLogisticRouteTask')->dailyAt('12:01');//同步快递信息到orderPackage
+        $schedule->command('updateOrderPackageExceptionTypeCountingRecordTask')->dailyAt('2:20');//更新OrderPackageExceptionTypeCountingRecord
         $schedule->command('SyncWmsCommoditiesInformation')->everyMinute();
-        $schedule->command('clear:cancelledOrder')->everyTenMinutes();
+        $schedule->command('clear:cancelledOrder')->everyMinute();
         $schedule->command('WasSyncWmsAsnInformation')->everyMinute();
         $schedule->command('create:weightStatistic')->dailyAt("00:30");
         $schedule->command('sync:carrier')->hourlyAt(1);

+ 41 - 0
app/Events/UpdateOrderPackageExceptionListenerEvent.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Events;
+
+use Illuminate\Broadcasting\Channel;
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Broadcasting\PresenceChannel;
+use Illuminate\Broadcasting\PrivateChannel;
+use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+class UpdateOrderPackageExceptionListenerEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * @var $order_package_ids array
+     */
+    public $order_package_ids;
+
+    /**
+     * UpdateOrderPackageExceptionListenerEvent constructor.
+     * @param $order_package_ids
+     */
+    public function __construct($order_package_ids)
+    {
+        $this->order_package_ids = $order_package_ids;
+    }
+
+
+    /**
+     * Get the channels the event should broadcast on.
+     *
+     * @return \Illuminate\Broadcasting\Channel|array
+     */
+    public function broadcastOn()
+    {
+        return new PrivateChannel('channel-name');
+    }
+}

+ 9 - 1
app/Filters/OrderPackageFilters.php

@@ -15,7 +15,7 @@ class OrderPackageFilters
     protected $request;
     protected $queryBuilder;
     protected $filters = ['logistic_number', 'status', 'received_at_start',
-        'received_at_end', 'is_weighed', 'logistic_id', 'owner_id', 'sent_at_start', 'sent_at_end', 'is_exception', 'exception_type', 'default_date'];
+        'received_at_end', 'is_weighed', 'logistic_id', 'owner_id', 'sent_at_start', 'sent_at_end', 'is_exception', 'exception_type', 'default_date','has_transfer_status'];
 
     public function __construct(Request $request)
     {
@@ -49,6 +49,14 @@ class OrderPackageFilters
     {
         $this->queryBuilder->where('exception_type', $exception_type);
     }
+    private function has_transfer_status($has_transfer_status)
+    {
+        if ($has_transfer_status=='是') {
+            $this->queryBuilder->whereNotNull('transfer_status');
+        } elseif ($has_transfer_status=='否') {
+            $this->queryBuilder->whereNull('transfer_status');
+        }
+    }
 
     private function status($status)
     {

+ 11 - 2
app/Http/Controllers/CacheShelfController.php

@@ -51,9 +51,18 @@ class CacheShelfController extends Controller
     public function lightOnApi(Request $request,CacheShelfService $service)
     {
         if($request['stationCode'] && $request['materialBoxCode'])
-        return $service->createStationTask($request['stationCode'],$request['materialBoxCode']);
-
+           return $service->createStationTask($request['stationCode'],$request['materialBoxCode']);
         return ['success' => false,'message' => '参数错误'];
     }
 
+    /**
+     * @param Request $request
+     * @return array|bool[]
+     */
+    public function clearTaskApi(Request $request): array
+    {
+        $code = $request['station'];
+        return app(CacheShelfService::class)->clearTask($code);
+    }
+
 }

+ 15 - 1
app/Http/Controllers/ControlPanelController.php

@@ -160,6 +160,20 @@ class ControlPanelController extends Controller
         $this->success(["title"=>$title,"data"=>$data]);
     }
 
+    public function exceptionTypeApi(Request $request)
+    {
+        $ownerIds=$request->owner_ids;
+        if (!$ownerIds || in_array('all',$ownerIds)) $ownerIds = $this->getCountingOwnerIds(null);
+        $service = app('OrderPackageExceptionTypeCountingRecordService');
+
+        $data = $service->get([
+            'start_date' => $request->start,
+            'end_date' => $request->end,
+            'owner_ids' => $ownerIds,
+        ]);
+        $this->success(["title"=>'',"data"=>$data]);
+    }
+
     /**
      * 根据指定日期获取目标统计数据
      *
@@ -172,7 +186,7 @@ class ControlPanelController extends Controller
             $sql = <<<sql
 SELECT DATE_FORMAT(order_packages.created_at,'%Y-%m-%d') date,
 SUM(CASE WHEN order_packages.weighed_at IS NOT NULL THEN 1 ELSE 0 END) AS count,
-COUNT(1) total FROM order_packages LEFT JOIN orders ON order_packages.order_id=orders.id WHERE orders.wms_status != '订单取消' 
+COUNT(1) total FROM order_packages LEFT JOIN orders ON order_packages.order_id=orders.id WHERE orders.wms_status != '订单取消'
 AND order_packages.created_at >= '{$date} 00:00:00' GROUP BY date
 sql;
 

+ 9 - 5
app/Http/Controllers/InventoryAccountController.php

@@ -193,18 +193,20 @@ class InventoryAccountController extends Controller
             $inventoryAccounts = app('inventoryAccountService')->some($queryParam);
         }
         $row = [[
-            'id' => '盘点号',
+            'id' => '盘点号',
             'status' => '盘点状态',
             'created_at' => '创建时间',
             'owner_id' => '货主',
             'type' => '任务类型',
             'start_at' => '起始时间',
             'end_at' => '结束时间',
-            'total' => '记录数',
-            'processed' => '已盘数',
-            'surplus' => '剩余数',
-            'difference' => '复盘差异',
+            'total' => '盘点任务数',
+            'processed' => '盘点数量',
+            'surplus' => '未盘数量',
+            'ignored' => '跳过数量',
+            'difference' => '差异数量',
             'returned' => '复盘归位',
+            'proportion' => '盘点比例',
         ]];
         $list = [];
         for ($i = 0; $i < count($inventoryAccounts); $i++) {
@@ -220,8 +222,10 @@ class InventoryAccountController extends Controller
                 'total' => isset($inventoryAccount->total) ? $inventoryAccount->total : '',
                 'processed' => isset($inventoryAccount->processed) ? $inventoryAccount->processed : '',
                 'surplus' => isset($inventoryAccount->surplus) ? $inventoryAccount->surplus : '',
+                'ignored' => isset($inventoryAccount->ignored) ? $inventoryAccount->ignored : '',
                 'difference' => isset($inventoryAccount->difference) ? $inventoryAccount->difference : '',
                 'returned' => isset($inventoryAccount->returned) ? $inventoryAccount->returned : '',
+                'proportion' => isset($inventoryAccount->processed) && isset($inventoryAccount->total) ? $inventoryAccount->processed.'/'.$inventoryAccount->total : '',
             ];
             $list[$i] = $w;
         }

+ 16 - 2
app/Http/Controllers/OwnerController.php

@@ -33,10 +33,24 @@ class OwnerController extends Controller
             ->orderBy('id', 'desc')
             ->whereNull('deleted_at');
         if ($request->has('name')) {
-            $query->where('name', 'like', $request->name . '%');
+            $name=$request->input('name');
+            if (strpos($name, ',') || strpos($name, ',') || strpos($name, ' ')) {
+                $arr = array_filter(preg_split('/[,, ]+/is', $name));
+                $query->whereIn('name', $arr);
+                unset($name);
+            } else {
+                $query->where('name','like',$name.'%');
+            }
         }
         if ($request->has('code')) {
-            $query->where('code', 'like', $request->code . '%');
+            $code=$request->input('code');
+            if (strpos($code, ',') || strpos($code, ',') || strpos($code, ' ')) {
+                $arr = array_filter(preg_split('/[,, ]+/is', $code));
+                $query->whereIn('code', $arr);
+                unset($code);
+            } else {
+                $query->where('code','like',$code.'%');
+            }
         }
         $owners = $query->paginate($request->paginate);
         return view('maintenance.owner.index', ['owners' => $owners]);

+ 17 - 9
app/Http/Controllers/PackageLogisticController.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Controllers;
 
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
 use App\Filters\OrderPackageFilters;
 use App\Logistic;
 use App\OrderPackage;
@@ -29,10 +30,8 @@ class PackageLogisticController extends Controller
         $orderPackages = OrderPackage::query()
             ->filter($filters)
             ->whereIn('owner_id', $owner_ids)->with(['order.logistic', 'order.owner', 'order.issue' => function ($query) {
-                /** @var Builder $query */
-                $query->with(['issueType','logs'=>function($query){
-                    /** @var Builder $query */
-                    $query->with('user')->orderByDesc('created_at');
+                $query->with(['issueType', 'logs'=>function($query) {
+                    $query->with('user')->orderBy('created_at', 'DESC');
                 }]);
             }])->orderByDesc('id')->paginate($request->paginate ?? 50);
         $logistics = Logistic::all();
@@ -50,17 +49,26 @@ class PackageLogisticController extends Controller
             $data['exception_type'] = $request->input('exception_type');
         }
         OrderPackage::query()->where('id', $request['id'])->update($data);
+        //更新统计数据
+        event(new UpdateOrderPackageExceptionListenerEvent([$request['id']]));
     }
 
     public function batchUpdate(Request $request)
     {
-        if ('无' == $request->input('exception_type')) {
-            $data['exception_type'] = $request->input('exception_type');
-            $data['exception'] = "否";
-        } else {
-            $data['exception_type'] = $request->input('exception_type');
+        $data = [];
+        if (array_key_exists('exception_type',$request->all())) {
+            if ('无' == $request->input('exception_type')) {
+                $data['exception_type'] = $request->input('exception_type');
+                $data['exception'] = "否";
+            } else {
+                $data['exception_type'] = $request->input('exception_type');
+            }
+        }else if (array_key_exists('status',$request->all())) {
+            $data['status'] = $request->input('status');
         }
         $logistic_numbers = $request->input('logistic_numbers');
         OrderPackage::query()->whereIn('logistic_number', $logistic_numbers)->update($data);
+        //更新统计数据
+        event(new UpdateOrderPackageExceptionListenerEvent($logistic_numbers));
     }
 }

+ 4 - 4
app/Http/Controllers/ProcurementController.php

@@ -64,7 +64,7 @@ class ProcurementController extends Controller
 
     public function index(Request $request,ProcurementFilters $filters)
     {
-        if(!Gate::allows('采购管理-采购-查询')){ return ["success"=>false,"data"=>"您无此权限操作!"];  }
+        if(!Gate::allows('采购管理-采购-查询')){ return redirect(url('/'));  }
         $paginateParams=$request->input();
         $owner_ids=app('UserService')->getPermittingOwnerIds(auth()->user());
         $procurements = Procurement::query()
@@ -272,7 +272,7 @@ class ProcurementController extends Controller
 
     public function checkBill(Request $request,ProcurementCheckSheetFilters $filters)
     {
-        if(!Gate::allows('采购管理-财务-对账单')){ return ["success"=>false,"data"=>"您无此权限操作!"];  }
+        if(!Gate::allows('采购管理-财务-对账单')){ return redirect(url('/'));  }
         $paginateParams=$request->input();
         /**@var SupplierService $supplierService*/
         $supplierService=app(SupplierService::class);
@@ -330,7 +330,7 @@ class ProcurementController extends Controller
 
     public function procurementBill(Request $request,ProcurementFilters $filters)
     {
-        if(!Gate::allows('采购管理-财务-采购账单')){ return ["success"=>false,"data"=>"您无此权限操作!"];  }
+        if(!Gate::allows('采购管理-财务-采购账单')){ return redirect(url('/'));  }
         $paginateParams=$request->input();
         $owner_ids=app('UserService')->getPermittingOwnerIds(auth()->user());
         $owners=app("OwnerService")->getIntersectPermitting();
@@ -360,7 +360,7 @@ class ProcurementController extends Controller
 
     public function monthlyBillReport(Request $request)
     {
-        if(!Gate::allows('采购管理-财务-月账单报表')){ return ["success"=>false,"data"=>"您无此权限操作!"];  }
+        if(!Gate::allows('采购管理-财务-月账单报表')){ return redirect(url('/'));  }
         $paginateParams=$request->input();
         /** @var ProcurementTotalBillService $procurementTotalBillService*/
         $procurementTotalBillService=app(ProcurementTotalBillService::class);

+ 8 - 1
app/Http/Controllers/RoleController.php

@@ -29,7 +29,14 @@ class RoleController extends Controller
             });
         }*/
         if($request->has('role')){
-            $query->where('name','like',$request->input('role'));
+            $role=$request->input('role');
+            if (strpos($role, ',') || strpos($role, ',') || strpos($role, ' ')) {
+                $arr = array_filter(preg_split('/[,, ]+/is', $role));
+                $query->whereIn('name', $arr);
+                unset($role);
+            } else {
+                $query->where('name','like',$role.'%');
+            }
         }
         $roles= $query->orderBy('id','desc')->paginate(35);
         return view('maintenance.role.index',['roles'=>$roles]);

+ 57 - 9
app/Http/Controllers/StationRuleBatchController.php

@@ -2,25 +2,73 @@
 
 namespace App\Http\Controllers;
 
+use App\Components\AsyncResponse;
+use App\Http\Requests\Station\StationRuleBatchRequest;
+use App\Services\OwnerService;
 use App\StationRuleBatch;
+use Illuminate\Contracts\Foundation\Application;
+use Illuminate\Contracts\View\Factory;
 use Illuminate\Http\Request;
+use Illuminate\Http\Response;
+use Illuminate\Support\Facades\Gate;
+use Illuminate\View\View;
+
 
 class StationRuleBatchController extends Controller
 {
+    use AsyncResponse;
+
     /**
      * Display a listing of the resource.
      *
-     * @return \Illuminate\Http\Response
+     * @param Request $request
+     * @param OwnerService $ownerService
+     * @return Application|Factory|View
      */
-    public function index()
+    public function index(Request $request,OwnerService $ownerService)
     {
-        //
+        if(!Gate::allows('站管理-站规则')){ return redirect(url('/'));  }
+        $stationRuleBatches = StationRuleBatch::query()->with('stationType','owner')->orderByDesc('id')->paginate($request['paginate'] ?? 50);
+        $owners = $ownerService->getAuthorizedOwners();
+        return view('station.rule.index',compact('stationRuleBatches','owners'));
+    }
+
+    /**
+     * store API
+     * @param StationRuleBatchRequest $request
+     */
+    public function storeApi(StationRuleBatchRequest $request)
+    {
+        $this->gate('站管理-站规则-编辑');
+        $stationRuleBatch = StationRuleBatch::query()->create($request->only(['name','owner_id']));
+        $stationRuleBatch->load('stationType','owner');
+        $this->success($stationRuleBatch);
+    }
+
+    /**
+     * update API
+     * @param StationRuleBatchRequest $request
+     */
+    public function updateApi(StationRuleBatchRequest $request)
+    {
+        $this->gate('站管理-站规则-编辑');
+        $stationRuleBatch = StationRuleBatch::query()->whereKey($request['id'])->first();
+        $stationRuleBatch->update($request->all());
+        $stationRuleBatch->load('stationType','owner');
+        $this->success($stationRuleBatch);
+    }
+
+    public function destroyApi(Request $request)
+    {
+        $this->gate('站管理-站规则-删除');
+        StationRuleBatch::query()->whereKey($request['id'])->delete();
+        $this->success();
     }
 
     /**
      * Show the form for creating a new resource.
      *
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function create()
     {
@@ -31,7 +79,7 @@ class StationRuleBatchController extends Controller
      * Store a newly created resource in storage.
      *
      * @param  \Illuminate\Http\Request  $request
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function store(Request $request)
     {
@@ -42,7 +90,7 @@ class StationRuleBatchController extends Controller
      * Display the specified resource.
      *
      * @param  \App\StationRuleBatch  $stationRuleBatch
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function show(StationRuleBatch $stationRuleBatch)
     {
@@ -53,7 +101,7 @@ class StationRuleBatchController extends Controller
      * Show the form for editing the specified resource.
      *
      * @param  \App\StationRuleBatch  $stationRuleBatch
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function edit(StationRuleBatch $stationRuleBatch)
     {
@@ -65,7 +113,7 @@ class StationRuleBatchController extends Controller
      *
      * @param  \Illuminate\Http\Request  $request
      * @param  \App\StationRuleBatch  $stationRuleBatch
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function update(Request $request, StationRuleBatch $stationRuleBatch)
     {
@@ -76,7 +124,7 @@ class StationRuleBatchController extends Controller
      * Remove the specified resource from storage.
      *
      * @param  \App\StationRuleBatch  $stationRuleBatch
-     * @return \Illuminate\Http\Response
+     * @return Response
      */
     public function destroy(StationRuleBatch $stationRuleBatch)
     {

+ 80 - 7
app/Http/Controllers/TestController.php

@@ -35,6 +35,7 @@ use App\Imports\OrderTrackingImport;
 use App\InventoryAccount;
 use App\Jobs\BatchTaskJob;
 use App\Jobs\DeleteRepetitionSkuItem;
+use App\Jobs\LogisticYTOSync;
 use App\Jobs\OrderCreateInstantBill;
 use App\Jobs\OrderFreeze;
 use App\Jobs\StoreCreateInstantBill;
@@ -43,6 +44,7 @@ use App\LaborReport;
 use App\LaborReportStatus;
 use App\Log;
 use App\Logistic;
+use App\MaterialBox;
 use App\MeasuringMachine;
 use App\Menu;
 use App\Notifications\SendEmailNotification;
@@ -104,6 +106,7 @@ use App\Services\OracleDocAsnHerderService;
 use App\Services\OracleDOCOrderHeaderService;
 use App\Services\OracleDocWaveDetailService;
 use App\Services\OrderCommodityService;
+use App\Services\OrderPackageExceptionTypeCountingRecordService;
 use App\Services\OrderPackageReceivedSyncService;
 use App\Services\OrderPackageService;
 use App\Services\OrderService;
@@ -822,7 +825,7 @@ class TestController extends Controller
 
     public function reNewBatches3()
     {
-        $batches = Batch::query()->where('id', '>', 97397)->get('code');
+        $batches = Batch::query()->where('id', '>', 111090)->get('code');
         $batchCodes = $batches->map(function ($batch) {
             return $batch['code'];
         })->toArray();
@@ -849,7 +852,7 @@ class TestController extends Controller
 //        dd($logs);
         foreach ($batchCodes as $code) {
 //            $request=Cache::get('temp'.$code)['description'];
-            $request = Log::query()->select('description')->where('CREATED_AT', '>=', '2021-04-14')
+            $request = Log::query()->select('description')->where('CREATED_AT', '>=', '2021-05-18 15:00')
                 ->where('method', "issued_newBatch")
                 ->where('description', 'like', "%{$code}%")
                 ->first();
@@ -981,7 +984,7 @@ class TestController extends Controller
         dump($orderPackage);
     }
 
-    public function logistic_route_sync_SF()
+    public function logistic_route_sync()
     {
         $orderPackageReceivedSyncService = new OrderPackageReceivedSyncService();
         $orderPackageReceivedSyncService->syncLogisticRoute();
@@ -1001,9 +1004,14 @@ class TestController extends Controller
 
     public function ld2()
     {
-        /** @var LogisticService $logisticService */
-        $logisticService=app('LogisticService');
-        var_dump($logisticService->get(['name'=>'顺丰'])->first());
+        $m=MaterialBox::query()->first();
+        dump($m);
+        $m['status'] = '在缓存架';
+        dump($m['status']);
+        $m->update();
+        $m=MaterialBox::query()->first();
+        dump($m['status']);
+
     }
     public function y111()
     {
@@ -1527,5 +1535,70 @@ TEXT;
     {
         return view('httpTest');
     }
-}
 
+    public function updateStation()
+    {
+//        $hid = 'hengli004';
+//        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code' => $hid],['name' => $hid]); // 称重设备
+        StationTask::query()->where('id',709)->update(
+            ['status'=>'完成']
+        );
+//        StationTaskMaterialBox::query()->where('id',7033)->delete();
+//        Station::query()->where('id',9)->delete();
+//        Station::query()->where('code' ,'缓存架01')->update(['code' => 'B1']);
+//        Station::query()->where('code' ,'缓存架02')->update(['code' => 'B2']);
+//        Station::query()->where('name' ,'HAI缓存架01-03-03')->update(['name' => 'HAIB1-03-03']);
+    }
+
+    public function orderPackageUnique()
+    {
+        // select logistic_number,count(1) counts from order_packages where id >= 1590001   GROUP BY logistic_number HAVING counts > 1;
+        $orderPackages = OrderPackage::query()->selectRaw('count(1) counts,logistic_number')->where('id','>=','1590000')->groupBy('logistic_number')->having('counts','>','1')->get();
+        dd($orderPackages);
+        foreach ($orderPackages as $orderPackage) {
+            $items = OrderPackage::query()->where('logistic_number',$orderPackage['logistic_number'])->get();
+            $orderPackage = $items->first();
+            foreach ($items as $item) {
+                $orderPackage['batch_number'] = $item['batch_number'] ?? $orderPackage['batch_number'];
+                $orderPackage['batch_rule'] = $item['batch_rule'] ?? $orderPackage['batch_rule'];
+                $orderPackage['bulk'] = $item['bulk'] ?? $orderPackage['bulk'];
+                $orderPackage['weight'] = $item['weight'] ?? $orderPackage['weight'];
+                $orderPackage['length'] = $item['length'] ?? $orderPackage['length'];
+                $orderPackage['width'] = $item['width'] ?? $orderPackage['width'];
+                $orderPackage['height'] = $item['height'] ?? $orderPackage['height'];
+                $orderPackage['measuring_machine_id'] = $item['measuring_machine_id'] ?? $orderPackage['measuring_machine_id'];
+                $orderPackage['weighed_at'] = $item['weighed_at'] ?? $orderPackage['weighed_at'];
+                $orderPackage['owner_id'] = $item['owner_id'] ?? $orderPackage['owner_id'];
+                $orderPackage['received_at'] = $item['received_at'] ?? $orderPackage['received_at'];
+                $orderPackage['transfer_status'] = $item['transfer_status'] ?? $orderPackage['transfer_status'];
+                $orderPackage['status'] = $item['status'] != '无' ? $item['status'] : $orderPackage['transfer_status'];
+                $orderPackage['uploaded_to_wms'] = $item['uploaded_to_wms'] != '否' ? $item['uploaded_to_wms'] : $orderPackage['transfer_status'];
+            }
+            $orderPackages_filter = $items->filter(function($item)use($orderPackage){
+                if($orderPackage['id'] === $item['id'])return false;
+                return true;
+            });
+            $ids = $orderPackages_filter->map(function($item){
+                return $item['id'];
+            });
+            LogService::log('order_packages','order_packages_logistic_number_unique_delete',json_encode($orderPackages_filter));
+            OrderPackage::query()->whereIn('id',$ids)->delete();
+            $orderPackage->save();
+        }
+    }
+
+    public function endStationTask()
+    {
+        $stationTask = StationTask::query()->where('id',711)->first();
+        $stationTask->update(['status'=>'完成']);
+    }
+
+    public function order_package_exception_type_counting_record_init()
+    {
+        /**
+         * @var $service OrderPackageExceptionTypeCountingRecordService
+         */
+        $service = app('OrderPackageExceptionTypeCountingRecordService');
+        $service->updateOrCreate(30);
+    }
+}

+ 9 - 2
app/Http/Controllers/UserController.php

@@ -31,12 +31,19 @@ class UserController extends Controller
         $userDetailQuery = UserDetail::query()->select('user_id')->where('type','临时工');
         $query = User::with(['roles','logistics','userWorkgroups','suppliers','userDetail'])->whereNotIn('id',$userDetailQuery);
         if($request->has('user')){
-           $query->where('name','like',$request->input('user'));
+            $user=$request->input('user');
+            $query->where('name','like',$user.'%');
         }
         if($request->has('role')){
             $role = $request->input('role');
             $query->whereHas('roles',function($query) use ($role){
-                 $query->where('name','like',$role);
+                if (strpos($role, ',') || strpos($role, ',') || strpos($role, ' ')) {
+                    $arr = array_filter(preg_split('/[,, ]+/is', $role));
+                    $query->whereIn('name', $arr);
+                    unset($role);
+                } else {
+                    $query->where('name','like',$role.'%');
+                }
             });
         }
         if($request->input('owner_id')){

+ 7 - 1
app/Http/Controllers/UserLaborController.php

@@ -29,7 +29,13 @@ class UserLaborController extends Controller
         $full_name = $request->user_name ?? false;
         if ($full_name){
             $userLabors->whereHas('userDetail',function($query)use($full_name){
-                $query->where('full_name','like',$full_name."%");
+                if (strpos($full_name, ',') || strpos($full_name, ',') || strpos($full_name, ' ')) {
+                    $arr = array_filter(preg_split('/[,, ]+/is', $full_name));
+                    $query->whereIn('full_name', $arr);
+                    unset($full_name);
+                } else {
+                    $query->where('full_name','like',$full_name.'%');
+                }
             });
         }
         $userLabors = $userLabors->paginate($request->paginate ?? 50);

+ 17 - 0
app/Http/Controllers/WaybillController.php

@@ -941,5 +941,22 @@ class WaybillController extends Controller
         if (!$order)$this->error("暂无绑定订单");
         $this->success($order);
     }
+    //按日输入专线费
+    public function dailyBilling(Request $request): array
+    {
+        if(!Gate::allows('运输管理-运单-按日计算专线费')){return ['success'=>false,'message'=>'没有权限'];}
+        $dailyBilling=$request->input('param');
+        $waybills=app('waybillService')->dailyBilling($dailyBilling);
+        if (!isset($waybills))return ['success'=>false,'message'=>'该日有记录未填写重量'];
+        return ['success'=>true,'data'=>$waybills];
+    }
+    public function countPickUpFee(Request $request)
+    {
+        if(!Gate::allows('运输管理-运单-查询')){ return ['success'=>false,'message'=>'没有权限'];  }
+        $param=$request->input('param');
+        $waybills=app('waybillService')->get($param);
+        $total_pick_up_fee=$waybills->sum('pick_up_fee');
+        return ['success'=>true,'data'=>$total_pick_up_fee];
+    }
 
 }

+ 76 - 76
app/Http/Controllers/api/thirdPart/flux/SortingController.php

@@ -30,83 +30,83 @@ class SortingController extends Controller
      */
     public function newBatch(Request $request)
     {
-       $requestArr=$request->all();
+//       $requestArr=$request->all();
         app('LogService')->log(__METHOD__, 'issued_' . __FUNCTION__, json_encode($request->all()));
-        !$requestArr?$requestArr=json_decode($request->getContent(),true):false;
-        $errors=$this->newBatchValidator($requestArr)->errors();
-        if(count($errors)>0){
-            app('LogService')->log(__METHOD__, 'error' . __FUNCTION__, 'fields wrong, see Errors report please.'.'|'.json_encode($request->all()).'|'.json_encode($errors));
-            return response()->json(['Response'=>['return'=>['returnFlag'=>'0','returnCode'=>'0001',
-                'returnDesc'=>':Failure','resultInfo'=>'','errors'=>$errors]]])->setEncodingOptions(JSON_UNESCAPED_UNICODE);
-        }
-        $requestBatches = $requestArr['request']?? '';
-
-        foreach ($requestBatches as $requestBatch){
-            $requestBatch['edittime']&&strpos(trim($requestBatch['edittime']),' ')?$editTimeFormat='Y-m-d H:i:s':$editTimeFormat='YmdHis';
-            $batch=Batch::query()->firstOrCreate(['code' => $requestBatch['waveno']]);
-
-            if(!$batch)$batch=new Batch();
-            $batch->fill([
-                    'code' => $requestBatch['waveno'],
-                    'wms_type' => $requestBatch['batch_type']??'',
-                    'wms_status' => $requestBatch['docstatus']??'',
-                    'status' => '未处理',
-                    'wms_created_at' => $requestBatch['edittime']?Carbon::createFromFormat($editTimeFormat,$requestBatch['edittime']):'',
-            ]);
-            $batch->save();
-            $oracleAlloactions=OracleActAllocationDetails::query()->where('waveno',$requestBatch['waveno'])->get();
-            foreach($requestBatch['order_list'] as $requestOrder){
-                $owner=Owner::query()->where('code',$requestOrder['customerid'])->first();
-                $order=app("OrderService")->first(['code'=>$requestOrder['docno']]);
-                if(!$order){
-                    $order=app("OrderService")->createOrder([
-                        'batch_id' => $batch['id'],
-                        'code' => $requestOrder['docno'],
-                        'owner_id' => $owner['id'],
-                        'wms_status' => $requestOrder['docstatus']??'波次下发',
-                        'status' => '未处理',
-                    ]);
-                    app('LogService')->log(__METHOD__,__FUNCTION__,'创建 Order'.json_encode($order));
-                }else{
-                    $order['batch_id']= $batch['id'] ;
-                    $order['owner_id']=$order['owner_id']??$owner['owner_id'];
-                    $order['wms_status']=$order['wms_status']??$requestOrder['docstatus']??'波次下发';
-                    $order['status']=$order['status']??'未处理';
-                }
-                $order->save();
-                OrderBin::query()->firstOrCreate([
-                    'order_id' => $order['id'],
-                    'number' => $requestOrder['reservedfield01'],
-                ]);
-                foreach($requestOrder['barcode_list'] as $requestBarcode){
-                    $orderCommodity=OrderCommodity::query()
-                        ->where('order_id',$order['id'])->where('wms_ptltaskid',$requestBarcode['ptltaskid'])->first();
-                    if(!$orderCommodity){
-                        /** @var CommodityService $commodityService */
-                        $commodityService=app('CommodityService');
-                        $commodity=$commodityService->syncBarcodes($requestBarcode['alternate_sku1'],$owner['id'],$requestBarcode['sku']);
-                        $orderCommodity=OrderCommodity::query()->firstOrCreate(['order_id'=>$order['id'],'commodity_id'=>$commodity['id']]);
-                        if(!$orderCommodity){
-                            $orderCommodity = new OrderCommodity([
-                                'order_id' => $order['id'],
-                                'commodity_id' => $commodity['id'],
-                                'amount' => $requestBarcode['fmqty_each']??0,
-                                'wms_ptltaskid' => $requestBarcode['ptltaskid'],
-                            ]);
-                        }else{
-                            $orderCommodity['order_id']=$order['id'];
-                            $orderCommodity['commodity_id']=$commodity['id'];
-                            $orderCommodity['amount']=$requestBarcode['fmqty_each']??0;
-                            $orderCommodity['wms_ptltaskid']=$requestBarcode['ptltaskid']??0;
-                        }
-                        $allocation=$oracleAlloactions->where('orderno',$requestOrder['docno'])->where('sku',$commodity['sku'])->where('qty',$requestBarcode['fmqty_each'])->first();
-                        if($allocation)
-                            $orderCommodity['location'] = $allocation['location'];
-                        $orderCommodity->save();
-                    }
-                }
-            }
-        }
+//        !$requestArr?$requestArr=json_decode($request->getContent(),true):false;
+//        $errors=$this->newBatchValidator($requestArr)->errors();
+//        if(count($errors)>0){
+//            app('LogService')->log(__METHOD__, 'error' . __FUNCTION__, 'fields wrong, see Errors report please.'.'|'.json_encode($request->all()).'|'.json_encode($errors));
+//            return response()->json(['Response'=>['return'=>['returnFlag'=>'0','returnCode'=>'0001',
+//                'returnDesc'=>':Failure','resultInfo'=>'','errors'=>$errors]]])->setEncodingOptions(JSON_UNESCAPED_UNICODE);
+//        }
+//        $requestBatches = $requestArr['request']?? '';
+//
+//        foreach ($requestBatches as $requestBatch){
+//            $requestBatch['edittime']&&strpos(trim($requestBatch['edittime']),' ')?$editTimeFormat='Y-m-d H:i:s':$editTimeFormat='YmdHis';
+//            $batch=Batch::query()->firstOrCreate(['code' => $requestBatch['waveno']]);
+//
+//            if(!$batch)$batch=new Batch();
+//            $batch->fill([
+//                    'code' => $requestBatch['waveno'],
+//                    'wms_type' => $requestBatch['batch_type']??'',
+//                    'wms_status' => $requestBatch['docstatus']??'',
+//                    'status' => '未处理',
+//                    'wms_created_at' => $requestBatch['edittime']?Carbon::createFromFormat($editTimeFormat,$requestBatch['edittime']):'',
+//            ]);
+//            $batch->save();
+//            $oracleAlloactions=OracleActAllocationDetails::query()->where('waveno',$requestBatch['waveno'])->get();
+//            foreach($requestBatch['order_list'] as $requestOrder){
+//                $owner=Owner::query()->where('code',$requestOrder['customerid'])->first();
+//                $order=app("OrderService")->first(['code'=>$requestOrder['docno']]);
+//                if(!$order){
+//                    $order=app("OrderService")->createOrder([
+//                        'batch_id' => $batch['id'],
+//                        'code' => $requestOrder['docno'],
+//                        'owner_id' => $owner['id'],
+//                        'wms_status' => $requestOrder['docstatus']??'波次下发',
+//                        'status' => '未处理',
+//                    ]);
+//                    app('LogService')->log(__METHOD__,__FUNCTION__,'创建 Order'.json_encode($order));
+//                }else{
+//                    $order['batch_id']= $batch['id'] ;
+//                    $order['owner_id']=$order['owner_id']??$owner['owner_id'];
+//                    $order['wms_status']=$order['wms_status']??$requestOrder['docstatus']??'波次下发';
+//                    $order['status']=$order['status']??'未处理';
+//                }
+//                $order->save();
+//                OrderBin::query()->firstOrCreate([
+//                    'order_id' => $order['id'],
+//                    'number' => $requestOrder['reservedfield01'],
+//                ]);
+//                foreach($requestOrder['barcode_list'] as $requestBarcode){
+//                    $orderCommodity=OrderCommodity::query()
+//                        ->where('order_id',$order['id'])->where('wms_ptltaskid',$requestBarcode['ptltaskid'])->first();
+//                    if(!$orderCommodity){
+//                        /** @var CommodityService $commodityService */
+//                        $commodityService=app('CommodityService');
+//                        $commodity=$commodityService->syncBarcodes($requestBarcode['alternate_sku1'],$owner['id'],$requestBarcode['sku']);
+//                        $orderCommodity=OrderCommodity::query()->firstOrCreate(['order_id'=>$order['id'],'commodity_id'=>$commodity['id']]);
+//                        if(!$orderCommodity){
+//                            $orderCommodity = new OrderCommodity([
+//                                'order_id' => $order['id'],
+//                                'commodity_id' => $commodity['id'],
+//                                'amount' => $requestBarcode['fmqty_each']??0,
+//                                'wms_ptltaskid' => $requestBarcode['ptltaskid'],
+//                            ]);
+//                        }else{
+//                            $orderCommodity['order_id']=$order['id'];
+//                            $orderCommodity['commodity_id']=$commodity['id'];
+//                            $orderCommodity['amount']=$requestBarcode['fmqty_each']??0;
+//                            $orderCommodity['wms_ptltaskid']=$requestBarcode['ptltaskid']??0;
+//                        }
+//                        $allocation=$oracleAlloactions->where('orderno',$requestOrder['docno'])->where('sku',$commodity['sku'])->where('qty',$requestBarcode['fmqty_each'])->first();
+//                        if($allocation)
+//                            $orderCommodity['location'] = $allocation['location'];
+//                        $orderCommodity->save();
+//                    }
+//                }
+//            }
+//        }
         return response()->json(['Response'=>['return'=>['returnFlag'=>'1','returnCode'=>'0000',
             'returnDesc'=>'消息处理成功:Success','resultInfo'=>'']]])->setEncodingOptions(JSON_UNESCAPED_UNICODE);
     }

+ 10 - 7
app/Http/Controllers/api/thirdPart/haiq/LightController.php

@@ -8,7 +8,9 @@ namespace App\Http\Controllers\api\thirdPart\haiq;
 
 use App\Services\CacheShelfService;
 use App\Services\ForeignHaiRoboticsService;
+use App\Station;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Log;
 
 class LightController
 {
@@ -30,13 +32,14 @@ class LightController
      * @return array
      */
     public function update(Request $request){// 拍灯以后的消息发至此处
-
-//        if($request['PTLAction'] == 0){  // 拍灯 推送任务
-//            /** @var CacheShelfService $cacheShelfService */
-//            $cacheShelfService = app(CacheShelfService::class);
-//            $result =   $cacheShelfService->lightOffTask($request['locCode'],$request['PTLAction']);
-//            return ['location'=>$result['success'] ? 200 :0,'errMsg'=>$result['errMsg'] ?? null,'data'=>$request->all()];
-//        }
+        $station = Station::query()->with('stationType')->where('code',$request['locCode'])->first();
+        if( ($station ?? false) && ($station->stationType->name ?? false) && $station->stationType->name == '缓存架' ){  // 拍灯 推送任务
+            if($request['PTLAction'] !== 0) return ['location' => 200,'errMsg' => 'is cacheShelf','data' => $request->all()];
+            /** @var CacheShelfService $cacheShelfService */
+            $cacheShelfService = app(CacheShelfService::class);
+            $result =   $cacheShelfService->lightOffTask($request['locCode'],$request['PTLAction']);
+            return ['location'=>$result['success'] ? 200 :0,'errMsg'=>$result['errMsg'] ?? null,'data'=>$request->all()];
+        }
         $success = $request->input('success');
         $location = $success?200:0;
         app('LogService')->log(__METHOD__,__FUNCTION__,'拍灯:'.json_encode($request->all()));

+ 6 - 2
app/Http/Controllers/api/thirdPart/haiq/StorageController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\api\thirdPart\haiq;
 
 
 use App\Http\Requests\ForeignHaiRobotic_taskUpdateRequest;
+use App\MaterialBox;
 use App\Services\ForeignHaiRoboticsService;
 use App\Services\LogService;
 use Illuminate\Http\Request;
@@ -199,8 +200,8 @@ class StorageController
             "areaCode"=> "1004",
             "PTLAction"=> 1, //1是开,0是关
             "PTLSettings"=> [
-                "color"=> 1,
-                "frequency"=> 1
+                "color"=> 2, //灯颜色,0红,1绿,2绿,3黄
+                "frequency"=> 0 //频率 0是不动,最大是3
             ],
             "displayInfo"=> [
                 "detail01"=> "detail01",
@@ -323,6 +324,9 @@ class StorageController
         $responseBody = $response->body();
         LogService::log(__CLASS__,__METHOD__,$responseBody);
         $responseBody = strstr($responseBody,'200')?'请求出库料箱"'.implode(',',$codes).'"成功':$responseBody;
+        if(strstr($responseBody,'成功')){
+            MaterialBox::query()->whereIn('code',$codes)->update(['status'=>'在出库中']);
+        }
         return ['result'=> $responseBody];
     }
 }

+ 1 - 1
app/Http/Controllers/api/thirdPart/weight/WeightBaseController.php

@@ -289,7 +289,7 @@ class WeightBaseController
     {
         $hid = $this->getValue($this->hid, $params);
         /** @var MeasuringMachine $measuringMachine */
-        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code' => $hid]); // 称重设备
+        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code' => $hid],['name' => $hid]); // 称重设备
         $measuringMachine->turnOn();
         $measuringMachine->turnOffInMinutes(30);
         return $measuringMachine;

+ 70 - 0
app/Http/Requests/Station/StationRuleBatchRequest.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace App\Http\Requests\Station;
+
+use App\Traits\RequestApiFormValidation;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Support\Facades\Route;
+
+class StationRuleBatchRequest extends FormRequest
+{
+    use RequestApiFormValidation;
+
+    protected $storeApiRules = [
+        'name' => 'required',
+        'owner_id' => 'required'
+    ];
+    protected $updateApiRules = [
+        'name' => 'required',
+        'owner_id' => 'required'
+    ];
+    protected $storeApiMessage = [
+        'name.required' => '规则名称为必填项',
+        'owner_id.required' => '货主为必填项',
+    ];
+    protected $updateApiMessage = [
+        'name.required' => '规则名称为必填项',
+        'owner_id.required' => '货主为必填项',
+    ];
+
+    /**
+     * Determine if the user is authorized to make this request.
+     *
+     * @return bool
+     */
+    public function authorize()
+    {
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules(): array
+    {
+        $routeName = Route::currentRouteName();
+        switch ($routeName) {
+            case 'station.rule.storeApi':
+                return $this->storeApiRules;
+            case 'station.rule.updateApi':
+                return $this->updateApiRules;
+            default:
+                return [];
+        }
+    }
+
+    public function messages(): array
+    {
+        $routeName = Route::currentRouteName();
+        switch ($routeName) {
+            case 'station.rule.storeApi':
+                return $this->storeApiMessage;
+            case 'station.rule.updateApi':
+                return $this->updateApiMessage;
+            default:
+                return [];
+        }
+    }
+}

+ 50 - 0
app/Jobs/LogisticSFSync.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Services\LogisticSFService;
+use App\Services\LogService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class LogisticSFSync implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    public $logistic_number;
+
+    /**
+     * @var LogisticSFService $logisticSFService
+     */
+    public $logisticSFService;
+    public $orderPackageReceivedSyncService;
+
+    /**
+     * LogisticSFSync constructor.
+     * @param $logistic_number
+     */
+    public function __construct($logistic_number)
+    {
+        $this->logistic_number = $logistic_number;
+    }
+
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     * @throws \Exception
+     */
+    public function handle()
+    {
+        ini_set('max_execution_time', 60);
+        LogService::log(LogisticSFSync::class, "{$this->logistic_number}-JOB-SF", '');
+        $this->logisticSFService = app('LogisticSFService');
+        $formedData = $this->logisticSFService->get([$this->logistic_number]);
+        $this->orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+        $this->orderPackageReceivedSyncService->update($formedData);
+    }
+}

+ 59 - 0
app/Jobs/LogisticYDSync.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Services\LogisticYDService;
+use App\Services\LogService;
+use App\Services\OrderPackageReceivedSyncService;
+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;
+    /**
+     * @var $logisticYDService LogisticYDService
+     * @var $orderPackageReceivedSyncService OrderPackageReceivedSyncService
+     * @var $orderPackageReceivedSyncService OrderPackageReceivedSyncService
+     * @var $logistic_number string
+     */
+
+    protected $logistic_number;
+
+    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', 60);
+        LogService::log(LogisticYDSync::class, "{$this->logistic_number}-JOB-YD", '');
+        $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]);
+    }
+}

+ 54 - 0
app/Jobs/LogisticYTOSync.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Services\LogisticYDService;
+use App\Services\LogisticYTOService;
+use App\Services\LogService;
+use App\Services\OrderPackageReceivedSyncService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class LogisticYTOSync implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+    /**
+     * @var $logisticYTOService LogisticYTOService
+     * @var $orderPackageReceivedSyncService OrderPackageReceivedSyncService
+     * @var $logistic_number string
+     */
+
+    protected $logistic_number;
+
+    protected $logisticYTOService;
+    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', 60);
+        LogService::log(LogisticYTOSync::class, "{$this->logistic_number}-JOB-YTO", '');
+        $this->logisticYTOService = app('LogisticYTOService');
+        $nativeResponse = $this->logisticYTOService->query($this->logistic_number);
+        $formattedData = $this->logisticYTOService->format($nativeResponse);
+        $this->orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+        $this->orderPackageReceivedSyncService->update([$formattedData]);
+    }
+}

+ 9 - 159
app/Jobs/LogisticZopSync.php

@@ -6,6 +6,7 @@ use App\library\zop\ZopClient;
 use App\library\zop\ZopProperties;
 use App\library\zop\ZopRequest;
 use App\OrderPackage;
+use App\Services\LogService;
 use App\Services\OrderPackageReceivedSyncService;
 use Illuminate\Bus\Queueable;
 use Illuminate\Contracts\Queue\ShouldQueue;
@@ -37,8 +38,8 @@ class LogisticZopSync implements ShouldQueue
      */
     public function handle()
     {
-        //
-        ini_set('max_execution_time', 10);
+        ini_set('max_execution_time', 60);
+        LogService::log(LogisticZopSync::class, "{$this->logistic_number}-JOB-ZOP", '');
         $zopResult = [];
         $response = $this->sentRequestToZT();
         if(is_null($response)) return;
@@ -92,7 +93,10 @@ class LogisticZopSync implements ShouldQueue
             $resultItem['transfer_status'] = [];
         }
         try {
-            $resultItem = $this->setExceptionType($resultItem, $lastRoute ? $lastRoute->scanDate / 1000 : null);
+            $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+            $exceptionData = $orderPackageReceivedSyncService->setExceptionType($resultItem, $lastRoute ? $lastRoute->scanDate / 1000 : null);
+            $resultItem['exception_type'] = $exceptionData['exception_type'];
+            $resultItem['exception'] = $exceptionData['exception'];
         } catch (\Exception $e) {
         }
         if ($resultItem['status'] == null) {
@@ -107,164 +111,10 @@ class LogisticZopSync implements ShouldQueue
             $resultItem['exception_type'] = '无';
             $resultItem['exception'] = '否';
         }
+        $resultItem['routes_length'] = array_key_exists('transfer_status', $resultItem) ? count($resultItem['transfer_status']) : 0;
         $result[] = $resultItem;
         return $result;
     }
-
-    /**
-     * @param array $data
-     * @param $lastRouteDate
-     * @return array
-     */
-    private function setExceptionType(array $data, $lastRouteDate = null): 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 $data;
-    }
-
     /**
      * 正常的状态与签收时间
      * @param $lastRoute
@@ -332,7 +182,7 @@ class LogisticZopSync implements ShouldQueue
         $request->setUrl($url);
         $request->setBody(json_encode([
             'billCode' => $this->logistic_number,
-        ]));
+        ],JSON_UNESCAPED_UNICODE));
         return json_decode($client->execute($request));
     }
 }

+ 5 - 1
app/Listeners/AddOrUpdateOrderIssuesListener.php

@@ -3,6 +3,7 @@
 namespace App\Listeners;
 
 use App\Events\AddOrUpdateOrderIssues;
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
 use App\OrderIssue;
 use App\OrderPackage;
 use Illuminate\Contracts\Queue\ShouldQueue;
@@ -28,7 +29,7 @@ class AddOrUpdateOrderIssuesListener implements ShouldQueue
     public function handle(AddOrUpdateOrderIssues $event)
     {
         $order_ids = OrderIssue::query()->select('order_id')->whereIn('order_id', $event->order_ids)->whereIn('order_issue_type_id', function ($query) {
-            $query->from('order_issue_types')->select('id')->whereNotIn('name', ['拦截', '信息更改', '其他', '错漏发', '仓库问题', '二次加工', '全检问题', '系统问题', '快递方式更改']);
+            $query->from('order_issue_types')->select('id')->whereNotIn('name', ['拦截', '信息更改', '其他', '错漏发', '仓库问题', '二次加工', '全检问题', '系统问题', '快递方式更改', '无记录']);
         })->pluck('order_id');
         OrderPackage::query()->whereIn('order_id',
             $order_ids)
@@ -36,5 +37,8 @@ class AddOrUpdateOrderIssuesListener implements ShouldQueue
                 'exception_type' => '其他',
                 'exception' => '是',
             ]);
+        //更新统计数据
+        $orderPackageIds = OrderPackage::query()->whereIn('order_id', $order_ids)->pluck('id');
+        event(new UpdateOrderPackageExceptionListenerEvent($orderPackageIds));
     }
 }

+ 5 - 1
app/Listeners/UpdateOrderPackageExceptionListener.php

@@ -3,6 +3,7 @@
 namespace App\Listeners;
 
 use App\Events\OrderIssueProcessLogCreateEvent;
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
 use App\OrderPackage;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Queue\InteractsWithQueue;
@@ -37,10 +38,13 @@ class UpdateOrderPackageExceptionListener implements ShouldQueue
             default:
                 $status = '无';
         }
-        OrderPackage::query()->whereIn('id', $event->orderPackageIds)->update([
+        $orderPackageIds = $event->orderPackageIds;
+        OrderPackage::query()->whereIn('id', $orderPackageIds)->update([
             'exception_type' => '无',
             'exception' => '否',
             'status' => $status,
         ]);
+        //更新统计数据
+        event(new UpdateOrderPackageExceptionListenerEvent($orderPackageIds));
     }
 }

+ 42 - 0
app/Listeners/UpdateOrderPackageExceptionTypeCountingRecordListener.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace App\Listeners;
+
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
+use App\OrderPackage;
+use App\Services\OrderPackageExceptionTypeCountingRecordService;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Support\Facades\DB;
+
+class UpdateOrderPackageExceptionTypeCountingRecordListener implements ShouldQueue
+{
+    /**
+     * Create the event listener.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        //
+    }
+
+    /**
+     * Handle the event.
+     *
+     * @param UpdateOrderPackageExceptionListenerEvent $event
+     * @return void
+     */
+    public function handle(UpdateOrderPackageExceptionListenerEvent $event)
+    {
+        $order_package_ids = $event->order_package_ids;
+        $dates = OrderPackage::query()->select(DB::raw("DATE_FORMAT( sent_at, '%Y-%m-%d' ) AS sent_at_date "))->whereIn('id', $order_package_ids)->get();
+        /**
+         * @var $service OrderPackageExceptionTypeCountingRecordService
+         */
+        $service = app('OrderPackageExceptionTypeCountingRecordService');
+        foreach ($dates as $date) {
+            $service->updateOrCreateByDate($date->sent_at_date);
+        }
+    }
+}

+ 30 - 1
app/MaterialBox.php

@@ -10,5 +10,34 @@ class MaterialBox extends Model
 {
     use ModelLogChanging;
 
-    protected $fillable=['code'];
+    protected $fillable=['code','status'];
+
+    static public $enums=[
+        'status'=>[
+            '在库外'=>1,
+            '在U型线'=>2,
+            '在缓存架'=>3,
+            '在立库'=>4,
+            '在出库中'=>5,
+            '在入库中'=>6,
+            '未知'=>7,
+            '异常'=>8,
+        ],
+    ];
+    function __construct(array $attributes = [])
+    {
+        foreach (self::$enums as &$enum) {
+            $enum=$enum+array_flip($enum);
+        }
+        parent::__construct($attributes);
+    }
+
+    public function getStatusAttribute($value)
+    {
+        return self::$enums['status'][$value];
+    }
+    public function setStatusAttribute($value)
+    {
+        $this->attributes['status']=self::$enums['status'][$value];
+    }
 }

+ 5 - 0
app/OracleDOCOrderHeader.php

@@ -9,6 +9,7 @@ use App\Traits\ModelTimeFormat;
 use Illuminate\Database\Eloquent\Model;
 
 use App\Traits\ModelLogChanging;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 class OracleDOCOrderHeader extends Model
 {
@@ -66,6 +67,10 @@ class OracleDOCOrderHeader extends Model
         return $this->hasOne('App\OracleBasCode','code','ordertype')->where('codeid','SO_TYP');
     }
 
+    public function oracleDOCWaveDetail(): BelongsTo
+    {
+        return $this->belongsTo(OracleDOCWaveDetails::class,'orderno','orderno');
+    }
     public function getLogistic()
     {
         /** @var LogisticService $logistic_service */

+ 2 - 2
app/OracleDOCWaveDetails.php

@@ -13,14 +13,14 @@ class OracleDOCWaveDetails extends Model
     protected $connection='oracle';
     protected $table='DOC_WAVE_DETAILS';
     public $timestamps=false;
-    protected $primaryKey = 'OrdderNo';
+    protected $primaryKey = 'OrderNo';
     function getIncrementing()
     {
         return false;
     }
 
     static public function unpackedOrders($batchNumber){
-        return OracleDOCWaveDetails::where('doc_wave_details.waveno', $batchNumber)->leftJoin('doc_order_header','doc_order_header.orderno','doc_wave_details.orderno')->where(function ($query){
+        return OracleDOCWaveDetails::query()->where('doc_wave_details.waveno', $batchNumber)->leftJoin('doc_order_header','doc_order_header.orderno','doc_wave_details.orderno')->where(function ($query){
             $query->where('doc_order_header.SOSTATUS','<>','99')->where('doc_order_header.SOSTATUS','<>','63');
         })->get();
     }

+ 1 - 0
app/OrderIssueRejectedBill.php

@@ -10,6 +10,7 @@ class OrderIssueRejectedBill extends Model
 {
     use ModelLogChanging;
     protected $table='order_issue_rejected_bill';
+    public $timestamps = false;
     protected $fillable = [
         'order_issue_id','logistic_number_return'
     ];

+ 17 - 0
app/OrderPackageExceptionTypeCountingRecord.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class OrderPackageExceptionTypeCountingRecord extends Model
+{
+    use ModelLogChanging;
+    public $timestamps = false;
+
+
+    //
+    public $fillable = ["sent_at_date", 'exception_type', 'exception_type_count', 'owner_id',];
+}

+ 8 - 0
app/Providers/AppServiceProvider.php

@@ -24,6 +24,8 @@ use App\Services\ForeignHaiRoboticsService;
 use App\Services\InventoryAccountMissionService;
 use App\Services\InventoryCompareService;
 use App\Services\LaborReportsCountingRecordService;
+use App\Services\LogisticSFService;
+use App\Services\LogisticYTOService;
 use App\Services\LogService;
 use App\Services\MaterialBoxService;
 use App\Services\OracleBasCustomerService;
@@ -111,6 +113,8 @@ use Ramsey\Uuid\Uuid;
 use Illuminate\Support\Facades\Validator;
 use App\Services\SupplierService;
 use App\Services\OrderPackageCommoditySerialNumberService;
+use App\Services\OrderPackageExceptionTypeCountingRecordService;
+use App\Services\LogisticYDService;
 
 class AppServiceProvider extends ServiceProvider
 {
@@ -183,7 +187,10 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('InventoryDailyLogService',InventoryDailyLogService::class);
         app()->singleton('LaborReportsCountingRecordService',LaborReportsCountingRecordService::class);
         app()->singleton('LogService',LogService::class);
+        app()->singleton('LogisticSFService',LogisticSFService::class);
         app()->singleton('LogisticService',LogisticService::class);
+        app()->singleton('LogisticYDService',LogisticYDService::class);
+        app()->singleton('LogisticYTOService',LogisticYTOService::class);
         app()->singleton('MaterialBoxService',MaterialBoxService::class);
         app()->singleton('OracleActAllocationDetailService',OracleActAllocationDetailService::class);
         app()->singleton('OracleBasCustomerService',OracleBasCustomerService::class);
@@ -201,6 +208,7 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('OrderIssueWorkLoadService',OrderIssueWorkLoadService::class);
         app()->singleton('OrderPackageCommoditiesService',OrderPackageCommoditiesService::class);
         app()->singleton('OrderPackageCommoditySerialNumberService',OrderPackageCommoditySerialNumberService::class);
+        app()->singleton('OrderPackageExceptionTypeCountingRecordService',OrderPackageExceptionTypeCountingRecordService::class);
         app()->singleton('OrderPackageReceivedSyncService',OrderPackageReceivedSyncService::class);
         app()->singleton('OrderPackageService',OrderPackageService::class);
         app()->singleton('OrderService',OrderService::class);

+ 7 - 4
app/Providers/EventServiceProvider.php

@@ -35,11 +35,14 @@ class EventServiceProvider extends ServiceProvider
         'App\Events\SendEmailEvent' => [
             'App\Listeners\SendEmailListener'
         ],
-        'App\Events\AddOrUpdateOrderIssues' => [
-            'App\Listeners\AddOrUpdateOrderIssuesListener',
+        'App\Events\AddOrUpdateOrderIssues' => [//问题件新增或更新
+            'App\Listeners\AddOrUpdateOrderIssuesListener',//将对应的order_packages的数据的异常装变更
         ],
-        'App\Events\OrderIssueProcessLogCreateEvent' => [
-            'App\Listeners\UpdateOrderPackageExceptionListener',
+        'App\Events\OrderIssueProcessLogCreateEvent' => [//orderIssue增添日志时
+            'App\Listeners\UpdateOrderPackageExceptionListener',//将对应的order_packages的数据的异常装变更为无
+        ],
+        'App\Events\UpdateOrderPackageExceptionListenerEvent' => [//order_packages的数据的异常数据变更时
+            'App\Listeners\UpdateOrderPackageExceptionTypeCountingRecordListener',//更新OrderPackageExceptionTypeCountingRecord的统计信息
         ],
     ];
 

+ 151 - 23
app/Services/CacheShelfService.php

@@ -6,18 +6,24 @@ use App\Events\BroadcastToStation;
 use App\Exceptions\ErrorException;
 use App\MaterialBox;
 use App\Station;
+use App\StationTask;
+use App\StationTaskChildren;
 use App\StationTaskMaterialBox;
 use App\StationType;
 use App\Traits\ServiceAppAop;
+use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Collection;
 
-class CacheShelfService
+class   CacheShelfService
 {
     use ServiceAppAop;
 
     protected $modelClass = Station::class;
+
+    /** @var StationService $stationService */
+    private $stationService;
     /** @var StationTaskMaterialBoxService $stationTaskMaterialBoxService */
     private $stationTaskMaterialBoxService;
     /** @var ForeignHaiRoboticsService $foreignHaiRoboticsService */
@@ -46,13 +52,11 @@ class CacheShelfService
      */
     public function lightOffTask($locCode, $PTLAction): array
     {
-
-        $station = Station::query()->where('code', $locCode)->first();
+        $station = Station::query()->with('pendingStationTask.stationTaskMaterialBoxes.materialBox')->where('code', $locCode)->first();
         try {
             $bool = $this->putBinToStore($station);                         // 推送任务
             if($bool){
-                $this->_stationCacheLightOff($locCode);                     // 格口灭灯
-                $this->_stationCacheBroadCast($locCode,$PTLAction);         // 灭灯广播
+                LogService::log(__CLASS__,'lightOffTask','code' .' true'. $locCode.json_encode($station));
                 return ['success' => true];
             }else{
                 return ['success' => false,'errMsg' => '机器人推送失败'];
@@ -73,10 +77,53 @@ class CacheShelfService
     {
         $this->instant($this->stationTaskMaterialBoxService, 'StationTaskMaterialBoxService');
         $this->instant($this->foreignHaiRoboticsService, 'ForeignHaiRoboticsService');
+        $this->instant($this->stationService, 'StationService');
+        $this->instant($this->stationTaskService, 'StationTaskService');
+        $this->instant($this->stationTaskChildService, 'StationTaskChildService');
+
+        /** @var StationTaskMaterialBox $takeStationTaskMaterialBox */
+        $takeStationTaskMaterialBox = $station['pendingStationTask']['stationTaskMaterialBoxes']->first();
+        $formStation = $this->stationService->getStation_byType('立库');
+
+        // 查询是否有待处理的入库任务
+        $putStationTaskMaterialBox = StationTaskMaterialBox::query()->where([
+            'station_id' => $formStation['id'],
+            'material_box_id' => $takeStationTaskMaterialBox['material_box_id'],
+            'status' => '待处理',
+        ])->first();
+
+        // 创建入立库任务
+        if(!$putStationTaskMaterialBox){
+            $stationTask = $this->stationTaskService->create(1);               // 生成站任务
+            $this->stationTaskService->registerStations($stationTask,[$formStation['id']]);   // 注册站任务站
+            /** @var StationTaskMaterialBox $putStationTaskMaterialBox */
+            $putStationTaskMaterialBox = $this->stationTaskMaterialBoxService->create([
+                'station_id' => $formStation['id'],
+                'material_box_id' => $takeStationTaskMaterialBox['material_box_id'],
+                'status' => '待处理',
+            ]);
+            $putStationTaskMaterialBox['station_task_id'] = $stationTask->first()['id'];
+            $putStationTaskMaterialBox['type'] = '放';
+            $putStationTaskMaterialBox->update();
+
+            $params = [[
+                'station_task_id'=>$stationTask->first()['id'],
+                'station_taskable_type'=>StationTaskMaterialBox::class,
+                'station_taskable_id'=>$putStationTaskMaterialBox['id']
+            ]];
+
+            $this->stationTaskChildService->insert($params);    // 任务任务注册
+        }
 
-        /** @var StationTaskMaterialBox $stationTaskMaterialBox */
-        $stationTaskMaterialBox = $station['pendingStationTask']['stationTaskMaterialBoxes']->first();
-        return $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($stationTaskMaterialBox);
+        // 推立库任务
+        $isSuccess =  $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($putStationTaskMaterialBox,$station['code']);
+        if($isSuccess) $this->stationTaskMaterialBoxService->set($takeStationTaskMaterialBox,['status' => '处理中']);  // 任务推送成功 标记站任务为处理中
+        else {
+            $materialBoxCode = $station['pendingStationTask']['stationTaskMaterialBoxes']->first()->code ?? '';
+            $this->_stationCacheBroadCast($station->code,0,'error');
+            $this->_stationCacheLightOn($station->code,$materialBoxCode,'拍灯重试任务');
+        }
+        return $isSuccess;
     }
 
     /**
@@ -100,39 +147,51 @@ class CacheShelfService
             $parentStation = Station::query()->firstOrCreate(['code'=>$parentCode],['station_type_id'=>$stationType['id']]);
             $station = Station::query()->firstOrCreate(['code' => $stationCode,'parent_id'=>$parentStation['id']],['name'=>$stationCode,'station_type_id' => $stationType['id']]);
         }
+
         $materialBox = MaterialBox::query()->firstOrCreate(['code' => $materialBoxCode]);
-        if($station['pendingStationTask'] ?? false){
-            return ['success' => false,'message' => '当前已有未完成的站任务'];
+
+        $station->load('pendingStationTask.stationTaskMaterialBoxes.materialBox');
+        if($station->pendingStationTask){
+            if($station['pendingStationTask']['stationTaskMaterialBoxes']->first()->materialBox->code == $materialBoxCode){
+                $response = $this->_stationCacheLightOn($stationCode,$materialBoxCode,'任务重试');
+                if($response->code) return ['success'=>true,'message' =>  '任务重试'];
+                return ['success'=>true,'message' =>  '任务重试失败'];
+            }
+            return ['success' => false,'message' => '当前已有进行重的任务'];
         }
-        $stationTask = $this->stationTaskService->create(1);                                                    // 生成站任务
+
+        $stationTask = $this->stationTaskService->create(1);                                                       // 生成站任务
         $stationTaskMaterialBox = $this->stationTaskMaterialBoxService->createByStationAndMaterialBox($station,$materialBox);     // 创建料箱任务
-        $this->stationTaskService->registerStations($stationTask,[$station['id']]);                                            // 注册站任务站
+        $this->stationTaskService->registerStations($stationTask,[$station['id']]);                                               // 注册站任务站
+        $stationTaskMaterialBox['station_task_id'] = $stationTask->first()['id'];
+        $stationTaskMaterialBox->update();
         $params = [[
                 'station_task_id'=>$stationTask->first()['id'],
                 'station_taskable_type'=>StationTaskMaterialBox::class,
                 'station_taskable_id'=>$stationTaskMaterialBox['id']
             ]];
         $this->stationTaskChildService->insert($params);                                                                        // 任务任务注册
-        return['success'=>true];
+
+        $body = $this->_stationCacheLightOn($stationCode,$materialBoxCode);
+        if($body->code == 200)return ['success'=>true];
+        return ['success' => false,'message' => '机器人亮灯异常'];
     }
 
     /**
      * 控制格口亮灯
      * @param $locCode
-     * @param string $title
      * @param null $materialCode
+     * @param string $title
+     * @param string $color
      * @return mixed
      */
-    public function _stationCacheLightOn($locCode,$materialCode = null,$title = 'title')
+    public function _stationCacheLightOn($locCode,$materialCode = null,$title = 'title' ,string $color = '1')
     {
         $params = [
             "areaCode" => "1004",
             'locCode' => $locCode,
             'PTLAction' => 1,
-            'PTLSettings' => [
-                'color'=> 1,
-                'frequency'  =>1
-                ],
+            'PTLSettings' => ['color'=> $color, 'frequency'  =>1],
             "displayInfo" => [
                 "detail01" => $materialCode,
                 "detail02" => "detail02",
@@ -146,8 +205,9 @@ class CacheShelfService
                 "uomDesc02" => "uo"
             ],
         ];
-        $response = Http::post(config('api.haiq.storage.light'), $params);
-        return json_decode($response->body());
+        return new MaterialBox(['code' => 200]);
+//        $response = Http::post(config('api.haiq.storage.light'), $params);
+//        return json_decode($response->body());
     }
 
     /**
@@ -156,6 +216,7 @@ class CacheShelfService
      * @return mixed
      */
     public function _stationCacheLightOff($locCode){
+        if(!$locCode)return null;
         $params = [
             "areaCode" => "1004",
             'locCode' => $locCode,
@@ -166,22 +227,89 @@ class CacheShelfService
     }
 
     /**
-     * 广播 通知货物被取走
+     * 广播 type success成功 error 异常
      * @param $locCode
      * @param $PTLAction
+     * @param string $type
      */
-    public function _stationCacheBroadCast($locCode,$PTLAction)
+    public function _stationCacheBroadCast($locCode, $PTLAction,string $type = 'success')
     {
         if($PTLAction == 0){
             $station = Station::query()->with('parent')->where('code',$locCode)->first();
+
             $json = json_encode( [
                 'station_id' => $station['parent']['id'],
                 'code'  => $station['parent']['code'],
                 'gird_id' => $station['id'],
                 'grid_code' => $station['code'],
+                'type' => $type
             ]);
             broadcast(new BroadcastToStation($station['parent_id'],$json));
         }
     }
 
+    /**
+     * 根据立库任务完成 缓存架任务 和 入立架任务
+     * @param StationTaskMaterialBox $putStationTaskMaterial
+     */
+    public function putStationTaskMaterialBoxProcess(StationTaskMaterialBox $putStationTaskMaterial)
+    {
+        $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');
+
+        $takeStationTaskMaterialBox = StationTaskMaterialBox::query()->with('station','stationTask')->where('material_box_id',$putStationTaskMaterial['material_box_id'])->whereIn('station_id',function($query){
+            $query->from('stations')->selectRaw('id')->whereIn('station_type_id',function($query){
+                $query->from('station_types')->selectRaw('id')->where('name','缓存架');
+            });
+        })->where('status','处理中')->first();
+
+        if(!$takeStationTaskMaterialBox)return ;
+        $this->stationTaskMaterialBoxService->set($takeStationTaskMaterialBox, [
+            'status' => '完成'
+        ]);
+
+        // 缓存架任务
+        if($takeStationTaskMaterialBox->stationTask)$takeStationTaskMaterialBox->stationTask->update(['status' => '完成']);
+        // 入立架任务
+        if($putStationTaskMaterial->stationTask)$putStationTaskMaterial->stationTask->update(['status' => '完成']);
+
+        $this->_stationCacheLightOff($takeStationTaskMaterialBox->station->code ?? null);  //海柔格口灭灯
+        $this->_stationCacheBroadCast($takeStationTaskMaterialBox->station->code, 0);    //通知缓存架任务完成
+    }
+
+    /**
+     * 取消任务
+     * @param $stationCode
+     * @return array
+     */
+    public function clearTask($stationCode): array
+    {
+        $station = Station::query()->with(['currentStationTask.stationTaskMaterialBoxes.materialBox',
+            'pendingStationTask.stationTaskMaterialBoxes.materialBox'])
+            ->where('code',$stationCode)->first();
+
+        if($station->currentStationTask)return ['success' => false,'message' => '当前任务正在执行','data'=>$stationCode];
+        if($station->pendingStationTask->stationTaskMaterialBoxes->count() == 0){
+            $station->pendingStationTask->delete();
+            return ['success' => true];
+        }
+
+        $taskStationTaskMaterialBox = $station->pendingStationTask->stationTaskMaterialBoxes->first() ?? null;
+        $stationTaskMaterialBoxes = StationTaskMaterialBox::query()->with('stationTask')
+            ->where('material_box_id',$taskStationTaskMaterialBox['material_box_id'])
+            ->where('station_id','!=',$station->pendingStationTask['id'])
+            ->get();
+
+        foreach ($stationTaskMaterialBoxes as $stationTaskMaterialBox) {
+            if($stationTaskMaterialBox->stationTask){
+                StationTaskChildren::query()->where([
+                    'station_task_id' => $stationTaskMaterialBox->stationTask['id'],
+                    'station_taskable_type'=>StationTaskMaterialBox::class,
+                    'station_taskable_id'=>$stationTaskMaterialBox['id']])->delete();
+
+                $stationTaskMaterialBox->stationTask->delete();
+            }
+            $stationTaskMaterialBox->delete();
+        }
+        return ['success' => true];
+    }
 }

+ 1 - 1
app/Services/CityService.php

@@ -34,7 +34,7 @@ class CityService
         if(isset($city))return $city;
         if(!$name)return null;
         foreach (CityService::$cities as $city) {
-            if(strstr($city,$name) != null){
+            if(strstr($city,$name) != null || strstr($name,$city)){
                return City::query()->where('name','like',$city.'%')->first();
             }
         }

+ 35 - 22
app/Services/ForeignHaiRoboticsService.php

@@ -13,6 +13,7 @@ use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Http;
 use App\Traits\ServiceAppAop;
+use Illuminate\Support\Facades\Log;
 
 
 class ForeignHaiRoboticsService
@@ -99,7 +100,7 @@ class ForeignHaiRoboticsService
             $groupIdPrefix
         );
         LogService::log(__METHOD__,'runMany','波次任务分配6.r5f2:'.json_encode($dataToPost));
-        return $this->controlHaiRobot($dataToPost);
+        return $this->controlHaiRobot($dataToPost,$taskMaterialBoxes,'立架出至输送线');
     }
 
     public function moveBin(){
@@ -213,11 +214,11 @@ class ForeignHaiRoboticsService
                 '输送线入立架',
                 'BIN-IN1',//TODO:这里应该是动态取得,参考出立架getULineExit()方法,不然不能从站获得对应的出口,而且要改Station的child为children
                 '',
-                $stationTaskMaterialBox['stationTaskBatch']['id']
+                $stationTaskMaterialBox_toStore['stationTaskBatch']['id']
             );
-            $this->controlHaiRobot($dataToPost);
+            $this->controlHaiRobot($dataToPost,collect([$stationTaskMaterialBox_toStore]),'输送线入立架');
 
-            $stationTaskMaterialBox = $stationTaskMaterialBox??$materialBox??null;
+            $stationTaskMaterialBox = $stationTaskMaterialBox_toStore??$materialBox??null;
             if($stationTaskMaterialBox && get_class($stationTaskMaterialBox)==MaterialBox::class){
                 $stationTaskMaterialBox = StationTaskMaterialBox::query()
                     ->where('material_box_id',$stationTaskMaterialBox['id'])
@@ -256,45 +257,40 @@ class ForeignHaiRoboticsService
         );
         LogService::log('海柔请求','putBinToStore3',
             json_encode($dataToPost));
-        $controlSuccess = $this->controlHaiRobot($dataToPost);
-        if($controlSuccess){
-        }
+        $controlSuccess = $this->controlHaiRobot($dataToPost,collect([$stationTaskMaterialBox_toStore]),'输送线入立架');
+
         return $controlSuccess;
     }
 
     /** 缓存架入立架 料箱 任务
      * @param StationTaskMaterialBox|null $stationTaskMaterialBox
+     * @param string|null $formLocation
      * @return bool
      * @throws ErrorException
      */
-    public function putBinToStore_fromCacheShelf(?StationTaskMaterialBox $stationTaskMaterialBox): bool
+    public function putBinToStore_fromCacheShelf(?StationTaskMaterialBox $stationTaskMaterialBox,
+                                                 string $formLocation): bool
     {
         LogService::log('海柔请求','putBinToStore_fromCacheShelf1', '');
         LogService::log('海柔请求','putBinToStore_fromCacheShelf2', json_encode($stationTaskMaterialBox));
 
-        // 缓存架格口
-        $formLocation = $stationTaskMaterialBox['station']['code'];
-
-        /** 创建料箱 从缓存架 到 立架任务 */
         $dataToPost=$this->makeJson_move(
             collect([$stationTaskMaterialBox]),
             '缓存架入立架',
-            $formLocation,              //TODO:通过计算StationCacheShelfGrid 的 Grid_id 获取格口的编号
+            $formLocation,
             ''
         );
-
         LogService::log('海柔请求','putBinToStore_fromCacheShelf3', json_encode($dataToPost));
 
-        /** 控制海柔机器人执行任务 */
-        $controlSuccess = $this->controlHaiRobot($dataToPost);
+        $controlSuccess = $this->controlHaiRobot($dataToPost,collect([$stationTaskMaterialBox]),'缓存架入立架');
+        LogService::log('海柔请求','putBinToStore_fromCacheShelf4', 'controlHaiRobot '. json_encode($controlSuccess));
+
         if($controlSuccess){
             $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');
             $this->stationTaskMaterialBoxService->set($stationTaskMaterialBox,[
-                'id' => $stationTaskMaterialBox['id'],
-                'status' => $stationTaskMaterialBox['status']='处理中',
-                'station_id' => $stationTaskMaterialBox['station']['id']?? '',
+                'status' => '处理中',
             ]);
-            $stationTaskMaterialBox->stationTask()->update(['status' => '完成']);
+            LogService::log('海柔请求','putBinToStore_fromCacheShelf5', 'controlHaiRobot '. json_encode($stationTaskMaterialBox));
         }
         return $controlSuccess;
     }
@@ -384,7 +380,7 @@ class ForeignHaiRoboticsService
      * @param array $dataToPost
      * @return bool
      */
-    public function controlHaiRobot(array $dataToPost): bool
+    public function controlHaiRobot(array $dataToPost,Collection $taskMaterialBoxes,$modeName): bool
     {
         LogService::log('海柔请求','runMany','波次任务分配6.r5f2c1:'.json_encode($dataToPost));
         try{
@@ -428,7 +424,24 @@ class ForeignHaiRoboticsService
             . '请求:' . json_encode($dataToPost)
             . '调用堆栈c:' . json_encode(array_slice(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), 0, 3))
         );
-        return $isSuccess = !$errMsg;
+        $isSuccess = !$errMsg;
+        $标记料箱状态=(function() use ($taskMaterialBoxes,$modeName){
+            foreach ($taskMaterialBoxes as $taskMaterialBox){
+                switch ($modeName){
+                    case '缓存架入立架':
+                    case '输送线入立架':
+                    case '移动立架内位置':
+                    $taskMaterialBox->materialBox['status']='在入库中';break;
+                    case '立架出至输送线':
+                    case '立架出至缓存架':
+                    $taskMaterialBox->materialBox['status']='在出库中';break;
+                    default:
+                        $taskMaterialBox->materialBox['status']='未知';break;
+                }
+                $taskMaterialBox->materialBox->update();
+            }
+        })();
+        return $isSuccess;
     }
 
 }

+ 8 - 0
app/Services/LaborReportService.php

@@ -105,12 +105,20 @@ class LaborReportService
             $yesterdayDate=Carbon::now()->subDays(1)->format('Y-m-d');
             $laborReportYesterday=LaborReport::query()->where('user_id',$userDutyCheck->user_id)->where('created_at','like',$yesterdayDate.'%')->orderBy('id','desc')->first();
             if ($laborReportYesterday){
+                if (!$laborReportYesterday->check_out_at&&$laborReportYesterday['user_workgroup_id']){
+                    UserDutyCheck::where('user_id',$laborReportYesterday->user_id)->where('type','登出')->where('checked_at','like',Carbon::now()->format('Y-m-d H:i').'%')->orderBy('id','desc')->delete();
+                    return "<h1 style='color: darkred;text-align:center'>您还未退组,暂不可退场,请联系组长!</h1>";
+                }
                 $exportReport=LaborReport::exitAndChangeLaborReport($laborReportYesterday,$userDutyCheck);
                 Controller::logS(__METHOD__,"退场更改临时工报表信息__".__FUNCTION__,json_encode([$laborReportYesterday,$userDutyCheck]));
                 if ($exportReport) event(new ExportEvent($exportReport));
             }
         }
         if($laborReport&&$importAndExportQRCodeType=='export'){
+            if (!$laborReport['check_out_at']&&$laborReport['user_workgroup_id']){
+                UserDutyCheck::where('user_id',$laborReport->user_id)->where('type','登出')->where('checked_at','like',Carbon::now()->format('Y-m-d H:i').'%')->orderBy('id','desc')->delete();
+                return "<h1 style='color: darkred;text-align:center'>您还未退组,暂不可退场,请联系组长!</h1>";
+            }
             $exportReport=LaborReport::exitAndChangeLaborReport($laborReport,$userDutyCheck);
             Controller::logS(__METHOD__,"退场更改临时工报表信息__".__FUNCTION__,json_encode([$laborReport,$userDutyCheck]));
             if ($exportReport) event(new ExportEvent($exportReport));

+ 15 - 122
app/Services/LogisticSFService.php

@@ -101,7 +101,10 @@ xml;
             $data = $this->switchOpCodeToStatus($lastRoute, $data);
             $data['transfer_status'] = $this->transformRoutes($routeResponse['Route']);
             if (!array_key_exists('exception', $data)) {//当顺丰返回异常时,不需要再根据时间判断是否异常,直接用顺丰的异常就好
-                $data = $this->setExceptionType($data, $lastRoute['accept_time']);
+                $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+                $exceptionData = $orderPackageReceivedSyncService->setExceptionType($data, array_key_exists('accept_time',$lastRoute) ? $lastRoute['accept_time'] : null);
+                $data['exception_type'] = $exceptionData['exception_type'];
+                $data['exception'] = $exceptionData['exception'];
             }
             //如果没有发现额外的异常,且查询到物流轨迹,将异常置为无
             if (!array_key_exists('exception', $data)
@@ -114,18 +117,22 @@ xml;
         } catch (Exception $e) {
             throw new WarningException("单号没有查询到快递路由信息','LogisticSFService->transformSFOneToArr->{$data['logistic_number']}");
         } finally {
+            $data['routes_length'] = array_key_exists('transfer_status', $data) ? count($data['transfer_status']) : 0;
             return $data;
         }
     }
 
     /**
      * 转换快递路由信息
-     * @param array $routs 快递路由
+     * @param  $routs 快递路由
      * @return array
      */
-    public function transformRoutes(array $routs): array
+    public function transformRoutes($routs): array
     {
         $result = [];
+        if (!is_array($routs)) {
+            $routs = [$routs];
+        }
         foreach ($routs as $route) {
             $route = get_object_vars($route)['@attributes'];
             $data['accept_time'] = $route['accept_time'];
@@ -155,7 +162,6 @@ xml;
                 case 36:
                     $data['status'] = '在途';
                     break;
-                case 70:
                 case 33:
                     $data['status'] = '派送异常';
                     $data['exception_type'] = '派件异常';
@@ -178,6 +184,11 @@ xml;
                 case 99:
                     $data['status'] = '返回中';
                     break;
+                case 70:
+                    $data['status'] = '无';
+                    $data['exception'] = '是';
+                    $data['exception_type'] = '其他';
+                    break;
                 default:
                     throw new WarningException("未知的丰桥状态码: {$lastRoute['opcode']}->{json_encode($lastRoute)}");
             }
@@ -223,122 +234,4 @@ xml;
         }
         return $result;
     }
-
-
-    /**
-     * @param array $data
-     * @param $lastRouteDate
-     * @return array
-     */
-    private function setExceptionType(array $data, $lastRouteDate = null): 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 = 24;
-        $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:
-                    break;
-            }
-        })($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 $data;
-    }
 }

+ 182 - 0
app/Services/LogisticYDService.php

@@ -0,0 +1,182 @@
+<?php
+
+namespace App\Services;
+
+use App\OrderPackage;
+use App\Traits\ServiceAppAop;
+use Carbon\Carbon;
+use Illuminate\Support\Facades\Http;
+
+class LogisticYDService
+{
+    use ServiceAppAop;
+
+    private $app_key;
+    private $app_secret;
+    private $url;
+
+
+    /**
+     * 批量订阅接口
+     * @param $logistic_numbers array
+     * @return mixed
+     */
+    public function registerApi(array $logistic_numbers)
+    {
+        $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" => "上海市",
+            "county" => "松江区",
+            "name" => "施尧",
+            "phone" => '13761413262',
+            "province" => "上海市"
+        ];
+        $body = [
+            "orders" => [],
+        ];
+        $order_packages = OrderPackage::query()
+            ->with('order')
+            ->whereIn('logistic_number', $logistic_numbers)->get();
+        foreach ($order_packages as $order_package) {
+            $order = $order_package->order;
+            $body['orders'][] = [
+                'orderid' => $order->client_code,
+                "mailno" => $order_package->logistic_number,
+                "receiver" => [
+                    "address" => $order->address,
+                    "city" => $order->city,
+                    "county" => $order->district,
+                    "name" => $order->consignee_name,
+                    "phone" => $order->consignee_phone,
+                    "province" => $order->province
+                ],
+                "sender" => $sender
+            ];
+        }
+        $json_body = json_encode($body, JSON_UNESCAPED_UNICODE);
+        $sign = md5($json_body . '_' . $this->app_secret);
+        $headers = [
+            'app-key' => $this->app_key,
+            'sign' => $sign,
+            'req-time' => now()->timestamp,
+            "Content-Type" => "application/json"
+        ];
+        $response = Http::withHeaders($headers)->withBody($json_body, 'application/json')->post($this->url);
+        return json_decode($response);
+    }
+
+    public function query($logistic_number)
+    {
+        $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
+        ];
+        $sign = md5(json_encode($body, JSON_UNESCAPED_UNICODE) . '_' . $this->app_secret);
+        $headers = [
+            'app-key' => $this->app_key,
+            'sign' => $sign,
+            'req-time' => now()->timestamp,
+            "Content-Type" => "application/json"
+        ];
+        $response = Http::withHeaders($headers)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json')->post($this->url);
+        return json_decode($response->body());
+    }
+
+    public function format($nativeResponse)
+    {
+        if ($nativeResponse->code != '0000' || $nativeResponse->data->result=="false") {
+            return [];
+        } else {
+            $nativeData = $nativeResponse->data;
+            try {
+                $result['logistic_number'] = $nativeData->mailno;
+            } catch (\Exception $e) {
+                LogService::log(LogisticYDService::class, "YD快递信息异常", $nativeResponse);
+                return [];
+            }
+            $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);
+                $result['routes_length'] = array_key_exists('transfer_status', $result) ? count($result['transfer_status']) : 0;
+                $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+                $exceptionData = $orderPackageReceivedSyncService->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 $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;
+    }
+}

+ 126 - 0
app/Services/LogisticYTOService.php

@@ -0,0 +1,126 @@
+<?php
+
+namespace App\Services;
+
+use App\OrderPackage;
+use App\Traits\ServiceAppAop;
+use Carbon\Carbon;
+use Doctrine\DBAL\Connection;
+use Illuminate\Support\Facades\Http;
+
+class LogisticYTOService
+{
+    use ServiceAppAop;
+
+
+    public function query($logistic_number)
+    {
+        $app_key = config('api_logistic.YTO.prod.app-key');
+        $app_secret = config('api_logistic.YTO.prod.app-secret');
+        $user_id = config('api_logistic.YTO.prod.user_id');
+        $method = config('api_logistic.YTO.prod.method');
+        $format = config('api_logistic.YTO.prod.format');
+        $v = config('api_logistic.YTO.prod.v');
+        $url = config('api_logistic.YTO.prod.search.url');
+        $body = [
+            "Number" => $logistic_number
+        ];
+        $secret=$app_secret.'app_key'.$app_key.'format'.$format.'method'.$method.'timestamp'.Carbon::now()->toDateTimeString().'user_id'.$user_id.'v'.$v;
+        $sign = strtoupper(md5($secret));
+        $headers = [
+            'sign' => $sign,
+            'app_key' => $app_key,
+            'format' => $format,
+            'method' => $method,
+            'timestamp' => Carbon::now()->toDateTimeString(),
+            'user_id' => $user_id,
+            'v' => $v,
+            'param'=>json_encode($body, JSON_UNESCAPED_UNICODE)
+        ];
+
+        $response = Http::asForm()->post($url,$headers);
+        return json_decode($response->body());
+    }
+
+    public function format($response): array
+    {
+        $result = [];
+        if (is_object($response) && $response->code=='1001') {return [];}
+        else {
+            try {
+                $result['logistic_number'] = $response[0]->waybill_No;
+            } catch (\Exception $e) {
+                LogService::log(LogisticYTOService::class, "YTO快递信息异常", $response);
+            }
+            if (!empty($response)) {
+                $lastNativeRoute = $response[count($response) - 1];
+                $result['status'] = $this->getStatus($lastNativeRoute);
+                if ($result['status'] == '已收件') $result['received_at'] = $lastNativeRoute->upload_Time;
+                $result['transfer_status'] = $this->getTransferStatus($response);
+                $result['routes_length'] = array_key_exists('transfer_status', $result) ? count($result['transfer_status']) : 0;
+                $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+                $exceptionData = $orderPackageReceivedSyncService->setExceptionType($result, $lastNativeRoute ? $lastNativeRoute->upload_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 $nativeData
+     * @return string
+     */
+    private function getStatus($nativeData): string
+    {
+        $status = null;
+        switch ($nativeData->infoContent) {
+            case 'ARRIVAL':
+            case 'GOT':
+                $status = '已揽收';
+                break;
+            case 'DEPARTURE':
+            case 'PACKAGE':
+                $status = '在途';
+                break;
+            case 'SENT_SCAN':
+            case 'INBOUND':
+                $status = '派送中';
+                break;
+            case 'SIGNED':
+                $status = '已收件';
+                break;
+            case 'TMS_RETURN':
+                $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->upload_Time;
+            $item['accept_address'] = $nativeRoute->processInfo;
+            $item['remark'] = "";
+            $transferStatus[] = $item;
+        }
+        return $transferStatus;
+    }
+}

+ 12 - 10
app/Services/OracleDocWaveDetailService.php

@@ -25,9 +25,9 @@ class OracleDocWaveDetailService
             $waveNos = array_values(array_diff(data_get($items, '*.waveno'),['*']));
             try {
                 OracleDOCWaveDetails::query()->whereIn('OrderNo', $clearOrderNos)->whereIn('WaveNo', $waveNos)->delete();
-                app('LogService')->log(__CLASS__, __METHOD__, 'Delete OracleDOCWaveDetails' . '  ' . json_encode($clearOrderNos).json_encode($waveNos));
+                app('LogService')->log(__CLASS__, __FUNCTION__, 'Delete OracleDOCWaveDetails' . '  ' . json_encode($clearOrderNos).json_encode($waveNos));
             } catch (Exception $e) {
-                app('LogService')->log(__CLASS__, __METHOD__,'Error clearCancelledOrder'.json_encode($clearOrderNos).json_encode($waveNos));
+                app('LogService')->log(__CLASS__, __FUNCTION__,'Error clearCancelledOrder'.json_encode($clearOrderNos).json_encode($waveNos));
             }
         });
     }
@@ -92,36 +92,38 @@ class OracleDocWaveDetailService
         $start_time = Carbon::now();
 
         if (isset($last_start_at) && empty($last_end_at) && $start_time->diffInMinutes(Carbon::parse($last_start_at)) < $restart) return;
+
         if (isset($last_start_at) && isset($last_end_at)
             && Carbon::parse($last_end_at)->lt(Carbon::parse($last_start_at))
             && $start_time->diffInMinutes(Carbon::parse($last_start_at)) < $restart)
             return;
 
         $orderHeaders = OracleDOCOrderHeader::query()
-            ->selectRaw('orderno,waveno,editTime')
-            ->where('EDITTIME', '>', Carbon::parse($sync_at))
-            ->where('ERPCANCELFLAG', 'Y')
-            ->orderByDesc('editTime')->get();
-        $orderHeaderList = $orderHeaders->chunk(3000);
+            ->selectRaw('orderno,waveno,edittime,erpcancelflag')
+            ->where('EditTime', '>', Carbon::parse($sync_at))
+            ->where('WaveNo','!=','*')
+            ->where('ERPCancelFLAG', 'Y')
+            ->orderByDesc('EditTime')->get();
+        $orderHeaderList = $orderHeaders->chunk(50);
         $update_at = Carbon::now();
         if(count($orderHeaders)>0){
             foreach ($orderHeaderList as $items) {
                 $this->clearCancelledOrder($items);
                 if ($items->count() > 0) {
                     OracleDOCOrderHeader::query()
-                        ->whereIn('orderNo', data_get($items, '*.orderno'))
+                        ->whereIn('orderno', data_get($items, '*.orderno'))
                         ->whereIn('waveno', data_get($items, '*.waveno'))
                         ->update(['waveno' => '*','editTime' =>$update_at]);
                     $json = json_encode($items->map(function ($orderHeader) {
                         return ['orderno' => $orderHeader->orderno, 'waveno' => $orderHeader->waveno];
                     }));
-                    app('LogService')->log(__CLASS__, __METHOD__, 'update OrderHeader' . '  ' . $json);
+                    app('LogService')->log(__CLASS__, __FUNCTION__, 'update OrderHeader' . '  ' . $json);
                     $this->disposeOrderBatchId(data_get($items, '*.orderno'));
                 }
             }
         }
         $end_time = (string)Carbon::now();
-        $sync_at = $orderHeaders->first()->editTime ?? $sync_at;
+        $sync_at = $orderHeaders->first()->edittime ?? $sync_at;
         $this->setSyncAt($sync_at);
         $this->setSyncStartAt((string)$start_time);
         $this->setSyncEndAt($end_time);

+ 71 - 0
app/Services/OrderPackageExceptionTypeCountingRecordService.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace App\Services;
+
+use App\Traits\ServiceAppAop;
+use App\OrderPackageExceptionTypeCountingRecord;
+use Carbon\Carbon;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\DB;
+
+class OrderPackageExceptionTypeCountingRecordService
+{
+    use ServiceAppAop;
+
+    protected $modelClass = OrderPackageExceptionTypeCountingRecord::class;
+
+    /**
+     * 同步当前日期多少天前数据
+     */
+    public function updateOrCreate($days)
+    {
+        DB::table("order_packages")
+            ->select(['exception_type',
+                DB::raw('count( * ) AS exception_type_count'),
+                DB::raw("DATE_FORMAT( sent_at, '%Y-%m-%d' ) AS sent_at_date "),
+                'owner_id',
+            ])
+            ->where('sent_at', '>=', now()->subDays($days)->startOfDay())
+            ->whereNotNull(['owner_id', 'sent_at'])
+            ->where('exception_type','!=','无')
+            ->groupBy(['exception_type',
+                'sent_at_date',
+                'owner_id'])->orderBy('sent_at_date')->chunk(1000, function ($items) {
+                foreach ($items as $item) {
+                    OrderPackageExceptionTypeCountingRecord::query()->updateOrCreate((array)$item);
+                }
+            });
+    }
+
+    public function updateOrCreateByDate($date)
+    {
+        DB::table("order_packages")
+            ->select(['exception_type',
+                DB::raw('count( * ) AS exception_type_count'),
+                DB::raw("DATE_FORMAT( sent_at, '%Y-%m-%d' ) AS sent_at_date "),
+                'owner_id',
+            ])
+            ->where('sent_at', '>=', Carbon::parse($date)->startOfDay())
+            ->where('sent_at', '<=', Carbon::parse($date)->endOfDay())
+            ->whereNotNull(['owner_id', 'sent_at'])
+            ->where('exception_type','!=','无')
+            ->groupBy(['exception_type',
+                'sent_at_date',
+                'owner_id'])->orderBy('sent_at_date')->chunk(1000, function ($items) {
+                foreach ($items as $item) {
+                    OrderPackageExceptionTypeCountingRecord::query()->updateOrCreate((array)$item);
+                }
+            });
+    }
+
+    public function get(array $kvPairs): ?Collection
+    {
+        return OrderPackageExceptionTypeCountingRecord::query()
+            ->select(['exception_type', DB::raw('sum(exception_type_count) as count')])
+            ->where('sent_at_date', '>=', Carbon::parse($kvPairs['start_date'])->startOfDay())
+            ->where('sent_at_date', '<=', Carbon::parse($kvPairs['end_date'])->endOfDay())
+            ->where('exception_type','!=','无')
+            ->whereIn('owner_id', $kvPairs['owner_ids'])
+            ->groupBy('exception_type')->get();
+    }
+}

+ 224 - 32
app/Services/OrderPackageReceivedSyncService.php

@@ -4,6 +4,9 @@
 namespace App\Services;
 
 
+use App\Jobs\LogisticSFSync;
+use App\Jobs\LogisticYDSync;
+use App\Jobs\LogisticYTOSync;
 use App\Jobs\LogisticZopSync;
 use App\OrderPackage;
 use Carbon\Carbon;
@@ -23,13 +26,58 @@ class OrderPackageReceivedSyncService
      */
     public function syncLogisticRoute()
     {
-        $logisticNumbers = $this->getLogisticNumbers();
-        $this->update($this->getLogisticRoutes($logisticNumbers));
-        //更新中通
-        $ZTOLogisticNumbers = $logisticNumbers['ZTO'];
-        foreach ($ZTOLogisticNumbers as $logisticNumber) {
-            LogisticZopSync::dispatch($logisticNumber);
+        LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法", '');
+        ini_set('max_execution_time', 60 * 60);
+        //初始化时间 2020-12-31 23:59:59
+        $initDate = Carbon::parse(config('api_logistic.init_date'));
+        $query = OrderPackage::query()
+            ->select(['logistic_number', 'order_id'])
+            ->with(['order' => function ($query) {
+                return $query->with('logistic');
+            }]);
+        if (Carbon::now()->lte($initDate)) {//当前时间小于等于初始化时间
+            //初始化查询一个月的数据,exception为否
+            $query = $query->where('sent_at', '>=', $initDate->subDays((int)config('api_logistic.days'))->toDateTimeString())
+                ->whereNull('received_at');
+        } else {//查询20天以内的数据
+            $query = $query->where('sent_at', '>=', now()->subDays(20))
+                ->whereNull('received_at');
         }
+        $query->chunk(2000, function ($orderPackages) {
+            $logisticNumbers = $this->buildData($orderPackages);
+            //sf
+            if (array_key_exists('SF', $logisticNumbers)) {
+                $SFLogisticNumbers = $logisticNumbers['SF'];
+                LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-SF", '');
+                foreach ($SFLogisticNumbers as $logisticNumber) {
+                    LogisticSFSync::dispatch($logisticNumber);
+                }
+            }
+            //更新中通
+            if (array_key_exists('ZTO', $logisticNumbers)) {
+                $ZTOLogisticNumbers = $logisticNumbers['ZTO'];
+                LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-ZTO", '');
+                foreach ($ZTOLogisticNumbers as $logisticNumber) {
+                    LogisticZopSync::dispatch($logisticNumber);
+                }
+            }
+            //更新韵达
+            if (array_key_exists('YUNDA', $logisticNumbers)) {
+                $YDLogisticNumbers = $logisticNumbers['YUNDA'];
+                LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-YUNDA", '');
+                foreach ($YDLogisticNumbers as $logistic_number) {
+                    LogisticYDSync::dispatch($logistic_number);
+                }
+            }
+            //更新圆通
+            if (array_key_exists('YTO', $logisticNumbers)) {
+                $YTOLogisticNumbers = $logisticNumbers['YTO'];
+                LogService::log(OrderPackageReceivedSyncService::class, "同步快递信息定时方法-YTO", '');
+                foreach ($YTOLogisticNumbers as $logistic_number) {
+                    LogisticYTOSync::dispatch($logistic_number);
+                }
+            }
+        });
     }
 
     /**
@@ -85,6 +133,7 @@ class OrderPackageReceivedSyncService
     public function update(array $orderPackages)
     {
         foreach ($orderPackages as $data) {
+            if (empty($data)) continue;
             $orderPackage = OrderPackage::query()->where('logistic_number', $data['logistic_number'])->first();
             if (isset($data['status'])) $orderPackage->status = $data['status'];
             if (isset($data['received_at'])) $orderPackage->received_at = $data['received_at'];
@@ -95,39 +144,15 @@ class OrderPackageReceivedSyncService
         }
     }
 
-    /**
-     * 查询当前日期前的快递单号并按照承运商分类
-     */
-    public function getLogisticNumbers(): array
-    {
-        //初始化时间 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', '否')
-                ->whereNull('received_at');
-        } else {//当前时间大于初始化时间,exception为否且未收货
-            $query = $query->where('created_at', '>=', $initDate->toDateTimeString())
-//                ->where('exception', '否')
-                ->whereNull('received_at');
-        }
-        return $this->buildData($query->get(), $data);
-    }
 
     /**
      * 将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;
@@ -142,4 +167,171 @@ class OrderPackageReceivedSyncService
         }
         return $data;
     }
+
+
+    /**
+     * @param array $data
+     * @param $lastRouteDate
+     * @return array
+     */
+    public 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;
+        $HAVEN_SECOND_GOT_HOURS = 24;
+        $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 派送异常
+        $IS_SECOND_ROUTE_HAVE = 256;     //0100 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, $HAVEN_SECOND_GOT_HOURS, $IS_SECOND_ROUTE_HAVE,
+            $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;
+            $conclusion |= ($delivered_duration > $HAVEN_SECOND_GOT_HOURS && $data['routes_length'] < 2) ? $IS_SECOND_ROUTE_HAVE : 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'] = '派件异常';
+        }
+        if ($conclusion
+            == ($conclusion | $IS_SECOND_ROUTE_HAVE)) {
+            $data['exception_type'] = '派件异常';
+            $data['exception'] = '是';
+
+        }
+        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,
+        ];
+    }
 }

+ 3 - 3
app/Services/OwnerPriceExpressService.php

@@ -225,9 +225,9 @@ class OwnerPriceExpressService
     {
         return app(CacheService::class)->getOrExecute("logistics_owner_".$owner,function ()use($owner){
             $query = DB::raw(<<<sql
-    SELECT logistic_id FROM `owner_price_express_owner` e 
-    LEFT JOIN owner_price_express_logistic l 
-    ON e.owner_price_express_id = l.owner_price_express_id 
+    SELECT logistic_id FROM `owner_price_express_owner` e
+    LEFT JOIN owner_price_express_logistic l
+    ON e.owner_price_express_id = l.owner_price_express_id
     WHERE e.owner_id = ?
 sql
             );

+ 2 - 2
app/Services/PackageStatisticsService.php

@@ -26,8 +26,8 @@ class PackageStatisticsService
                 ->selectRaw('orders.owner_id,logistic_id');
 
         $columnQueryRules=[
-            'created_at_start' => ['alias' => 'created_at','startDate' => ":00"],
-            'created_at_end' => ['alias' => 'created_at','endDate' => ":59"],
+            'created_at_start' => ['alias' => 'weighed_at','startDate' => ":00"],
+            'created_at_end' => ['alias' => 'weighed_at','endDate' => ":59"],
             'logistic_id' => ['multi' => ','],
             'owner_id' => ['multi' => ','],
         ];

+ 1 - 1
app/Services/ProvinceService.php

@@ -21,7 +21,7 @@ class ProvinceService
         if(isset($province))return $province;
 
         foreach (ProvinceService::$provinces as $province) {
-            if(strstr($province,$name) != null){
+            if(strstr($province,$name) != null || strstr($name,$province) != null){
                 return Province::query()->where('name',$province)->first();
             }
         }

+ 16 - 2
app/Services/StationTaskMaterialBoxService.php

@@ -150,6 +150,7 @@ class StationTaskMaterialBoxService
         $this->instant($this->stationTaskCommodityService,'StationTaskCommodityService');
         $this->instant($this->stationTaskService,'StationTaskService');
         $this->instant($this->stationService,'StationService');
+        $this->instant($this->cacheShelfService,'CacheShelfService');
         try{
             LogService::log('海柔请求','markHasTaken1','');
             $taskType=$this->getServingTaskType($stationTaskMaterialBox);
@@ -164,14 +165,22 @@ class StationTaskMaterialBoxService
                     /** @var StationTask $stationTask */
                     $stationTask = $this->stationTaskService->getProcessing();
                     $this->stationService->broadcastBinMonitor($stationTaskMaterialBox['station_id'], $stationTask);
+                    $stationTaskMaterialBox->materialBox['status']='在U型线';
+                    $stationTaskMaterialBox->materialBox->update();
                     break;
                 case '入立库':
                     $this->set($stationTaskMaterialBox,[
                         'id' => $stationTaskMaterialBox['station_id'],
                         'status' => '完成',
                     ]);
+                    $this->cacheShelfService->putStationTaskMaterialBoxProcess($stationTaskMaterialBox);
+                    $stationTaskMaterialBox->materialBox['status']='在立库';
+                    $stationTaskMaterialBox->materialBox->update();
+                    break;
+                case '入缓存架':
+                    $stationTaskMaterialBox->materialBox['status']='在缓存架';
+                    $stationTaskMaterialBox->materialBox->update();
                     break;
-                case '入缓存架':break;
                 default:;
             }
         }catch (\Exception $e){
@@ -210,7 +219,7 @@ class StationTaskMaterialBoxService
 
     function markProcessed(StationTaskMaterialBox $stationTaskMaterialBox){
         $stationTaskMaterialBox['status'] = '完成';
-        $stationTaskMaterialBox->update();
+        $stationTaskMaterialBox->save();
     }
     function getNotProcessedSiblings($stationTaskMaterialBox){
         return StationTaskMaterialBox::query()
@@ -314,6 +323,11 @@ class StationTaskMaterialBoxService
         ){
             return '入立库';
         }
+        if($isCacheShelf=(
+            $stationTaskMaterialBox['station']['stationType']['name'] == '缓存架')
+        ){
+            return '入缓存架';
+        }
 //        if($isStoring=false){
 //            return '入库';
 //        }

+ 34 - 1
app/Services/WaybillService.php

@@ -3,10 +3,12 @@
 namespace App\Services;
 
 use App\OwnerFeeDetail;
+use App\Services\common\BatchUpdateService;
 use App\Services\common\QueryService;
 use App\Traits\ModelSearchWay;
 use App\Waybill;
 use App\WaybillAuditLog;
+use Carbon\Carbon;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
@@ -26,7 +28,7 @@ class WaybillService
      */
     private function conditionQuery(array $param){
         $waybills = Waybill::filterAuthorities()->with(['owner','logistic','originationCity','destinationCity.parent',
-            'uploadFile','amountUnit','warehouseWeightUnit','carrierWeightUnit','district',
+            'uploadFile','amountUnit','warehouseWeightUnit','carrierWeightUnit','district','order',
             'warehouseWeightUnitOther','carrierWeightUnitOther','carType','uploadFile','waybillAuditLogs.user'])
             ->selectRaw('waybills.* ,waybill_on_tops.id top_id ,waybill_on_tops.remark,waybill_on_tops.updated_at top_update')
             ->leftJoin('waybill_on_tops','waybill_on_tops.waybill_id','=','waybills.id')
@@ -150,6 +152,37 @@ class WaybillService
         $waybills = $this->conditionQuery($param);
         return $waybills->get();
     }
+    public function dailyBilling(array $param){
+        $waybills = Waybill::query()->with(['owner','logistic','originationCity','destinationCity.parent',
+            'uploadFile','amountUnit','warehouseWeightUnit','carrierWeightUnit','district','order',
+            'warehouseWeightUnitOther','carrierWeightUnitOther','carType','uploadFile','waybillAuditLogs.user'])
+            ->selectRaw('waybills.* ,waybill_on_tops.id top_id,waybill_on_tops.remark,waybill_on_tops.updated_at top_update')
+            ->leftJoin('waybill_on_tops','waybill_on_tops.waybill_id','=','waybills.id')
+            ->whereNull('waybill_on_tops.deleted_at')
+            ->orderBy('waybill_on_tops.updated_at','desc')
+            ->orderBy('waybills.id','desc')
+            ->where('waybills.created_at','like',$param['screenDate'].'%')
+            ->where('waybills.type','专线')
+            ->whereNotNull('waybills.deliver_at')
+            ->get();
+        foreach ($waybills as $waybill){
+            if (!$waybill['carrier_weight_other'] && !$waybill['carrier_weight']) return null;
+            if (!$waybill['carrier_weight_other']) $waybill['carrier_weight_other']=($waybill['carrier_weight']/0.4);
+        }
+        $daily_total_weight=$waybills->sum('carrier_weight_other');
+        $updateParams = [['id','pick_up_fee','updated_at']];
+        foreach ($waybills as $waybill){
+            $waybill['pick_up_fee']=round(($waybill->carrier_weight_other/$daily_total_weight)*$param['billing']);
+            $updateParams[] = [
+                'id' => $waybill->id,
+                'pick_up_fee' => (($waybill->carrier_weight_other/$daily_total_weight)*$param['billing']),
+                'updated_at' => Carbon::now()->toDateTimeString(),
+            ];
+        }
+        if (count($updateParams)>0)app(BatchUpdateService::class)->batchUpdate('waybills', $updateParams);
+        return $waybills;
+
+    }
 
     public function store(Request $request){
         return DB::transaction(function ()use($request){

+ 5 - 0
app/StationRuleBatch.php

@@ -18,4 +18,9 @@ class StationRuleBatch extends Model
     {
         return $this->belongsTo(StationType::class);
     }
+
+    public function owner() :BelongsTo
+    {
+        return $this->belongsTo(Owner::class);
+    }
 }

+ 10 - 11
app/library/zop/ZopClient.php

@@ -3,6 +3,7 @@
 
 namespace App\library\zop;
 use App\library\zop\ZopHttpUtil;
+use Illuminate\Support\Facades\Http;
 
 class ZopClient
 {
@@ -40,22 +41,20 @@ class ZopClient
             $data_digest = base64_encode(md5($str_to_digest, TRUE));
             $headers = array(
                 "Content-Type: application/x-www-form-urlencoded; charset=UTF-8",
-                "x-companyid: " .$this->zopProperties->getCompanyid(),
-                "x-datadigest: " .$data_digest
+                "x-companyid: " . $this->zopProperties->getCompanyid(),
+                "x-datadigest: " . $data_digest
             );
             return $this->httpClient->post($url, $headers, http_build_query($fixedParams), 2000);
-        } else{
+        } else {
             $url = $zopRequest->getUrl();
             $body = $zopRequest->getBody();
-            $str_to_digest = $body.$this->zopProperties->getKey();
+            $str_to_digest = $body . $this->zopProperties->getKey();
             $data_digest = base64_encode(md5($str_to_digest, TRUE));
-            $headers = array(
-                "Content-Type: application/json; charset=UTF-8",
-                "x-companyid: ".$this->zopProperties->getCompanyid(),
-                "x-datadigest: ".$data_digest
-            );
-            return $this->httpClient->post($url, $headers, $body, 2000);
-
+            return Http::withHeaders([
+                'Content-Type' => 'application/json; charset=UTF-8',
+                'x-companyid' => $this->zopProperties->getCompanyid(),
+                'x-datadigest' => $data_digest,
+            ])->withBody(json_encode((array)json_decode($body), JSON_UNESCAPED_UNICODE), 'application/json')->post($url)->body();
         }
     }
 }

+ 53 - 7
config/api_logistic.php

@@ -1,6 +1,6 @@
 <?php
 return [
-    'logistic'=>[
+    'logistic' => [
         'ZTO' => 'ZTO',
         'SF' => 'SF',
         'YUNDA' => 'YUNDA',
@@ -77,9 +77,9 @@ return [
     ],
     //丰桥
     'SF' => [
-        'url' =>  'https://bspsw.sf-express.com/sfexpressService',
-        'head' =>  'BSGYLGL',
-        'check_word' =>  'DcauTQEavq5qqpFaYmltzR7gzVCTjvtz',
+        'url' => 'https://bspsw.sf-express.com/sfexpressService',
+        'head' => 'BSGYLGL',
+        'check_word' => 'DcauTQEavq5qqpFaYmltzR7gzVCTjvtz',
         'max_size' => 10,
         'op_code_map' => [
             30 => '快件在【XXX营业点】已装车,准备发往 【XXX集散中心】',
@@ -102,10 +102,56 @@ return [
     ],
     //中通 https://op.zto.cn/#/Console?type=API
     'ZTO' => [
-        'url' =>  'https://japi.zto.com/zto.open.getRouteInfo',
+        'url' => 'https://japi.zto.com/zto.open.getRouteInfo',
         'x-appKey' => 'c51c718eb899e9f706979',
         'appSecret' => '9f664e3ab08049874aa417720840161a',
     ],
-    'init_date' => '2021-04-14 23:59:59',
-    'days' => 4,
+    'YD' => [
+        'test' => [
+            'app-key' => '999999',
+            'app-secret' => '04d4ad40eeec11e9bad2d962f53dda9d',
+            'search' => [
+                'url' => 'https://u-openapi.yundasys.com/openapi/outer/logictis/query',
+            ],
+            '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',
+            ],
+        ]
+    ],
+    'YTO' => [
+        'test' => [
+            'app-key' => 'sF1Jzn',
+            'app-secret' => '1QLlIZ',
+            'user_id' => 'YTOTEST',
+            'method' => 'yto.Marketing.WaybillTrace',
+            'format' => 'JSON',
+            'v' => '1.01',
+            'search' => [
+                'url' => 'http://opentestapi.yto.net.cn/service/waybill_query/v1/gy6h76',
+            ],
+        ],
+        'prod' => [
+            'app-key' => 'CWJVR1',
+            'app-secret' => 'ii3xrv',
+            'user_id' => 'gy6h76',
+            'method' => 'yto.Marketing.WaybillTrace',
+            'format' => 'JSON',
+            'v' => '1.01',
+            'search' => [
+                'url' => 'http://openapi.yto.net.cn/service/waybill_query/v1/gy6h76',
+            ],
+        ],
+    ],
+    'init_date' => '2021-05-17 23:59:59',
+    'days' => 2,
 ];

+ 1 - 1
database/factories/OracleBasCustomerFactory.php

@@ -9,6 +9,6 @@ $factory->define(OracleBasCustomer::class, function (Faker $faker) {
     return [
         'customer_type'=> $faker->uuid,
         'customerid'=> $faker->uuid,
-        'descr_c'=> $faker->name
+        'descr_c'=> $faker->name,
     ];
 });

+ 12 - 0
database/factories/OrderPackageExceptionTypeCountingRecordFactory.php

@@ -0,0 +1,12 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OrderPackageExceptionTypeCountingRecord;
+use Faker\Generator as Faker;
+
+$factory->define(OrderPackageExceptionTypeCountingRecord::class, function (Faker $faker) {
+    return [
+        //
+    ];
+});

+ 24 - 1
database/factories/OrderPackageFactory.php

@@ -2,11 +2,34 @@
 
 /** @var \Illuminate\Database\Eloquent\Factory $factory */
 
+use App\Order;
 use App\OrderPackage;
 use Faker\Generator as Faker;
 
 $factory->define(OrderPackage::class, function (Faker $faker) {
+    $statuses = ['无', '已称重', '已揽收', '在途', '在途异常', '派送中', '派送异常', '返回中', '返回异常', '返回派件', '其他异常', '已收件',];
+    $exceptions = ['是', '否'];
+    $exception_types = ['疑似库内丢件','揽件异常','中转异常','疑似丢件','派件异常','其他','无'];
     return [
-        'logistic_number' => $faker->uuid
+        'logistic_number' => $faker->uuid,
+        'order_id' => random_int(1, 10000),
+        'batch_number' => random_int(1, 100),
+        'batch_rule' => null,
+        'bulk' => null,
+        'weight' => null,
+        'height' => null,
+        'paper_box_id' => random_int(1, 100),
+        'measuring_machine_id' => random_int(1, 100),
+        'weighed_at' => now()->subHours(3),
+        'status' => $faker->randomElement($statuses),
+        'sent_at' => now()->subHours(1),
+        'received_at' => null,
+        'exception' => $faker->randomElement($exceptions),
+        'transfer_status' => null,
+        'remark' => null,
+        'owner_id' => random_int(1, 100),
+        'uploaded_to_wms' => '是',
+        'exception_message' => $faker->name,
+        'exception_type' => $faker->randomElement($exception_types),
     ];
 });

+ 1 - 1
database/factories/OwnerBillReportFactory.php

@@ -11,7 +11,7 @@ $factory->define(OwnerBillReport::class, function (Faker $faker) {
     return [
         "owner_id" => factory(\App\Owner::class),       //项目ID
         "counting_month" => $faker->date(), //结算月
-        "initial_fee" => $initial_fee,    //原始账单金额
+//        "initial_fee" => $initial_fee,    //原始账单金额
         "confirm_fee" => $confirm_fee,    //确认账单金额
         "difference" => $confirm_fee - $initial_fee,     //差额
         "confirmed" => "否",      //确认状态

+ 0 - 1
database/factories/OwnerReportFactory.php

@@ -14,6 +14,5 @@ $factory->define(OwnerReport::class, function (Faker $faker)use($owner) {
         "current_month_counting_area" => mt_rand(100,100000) / 50,  //结算月盘点面积
         "last_month_counting_area"   => mt_rand(100,100000) / 50,  //结算月上月盘点面积
         "owner_bill_report_id"  =>factory(App\OwnerBillReport::class),        //账单ID
-        "total" => mt_rand(1,2000),
     ];
 });

+ 13 - 0
database/factories/TaxRateFactory.php

@@ -0,0 +1,13 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\Model;
+use App\TaxRate;
+use Faker\Generator as Faker;
+
+$factory->define(TaxRate::class, function (Faker $faker) {
+    return [
+
+    ];
+});

+ 3 - 1
database/factories/WarehouseFactory.php

@@ -8,6 +8,8 @@ use Faker\Generator as Faker;
 $factory->define(Warehouse::class, function (Faker $faker) {
     return [
         'name' => $faker->name,
-        'code' => $faker->uuid
+        'code' => $faker->uuid,
+        'production_capacity'=> round(2),
+        'reduced_production_capacity_coefficient'=> round(2),
     ];
 });

+ 32 - 0
database/migrations/2021_05_07_141019_add_index_exception_type_sent_at_owner_id_order_packages_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddIndexExceptionTypeSentAtOwnerIdOrderPackagesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->index(['sent_at', 'exception_type', 'owner_id']);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->dropIndex(['sent_at', 'exception_type', 'owner_id']);
+        });
+    }
+}

+ 35 - 0
database/migrations/2021_05_07_141912_create_order_package_exception_type_counting_records_table.php

@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOrderPackageExceptionTypeCountingRecordsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('order_package_exception_type_counting_records', function (Blueprint $table) {
+            $table->id();
+            $table->date("sent_at_date")->comment("发出日期");
+            $table->string('exception_type')->comment('异常名称');
+            $table->integer('exception_type_count')->comment('异常类型的统计数量');
+            $table->unsignedBigInteger('owner_id')->comment('货主ID');
+            $table->index(['sent_at_date', 'exception_type_count', 'owner_id'],'order_packages_s_et_o_index');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('order_package_exception_type_counting_records');
+    }
+}

+ 35 - 0
database/migrations/2021_05_18_093618_add_authorities_wabill.php

@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddAuthoritiesWabill extends Migration
+{
+    protected $authorities = [
+        "运输管理-运单-按日计算专线费",
+    ];
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        foreach ($this->authorities as $authority){
+            \App\Authority::query()->firstOrCreate(["name"=>$authority],["name"=>$authority,"alias_name"=>$authority]);
+        }
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        foreach ($this->authorities as $authority){
+            \App\Authority::query()->where("name",$authority)->delete();
+        }
+    }
+}

+ 30 - 0
database/migrations/2021_05_18_151348_add_authority_order_package_remark.php

@@ -0,0 +1,30 @@
+<?php
+
+use App\Authority;
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddAuthorityOrderPackageRemark extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Authority::query()->firstOrCreate(["name" => "包裹管理-快递-客服备注"],["alias_name"=>"包裹管理-快递-客服备注"]);
+
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Authority::query()->where('name', '包裹管理-快递-客服备注')->delete();
+    }
+}

+ 38 - 0
database/migrations/2021_05_19_171047_add_station_rule_batch_author.php

@@ -0,0 +1,38 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddStationRuleBatchAuthor extends Migration
+{
+    public $names = [
+        '站管理-站规则',
+        '站管理-站规则-编辑',
+        '站管理-站规则-创建',
+        '站管理-站规则-删除',
+    ];
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        foreach ($this->names as $item) {
+            \App\Authority::query()->firstOrCreate(['name' => $item],['alias_name' => $item]);
+        }
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        foreach ($this->names as $item) {
+            \App\Authority::query()->where('name' , $item)->delete();
+        }
+    }
+}

+ 32 - 0
database/migrations/2021_05_19_173442_add_materialBoxes_field_status.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddMaterialBoxesFieldStatus extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('material_boxes', function (Blueprint $table) {
+            $table->tinyInteger('status')->nullable()->index('material_boxes_i_status');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('material_boxes', function (Blueprint $table) {
+            $table->dropColumn('status');
+        });
+    }
+}

+ 16 - 0
database/seeds/OrderPackageExceptionTypeCountingRecordSeeder.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Database\Seeder;
+
+class OrderPackageExceptionTypeCountingRecordSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     *
+     * @return void
+     */
+    public function run()
+    {
+        //
+    }
+}

+ 1 - 0
database/seeds/StationRuleBatchSeeder.php

@@ -12,5 +12,6 @@ class StationRuleBatchSeeder extends Seeder
     public function run()
     {
         //
+        factory(\App\StationRuleBatch::class)->times(3)->create();
     }
 }

BIN
public/images/QRCodeIMG/1.png


+ 25 - 4
public/t.php

@@ -1,5 +1,26 @@
 <?php
-$codes=['sdf',33,'4'];
-$responseBody = 'sadfsdlfkj200,34324';
-$responseBody = strstr($responseBody,'200')?'取料箱'.implode(',',$codes).'成功':$responseBody;
-var_dump($responseBody);
+
+
+class Aa
+{
+    static public $enums=[
+        'status'=>[
+            '在库外'=>6,
+            '在U型线'=>1,
+            '在出库中'=>2,
+            '在入库中'=>3,
+            '在立库'=>4,
+            '异常'=>5,
+        ],
+    ];
+    function __construct(array $attributes = [])
+    {
+        foreach (self::$enums as &$enum) {
+            $enum=$enum+array_flip($enum);
+        }
+    }
+
+}
+
+$aa = new Aa();
+var_dump(Aa::$enums['status'][1]);

+ 3 - 3
resources/js/queryForm/queryForm.js

@@ -97,14 +97,14 @@ const query = function getQueryForm(data) {
     }
 
     function getToggleBtn(){
-        _toggle_btn = $("<button  type='button' class='btn btn-sm btn-success position-fixed' style='left:-5px;top:290px;z-index:10;width: 25px;'>展开</button>")
+        _toggle_btn = $("<button  type='button' class='btn btn-sm btn-success position-fixed' style='left:-5px;top:290px;z-index:10;width: 28px;'>展开筛选</button>")
         _toggle_btn.click(function(){
-            if(_toggle_btn.text() === "展开"){
+            if(_toggle_btn.text() === "展开筛选"){
                 _toggle_btn.text("收缩");
                 _table.removeClass("d-none")
                 _table.css("z-index",9);
             }else if(_toggle_btn.text() === "收缩"){
-                _toggle_btn.text("展开");
+                _toggle_btn.text("展开筛选");
                 _table.addClass("d-none")
             }
         });

+ 93 - 0
resources/views/control/panel.blade.php

@@ -364,7 +364,35 @@
                     </div>
                 </div>
                 @endcan
+                <div class="col-6">
+                    <div class="card">
+                        <div class="card-header">
+                            <div class="flex-column">
+                                <el-date-picker size="small" class="col-6 date" @blur="loadExceptionTypeInfo()"
+                                                type="daterange" align="right"
+                                                v-model="searchOption.exceptionTypeDate" unlink-panels range-separator="-"
+                                                start-placeholder="开始日期" end-placeholder="结束日期"
+                                                value-format="yyyy-MM-dd">
+                                </el-date-picker>
+                                <el-select class="col-3"  placeholder="请选择对应货主" multiple v-model="selectExceptionTypeOwners" size="small" style="width: 20%"  @change="loadExceptionTypeInfo()">
+                                    <el-option label="选择所有" value="all"></el-option>
+                                    <el-option v-for="item in owners" :label="item.name" :value="item.id" :key="item.id"></el-option>
+                                </el-select>
+                                <label class="col-3 ">
+                                    <select class="form-control rounded" v-model="searchOption.exceptionTypeSelect"
+                                            @change="switchExceptionTypeDate()">
+                                        <option v-for="(date,i) in dateOptions" :value="i">@{{ date.text }}</option>
+                                    </select>
+                                </label>
+                            </div>
+                        </div>
+                        <div class="card-body row">
+                            <div id="exceptionType" class="col-12" style="min-height: 500px"></div>
+                        </div>
+                    </div>
+                </div>
             </div>
+
         </div>
     </div>
 @endsection
@@ -380,6 +408,7 @@
                 owners:{!! $owners !!},
                 selectOrderOwners: [],
                 selectLogisticsOwners: [],
+                selectExceptionTypeOwners: [],
                 warehousesOrders:{!! $warehousesOrders !!},
                 orderCountingRecords:{},
                 logisticsCountingRecords:{},
@@ -481,7 +510,9 @@
                 cardPool:{},
                 searchOption:{
                     weightDate:[],
+                    exceptionTypeDate: [],
                     weightSelect:"",
+                    exceptionTypeSelect:"",
                 },
             },
             watch:{
@@ -506,7 +537,9 @@
                 $('#list').removeClass('d-none');
                 let index = 4;
                 this.searchOption.weightSelect = index;
+                this.searchOption.exceptionTypeSelect = index;
                 this.searchOption.weightDate = [this.dateOptions[index].start, this.dateOptions[index].end];
+                this.searchOption.exceptionTypeDate = [this.dateOptions[index].start, this.dateOptions[index].end];
                 let _this = this;
                 this.warehousesOrders.forEach(function (item) {
                     _this.totalOrders.total += parseInt(item.total);
@@ -543,6 +576,8 @@
                 this.cardPool.weight = echarts.init(document.getElementById("weight"));
                 this.loadWeightInfo();
                 @endcan
+                this.cardPool.exceptionType = echarts.init(document.getElementById("exceptionType"));
+                this.loadExceptionTypeInfo();
             },
             methods: {
                 switchDataPanel_forOrderCountingRecords(fromUnit, toUnit) {
@@ -898,11 +933,34 @@
                         this.cardPool.weight.setOption(this._setWeightData(res.title,res.data));
                     });
                 },
+                loadExceptionTypeInfo() {
+                    window.tempTip.setDuration(3000);
+                    if (!this.searchOption.exceptionTypeDate[0]){
+                        window.tempTip.show("开始时间未选择");
+                        return;
+                    }
+                    if (!this.searchOption.exceptionTypeDate[1]){
+                        window.tempTip.show("结束时间未选择");
+                        return;
+                    }
+                    this.cardPool.exceptionType.showLoading('default',{text:"加 载 中",color:'#C0C0C0'});
+                    let url = "{{url('apiLocal/control/panel/menu/exceptionTypeApi')}}";
+                    let params = {start:this.searchOption.exceptionTypeDate[0],end:this.searchOption.exceptionTypeDate[1],owner_ids:this.selectExceptionTypeOwners};
+                    window.tempTip.postBasicRequest(url,params,res=>{
+                        this.cardPool.exceptionType.hideLoading();
+                        this.cardPool.exceptionType.setOption(this._setExceptionTypeData(res.data));
+                    });
+                },
                 switchWeightDate(){
                     let obj = this.dateOptions[this.searchOption.weightSelect];
                     this.searchOption.weightDate = [obj.start,obj.end];
                     this.loadWeightInfo();
                 },
+                switchExceptionTypeDate(){
+                    let obj = this.dateOptions[this.searchOption.exceptionTypeSelect];
+                    this.searchOption.exceptionTypeDate = [obj.start,obj.end];
+                    this.loadExceptionTypeInfo();
+                },
                 _setWeightData(title, data){
                     return {
                         title: {
@@ -937,6 +995,41 @@
                         }]
                     };
                 },
+                _setExceptionTypeData(data) {
+                    let resData = [];
+                    data.forEach(item => {
+                        resData.push({
+                            value:item.count,
+                            name:item.exception_type
+                        })
+                    })
+                    return {
+                        title: {
+                            text: '异常分布',
+                            left: 'left'
+                        },
+                        tooltip: {
+                            trigger: 'item',
+                            formatter: '{a} <br/>{b} : {c} ({d}%)'
+                        },
+                        series: [
+                            {
+                                name: '异常分布',
+                                type: 'pie',
+                                radius: '55%',
+                                center: ['50%', '60%'],
+                                data: resData,
+                                emphasis: {
+                                    itemStyle: {
+                                        shadowBlur: 10,
+                                        shadowOffsetX: 0,
+                                        shadowColor: 'rgba(0, 0, 0, 0.5)'
+                                    }
+                                }
+                            }
+                        ]
+                    }
+                }
             }
         });
     </script>

+ 16 - 5
resources/views/inventory/stockInventory/mission.blade.php

@@ -34,9 +34,21 @@
         </form>
         </div>
         <div id="form_div" class="mt-2"></div>
+        <div class="row mt-2">
+        <span class="dropdown ml-3">
+        <button class="btn btn-outline-dark btn-sm form-control-sm dropdown-toggle tooltipTarget"
+                data-toggle="dropdown" title="导出所有页将会以搜索条件得到的筛选结果,将其全部记录(每一页)导出">
+            导出Excel
+        </button>
+        <div class="dropdown-menu">
+            <a class="dropdown-item" @click="inventoryExport(false)" href="javascript:">导出勾选内容</a>
+            <a class="dropdown-item" @click="inventoryExport(true)" href="javascript:">导出所有页</a>
+        </div>
+        </span>
+        </div>
         <div class=" pt-1">
             <table class="table table-sm text-nowrap table-striped table-bordered m-0 td-min-width-80" id="table">
-                <tr v-for="(inventory,i) in inventoryAccounts" @click="selectedColor(inventory.id,$event)" :style="{'font-weight': inventory.id==selectedStyle?'bold':''}">
+                <tr v-for="(inventory,i) in inventoryAccounts" @click="selectedColor(inventory.id,$event)" :style="{'font-weight': inventory.id===selectedStyle?'bold':''}" :class="selectedStyle === inventory.id ? 'focusing':''">
                     <td>
                         <input class="checkItem" type="checkbox" :value="inventory.id">
                     </td>
@@ -176,17 +188,16 @@
             methods:{
                 selectedColor(id,e){
                     $('#headerParent tr[class=focusing]').removeClass('focusing')
-                    if (id==this.selectedStyle){
+                    if (id===this.selectedStyle){
                         this.selectedStyle='';
                         return;
                     }
                     this.selectedStyle=id;
-                    $(e.target).parent('tr').addClass('focusing')
                 },
-                inventoryExport(checkAllSign){
+                inventoryExport(selectAll){
                     let url = '{{url('inventory/stockInventoryExport')}}';
                     let token='{{ csrf_token() }}';
-                    excelExport(checkAllSign,checkData,url,this.sum,token);
+                    excelExport(selectAll,checkData,url,this.sum,token);
                 },
                 //生成盘点任务
                 createInventoryMission(){

+ 2 - 2
resources/views/maintenance/owner/index.blade.php

@@ -56,8 +56,8 @@
             },
             mounted:function(){
                 let data = [
-                   [{name: 'code', type: 'input',tip:'货主编码:可在两侧添加百分号(%)进行模糊搜索',placeholder:'货主编码'},
-                   {name: 'name', type: 'input',tip:'货主名称:可在两侧添加百分号(%)进行模糊搜索',placeholder:'货主名称'}]
+                   [{name: 'code', type: 'input',tip:'可支持多货主编码,模糊搜索可在两侧添加百分号(%)进行',placeholder:'货主编码'},
+                   {name: 'name', type: 'input',tip:'可支持多货主名称,模糊搜索可在两侧添加百分号(%)进行',placeholder:'货主名称'}]
                 ];
                 this.from =new query({
                     el: '#form_div',

+ 2 - 1
resources/views/maintenance/role/index.blade.php

@@ -15,6 +15,7 @@
                 @endif
                 <table class="table table-striped table-sm td-min-width-80" id="table">
                     <tr v-for="(role,i) in roles"  @click="selectTr===i+1?selectTr=0:selectTr=i+1" :class="selectTr===i+1?'focusing' : ''">
+                        <td><input class="checkItem" type="checkbox" :value="role.id"></td>
                         <td class="text-muted"><span>@{{role.id}}</span></td>
                         <td><span>@{{role.name}}</span></td>
                         <td>
@@ -65,7 +66,7 @@
             },
             mounted:function(){
                 let data = [[
-                    {name:'role',type:'input',tip:'角色名:可在两侧添加百分号(%)进行模糊搜索',placeholder:'角色名'}]];
+                    {name:'role',type:'input',tip:'可支持角色名,模糊搜索可在两侧添加百分号(%)进行',placeholder:'角色名'}]];
                 this.form = new query({
                     el: '#form_div',
                     condition: data,

+ 1 - 1
resources/views/maintenance/tutorial/create.blade.php

@@ -1,7 +1,7 @@
 @extends('layouts.app')
 @section('title')录入-教程@endsection
 @section('head')
-    <link rel="stylesheet" type="text/css" href="{{mix('css/trix.css')}}">
+    <link rel="stylesheet" type="text/css" href="{{asset('css/trix.css')}}">
     <script type="text/javascript" src="{{mix('js/trix.js')}}"></script>
     <script>
 

+ 2 - 1
resources/views/maintenance/user/index.blade.php

@@ -16,6 +16,7 @@
                 <div id="list">
                     <table class="table table-striped table-sm td-min-width-80" id="table">
                         <tr v-for="(user,i) in users"  @click="selectTr===i+1?selectTr=0:selectTr=i+1" :class="selectTr===i+1?'focusing' : ''">
+                            <td><input class="checkItem" type="checkbox" :value="user.id"></td>
                             <td class="text-muted"><span>@{{user.id}}</span></td>
                             <td><span>@{{user.name}}</span></td>
                             <td>
@@ -74,7 +75,7 @@
             mounted:function(){
                 let data = [
                     [{name:'user',type:'input',tip:'用户名:可在两侧添加百分号(%)进行模糊搜索',placeholder:'用户名'},
-                    {name:'role',type:'input',tip:'角色名:可在两侧添加百分号(%)进行模糊搜索',placeholder:'角色名'},
+                    {name:'role',type:'input',tip:'可支持多角色名,模糊搜索可在两侧添加百分号(%)进行',placeholder:'角色名'},
                         {name:'owner_id',type:'select_multiple_select',tip:['输入关键词快速定位下拉列表,回车确定','选择要显示的客户'],
                             placeholder:['货主','定位或多选货主'],data:this.owners},
                     ]

+ 1 - 1
resources/views/maintenance/userLabor/index.blade.php

@@ -136,7 +136,7 @@
             mounted(){
                 let data=[
                    [
-                       {name: 'user_name', type: 'input', tip: '姓名:可在左侧增加百分号(%)进行模糊搜索', placeholder: '姓名'},
+                       {name: 'user_name', type: 'input', tip: '可支持多姓名查找,模糊搜索可在左侧增加百分号(%)进行', placeholder: '姓名'},
                    ]
                 ];
                 this.form = new query({

+ 2 - 2
resources/views/order/issue/index.blade.php

@@ -356,7 +356,7 @@
                                 </button>
                             </div>
                         </td>
-                        <td class="td-yellow p-0 m-0 child-layer-2 w-50" v-if="index===0" :rowspan="orderIssues.length">
+                        <td class="td-yellow p-0 m-0 child-layer-2 w-50"  style="width:50px;" v-if="index===0" :rowspan="orderIssues.length">
                             <span class="btn" :class="isShowOrderInfo ? 'btn-outline-secondary':'btn-outline-info'"
                                   @click="toggleOrderInfo" :style="{'min-height':toggleBtnHeight+'px'}">
                                 @{{ isShowOrderInfo ? '隐藏运单列' : '展开运单列'}}
@@ -1202,7 +1202,7 @@
                 })
                 this.form.init();
                 let order = $('.table-head-warning')[0];
-                $('.top').css('min-width', $(order).outerWidth(true));
+                $('.top').css('min-width', $(order).outerWidth(true)-50);
                 this._initializePage();
             },
             watch: {

+ 56 - 18
resources/views/package/logistic/index.blade.php

@@ -8,7 +8,7 @@
     <div id="list" class="d-none">
         <div class="container-fluid">
             <div id="form_div"></div>
-            <div class="ml-3 form-inline" id="btn">
+            <div class="form-inline" id="btn">
                 @can('包裹管理-快递-异常类型-编辑')
                     <select class="form-control-sm" v-model="batchExceptionType">
                         <option v-for="(value,index) in exception_types" :value="value"
@@ -18,6 +18,14 @@
                     <button @click="batchExceptionTypeUpdate()" type="button"
                             class="btn btn-sm ml-2 btn-outline-primary">批量异常状态修改
                     </button>
+                    <select class="form-control-sm ml-2" v-model="batchStatus">
+                        <option v-for="(value,index) in statuses" :value="value"
+                                :name="value" :key="index">@{{ value }}
+                        </option>
+                    </select>
+                    <button @click="batchStatusUpdate()" type="button"
+                            class="btn btn-sm ml-2 btn-outline-danger">批量状态修改
+                    </button>
                 @endcan
             </div>
             <table class="table table-striped table-sm text-nowrap table-hover" id="table">
@@ -67,16 +75,18 @@
                         </div>
                     </td>
                     <td @mouseover="remarkHover = package.id" @mouseleave="remarkHover=null;remark=null;isShowRemarkInput = false">
+                        @can('包裹管理-快递-客服备注')
                         <button @click="isShowRemarkInput = true" v-if="remarkHover===package.id">新增</button>
                         <input @keydown.enter="submitRemark(package)" v-if="isShowRemarkInput && remarkHover===package.id" type="text" v-model="remark">
-                        <div v-if="package.remark && package.remark.length>0"
-                             class="text-overflow-warp-200 up" :id="'remark-'+i">
-                            <p v-for="remark_item in package.remark">
-                                @{{ remark_item }}
-                            </p>
-                        </div>
-                        <div class="text-overflow-warp-200 " v-if=" package.remark && !showRemarkList[i] && package.remark.length > 0">
-                            @{{ package.remark[0] }}
+                        <div v-if="package.remark && package.remark.length>0" :id="'remark-'+i">
+                            <div v-if="showRemarkList[i]" class="text-overflow-warp-200 up" >
+                                <p v-for="remark_item in package.remark">
+                                    @{{ remark_item }}
+                                </p>
+                            </div>
+                            <div class="text-overflow-warp-200" v-else>
+                                @{{ package.remark[0] }}
+                            </div>
                         </div>
                         <div @click="showRemarkItem(i)" v-if="package.remark && package.remark.length > 1">
                             <label class="text-center mt-0 p-0 cursor-pointer pull-left">
@@ -86,6 +96,7 @@
                                     v-else>展开</span>&nbsp;@{{ package.remark.length }} 条
                             </label>
                         </div>
+                        @endcan
                     </td>
                     <td class="text-overflow-warp-200"><span v-if="package.order && package.order.issue">@{{ package.order.issue.result_explain }}</span>
                     </td>
@@ -147,9 +158,14 @@
                     '其他',
                     '无',
                 ],
+                statuses: [
+                  '已揽收',
+                  '无',
+                ],
                 exception_editable: @can('包裹管理-快递-异常类型-编辑') true @else false  @endcan,
                 selectedExceptionType: '修改异常类型',
                 batchExceptionType: null,
+                batchStatus: null,
                 remarkHover: null,
                 remark: null,
                 isShowRemarkInput: false
@@ -199,9 +215,6 @@
 
 
                         {name: 'sent_at_start', type: 'dateTime', tip: '选择显示发出时间的起始时间'},
-                        {name: 'received_at_start', type: 'dateTime', tip: '选择显示收货时间的起始时间'},
-
-
                         {
                             name: 'is_weighed',
                             type: 'select',
@@ -209,6 +222,14 @@
                             placeholder: '是否称重',
                             data: [{name: false, value: '无'}, {name: true, value: '已称重'}]
                         },
+                        {name: 'received_at_start', type: 'dateTime', tip: '选择显示收货时间的起始时间'},
+                        {
+                            name: 'has_transfer_status',
+                            type: 'select',
+                            tip: ['输入关键词快速定位下拉列表,回车确定', '选择要显示的状态'],
+                            placeholder: '是否有物流信息',
+                            data: [{name: '是', value: '是'}, {name: '否', value: '否'}]
+                        },
                         {name: 'default_date', type: 'checkbox', tip: '默认15天', data: [{name: 'ture', value: '默认15天'}]},
 
                     ], [
@@ -227,8 +248,6 @@
                             data: _this.owners
                         },
                         {name: 'sent_at_end', type: 'dateTime', tip: '选择显示发出时间的截止时间'},
-                        {name: 'received_at_end', type: 'dateTime', tip: '选择显示收货时间的截止时间'},
-
                         {
                             name: 'is_exception',
                             type: 'select',
@@ -236,6 +255,8 @@
                             placeholder: '是否有异常',
                             data: [{name: '是', value: '是'}, {name: '否', value: '否'}]
                         },
+                        {name: 'received_at_end', type: 'dateTime', tip: '选择显示收货时间的截止时间'},
+
                         {
                             name: 'exception_type',
                             type: 'select',
@@ -288,7 +309,6 @@
             },
             methods: {
                 showRoute(id) {
-                    // item.isShowTransferStatus = true;
                     if (this.showList[id]) {
                         this.$set(this.showList, id, false);
                         $("#route-" + id).slideUp();
@@ -299,7 +319,6 @@
                     this.$forceUpdate();
                 },
                 showRemarkItem(id) {
-                    // item.isShowTransferStatus = true;
                     if (this.showRemarkList[id]) {
                         this.$set(this.showRemarkList, id, false);
                         $("#remark-" + id).slideUp();
@@ -327,7 +346,21 @@
                         logistic_numbers: checkData
                     }).then(() => {
                         tempTip.setDuration(1000);
-                        tempTip.showSuccess('批量更新异常类型成功');
+                        tempTip.showSuccess('批量更新异常状态成功');
+                    })
+                },
+                batchStatusUpdate() {
+                    let _this = this;
+                    if (checkData.length === 0) {
+                        tempTip.show('没有勾选记录');
+                        return
+                    }
+                    axios.put('{{url('package/logistic/batchUpdate')}}', {
+                        status: this.batchStatus,
+                        logistic_numbers: checkData
+                    }).then(() => {
+                        tempTip.setDuration(1000);
+                        tempTip.showSuccess('批量状态成功');
                     })
                 },
                 submitRemark(orderPackage) {
@@ -349,7 +382,12 @@
                         tempTip.setDuration(3000);
                         tempTip.show("网络错误:"+err)
                     });
-                }
+                },
+                {{--orderPackageExport(checkAllSign){--}}
+                {{--    let url = '{{url('package/logistic/export')}}';--}}
+                {{--    let token='{{ csrf_token() }}';--}}
+                {{--    excelExport(checkAllSign,checkData,url,this.packages.length,token,{is_merge : this.is_merge});--}}
+                {{--},--}}
             },
             filters: {
                 toObjected: function (value) {

+ 1 - 1
resources/views/package/measureMonitor/index.blade.php

@@ -159,7 +159,7 @@
             methods:{
                 clickMeasuringMachine(e){
                     let _this=this;
-                    window.axios.post('{{url('package/measureMonitor/data')}}',{id:e})
+                    window.axios.post('{{url('package/weigh/measureMonitor/data')}}',{id:e})
                         .then(function (response) {
                             if (response.data.id){
                                 let orderPackage=response.data;

+ 1 - 1
resources/views/procurement/finance/procurementBill.blade.php

@@ -131,8 +131,8 @@
                     {name: 'deliver_amount', value: '收货数量', neglect: true,class: 'text-center'},
                     {name: '采购单价', value: '采购单价(元)', neglect: true,class: 'text-center'},
                     {name: 'unit_price', value: '销售单价(元)', neglect: true,class: 'text-center'},
-                    {name: '应收金额', value: '应收金额(元)', neglect: true,class: 'text-center'},
                     {name: '应付金额', value: '应付金额(元)', neglect: true,class: 'text-center'},
+                    {name: '应收金额', value: '应收金额(元)', neglect: true,class: 'text-center'},
                     {name: '状态', value: '状态', neglect: true,class: 'text-center'},
                     {name: '操作', value: '操作', neglect: true,class: 'text-center'},
                 ];

+ 4 - 1
resources/views/station/cachingShelf/list/_fillBox.blade.php

@@ -14,6 +14,9 @@
                         <input type="text" id="material-box" class="form-control col" @keydown.enter="pushMaterialBox()" v-model="materialBoxCode">
                     </div>
                 </div>
+                <div class="container" id="alert-box">
+                    <div class="alert-info" >加载中......</div>
+                </div>
                 <hr>
                 <div class="container">
                     <div class="row">
@@ -26,7 +29,7 @@
                 </div>
                 <div class="modal-footer">
                     <button class="btn btn-primary" data-dismiss="modal">关闭</button>
-                    <button class="btn btn-primary" @click="clearCurrentStation">清空</button>
+{{--                    <button class="btn btn-primary" @click="clearCurrentStation">清空</button>--}}
                 </div>
             </div>
         </div>

+ 41 - 15
resources/views/station/cachingShelf/list/index.blade.php

@@ -57,7 +57,8 @@
                             stationCode:stationCode,
                             materialBoxCode:null,
                             row:row,
-                            col:col
+                            col:col,
+                            type:null
                         }
                     }
                 },
@@ -91,19 +92,20 @@
                     $('#box').modal('show');
                 },
                 /** 清空格口号 */
-                clearCurrentStation() {
-                    this.currentStation.data.forEach(function (item, index, items) {
-                        items[index].forEach(function (item, index, self) {
-                            self[index]['code'] = null;
-                        })
-                    });
-                    this.$forceUpdate();
-                },
+                // clearCurrentStation() {
+                //     this.currentStation.data.forEach(function (item, index, items) {
+                //         items[index].forEach(function (item, index, self) {
+                //             self[index]['code'] = null;
+                //         })
+                //     });
+                //     this.$forceUpdate();
+                // },
                 /** 初始化格口 */
                 initCacheGrid() {
                     let url = '{{url('apiLocal/station/cacheShelf/getTasks')}}'+'/'+this.currentStation.id;
                     window.tempTip.setIndex(1099);
                     window.tempTip.setDuration(3000);
+                    $('#alert-box').show();
                     window.axios.get(url).then(res => {
                         if (res.data.data) {
                             for (let index = 0; index < res.data.data.length; index++) {
@@ -115,21 +117,26 @@
                                 let materialBoxCode = res.data.data[index]['pending_station_task']['station_task_material_boxes'][0]['material_box']['code'] ?? null;
                                 this.$set(this.currentStation.grids[stationCode],'materialBoxCode',materialBoxCode);
                             }
+                            $('#alert-box').hide();
                             this.$forceUpdate();
                             return;
                         }
                         window.tempTip.show('获取缓存货架信息失败');
+                        $('#alert-box').hide();
                     }).catch(err => {
                         window.tempTip.show('获取缓存货架信息异常:' + err);
+                        $('#alert-box').hide();
                     });
                 },
                 /** 扫码 1、料箱扫码 */
                 pushMaterialBox(grid = null,$e = null) {
                     // 从格口输入
-                    if(grid) {
+                    if($e) {
                         let materialBoxCode = $($e.target).val();
                         let stationCode = grid['stationCode'];
-                        this.lightOn(stationCode,materialBoxCode);
+
+                        if(materialBoxCode.trim()!=='')this.lightOn(stationCode,materialBoxCode);
+                        else this.clearTask(stationCode);
                         return;
                     }
                     for (const key in this.currentStation.grids) {
@@ -148,7 +155,7 @@
                     window.tempTip.setDuration(2000);
                     window.tempTip.setIndex(1999);
 
-                    if(this.checkMaterialBoxCodeExist(materialBoxCode)){
+                    if(this.checkMaterialBoxCodeExist(materialBoxCode,stationCode)){
                         window.tempTip.show('料箱已被占用');
                         return ;
                     }
@@ -166,10 +173,28 @@
                         window.tempTip.show(err);
                     });
                 },
+                clearTask(stationCode){
+                    let url = '{{url('apiLocal/station/cacheShelf/clearTask')}}';
+                    let data = {station:stationCode};
+                    window.tempTip.setDuration(2000);
+                    window.tempTip.setIndex(1999);
+                    window.axios.post(url,data).then(res=>{
+                        if(res.data.success){
+                            window.tempTip.showSuccess(res.data.message ? res.data.message : '取消任务成功');
+                            this.$set(this.currentStation.grids[stationCode],'materialBoxCode',null);
+                            this.$forceUpdate();
+                            $('#material-box').focus();
+                            return ;
+                        }
+                        window.tempTip.show('取消任务异常:'+res.data.message);
+                    }).catch(err=>{
+                        window.tempTip.show(err);
+                    });
+                },
                 /** 校验是否存在 */
-                checkMaterialBoxCodeExist(materialBoxCode) {
+                checkMaterialBoxCodeExist(materialBoxCode,stationCode) {
                     for (const key in this.currentStation.grids) {
-                        if(this.currentStation.grids[key]['materialBoxCode'] === materialBoxCode)return true;
+                        if(this.currentStation.grids[key]['materialBoxCode'] === materialBoxCode && key !== stationCode )return true;
                     }
                     return false;
                 },
@@ -181,7 +206,8 @@
                         if (!json || json.length === 0) return;
                         if(json['code'] !== this.currentStation.code)return ;
                         if(json['grid_code']){
-                            this.$set(this.currentStation.grids[json['grid_code']],'materialBoxCode',null);
+                            if(json['type'] === 'success') this.$set(this.currentStation.grids[json['grid_code']],'materialBoxCode',null);
+                            if(json['type'] === 'error') this.$set(this.currentStation.grids[json['grid_code']],'type','error');
                             this.$forceUpdate();
                         }
                     });

+ 5 - 0
resources/views/station/menu.blade.php

@@ -10,6 +10,11 @@
                 <li class="nav-item">
                     <a target="station/cachingShelf/index" class="nav-link" href="{{url('station/cachingShelf/index')}}" :class="{active:isActive('cachingShelf',2)}">缓存架</a>
                 </li> @endcan
+            @can('站管理-站规则')
+                <li class="nav-item">
+                    <a target="station/rule/index" class="nav-link" href="{{url('station/rule/index')}}" :class="{active:isActive('rule','2')}">站规则</a>
+                </li>
+            @endcan
         </ul>
     </div>
 </div>

+ 51 - 0
resources/views/station/rule/_edit.blade.php

@@ -0,0 +1,51 @@
+<div class="modal face" id="box">
+    <div class="modal-dialog modal-lg boxClass" >
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="modal-title">
+                    <span v-show="tag==='update'">修改规则</span>
+                    <span v-show="tag==='create'">创建规则</span>
+                </div>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <form>
+                    <div class="form-group row">
+                        <label for="owner-id" class="col-sm-3 col-form-label text-right">货主</label>
+                        <div class="col-sm-9 form-inline">
+                            <select id="owner-id" class="form-control col-sm-6"
+                                    :class="errors.owner_id?'is-invalid':''"
+                                    v-model="stationRuleBatch.owner_id" @input="setStationRuleBatchName($event)"
+                                    @change="errors.owner_id = null">
+                                <option value=""></option>
+                                <option :value="owner.id" v-for="owner in ownerFilters">@{{ owner.name }}</option>
+                            </select>
+                            <input type="text" name="material-code" id="owner-id" class="form-control col-sm-3" placeholder="货主" @input="filterOwner($event)" v-model="filterName">
+                            <div class="invalid-feedback" v-if="errors.owner_id">
+                                @{{ errors.owner_id ? errors.owner_id[0] : ''  }}
+                            </div>
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="rule-name" class="col-sm-3 col-form-label text-right">名称</label>
+                        <div class="col-sm-9 form-inline">
+                            <input type="text" name="phone" id="rule-name" class="form-control col-9"
+                                   :class="errors.name &&  !stationRuleBatch.name ?'is-invalid':''"
+                                   v-model="stationRuleBatch.name" @change="errors.name = null">
+                            <div class="invalid-feedback" v-if="errors.name">
+                                @{{ errors.name ? errors.name[0] : ''  }}
+                            </div>
+                        </div>
+                    </div>
+                </form>
+            </div>
+            <div class="modal-footer">
+                <button class="btn btn-primary" @click="_edit" v-show="tag==='update'">修改</button>
+                <button class="btn btn-primary" @click="_create" v-show="tag==='create'">创建</button>
+            </div>
+        </div>
+    </div>
+</div>
+

+ 47 - 0
resources/views/station/rule/_table.blade.php

@@ -0,0 +1,47 @@
+<table class="table table-striped table-md table-hover" id="table">
+    <thead>
+    <tr>
+        <th>
+            序号
+        </th>
+        <th>
+            货主
+        </th>
+        <th>
+            规则名称
+        </th>
+        <th>
+            设备类型
+        </th>
+        <th>
+            波次类型
+        </th>
+        <th>
+            操作
+        </th>
+    </tr>
+    <template v-if="stationRuleBatches.length > 0">
+        <tr v-for="(stationRuleBatch,i) in stationRuleBatches" @click="selectTr===i+1?selectTr=0:selectTr=i+1" :class="selectTr===i+1?'focusing' : ''">
+            <td>
+                @{{ i+1 }}
+            </td>
+            <td>
+                @{{ stationRuleBatch.owner ? stationRuleBatch.owner.name : '' }}
+            </td>
+            <td>
+                @{{ stationRuleBatch.name }}
+            </td>
+            <td>
+                @{{ stationRuleBatch.station_type ? stationRuleBatch.station_type.name  : ''}}
+            </td>
+            <td>
+                @{{ stationRuleBatch.batch_type ? stationRuleBatch.batch_type :'无'}}
+            </td>
+            <td>
+                @can('站管理-站规则-编辑')<button class="btn btn-sm btn-outline-primary" @click="editStationRuleBatch(stationRuleBatch,i)">编辑</button>@endcan
+                @can('站管理-站规则-删除')<button class="btn btn-sm btn-outline-danger" @click="deleteStationRuleBatch(stationRuleBatch,i)">删除</button>@endcan
+            </td>
+        </tr>
+    </template>
+    </thead>
+</table>

+ 140 - 0
resources/views/station/rule/index.blade.php

@@ -0,0 +1,140 @@
+@extends('layouts.app')
+
+@section('title','站规则')
+
+@section('content')
+    <span id="nav2">
+        @component('station.menu')@endcomponent
+        @component('station.rule.menu')@endcomponent
+    </span>
+    <div class="container-fluid d-none" id="list">
+        @can('站管理-站规则-创建')
+            <button class="btn btn-md btn-outline-primary ml-1" @click="createStationRuleBatch">创建</button>
+        @endcan
+        @include('station.rule._table')
+        @include('station.rule._edit')
+    </div>
+@endsection
+
+@section('lastScript')
+    <script>
+        let vue = new Vue({
+            el: '#list',
+            data: {
+                selectTr: null,
+                stationRuleBatches: {!! $stationRuleBatches->toJson() !!}['data'],
+                owners:{!! $owners !!},
+                ownerFilters: [],
+                filterName: null,
+                tag: null,
+                tagIndex: null,
+                stationRuleBatch: {},
+                errors: {}
+            },
+            mounted() {
+                $('#list').removeClass('d-none');
+                this.filterOwner();
+            },
+            methods: {
+                createStationRuleBatch() {
+                    this.tag = 'create';
+                    this.filterOwner();
+                    this.stationRuleBatch = {};
+                    this.errors = {};
+                    $('#box').modal('show');
+                },
+                editStationRuleBatch(item, index) {
+                    this.stationRuleBatch = JSON.parse(JSON.stringify(item));
+                    this.tag = 'update';
+                    this.tagIndex = index;
+                    this.filterOwner();
+                    this.errors = {};
+                    $('#box').modal('show');
+                },
+                deleteStationRuleBatch(item, index) {
+                    if (!confirm("确定要删除对应的栈规则")) {
+                        return;
+                    }
+                    let url = '{{url('apiLocal/station/rule/destroy')}}' + '/?id=' + item['id'];
+                    window.axios.delete(url).then(res => {
+                        if (res.data.success) {
+                            window.tempTip.showSuccess('删除成功');
+                            this.$delete(this.stationRuleBatches, index);
+                            return;
+                        }
+                        window.tempTip.show('删除异常,刷新页面重试');
+                    }).catch(err => {
+                        window.tempTip.show('网络异常,' + err);
+                    });
+                },
+                _create() {
+                    let url = '{{url('apiLocal/station/rule/store')}}';
+                    console.log(this.stationRuleBatch);
+                    window.axios.post(url, this.stationRuleBatch).then(res => {
+                        if (res.data.success) {
+                            this.stationRuleBatches.unshift(res.data.data);
+                            window.tempTip.showSuccess('创建成功');
+                            $('#box').modal('hide');
+                            this.$forceUpdate();
+                            this.tag = null;
+                            this.tagIndex = null;
+                            this.stationRuleBatch = {};
+                            return;
+                        }else if(res.data.errors){
+                            this.errors = res.data.errors;
+                            this.$forceUpdate();
+                            return;
+                        }
+                        window.tempTip.show('创建异常');
+                    }).catch(err => {
+                        window.tempTip.show('网络异常,' + err);
+                    });
+                },
+                _edit() {
+                    let url = '{{url('apiLocal/station/rule/update')}}';
+                    window.axios.put(url, this.stationRuleBatch).then(res => {
+                        if (res.data.success) {
+                            this.$set(this.stationRuleBatches, this.tagIndex, res.data.data);
+                            window.tempTip.showSuccess('修改成功!');
+                            $('#box').modal('hide');
+                            this.tag = null;
+                            this.tagIndex = null;
+                            this.stationRuleBatch = {};
+                            this.$forceUpdate();
+                            return;
+                        }else if(res.data.errors){
+                            this.errors =res.data.errors;
+                            this.$forceUpdate();
+                            return;
+                        }
+                        window.tempTip.show('编辑异常,刷新页面重试');
+                    }).catch(err => {
+                        window.tempTip.show('网络异常,' + err);
+                    });
+                },
+                setStationRuleBatchName($e){
+                    let selectValue = $($e.target).find('option:selected').text();
+                    if(selectValue && !this.stationRuleBatch.name )
+                        this.$set(this.stationRuleBatch,'name',selectValue)
+                },
+                filterOwner($e = null) {
+                    let copyOwner = JSON.parse(JSON.stringify(this.owners));
+                    this.ownerFilters = copyOwner;
+                    if ($e !== null) {
+                        let value = $($e.target).val();
+                        this.ownerFilters = copyOwner.filter(function (owner) {
+                            return owner.name.indexOf(value) !== -1;
+                        });
+                        if (this.ownerFilters.length !== this.owners.length && this.ownerFilters.length > 0) {
+                            this.$set(this.stationRuleBatch,'owner_id',this.ownerFilters[0]['id']);
+                            this.$set(this.stationRuleBatch,'name',this.ownerFilters[0]['name']);
+                        } else {
+                            this.$set(this.stationRuleBatch,'owner_id',null);
+                        }
+                    }
+                    this.$forceUpdate();
+                }
+            }
+        })
+    </script>
+@endsection

+ 9 - 0
resources/views/station/rule/menu.blade.php

@@ -0,0 +1,9 @@
+<div class="container-fluid nav3">
+    <div class="card">
+        <ul class="nav nav-pills">
+            <li class="nav-item">
+                <a target="station/rule/index" class="nav-link" href="{{url('station/rule/index')}}" :class="{active:isActive('rule','2')}">查询</a>
+            </li>
+        </ul>
+    </div>
+</div>

+ 36 - 0
resources/views/transport/waybill/_dailyBilling.blade.php

@@ -0,0 +1,36 @@
+<div class="modal fade" id="dailyBilling" role="dialog" tabindex="-1" >
+    <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title text-center">按日输入专线费</h5>
+                <button type="button" class="close" data-dismiss="modal">
+                    <span>&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="form-group row">
+                    <label for="screenDate" class="col-2 col-form-label text-right">选定日期</label>
+                    <div class="col-8">
+                        <input type="date" class="form-control" :class="error.screenDate ? 'is-invalid' : ''" name="screenDate" autocomplete="off"  v-model="dailyBilling.screenDate" >
+                        <span class="invalid-feedback" role="alert" v-if="error.screenDate">
+                                <strong>@{{ error.screenDate }}</strong>
+                            </span>
+                    </div>
+                </div>
+                <div class="form-group row">
+                    <label for="billing" class="col-2 col-form-label text-right">输入专线费</label>
+                    <div class="col-8">
+                        <input type="text" class="form-control " :class="error.billing ? 'is-invalid' : ''" name="billing" autocomplete="off"  v-model="dailyBilling.billing">
+                        <span class="invalid-feedback" role="alert" v-if="error.billing">
+                                <strong>@{{ error.billing }}</strong>
+                            </span>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary"  data-dismiss="modal" >关闭</button>
+                <button type="button" class="btn btn-primary" @click="dailyBillingCount()">提交</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 107 - 19
resources/views/transport/waybill/index.blade.php

@@ -9,23 +9,24 @@
     <div class="container-fluid" style="min-width: 1500px;">
         <div class="d-none" id="list">
 
+            @include("transport.waybill._dailyBilling")
             @include("transport.waybill._batchUploadImg")
 
             <div class="container-fluid nav3">
                 <div class="card menu-third" >
                     <ul class="nav nav-pills">
                         @can('运输管理-运单-查询')
-                        <li class="nav-item">
-                            <a class="nav-link @if($uriType=='') active @endif" href="{{url('transport/waybill/index')}}">全部</a>
-                        </li> @endcan
+                            <li class="nav-item">
+                                <a class="nav-link @if($uriType=='') active @endif" href="{{url('transport/waybill/index')}}">全部</a>
+                            </li> @endcan
                         @can('运输管理-运单-查询')
-                        <li class="nav-item">
-                            <a class="nav-link @if($uriType=='专线') active @endif" href="{{url('transport/waybill/index?uriType=专线')}}">专线</a>
-                        </li> @endcan
+                            <li class="nav-item">
+                                <a class="nav-link @if($uriType=='专线') active @endif" href="{{url('transport/waybill/index?uriType=专线')}}">专线</a>
+                            </li> @endcan
                         @can('运输管理-运单-查询')
-                        <li class="nav-item">
-                            <a class="nav-link @if($uriType=='直发车') active @endif" href="{{url('transport/waybill/index?uriType=直发车')}}">直发车</a>
-                        </li> @endcan
+                            <li class="nav-item">
+                                <a class="nav-link @if($uriType=='直发车') active @endif" href="{{url('transport/waybill/index?uriType=直发车')}}">直发车</a>
+                            </li> @endcan
                     </ul>
                 </div>
             </div>
@@ -41,6 +42,11 @@
                 </div>
             </span>
             @can('运输管理-运单-图片上传')<button class="btn btn-sm btn-outline-info" data-target="#batchUploadImg" data-toggle="modal">批量上传图片</button>@endcan
+            @if($uriType=='' || $uriType=='专线')
+                @can('运输管理-运单-按日计算专线费')
+                    <button class="btn btn-sm btn-outline-success tooltipTarget" data-target="#dailyBilling" data-toggle="modal"
+                            title="计算指定日期下的所有专线费,不考虑有无货主权限">按日输入专线费</button>@endcan
+            @endif
             <div>
                 @if(Session::has('successTip'))
                     <div class="alert alert-success h1">{{Session::get('successTip')}}</div>
@@ -123,11 +129,11 @@
                     <td class="td-warm"><span>@{{waybill.end_date}}</span></td>
                     <td class="td-warm"><span>@{{waybill.waybill_number}}</span></td>
                     @can('运输管理-运单-运单编辑')
-                    <td class="td-warm" >
-                        <span v-if="waybill.charge" class="btn-sm btn-outline-secondary btn" @click="waybillChargeCheck($event)" :data_id="waybill.id">@{{waybill.charge|money}}</span>
-                        <input v-else type="number" class="form-control form-control-sm" @blur="addWaybillCharge($event)" onfocus="$(this).css('width','85px')" :value="waybill.charge" :data_id="waybill.id" >
-                        <input type="number" class="form-control form-control-sm"  @blur="updateWaybillCharge($event)" :value="waybill.charge" :data_id="waybill.id" style="min-width:85px;display: none">
-                    </td>
+                        <td class="td-warm" >
+                            <span v-if="waybill.charge" class="btn-sm btn-outline-secondary btn" @click="waybillChargeCheck($event)" :data_id="waybill.id">@{{waybill.charge|money}}</span>
+                            <input v-else type="number" class="form-control form-control-sm" @blur="addWaybillCharge($event)" onfocus="$(this).css('width','85px')" :value="waybill.charge" :data_id="waybill.id" >
+                            <input type="number" class="form-control form-control-sm"  @blur="updateWaybillCharge($event)" :value="waybill.charge" :data_id="waybill.id" style="min-width:85px;display: none">
+                        </td>
                     @else
                         <td class="td-warm" ><span v-if="waybill.charge">@{{waybill.charge|money}}</span></td>
                     @endcan
@@ -136,7 +142,7 @@
                     <td class="td-warm">
                         <div align="center" @mouseleave="removeCommonImg('common_img_'+waybill.id)" @mouseenter="commonImg('img_'+waybill.id,waybill.url,waybill.suffix)">
                             <img v-if="waybill.url" :id="'img_'+waybill.id"  :src="waybill.url+'-thumbnail.'+waybill.suffix"
-                                    {{--:data-src="waybill.url+'-thumbnail.'+waybill.suffix" src="{{url('icon/img404-thumbnail.jpg')}}"--}}>
+                                {{--:data-src="waybill.url+'-thumbnail.'+waybill.suffix" src="{{url('icon/img404-thumbnail.jpg')}}"--}}>
                             @can('运输管理-运单-图片上传')<div v-if="!waybill.url">
                                 <input class="btn  btn-sm btn-outline-secondary" type="button" @click="certiimg(waybill.waybill_number)" value="上传照片 "/>
                                 <input type="file" @change="submitFile($event,waybill.waybill_number)" :id="waybill.waybill_number"
@@ -328,8 +334,9 @@
                         mileage:'{{$waybill->mileage}}',
                         amount:'{{$waybill->amount}}',
                         @if($waybill->carType)carType:{!! $waybill->carType !!},car_owner_info:'{{$waybill->car_owner_info}}',@endif
-                        @can('运输管理-运单-可见费用项') fee:'{{$waybill->fee}}',
-                        pick_up_fee:'{{$waybill->pick_up_fee}}',other_fee:'{{$waybill->other_fee}}',
+                            @can('运输管理-运单-可见费用项') fee:'{{$waybill->fee}}',
+                        pick_up_fee:'{{$waybill->pick_up_fee? round($waybill->pick_up_fee) :''}}',
+                        other_fee:'{{$waybill->other_fee}}',
                         collect_fee:'{{$waybill->collect_fee}}', @endcan
                         deliver_at:'{{$waybill->deliver_at}}',
                         dispatch_remark:'{{$waybill->dispatch_remark}}',
@@ -380,6 +387,8 @@
                 batchUploadError:[],
                 size:0,
                 selectTr:'',
+                dailyBilling:{screenDate:'', billing:''},
+                error:{screenDate:'', billing:''},
             },
             mounted:function(){
                 $(".tooltipTarget").tooltip({'trigger':'hover'});
@@ -427,8 +436,87 @@
                 this.paginate = $("#paginate").val();
                 let waybill =  $('.table-header-layer-1')[1];
                 $('.top').css('min-width', waybill.scrollWidth);
+                this.rendingFloatBtn();
             },
             methods:{
+                rendingFloatBtn(){
+                    let parent = $('.pick-btn :visible');
+                    if (parent.length<1)return;
+                    parent = parent[0];
+                    let node = document.createElement("btn");
+                    parent.className += "position-relative";
+                    node.className = "position-absolute btn btn-sm btn-success total-fee";
+                    node.style.top=0;
+                    node.style.left=0;
+                    node.style.marginTop="-16%";
+                    node.innerText = '总计';
+                    parent.before(node);
+                    node.onclick=this.countPickUpFee;
+                },
+                countPickUpFee(){
+                    let url = '{{url('transport/waybill/countPickUpFee')}}';
+                    let urlRequest = location.search; //获取url中"?"符后的字串
+                    let theRequest = {};
+                    if (urlRequest.indexOf("?") != -1) {
+                        let str = urlRequest.substr(1);
+                        let strs = str.split("&");
+                        for(let i = 0; i < strs.length; i ++) {
+                            theRequest[strs[i].split("=")[0]] = decodeURIComponent(decodeURI(strs[i].split("=")[1]));
+                        }
+                    }
+                    window.axios.post(url,{param:theRequest})
+                        .then(response=> {
+                                if (!response.data.success){
+                                     tempTip.setDuration(2000);
+                                     tempTip.show(response.data.message);
+                                }else{
+                                    $('.total-fee').text('总计:'+response.data.data);
+                                     tempTip.setDuration(2000);
+                                     tempTip.showSuccess('根据当前筛选条件计算专线提货费成功')
+                                }
+
+                            }
+                        ).catch(function (err){
+                         tempTip.setDuration(2000);
+                         tempTip.show('根据当前筛选条件计算专线提货费失败,网络连接错误!'+err)
+                    })
+                },
+                dailyBillingCount(){
+                    if (this.dailyBilling.screenDate==='')this.error.screenDate='请指定日期';
+                    if (this.dailyBilling.billing==='')this.error.billing='专线费必填';
+                    if (this.dailyBilling.billing && this.dailyBilling.screenDate)this.error={};
+                    if (this.error.billing ||this.error.screenDate)return;
+                    let url = '{{url('transport/waybill/dailyBilling')}}';
+                    let param=this.dailyBilling;
+                    window.axios.post(url,{param:param})
+                        .then(response=> {
+                                if (!response.data.success){
+                                    $('#dailyBilling').modal('hide');
+                                    this.dailyBilling={};
+                                    this.error={};
+                                    tempTip.setDuration(3000);
+                                    tempTip.show(response.data.message);
+                                }else{
+                                    this.waybills.forEach(function (waybill){
+                                        response.data.data.forEach(function (item){
+                                            if (waybill.id==item.id){
+                                                waybill.pick_up_fee=item.pick_up_fee;
+                                            }
+                                        })
+                                    })
+                                    $('#dailyBilling').modal('hide');
+                                    this.dailyBilling={};
+                                    this.error={};
+                                    tempTip.setDuration(3000);
+                                    tempTip.showSuccess('按日输入专线费成功')
+                                }
+
+                            }
+                        ).catch(function (err){
+                        tempTip.setDuration(3000);
+                        tempTip.show('按日输入专线费失败,网络连接错误!'+err)
+                    })
+                },
                 rendingHeader(){
                     let column = [
                             @can('运输管理-编辑','运输管理-运单-运单审核','运输管理-运单-调度','运输管理-编辑')
@@ -467,7 +555,7 @@
                         {name:'amount',value: '计件', neglect: true, class:"td-cool"},
                         {name:'mileage',value: '里程', neglect: true, class:"td-cool"},
                             @can('运输管理-运单-运费'){name:'fee',value: '运费', neglect: true, class:"td-helpful"},@endcan
-                        {name:'pick_up_fee',value: '提货费', neglect: true, class:"td-helpful"},
+                        {name:'pick_up_fee',value: '提货费', neglect: true, class:"td-helpful pick-btn"},
                         {name:'other_fee',value: '其他支出', neglect: true, class:"td-helpful"},
                         {name:'deliver_at',value: '发货时间', class:"td-helpful"},
                         {name:'dispatch_remark',value: '调度备注', class:"td-helpful"},
@@ -648,7 +736,7 @@
                         "<img src=\""+url+'-common.'+suffix+"\" style='position: relative;left:-50px;' >" +
                         "</a>" +
                         "</div>"+
-                            @can('运输管理-运单-图片删除')"<button type='button' class='btn btn-sm btn-danger' onclick='vue.btnDeleteImg(this)' value='"+id+"' style='position: relative;float: right;margin-right: 51px;margin-top: -30px;' >删除</button>" +@endcan
+                        @can('运输管理-运单-图片删除')"<button type='button' class='btn btn-sm btn-danger' onclick='vue.btnDeleteImg(this)' value='"+id+"' style='position: relative;float: right;margin-right: 51px;margin-top: -30px;' >删除</button>" +@endcan
                             "</div>"+
                         "</div>");
                 },

+ 11 - 1
routes/apiLocal.php

@@ -126,6 +126,7 @@ Route::group(['prefix'=>'control'],function () {
     Route::post('panel/menu/laborReportsCountingRecordApi','ControlPanelController@laborReportsCountingRecordApi');
     Route::post('panel/menu/laborReportsUserGroupsCountApi','ControlPanelController@laborReportsUserGroupsCountApi');
     Route::post('panel/menu/weightApi','ControlPanelController@weightApi');
+    Route::post('panel/menu/exceptionTypeApi','ControlPanelController@exceptionTypeApi');
 });
 
 /** 耗材 */
@@ -182,13 +183,22 @@ Route::group(['prefix'=>'demand'],function(){
 
 Route::get('/authority/get','AuthorityController@getAuthoritiesApi')->name('authority.getAuthoritiesApi');
 
-/** 缓存架 */
+/** 栈管理 */
 Route::group(['prefix' => 'station'],function(){
+    /** 缓存架 */
     Route::group(['prefix'=>'cacheShelf'],function(){
         Route::post('pushTask','CacheShelfController@pushTaskApi')->name('station.cacheShelf.pushTaskApi');
+        Route::post('clearTask','CacheShelfController@clearTaskApi')->name('station.cacheShelf.clearTaskApi');
         Route::post('lightOn','CacheShelfController@lightOnApi')->name('station.cacheShelf.lightOnApi');
         Route::get('getTasks/{id}','CacheShelfController@getTasksApi')->name('station.cacheShelf.getTasksApi');
     });
+
+    /** 栈规则 */
+    Route::group(['prefix'=>'rule'],function(){
+        Route::post('store','StationRuleBatchController@storeApi')->name('station.rule.storeApi');
+        Route::put('update','StationRuleBatchController@updateApi')->name('station.rule.updateApi');
+        Route::delete('destroy','StationRuleBatchController@destroyApi')->name('station.rule.destroyApi');
+    });
 });
 
 

+ 11 - 0
routes/web.php

@@ -299,6 +299,8 @@ Route::group(['prefix'=>'transport'],function(){
         Route::any('export','WaybillController@export');
         Route::any('waybillUpdate/{id}','WaybillController@waybillUpdate');
         Route::post('batchUploadImages','WaybillController@batchUploadImages');
+        Route::post('dailyBilling','WaybillController@dailyBilling');
+        Route::post('countPickUpFee','WaybillController@countPickUpFee');
         Route::resource('waybillFinancialSnapshot','WaybillFinancialSnapshotsController');
         Route::resource('waybillFinancialExcepted','WaybillFinancialExceptedController');
     });
@@ -376,6 +378,9 @@ Route::group(['prefix'=>'package'],function(){
 
     Route::resource('measureMonitor','MeasureMonitorController');
 
+    Route::group(['prefix'=>'measureMonitor'],function(){
+        Route::post('data','MeasureMonitorController@data');
+    });
     Route::group(['prefix' => 'weigh'], function () {
         Route::get('statistics','WeighController@statistics');
         /** 设备 */
@@ -799,14 +804,20 @@ Route::group(['prefix'=>'customer'],function(){
 /** 站管理 */
 Route::group(['prefix'=>'station'],function(){
     Route::get('index','StationController@monitorIndex');
+    /** 监视器 */
     Route::group(['prefix'=>'monitor'],function(){
         Route::get('/','StationController@monitorIndex');
         Route::get('/index','StationController@monitorIndex');
         Route::get('/{station}','StationController@monitorShow');
     });
+    /** 缓存架 */
     Route::group(['prefix'=>'cachingShelf'],function(){
         Route::get('/index','CacheShelfController@index');
     });
+    /** 栈规则 */
+    Route::group(['prefix'=>'rule'],function(){
+        Route::get('/index','StationRuleBatchController@index');
+    });
 });
 /** 控制台 */
 Route::group(['prefix'=>'control'],function () {

+ 1 - 1
tests/Feature/LogisticZopSyncTest.php

@@ -39,7 +39,7 @@ class LogisticZopSyncTest extends TestCase
 
     public function test_get()
     {
-        LogisticZopSync::dispatch('73228204974140');
+        LogisticZopSync::dispatch('75467972757443');
     }
 
 

+ 5 - 5
tests/Services/CacheService/GetOrExecuteTest.php

@@ -26,10 +26,10 @@ class GetOrExecuteTest extends TestCase
         $this->assertEquals('yes',Cache::pull($key));//销毁
     }
 
-    public function testNullFunction(){
-        $this->expectException(\Exception::class);
-        $key = md5(microtime(true));
-        $this->cacheService->getOrExecute($key,null);
-    }
+//    public function testNullFunction(){
+//        $this->expectException(\Exception::class);
+//        $key = md5(microtime(true));
+//        $this->cacheService->getOrExecute($key,null);
+//    }
 
 }

+ 114 - 0
tests/Services/CacheShelfService/ClearTaskTest.php

@@ -0,0 +1,114 @@
+<?php
+
+
+namespace Tests\Services\CacheShelfService;
+
+
+use App\Material;
+use App\MaterialBox;
+use App\Services\CacheShelfService;
+use App\Services\StationTaskChildService;
+use App\Services\StationTaskMaterialBoxService;
+use App\Services\StationTaskService;
+use App\Station;
+use App\StationTask;
+use App\StationTaskChildren;
+use App\StationTaskMaterialBox;
+use App\StationType;
+use Tests\TestCase;
+
+class ClearTaskTest extends TestCase
+{
+
+    /** @var CacheShelfService $service */
+    /** @var StationTaskService $stationTaskService  */
+    /** @var StationTaskMaterialBoxService $stationTaskMaterialBoxService  */
+    /** @var StationTaskChildService $stationTaskChildService  */
+    public $service;
+    public $stationTaskService;
+    public $stationTaskMaterialBoxService;
+    public $stationTaskChildService;
+    public $data =[];
+
+    protected function setUp(): void
+    {
+        parent::setUp(); // TODO: Change the autogenerated stub
+        $this->service = app(CacheShelfService::class);
+        $this->stationTaskService = app(StationTaskService::class);
+        $this->stationTaskMaterialBoxService = app(StationTaskMaterialBoxService::class);
+        $this->stationTaskChildService = app(StationTaskChildService::class);
+
+        $stationType = StationType::query()->firstOrCreate(['name'=>'立库']);
+
+        $this->data['LiKuStation'] = factory(Station::class)->create(['station_type_id'=>$stationType['id']]);
+        $this->data['station'] = factory(Station::class)->create();
+
+        $this->data['stationTask'] = [];
+        $this->data['stationTaskMaterialBoxes'] = [];
+        $this->data['materialBox'] = factory(MaterialBox::class)->create();
+
+        $this->data['stationTask'] = $this->stationTaskService->create(1);                                                    // 生成站任务
+        $this->data['stationTaskMaterialBoxes'][] = $this->stationTaskMaterialBoxService->createByStationAndMaterialBox($this->data['station'],$this->data['materialBox']);     // 创建料箱任务
+        $this->stationTaskService->registerStations($this->data['stationTask'],[$this->data['station']['id']]);                                            // 注册站任务站
+        $this->data['stationTaskMaterialBoxes'][0]['station_task_id'] = $this->data['stationTask'][0]['id'];
+        $this->data['stationTaskMaterialBoxes'][0]->update();
+        $params = [[
+            'station_task_id'=>$this->data['stationTask'][0]->first()['id'],
+            'station_taskable_type'=>StationTaskMaterialBox::class,
+            'station_taskable_id'=>$this->data['stationTaskMaterialBoxes'][0]['id']
+        ]];
+
+        $this->stationTaskChildService->insert($params);                                                                        // 任务任务注册
+    }
+
+    public function testClearTask()
+    {
+        $result = $this->service->clearTask($this->data['station']->code);
+        $stationTask = StationTask::query()->where('station_id',$this->data['station']['id'])->first();
+        $this->assertEmpty($stationTask);
+        $stationTaskMaterialBox = StationTaskMaterialBox::query()->where('material_box_id',$this->data['materialBox']['id'])->get();
+        $this->assertEmpty($stationTaskMaterialBox);
+    }
+
+    public function testClearTask_taskIsRunning()
+    {
+        StationTask::query()->where('station_id',$this->data['station']['id'])->update(['status' => '处理中']);
+        $result = $this->service->clearTask($this->data['station']->code);
+
+        $stationTask = StationTask::query()->where('station_id',$this->data['station']['id'])->first();
+
+        $this->assertEquals('处理中',$stationTask->status);
+        $this->assertFalse($result['success']);
+    }
+
+
+    protected function tearDown(): void
+    {
+        if($this->data['station']){
+            $stationTasks = StationTask::query()->where('station_id',$this->data['station']['id'])->get();
+            foreach ($stationTasks as $stationTask) {
+                $stationTaskMaterialBoxes = $stationTask->stationTaskMaterialBoxes;
+                foreach ($stationTaskMaterialBoxes as $stationTaskMaterialBox) {
+                    StationTaskChildren::query()->where(['station_task_id' => $stationTask['id'],'station_taskable_type'=> StationTaskMaterialBox::class,'station_taskable_id'=>$stationTaskMaterialBox['id']])->delete();
+                    $stationTaskMaterialBox->delete();
+                }
+            }
+            Station::query()->where('id',$this->data['station']['id'])->delete();
+        }
+
+        if($this->data['LiKuStation']){
+            $stationTasks = StationTask::query()->where('station_id',$this->data['LiKuStation']['id'])->get();
+            foreach ($stationTasks as $stationTask) {
+                $stationTaskMaterialBoxes = $stationTask->stationTaskMaterialBoxes;
+                foreach ($stationTaskMaterialBoxes as $stationTaskMaterialBox) {
+                    StationTaskChildren::query()->where(['station_task_id' => $stationTask['id'],'station_taskable_type'=> StationTaskMaterialBox::class,'station_taskable_id'=>$stationTaskMaterialBox['id']])->delete();
+                    $stationTaskMaterialBox->delete();
+                }
+            }
+            Station::query()->where('id',$this->data['LiKuStation']['id'])->delete();
+        }
+        if($this->data['materialBox'])MaterialBox::query()->where('id',$this->data['materialBox'])->delete();
+        parent::tearDown(); // TODO: Change the autogenerated stub
+    }
+
+}

+ 33 - 25
tests/Services/CacheShelfService/CreateStationTask.php

@@ -37,56 +37,64 @@ class CreateStationTask extends TestCase
         parent::setUp();
         $this->service = $this->subMock([
             'class' => CacheShelfService::class,
+            'methods' => [
+                '_stationCacheLightOn' => new MaterialBox(['code' => 200])
+            ],
             'subService' => [[
-                    'serviceName' => 'foreignHaiRoboticsService',
-                    'class' => ForeignHaiRoboticsService::class,
-                ], [
-                    'serviceName' => 'stationTaskService',
-                    'class' => StationTaskService::class
-                ],[
-                    'serviceName' => 'stationTaskMaterialBoxService',
-                    'class' => StationTaskMaterialBoxService::class
+                'serviceName' => 'foreignHaiRoboticsService',
+                'class' => ForeignHaiRoboticsService::class,
+                'methods' => [
+                    'controlHaiRobot' => true
                 ]
+            ], [
+                'serviceName' => 'stationTaskService',
+                'class' => StationTaskService::class
+            ], [
+                'serviceName' => 'stationTaskMaterialBoxService',
+                'class' => StationTaskMaterialBoxService::class,
+            ]
             ]
         ]);
         $this->stationTaskService = $this->subMock([
             'class' => StationTaskService::class,
         ]);
         $this->data['parentStation'] = factory(Station::class)->create();
-        $this->data['station'] = factory(Station::class)->create(['parent_id'=>$this->data['parentStation']['id']]);
+        $this->data['station'] = factory(Station::class)->create(['parent_id' => $this->data['parentStation']['id']]);
         $this->data['materialBox'] = factory(MaterialBox::class)->create();
     }
 
     public function testCreatStationTask()
     {
-        $data = $this->service->createStationTask($this->data['station']['code'],$this->data['materialBox']['code']);
+        $data = $this->service->createStationTask($this->data['station']['code'], $this->data['materialBox']['code']);
         $this->assertTrue($data['success']);
-        $stationTask = StationTask::query()->where('station_id',$this->data['station']['id'])->with('stationTaskMaterialBoxes')->first();
-        $stationTaskMaterialBox = StationTaskMaterialBox::query()->with('materialBox')->where('station_id',$this->data['station']['id'])->first();
-        $this->assertEquals($stationTask['status'],'待处理');
-        $this->assertEquals($stationTaskMaterialBox['materialBox']['code'],$this->data['materialBox']['code']);
-        $station = Station::query()->with(['pendingStationTask.stationTaskMaterialBoxes'])->where('id',$this->data['station']['id'])->first();
-        $this->assertEquals($station['pendingStationTask']['stationTaskMaterialBoxes']->first()['station_id'],$stationTask['station_id']);
+
+        $stationTask = StationTask::query()->where('station_id', $this->data['station']['id'])->with('stationTaskMaterialBoxes')->first();
+        $stationTaskMaterialBox = StationTaskMaterialBox::query()->with('materialBox')->where('station_id', $this->data['station']['id'])->first();
+        $this->assertEquals($stationTask['status'], '待处理');
+        $this->assertEquals($stationTaskMaterialBox['materialBox']['code'], $this->data['materialBox']['code']);
+
+        $station = Station::query()->with(['pendingStationTask.stationTaskMaterialBoxes'])->where('id', $this->data['station']['id'])->first();
+        $this->assertEquals($station['pendingStationTask']['stationTaskMaterialBoxes']->first()['station_id'], $stationTask['station_id']);
     }
 
     public function testStationTaskIsExists()
     {
         $this->data['stationTask'] = $this->stationTaskService->create(1);
-        $this->stationTaskService->registerStations($this->data['stationTask'],[$this->data['station']['id']]);
-        $data = $this->service->createStationTask($this->data['station']['code'],$this->data['materialBox']['code']);
+        $this->stationTaskService->registerStations($this->data['stationTask'], [$this->data['station']['id']]);
+
+        $data = $this->service->createStationTask($this->data['station']['code'], $this->data['materialBox']['code']);
         $this->assertFalse($data['success']);
     }
 
 
-
     protected function tearDown(): void
     {
-        Station::query()->where('id',$this->data['station']['id'])->delete();
-        Station::query()->where('id',$this->data['parentStation']['id'])->delete();
-        StationTask::query()->where('station_id',$this->data['station']['id'])->delete();
-        MaterialBox::query()->where('id',$this->data['materialBox']['id'])->delete();
-        StationTaskMaterialBox::query()->where('station_id',$this->data['station']['id'])->delete();
-        if($this->data['stationTask'])StationTask::query()->whereIn('id',data_get($this->data['stationTask'],'*.id'))->delete();
+        Station::query()->where('id', $this->data['station']['id'])->delete();
+        Station::query()->where('id', $this->data['parentStation']['id'])->delete();
+        StationTask::query()->where('station_id', $this->data['station']['id'])->delete();
+        MaterialBox::query()->where('id', $this->data['materialBox']['id'])->delete();
+        StationTaskMaterialBox::query()->where('station_id', $this->data['station']['id'])->delete();
+        if ($this->data['stationTask'] ?? false) StationTask::query()->whereIn('id', data_get($this->data['stationTask'], '*.id'))->delete();
         parent::tearDown();
     }
 }

+ 77 - 0
tests/Services/CacheShelfService/GetChildStationTest.php

@@ -0,0 +1,77 @@
+<?php
+
+
+namespace Tests\Services\CacheShelfService;
+
+use App\MaterialBox;
+use App\Services\CacheShelfService;
+use App\Station;
+use App\StationTask;
+use App\StationTaskChildren;
+use App\StationTaskMaterialBox;
+use App\StationType;
+use Faker\Factory;
+use Illuminate\Database\Eloquent\Collection;
+use Tests\TestCase;
+
+class GetChildStationTest extends TestCase
+{
+    /** @var CacheShelfService $service */
+    protected $service;
+
+    protected $data = [];
+
+    protected function setup(): void
+    {
+        parent::setup();
+        $this->service = app(CacheShelfService::class);
+
+        $stationType = StationType::query()->firstOrCreate(['name'=> '缓存架']);
+
+        $this->data['parentStation'] = factory(Station::class)->create(['station_type_id' => $stationType['id']]);
+        $this->data['station'] = factory(Station::class)->create(['parent_id'=>$this->data['parentStation']['id']]);
+        $this->data['materialBox'] = factory(MaterialBox::class)->create();
+        $this->data['stationTask'] = factory(StationTask::class)->create();
+        $this->data['stationTask']['station_id'] = $this->data['station']['id'];
+        $this->data['stationTask']->save();
+
+        $this->data['stationTaskMaterialBox'] = factory(StationTaskMaterialBox::class)->create([
+            'station_id' => $this->data['station']['id'],
+            'material_box_id' => $this->data['materialBox']['id'],
+            'status' => '待处理'
+        ]);
+
+        $this->data['stationTaskMaterialBox']['station_task_id'] = $this->data['stationTask']['id'];
+        $this->data['stationTaskMaterialBox']->save();
+
+        $this->data['stationTaskChildren']  = StationTaskChildren::query()->create([
+            "station_task_id" => $this->data['stationTask']['id'],
+        ]);
+    }
+
+    public function testGetTasks()
+    {
+        $grids = $this->service->getChildStation($this->data['station']['id']);
+        $this->assertTrue($grids ? true : false);
+    }
+
+
+    protected function tearDown(): void
+    {
+        $materialBox = MaterialBox::query()->where('id', $this->data['materialBox']['id'])->first();
+        if ($materialBox) {
+            $stationTaskMaterialBoxes = StationTaskMaterialBox::query()->where('material_box_id', $materialBox['id'])->get();
+            foreach ($stationTaskMaterialBoxes as $stationTaskMaterialBox) {
+                if($stationTaskMaterialBox->station->parent)$stationTaskMaterialBox->station->parent->delete();
+                if ($stationTaskMaterialBox->station) $stationTaskMaterialBox->station->delete();
+                if ($stationTaskMaterialBox->stationTask) $stationTaskMaterialBox->stationTask->delete();
+                $stationTaskMaterialBox->delete();
+            }
+            $materialBox->delete();
+        }
+        if($this->data['stationTaskChildren'])StationTaskChildren::query()->where('id',$this->data['stationTaskChildren']['id'])->delete();
+        parent::tearDown(); // TODO: Change the autogenerated stub
+    }
+
+
+}

+ 0 - 40
tests/Services/CacheShelfService/GetTasksTest.php

@@ -1,40 +0,0 @@
-<?php
-
-
-namespace Tests\Services\CacheShelfService;
-
-use App\MaterialBox;
-use App\Services\CacheShelfService;
-use App\Station;
-use Tests\TestCase;
-
-class GetTasksTest extends TestCase
-{
-    /** @var CacheShelfService $service */
-    protected $service;
-
-    protected $data = [];
-
-    protected function setup(): void
-    {
-        parent::setup();
-
-        $this->service = app(CacheShelfService::class);
-        $this->data['parentStation'] = factory(Station::class)->create(['code' => '']);
-        $this->data['station'] = factory(Station::class)->create(['code'=>'','parent_id'=>$this->data['parentStation']['id']]);
-        $this->data['materialBox']=factory(MaterialBox::class)->create(['code'=> '']);
-    }
-
-    public function testGetTasks()
-    {
-        $grids = $this->service->getTasks($this->data['station']);
-    }
-
-    protected function tearDown(): void
-    {
-        Station::query()->where('id', $this->data['station']['id'])->delete();
-        parent::tearDown(); // TODO: Change the autogenerated stub
-    }
-
-
-}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff