Kaynağa Gözat

Merge branch 'master' into yang

# Conflicts:
#	app/Http/Controllers/TestController.php
ANG YU 4 yıl önce
ebeveyn
işleme
b093f4be77
88 değiştirilmiş dosya ile 2580 ekleme ve 1505 silme
  1. 11 5
      app/Commodity.php
  2. 1 9
      app/Console/Commands/CreateWeightStatistic.php
  3. 13 2
      app/DeliveryAppointment.php
  4. 0 4
      app/DischargeTask.php
  5. 0 39
      app/Http/Controllers/CacheShelfController.php
  6. 41 25
      app/Http/Controllers/ControlPanelController.php
  7. 8 5
      app/Http/Controllers/DeliveryAppointmentController.php
  8. 93 11
      app/Http/Controllers/HandInStorageController.php
  9. 1 1
      app/Http/Controllers/MenuController.php
  10. 1 1
      app/Http/Controllers/RejectedController.php
  11. 2 1
      app/Http/Controllers/StationController.php
  12. 204 92
      app/Http/Controllers/StorageController.php
  13. 3 1
      app/Http/Controllers/StoreController.php
  14. 10 432
      app/Http/Controllers/TestController.php
  15. 50 0
      app/Http/Controllers/WaybillController.php
  16. 17 11
      app/Http/Controllers/api/thirdPart/flux/WaybillController.php
  17. 2 1
      app/Http/Controllers/api/thirdPart/haiq/HaiRoboticsController.php
  18. 2 14
      app/Http/Controllers/api/thirdPart/haiq/LightController.php
  19. 9 0
      app/Http/Controllers/api/thirdPart/jianshang/RejectedController.php
  20. 4 2
      app/Imports/DischargeTaskImport.php
  21. 87 12
      app/Jobs/CacheShelfTaskJob.php
  22. 2 3
      app/Jobs/ProcurementCheckConfirmInform.php
  23. 3 5
      app/Jobs/RejectedBillCreateInstantBill.php
  24. 1 1
      app/Logistic.php
  25. 6 0
      app/MaterialBox.php
  26. 18 0
      app/OracleBasLocation.php
  27. 6 1
      app/Owner.php
  28. 24 49
      app/Services/CacheShelfService.php
  29. 8 10
      app/Services/DbOpenService.php
  30. 17 1
      app/Services/DeliveryAppointmentService.php
  31. 4 22
      app/Services/ForeignHaiRoboticsService.php
  32. 191 41
      app/Services/HandInStorageService.php
  33. 22 0
      app/Services/MaterialBoxService.php
  34. 0 3
      app/Services/NewOrderCountingRecordService.php
  35. 2 1
      app/Services/OwnerPriceOperationService.php
  36. 32 3
      app/Services/StationService.php
  37. 90 23
      app/Services/StationTaskBatchService.php
  38. 29 38
      app/Services/StationTaskMaterialBoxService.php
  39. 178 68
      app/Services/StorageService.php
  40. 4 5
      app/Services/common/BatchUpdateService.php
  41. 12 3
      app/Station.php
  42. 4 0
      app/StationTaskCommodity.php
  43. 24 14
      app/TaskTransaction.php
  44. 4 4
      bashupMysql.sh
  45. 2 0
      config/api_logistic.php
  46. 2 0
      config/haiRou.php
  47. 0 7
      config/sync,php.php
  48. 0 2
      database/migrations/2021_07_02_092716_add_owner_price_operation_id_to_owner_store_out_fee_details.php
  49. 3 1
      database/migrations/2021_07_07_103716_change_warehouses_table.php
  50. 4 1
      database/migrations/2021_07_07_164742_change_waybills_add_db_table.php
  51. 7 1
      database/migrations/2021_07_15_173811_alert_order_type_column_in_waybills_table.php
  52. 0 2
      database/migrations/2021_07_16_092933_add_work_name_and_drop_other_to_owner_store_out_fee_details_table.php
  53. 1 3
      database/migrations/2021_07_28_115218_create_requirements_table.php
  54. 32 0
      database/migrations/2021_07_29_131718_change_task_transactions_table_add_bin_number_column.php
  55. 34 0
      database/migrations/2021_07_29_153104_change_waybills_wms_number_length.php
  56. 32 0
      database/migrations/2021_07_30_162047_change_name_column_in_order_package_counting_records_table.php
  57. 34 0
      database/migrations/2021_08_03_092749_change_task_transactions_add_column_lotnum.php
  58. 32 0
      database/migrations/2021_08_04_140019_change_owners_table_change_is_check_asn_column.php
  59. 5 0
      resources/sass/text.scss
  60. 33 32
      resources/views/control/panel.blade.php
  61. 5 5
      resources/views/customer/project/part/_three.blade.php
  62. 5 5
      resources/views/maintenance/carType/create.blade.php
  63. 0 1
      resources/views/maintenance/log/index.blade.php
  64. 7 1
      resources/views/station/monitor/show.blade.php
  65. 0 213
      resources/views/station/monitor/show_bak.blade.php
  66. 96 12
      resources/views/station/monitor/visual.blade.php
  67. 74 52
      resources/views/store/deliveryAppointment/appointment.blade.php
  68. 160 57
      resources/views/store/deliveryAppointment/list.blade.php
  69. 2 2
      resources/views/store/handInStorage/androidIndex.blade.php
  70. 262 0
      resources/views/store/handInStorage/putaway.blade.php
  71. 89 14
      resources/views/store/handInStorage/receive.blade.php
  72. 40 30
      resources/views/store/handInStorage/receiveDetailPage.blade.php
  73. 1 1
      resources/views/store/inStorage/_commodities.blade.php
  74. 36 0
      resources/views/store/inStorage/_lotModal.blade.php
  75. 25 0
      resources/views/store/inStorage/_setCommodityMaximum.blade.php
  76. 50 0
      resources/views/store/inStorage/_settingAsnRule.blade.php
  77. 2 0
      resources/views/store/inStorage/androidIndex.blade.php
  78. 8 10
      resources/views/store/inStorage/commodityBindModel.blade.php
  79. 61 47
      resources/views/store/inStorage/halfChestStorage.blade.php
  80. 25 2
      resources/views/store/inStorage/index.blade.php
  81. 53 0
      resources/views/store/inStorage/quickPutStorage.blade.php
  82. 27 29
      resources/views/transport/waybill/edit.blade.php
  83. 30 4
      resources/views/transport/waybill/index.blade.php
  84. 0 3
      routes/apiLocal.php
  85. 11 3
      routes/web.php
  86. 1 1
      syncProject.sh
  87. 5 0
      yarn.lock
  88. 44 1
      文档/SystemHandBook.md

+ 11 - 5
app/Commodity.php

@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Model;
 use App\Traits\ModelTimeFormat;
 
 use App\Traits\ModelLogChanging;
+use Illuminate\Database\Eloquent\Relations\HasOne;
 
 class Commodity extends Model
 {
@@ -16,11 +17,9 @@ class Commodity extends Model
         'width','height','volumn',"type","pack_spec",'updated_at',"remark"];
     protected $appends=['barcode'];
 
-    public function setNameAttribute($value){
-        $this->attributes['name']=str_replace(PHP_EOL,'',$value);
-    }
-    public function getNameAttribute($value){
-        return str_replace(array("\r\n","\n","\r","\"","""),' ',$value);
+    public function model():HasOne
+    {
+        return $this->hasOne(MaterialBoxModel::class,"commodity_id");
     }
     public function barcodes()
     {
@@ -29,6 +28,7 @@ class Commodity extends Model
     public function owner(){
         return $this->belongsTo('App\Owner','owner_id','id');
     }
+
     public function getBarcodeAttribute(){
         return $this->barcodes[0]['code']??'';
     }
@@ -38,6 +38,12 @@ class Commodity extends Model
     public function getOwnerCodeAttribute(){
         return $this->owner['code']??'';
     }
+    public function setNameAttribute($value){
+        $this->attributes['name']=str_replace(PHP_EOL,'',$value);
+    }
+    public function getNameAttribute($value){
+        return str_replace(array("\r\n","\n","\r","\"","""),' ',$value);
+    }
 
     public function newBarcode($barcode){
         $barcodeModel = $this->barcodes()->where('code', $barcode)->first();

+ 1 - 9
app/Console/Commands/CreateWeightStatistic.php

@@ -2,15 +2,7 @@
 
 namespace App\Console\Commands;
 
-use App\Order;
-use App\OrderBin;
 use App\OrderPackageCountingRecord;
-use App\Services\BatchService;
-use App\Services\common\BatchUpdateService;
-use App\Services\DocWaveHeaderService;
-use App\Services\LogService;
-use App\ValueStore;
-use Carbon\Carbon;
 use Illuminate\Console\Command;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\DB;
@@ -27,7 +19,7 @@ class CreateWeightStatistic extends Command
         $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 BETWEEN '{$yesterday} 00:00:00' AND '{$yesterday} 23:59:59' GROUP BY date
 sql;
         $result = DB::selectOne(DB::raw($sql));

+ 13 - 2
app/DeliveryAppointment.php

@@ -3,6 +3,7 @@
 namespace App;
 
 use App\Traits\ModelTimeFormat;
+use Carbon\Carbon;
 use Illuminate\Database\Eloquent\Model;
 
 use App\Traits\ModelLogChanging;
@@ -33,12 +34,14 @@ class DeliveryAppointment extends Model
     //时段 映射date_period字段 必须有序 否则展示数据错乱
     const PERIOD=[
         0 => "09-11",
-        1 => "13-17",
+        1 => "12-14",
+        2 => "14-17",
     ];
     //时长 映射PERIOD常量
     const HOUR=[
         0 => 3,
-        1 => 5
+        1 => 3,
+        2 => 4,
     ];
     //状态
     const STATUS=[
@@ -85,7 +88,15 @@ class DeliveryAppointment extends Model
         return $this->belongsTo(Logistic::class);
     }
 
+    /**
+     * 2021-08-05 在此之前所有 period为1的时间都为13-17
+     *
+     * @return string
+     */
     public function getPeriodAttribute(){
+        /** @var Carbon $create */
+        $create = $this["created_at"];
+        if ($create->lt(Carbon::parse("2021-08-05")) && $this["date_period"]==1)return '13-17';
         return self::PERIOD[$this["date_period"]];
     }
 }

+ 0 - 4
app/DischargeTask.php

@@ -61,8 +61,4 @@ class DischargeTask extends Model
         return $this->belongsTo(Warehouse::class);
     }
 
-    public function getTypeAttribute($index)
-    {
-        return $this::types[$index];
-    }
 }

+ 0 - 39
app/Http/Controllers/CacheShelfController.php

@@ -3,12 +3,10 @@
 namespace App\Http\Controllers;
 
 use App\Components\AsyncResponse;
-use App\Services\CacheShelfService;
 use App\Station;
 use Illuminate\Contracts\Foundation\Application;
 use Illuminate\Contracts\View\Factory;
 use Illuminate\Database\Eloquent\Builder;
-use Illuminate\Http\Request;
 use Illuminate\View\View;
 
 class CacheShelfController extends Controller
@@ -29,41 +27,4 @@ class CacheShelfController extends Controller
         return view('station.cachingShelf.list.index', compact('stations'));
     }
 
-    /**
-     * 获取缓存货架上的料箱
-     * @param Request $request
-     * @param string $id
-     * @param CacheShelfService $service
-     */
-    public function getChildStationApi(Request $request,string $id,CacheShelfService $service)
-    {
-        $stations = $service->getChildStation($id);
-        $this->success($stations);
-    }
-
-    /**
-     * 缓存架亮灯
-     * @param Request $request
-     * @param CacheShelfService $service
-     * @return mixed
-     */
-    public function lightOnApi(Request $request,CacheShelfService $service): array
-    {
-        if($request['stationCode'] && $request['materialBoxCode']){
-            return  $service->bindMaterialBox($request['stationCode'],$request['materialBoxCode']);
-        }
-        return ['success' => false,'message' => '参数错误'];
-    }
-
-    /**
-     * @param Request $request
-     * @param CacheShelfService $service
-     * @return array|bool[]
-     */
-    public function clearTaskApi(Request $request,CacheShelfService $service): array
-    {
-        $code = $request['station'];
-        return $service->clearTask($code);
-    }
-
 }

+ 41 - 25
app/Http/Controllers/ControlPanelController.php

@@ -123,39 +123,42 @@ class ControlPanelController extends Controller
     {
         //转化为Carbon
         $start = Carbon::parse(request("start"));
-        $end = Carbon::parse(request("end"));
+        $end   = Carbon::parse(request("end"));
 
         //定义三个数组 空间换时间 避免结果集二次转换
         $title = []; //标题
         $data = []; //核心数据,二维数组
-        foreach (CarbonPeriod::create($start, $end) as $date) {
+        foreach (CarbonPeriod::create($start,$end) as $date){
             /** @var $date Carbon */
             $str = $date->format("Y-m-d");
-            $data[] = $this->getTargetData($str);
+            $data = $this->getTargetData($str);
             $title[] = $str;
         }
 
         //大于31天转换为月份显示
-        if ($end->diffInDays($start) > 31) {
+        if ($end->diffInDays($start) > 31){
             $title = [];
             $sign = []; //标记是否已被插入
             $dataTemp = []; //临时存储
 
-            foreach ($data as $datum) {
-                $month = substr($datum["date"], 0, 7);
-                if (!isset($sign[$month])) {
-                    $dataTemp[] = ["date" => $month, "total" => $datum["total"], "count" => $datum["count"], "value" => $datum["value"]];
+            foreach ($data as $datum){
+                $month = substr($datum["date"],0,7);
+                if (!isset($sign[$month])){
+                    $dataTemp[] = ["date"=>$month,"total"=>$datum["total"],"count"=>$datum["count"],"value"=>$datum["value"]];
                     $title[] = $month;
-                    $sign[$month] = count($dataTemp) - 1;
-                } else {
+                    $sign[$month] = count($dataTemp)-1;
+                }else{
                     $dataTemp[$sign[$month]]["total"] += $datum["total"];
                     $dataTemp[$sign[$month]]["count"] += $datum["count"];
-                    $dataTemp[$sign[$month]]["value"] = (string)($dataTemp[$sign[$month]]["total"] ? intval(($dataTemp[$sign[$month]]["count"] / $dataTemp[$sign[$month]]["total"]) * 100) : 0);
+                    $dataTemp[$sign[$month]]["value"] = (string)($dataTemp[$sign[$month]]["total"] ? intval(($dataTemp[$sign[$month]]["count"]/$dataTemp[$sign[$month]]["total"])*100) : 0);
                 }
             }
             $data = $dataTemp;
         }
-        $this->success(["title" => $title, "data" => $data]);
+
+        array_unshift($title, 'product');
+        array_unshift($data, $title);
+        $this->success(["title"=>date("Y-m-d",strtotime($start)),"data"=>$data]);
     }
 
 
@@ -208,22 +211,35 @@ class ControlPanelController extends Controller
      */
     private function getTargetData(string $date)
     {
-        if ($date == date("Y-m-d")) {
+        $res = [];
+        if ($date == date("Y-m-d",1622908800)){
             $sql = <<<sql
-SELECT DATE_FORMAT(order_packages.created_at,'%Y-%m-%d') date,
+SELECT DATE_FORMAT(order_packages.created_at,'%Y-%m-%d') date,IFNULL(mm.name,'未知') name ,
 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 != '订单取消'
-AND order_packages.created_at >= '{$date} 00:00:00' GROUP BY date
+COUNT(1) total FROM order_packages LEFT JOIN orders ON order_packages.order_id=orders.id
+LEFT JOIN measuring_machines AS mm ON mm.id = order_packages.measuring_machine_id
+WHERE orders.wms_status != '订单取消'
+AND order_packages.created_at like '{$date}%' GROUP BY date,order_packages.measuring_machine_id
 sql;
-
-            $pack = DB::selectOne(DB::raw($sql));
-            if (!$pack) return ["date" => $date, "total" => 0, "count" => 0, "value" => 0];
-            return ["date" => $pack->date, "total" => $pack->total, "count" => $pack->count, "value" => (string)($pack->total ? intval(($pack->count / $pack->total) * 100) : 0)];
+            //todo 新写
+            $info = DB::select(DB::raw($sql));
+            if (!$info) return  $res;
+            $no_weight  =  isset($info[0]->name)  && $info[0]->name == '未知' ? $info[0]->total - $info[0]->count : 0;
+            foreach ($info as $v){
+                $res[] = [$v->name,$v->count];
+            }
+            array_push($res, ['未称重',$no_weight]);
+        }else{
+            $info = app(CacheService::class)->getOrExecute("weight.".$date,function ()use($date){
+                return OrderPackageCountingRecord::query()->where("targeted_at",$date)->get()->toArray();
+            },config("cache.expirations.forever"));
+            if (array_key_exists('date',$info)) return  $res;
+            $no_weight  =  isset($info[0]->name)  && $info[0]->name == '未知' ? $info[0]->total - $info[0]->count : 0;
+            foreach ($info as $v){
+                $res[] = [$v->name,$v->count];
+            }
+            array_push($res, ['未称重',$no_weight]);
         }
-        return app(CacheService::class)->getOrExecute("weight." . $date, function () use ($date) {
-            $count = OrderPackageCountingRecord::query()->where("targeted_at", $date)->first();
-            if (!$count) return ["date" => $date, "total" => 0, "count" => 0, "value" => 0];
-            return ["date" => $count->targeted_at, "total" => $count->total_count, "count" => $count->un_weigh_count, "value" => (string)($count->total_count ? intval(($count->un_weigh_count / $count->total_count) * 100) : 0)];
-        }, config("cache.expirations.forever"));
+        return $res;
     }
 }

+ 8 - 5
app/Http/Controllers/DeliveryAppointmentController.php

@@ -30,9 +30,9 @@ class DeliveryAppointmentController extends Controller
     {
         if(!Gate::allows('入库管理-入库预约-预约管理')){ return view("exception.authority");  }
         $list = app("DeliveryAppointmentService")->query(request()->input())
-            ->with(["logistic",'warehouse','details.commodity.barcodes','cars.car'])
+            ->with(["logistic",'warehouse'])
+            ->orderByRaw("if(status=0,0,1),created_at DESC")
             ->paginate(request("paginate") ?? 50);
-
         $warehouses = Warehouse::query()->select("id","name")->get();
         $owners = app("OwnerService")->getIntersectPermitting();
         $params = request()->input();
@@ -71,6 +71,7 @@ class DeliveryAppointmentController extends Controller
         $amount = request("detail_amount");
         $need = app("DeliveryAppointmentService")->calculateCapacity($tonne,$cubicMeter,$amount,$warehouse->reduced_production_capacity_coefficient);//所需产能
         $start = Carbon::today();
+        if (request("postpone"))$start = $start->addDays(request("postpone"));
         $end = Carbon::today()->addDays(6);
         $map = [];
         DeliveryAppointment::query()->selectRaw("appointment_date,date_period,SUM(capacity) AS capacity")
@@ -215,7 +216,7 @@ class DeliveryAppointmentController extends Controller
         ])->errors();
         if (count($errors)>0)$this->error("未选定预约日期");
         /** @var DeliveryAppointment|\stdClass $appointment */
-        $appointment = DeliveryAppointment::query()->with("cars")->find($id);
+        $appointment = DeliveryAppointment::query()->whereIn("status",[0,3])->with("cars")->find($id);
         if (!$appointment)$this->error("预约单不存在");
         foreach ($appointment->cars as $car){
             if ($car->status!=0)$this->error("车辆已达,无法修改预约");
@@ -235,10 +236,12 @@ class DeliveryAppointmentController extends Controller
                 $available = $total-$result->capacity;
                 if ($available < $appointment->capacity)$this->success(["isFail"=>true]);
             }
-            $appointment->update([
+            $update = [
                 "appointment_date"      => $selectDate["date"],
                 "date_period"           => $selectDate["time"],
-            ]);
+            ];
+            if ($appointment->status==3)$update["status"] = 0;
+            $appointment->update($update);
         });
         dispatch(new DeliveryAppointmentCheck($appointment->id))->delay(Carbon::parse($selectDate["date"]." ".(explode("-",DeliveryAppointment::PERIOD[$selectDate["time"]])[1]).":00:01"));
         //当日或次日预约单广播

+ 93 - 11
app/Http/Controllers/HandInStorageController.php

@@ -3,8 +3,10 @@
 namespace App\Http\Controllers;
 
 use App\Components\AsyncResponse;
+use App\OracleBasLocation;
 use App\OracleDOCASNHeader;
 use App\Services\HandInStorageService;
+use Doctrine\DBAL\Exception\DatabaseObjectExistsException;
 use Illuminate\Http\Request;
 
 class HandInStorageController extends Controller
@@ -15,22 +17,40 @@ class HandInStorageController extends Controller
      */
     public function selectAsn(Request $request)
     {
+        $this->gate("入库管理-手持入库-收货");
         /** @var HandInStorageService $handInStorageService  */
         $handInStorageService=app('HandInStorageService');
         $asnno= $request->input('asnno');
         $asns =$handInStorageService->selectAsn($asnno);
-        if ($asns->count()>0){
+        if (count($asns)>0){
+            foreach ($asns as $asn){
+                $asn->asnDetails=array();
+            }
             $this->success($asns);
         }else{
-            $this->error('未搜索到ASN单');
+            $this->error('无有效的ASN的订单');
         }
     }
+
+    public function checkAsnOperation(Request $request)
+    {
+        $this->gate("入库管理-手持入库-收货");
+        /** @var HandInStorageService $handInStorageService  */
+        $handInStorageService=app('HandInStorageService');
+        $info= $request->input('info');
+        $res=$handInStorageService->checkAsnOperation($info);
+        if ($res===1)$this->error('无有效的ASN的订单');
+        elseif ($res===2)$this->error('该asn无预约,暂不可收货');
+        else $this->success($res);
+    }
     /**
      * @param $asnno
      * 跳转到收货明细页面
      */
+
     public function receiveDetailPage($asnno,$customerid)
     {
+        $this->gate("入库管理-手持入库-收货");
         /** @var HandInStorageService $handInStorageService  */
         $handInStorageService=app('HandInStorageService');
         if (!$customerid||$customerid=='undefined')
@@ -47,11 +67,11 @@ class HandInStorageController extends Controller
      */
     public function selectAsnDetails(Request $request)
     {
+        $this->gate("入库管理-手持入库-收货");
         $asnno= $request->input('asnno');
         $asnDetails =app('HandInStorageService')->selectAsnDetails($asnno);
-        if ($asnDetails->count()>0)$this->success($asnDetails);
-        else $this->error('未搜索到ASN详情单');
-
+        if (count($asnDetails)>0)$this->success($asnDetails);
+        else $this->error('未查询到相应的asn明细');
     }
     /**
      * @param Request $request
@@ -60,24 +80,86 @@ class HandInStorageController extends Controller
     public function getBasSkuWithLot(Request $request): array
     {
         $customerid= $request->input('customerid');
-        $sku= $request->input('sku');
+        $skuOrBarcode= $request->input('sku');
         $asnno= $request->input('asnno');
-        $asnDetail=app('HandInStorageService')->getAsnDetail($asnno,$sku);
-        $basSku =app('HandInStorageService')->getBasSkuLotId($customerid,$sku);
+        $asnDetail=app('HandInStorageService')->getAsnDetail($asnno,$skuOrBarcode);
+        if (!$asnDetail)$this->error('无效条码');
+        $basSku =app('HandInStorageService')->getBasSkuLotId($customerid,$asnDetail->sku);
         if (isset($basSku)&&isset($asnDetail))return ['success'=>true,'basSku'=>$basSku,'asnDetail'=>$asnDetail];
         else $this->error('无效条码');
     }
 
+    /**
+     * @throws \Throwable
+     * 收货
+     */
     public function fluxHandIn(Request $request)
     {
+        $this->gate("入库管理-手持入库-收货");
         $info=$request->input('info');
-//        dd($info);
         if (!$info['customerid']||!$info['sku']||!$info['asnno']) $this->error('参数错误');
         if ($info['amount']+$info['receivedqty']>$info['expectedqty'])$this->error('收货数大于预期数');
+//        if ($info['location']){
+//            $location=OracleBasLocation::query()
+//                ->where('locationid',$info['location'])
+//                ->where('status','OK')
+//                ->first();
+//            if (!$location)$this->error('目标库位不存在');
+//        }
         /** @var HandInStorageService $handInStorageService  */
         $handInStorageService=app('HandInStorageService');
-        $handInStorageService->fluxHandIn($info);
-//        dd($result,"111");
+        try {
+            $result = $handInStorageService->fluxHandIn($info);
+            if ($result)$this->success("收货成功");
+            else $this->error("收货失败");
+        } catch (\Exception $e) {
+            app('LogService')->log(__METHOD__,'error_'.__FUNCTION__,json_encode($info).'|catch:'.$e->getMessage());
+        }
+    }
+
+    /**
+     * @param Request $request
+     * 根据商品条码和跟踪号 获取要上架的任务列表
+     */
+    public function getTsk(Request $request)
+    {
+        $this->gate("入库管理-手持入库-上架");
+        $barCode=$request->input('barCode');
+        $trackNumber=$request->input('trackNumber');
+        if(!$barCode)$this->error('条码不能为空');
+        if(!$trackNumber)$this->error('容器号不能为空');
+        /** @var HandInStorageService $handInStorageService  */
+        $handInStorageService=app('HandInStorageService');
+        $tasks=$handInStorageService->getTsk($trackNumber,$barCode);
+        if (count($tasks)>0)$this->success($tasks);
+        else $this->error("该商品暂无上架任务");
+    }
+
+    /**
+     * @throws \Throwable
+     * 上架
+     */
+    public function handFluxPa(Request $request)
+    {
+        $this->gate("入库管理-手持入库-上架");
+        $info=$request->input('info');
+        if (!$info['location']||!$info['amount']||!$info['trackNumber']||!$info['barCode']) $this->error('参数错误');
+        if (count($request->input('checkData'))==0) $this->error('请勾选要上架任务');
+        $checkData=$request->input('checkData')[0];
+        $location=OracleBasLocation::query()
+                ->where('locationid',$info['location'])
+                ->where('status','OK')
+                ->first();
+        if (!$location)$this->error('目标库位不存在');
+        /** @var HandInStorageService $handInStorageService  */
+        $handInStorageService=app('HandInStorageService');
+        try {
+            $result = $handInStorageService->fluxHandPa($info, $checkData);
+            if ($result)$this->success("上架成功");
+            else $this->error("上架失败");
+        } catch (\Exception $e) {
+            app('LogService')->log(__METHOD__,'error_'.__FUNCTION__,json_encode($info).'|catch:'.$e->getMessage());
+        }
     }
 
 

+ 1 - 1
app/Http/Controllers/MenuController.php

@@ -42,7 +42,7 @@ class MenuController extends Controller
         if (request()->has("font_style"))$update["font_style"] = request("font_style");
         if (request()->has("route"))$update["route"] = request("route");
         if (request()->has("diff")){
-            $diff = request("diff"); //TODO 此处需要查询出模型 ->get()->each()来进行update操作以确保观察者检测到 下面同理
+            $diff = request("diff"); //此处需要查询出模型 ->get()->each()来进行update操作以确保观察者检测到 下面同理
             Menu::query()->whereIn("id",request("child"))->get()->each(function ($menu)use($diff){
                $menu->update(["level"=>DB::raw("level - {$diff}")]);
             });

+ 1 - 1
app/Http/Controllers/RejectedController.php

@@ -322,7 +322,7 @@ class RejectedController extends Controller
     {
         if(!Gate::allows('退货管理-编辑')){return ['success'=>'false','fail_info'=>"没有权限"];   }
         $ids=$request->input('ids')??'';
-        $rejecteds=RejectedBill::whereIn('id',$ids)->get();
+        $rejecteds=RejectedBill::whereIn('id',$ids)->where("is_finished",false)->get();
         $rejecteds->each(function($rejected){
             $rejected['is_finished']=true;
             $re=$rejected->update();

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

@@ -64,7 +64,8 @@ SELECT COUNT(*) count FROM (SELECT SUM(QTY) qty FROM INV_LOT_LOC_ID WHERE
 TRACEID = '*' AND LOCATIONID IN {$codes} GROUP BY LOCATIONID) inv WHERE INV.qty!=0
 SQL;
             $count = DB::connection("oracle")->selectOne(DB::raw($sql))->count;
-            $res[] = intval($count/$len*1000)/10;
+            //$res[] = intval($count/$len*1000)/10;
+            $res[] = [$len,$count];
         }
         Cache::tags("loadBoxMonitor")->put($cacheKey,$res,1800);
         $this->success($res);

+ 204 - 92
app/Http/Controllers/StorageController.php

@@ -13,12 +13,14 @@ use App\Services\LogService;
 use App\Station;
 use App\StationTask;
 use App\StationTaskMaterialBox;
+use App\Store;
 use App\StoreItem;
 use App\TaskTransaction;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Foundation\Auth\AuthenticatesUsers;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Gate;
 use Illuminate\Support\Facades\Validator;
@@ -91,13 +93,42 @@ class StorageController extends Controller
      */
     public function checkMaximum()
     {
-        $item = app("StoreItemService")->getMaxAvailableDetail(request("asn"),request("barCode"));
-        if (!$item)$this->error("无此单据记录");
-        $models = CommodityMaterialBoxModel::query()->where("commodity_id",$item->commodity_id)->get();
-        if ($models->count()==0)$this->success(["material_box_model_id"=>null]);
+        $lotNum = request("lotNum");
+        $sql = <<<SQL
+SELECT * FROM INV_LOT_ATT WHERE LOTNUM = '{$lotNum}'
+SQL;
+        $lot = DB::connection("oracle")->selectOne(DB::raw($sql));
+        if (!$lot)$this->error("批次丢失");
+        $commodity = Commodity::query()->whereHas("owner",function ($query)use($lot){
+            $query->where("code",$lot->customerid);
+        })->where("sku",$lot->sku)->first();
+        if (!$commodity)$this->error("WAS无此商品信息");
+        $models = CommodityMaterialBoxModel::query()->where("commodity_id",$commodity->id)->get();
+        if ($models->count()==0)$this->success(["material_box_model_id"=>null,"commodity_id"=>$commodity->id]);
         $map = [];
         foreach ($models as $model)$map[$model->material_box_model_id] = $model;
-        $this->getMaterBoxModel($item,$map);
+        $models = app("MaterialBoxModelService")->getModelSortedByOwner($commodity->owner_id);
+        $m = null;
+        foreach ($models as $model){
+            if (!isset($map[$model->id]))continue;
+            $model->maximum = $map[$model->id]->maximum;
+            $boxCodes = app("MaterialBoxService")->getModelAvailableBox($model->id,true);
+            if (!$boxCodes)continue;
+            if (!$m)$m = $model;
+            $sql = <<<SQL
+SELECT LOCATIONID,({$model->maximum}-QTY) AS QTY FROM INV_LOT_LOC_ID WHERE LOTNUM = '{$lotNum}'
+AND LOCATIONID IN ({$boxCodes}) AND TRACEID = '*' AND {$model->maximum}-QTY > 0 ORDER BY (CASE QTY WHEN 0 THEN 1 ELSE 0 END),{$model->maximum}-QTY
+SQL;
+            $res = DB::connection("oracle")->selectOne(DB::raw($sql));
+            if ($res){
+                $m = $model;
+                $m->maximum = $res->qty;
+                $m->location = $res->locationid;
+                break;
+            }
+        }
+        if (!$m)$this->error("没有可用料箱");
+        $this->success(["need"=>$m->maximum,"material_box_model_id"=>$m->id,"commodity_id"=>$commodity->id,"location"=>$m->locationid]);
     }
 
     /**
@@ -167,48 +198,59 @@ sql;
         if (!$station)$this->error("未知库位");
         $isAvailable = app("StationService")->isAvailable($station);
         if (!$isAvailable)$this->error("库存被占用或存在任务未处理");
-        $amount = app("StorageService")->checkPutAmount(request("asn"),request("barCode"));
+        $amount = app("StorageService")->checkPutAmount(request("track"),request("barCode"),request("lotNum"));
         if ($amount<request("amount"))$this->error("待上架数量不足,最大可上数量为{$amount}");
 
         //发起取箱任务
-        $exe = function ($boxId)use($station){
+        $exe = function ($boxId)use($station,$amount){
             DB::beginTransaction();
-            $collection = new Collection();
-            $task = StationTask::query()->create([
-                'status' => "待处理",
-                'station_id' => $station->id,
-            ]);
-            $collection->add(StationTaskMaterialBox::query()->create([
-                'station_id' => $station->id,
-                'material_box_id'=>$boxId,
-                'status'=>"待处理",
-                'type' => '取',
-                'station_task_id' => $task->id,
-            ]));
-            if (!app("ForeignHaiRoboticsService")->fetchGroup($station->code,$collection,'','立架出至缓存架'))$this->error("呼叫机器人失败");
-            //生成临时任务事务
-            TaskTransaction::query()->create([
-                "doc_code" => request("asn"),
-                "bar_code" => request("barCode"),
-                "fm_station_id" => $station->id,
-                "material_box_id" => $boxId,
-                "commodity_id" => request("commodity_id"),
-                "amount" => request("amount"),
-                "type" => "入库",
-                "user_id" => Auth::id(),
-                "mark" => 1
-            ]);
-            DB::commit();
-            //亮灯
-            app("CacheShelfService")->lightUp($station->code,'2','1');
-            app("StationService")->locationOccupy($station->code);//占用库位
+            try{
+                $collection = new Collection();
+                $task = StationTask::query()->create([
+                    'status' => "待处理",
+                    'station_id' => $station->id,
+                ]);
+                $collection->add(StationTaskMaterialBox::query()->create([
+                    'station_id' => $station->id,
+                    'material_box_id'=>$boxId,
+                    'status'=>"待处理",
+                    'type' => '取',
+                    'station_task_id' => $task->id,
+                ]));
+                if (!app("ForeignHaiRoboticsService")->fetchGroup($station->code,$collection,'','立架出至缓存架'))$this->error("呼叫机器人失败");
+                //生成临时任务事务
+                TaskTransaction::query()->create([
+                    //"doc_code" => request("asn"),
+                    "bar_code" => request("barCode"),
+                    "fm_station_id" => $station->id,
+                    "material_box_id" => $boxId,
+                    "commodity_id" => request("commodity_id"),
+                    "amount" => request("amount"),
+                    "type" => "入库",
+                    "user_id" => Auth::id(),
+                    "mark" => 1,
+                    "lot_num" => request("lotNum"),
+                    "track_num" => request("track"),
+                ]);
+                //亮灯
+                app("CacheShelfService")->lightUp($station->code,'3','2');
+                app("StationService")->locationOccupy($station->code);//占用库位
+                Cache::forever("CACHE_SHELF_OCCUPANCY_{$station->id}",true);
+                DB::commit();
+                return true;
+            }catch (\Exception $e){
+                DB::rollBack();
+                return false;
+            }
         };
-        if ($boxId && app("MaterialBoxService")->checkUsableBox($boxId))$this->success($exe($boxId));
-        $item = app("StoreItemService")->getMaxAvailableDetail(request("asn"),request("barCode"));
-        if (!$item)$this->error("无此单据记录");
-        $models = app("MaterialBoxModelService")->getModelSortedByOwner($item->store->owner_id);
-        $models->load(["commodity"=>function($query)use($item){
-            $query->where("commodity_id",$item->commodity_id);
+        //检查获取的料箱仍然可用
+        if ($boxId && app("MaterialBoxService")->checkUsableBox($boxId))$this->success(["status"=>$exe($boxId),"amount"=>$amount-request("amount")]);
+
+        $commodity = Commodity::query()->find(request("commodity_id"));
+        if (!$commodity)$this->error("商品在WAS丢失");
+        $models = app("MaterialBoxModelService")->getModelSortedByOwner($commodity->owner_id);
+        $models->load(["commodity"=>function($query)use($commodity){
+            $query->where("commodity_id",$commodity->id);
         }]);
         //获取料箱
         if ($boxId){
@@ -216,18 +258,18 @@ sql;
             $boxId = null;
             //料箱存在且不可用
             /** @var \Illuminate\Database\Eloquent\Collection $models */
-
             foreach ($models as $model){
                 if (!$model->commodity)continue;
                 //料箱不可用寻找新料箱
-                $result = app("StorageService")->getHalfBoxLocation($model->commodity,$item,request("asn"),$blacklist);
+                $result = app("StorageService")->getMaxAvailableHalfBoxLocation($model->commodity, request("lotNum"), $blacklist);
                 while ($result){
+                    $materialBox = MaterialBox::query()->where("code",$result->locationid)->first();
                     //料箱可用并且数量符合本次半箱数量 跳出
-                    if (app("MaterialBoxService")->checkUsableBox($result->material_box_id)
-                        && $model->maximum-$result->amount>=request("amount"))$this->success($exe($result->material_box_id));
-                    else $blacklist[] = $result->material_box_id;
+                    if ($materialBox && app("MaterialBoxService")->checkUsableBox($materialBox->id)
+                        && $result->qty>=request("amount"))$this->success(["status"=>$exe($materialBox->id),"amount"=>$amount-request("amount")]);
+                    else if ($materialBox)$blacklist[] = $materialBox->id;
                     //否则黑名单此料箱继续查找 直至料箱为空
-                    $result = app("StorageService")->getHalfBoxLocation($model->commodity,$item,request("asn"),$blacklist);
+                    $result = app("StorageService")->getMaxAvailableHalfBoxLocation($model->commodity, request("lotNum"), $blacklist);
                 }
             }
         }
@@ -241,7 +283,7 @@ sql;
             }
         }else $box = app("MaterialBoxService")->getAnEmptyBox(MaterialBoxModel::query()->find($modelId));
         if (!$box)$this->error("无可用料箱");
-        $this->success($exe($box->id));
+        $this->success(["status"=>$exe($box->id),"amount"=>$amount-request("amount")]);
     }
 
     /**
@@ -394,61 +436,37 @@ sql;
     {
         $insert = function ($commodityId){
             $in = [];
-            $map = [];
             $ids = [];
             foreach (request("models") as $model){
-                $insert[] = [
+                $in[] = [
                     "commodity_id" => $commodityId,
                     "material_box_model_id" => $model["id"],
                     "maximum" => $model["maximum"]
                 ];
-                $map[$model["id"]] = $model;
                 $ids[] = $model["id"];
             }
-            return array($in,$map,$ids);
+            return array($in,$ids);
         };
-        if (request("commodityId")){
-            list($in,$map,$ids) = $insert(request("commodityId"));
-            if ($ids){
-                $map = array_flip($ids);
-                foreach (CommodityMaterialBoxModel::query()->whereIn("id",$ids)->lockForUpdate()->get() as $model){
-                    $index = $map[$model->id];
-                    if ($model->maximum != $in[$index]["maximum"])$model->update(["maximum"=>$in[$index]["maximum"]]);
-                    unset($in[$index]);
+        list($in,$ids) = $insert(request("commodityId"));
+        if ($ids){
+            $map = array_flip($ids);
+            foreach (CommodityMaterialBoxModel::query()->where("commodity_id",request("commodityId"))
+                         ->lockForUpdate()->get() as $model){
+                $index = $map[$model->material_box_model_id];
+                if ($model->maximum != $in[$index]["maximum"]){
+                    CommodityMaterialBoxModel::query()->where("commodity_id",request("commodityId"))
+                        ->where("material_box_model_id",$model->material_box_model_id)
+                        ->update(["maximum"=>$in[$index]["maximum"]]);
                 }
-                $in = array_values($in);
+                unset($in[$index]);
             }
-            if ($in){
-                LogService::log(__CLASS__,__METHOD__,json_encode($in));
-                CommodityMaterialBoxModel::query()->insert($in);
-            }
-            $this->success();
+            $in = array_values($in);
         }
-        $item = StoreItem::query()->whereHas("store",function (Builder $query){
-            $query->where("asn_code",request("asn"));
-        })->whereHas("commodity",function (Builder $query){
-            $query->whereHas("barcodes",function (Builder $query){
-                $query->where("code",request("barCode"));
-            });
-        })->first();
-        if (!$item)$this->error("商品不存在");
-        list($in,$map,$ids) = $insert($item->store->commodity_id);
-        LogService::log(__CLASS__,__METHOD__,json_encode($in));
-        CommodityMaterialBoxModel::query()->insert($in);
-        $this->getMaterBoxModel($item,$map);
-    }
-
-    private function getMaterBoxModel($item,$map)
-    {
-        $models = app("MaterialBoxModelService")->getModelSortedByOwner($item->store->owner_id);
-        foreach ($models as $model){
-            if (!isset($map[$model->id]))continue;
-            $result = app("StorageService")->getHalfBoxLocation($map[$model->id],$item,$item->store->asn_code);
-            if (!$result)continue;
-            $result->maximum = $model->maximum-$result->amount;
-            $this->success($result);
+        if ($in){
+            LogService::log(__CLASS__,__METHOD__,json_encode($in));
+            CommodityMaterialBoxModel::query()->insert($in);
         }
-        $this->success(["need"=>$models[0]->maximum,"material_box_model_id"=>$models[0]->material_box_model_id,"commodity_id"=>$item->commodity_id]);
+        $this->success();
     }
 
     /**
@@ -456,11 +474,105 @@ sql;
      */
     public function searchBarCode()
     {
-        $commodities = Commodity::query()->whereHas("barcodes",function (Builder $query){
+        $commodities = Commodity::query()->with("owner")->whereHas("barcodes",function (Builder $query){
             $query->where("code",request("barCode"));
         })->get();
         if (!$commodities->count())$this->error("库内无此商品信息");
         if ($commodities->count()>1)$commodities->load("owner");
         $this->success($commodities);
     }
+
+    /**
+     * 根据商品ID检索已存在的上限设定
+     */
+    public function searchModel()
+    {
+        $mapping = [];
+        foreach (CommodityMaterialBoxModel::query()->where("commodity_id",request("id"))->get() as $model){
+            $mapping[$model->material_box_model_id] = $model->maximum;
+        }
+        $this->success($mapping);
+    }
+
+    /**
+     * 根据ASN号检索未设定商品型号上限的信息
+     */
+    public function searchAsn()
+    {
+        $sql = <<<SQL
+SELECT CUSTOMERID,SKU FROM TSK_TASKLISTS WHERE DOCNO = ? AND TASKPROCESS = '00' AND TASKTYPE = 'PA' GROUP BY CUSTOMERID,SKU
+SQL;
+        $store = Store::query()->select("owner_id")->where("asn_code",request("asn"))->first();
+        if (!$store || !$store->owner_id)$this->error("WAS内无此ASN单信息");
+
+        $tasks = DB::connection("oracle")->select(DB::raw($sql),[request("asn")]);
+        $codes = array_column($tasks,"sku");
+        $model = MaterialBoxModel::query()->where("maximum_kind",1)->first();
+        if (!$model)$this->error("单品型号缺失");
+        $commodities = Commodity::query()->with("model")->where("owner_id",$store->owner_id)
+            ->whereIn("sku",$codes)->get()->toArray();
+        if (count($codes)!=count($commodities))$this->error("WAS商品信息不全");
+        foreach ($commodities as $index=>$commodity){
+            if ($commodity->model)unset($commodities[$index]);
+        }
+        $this->success(["commodities"=>array_values($commodities),"model"=>$model]);
+    }
+
+    /**
+     * 设置商品上限
+     */
+    public function settingCommodityMaximum()
+    {
+        $modelId = request("modelId");
+        $insert = [];
+        $date = date("Y-m-d H:i:s");
+        foreach (request("commodities") as $commodity){
+            $insert[] = [
+                "commodity_id" => $commodity["id"],
+                "material_box_model_id" => $modelId,
+                "maximum" => $commodity->maximum,
+                "created_at" => $date,
+                "updated_at" => $date,
+            ];
+        }
+        $this->success(CommodityMaterialBoxModel::query()->insert($insert));
+    }
+
+    /**
+     * 检查任务获取多批次
+     */
+    public function checkTask()
+    {
+        $track = request("track");
+        $barCode = request("barCode");
+        $sql = <<<SQL
+SELECT TSK_TASKLISTS.FMLOTNUM FROM TSK_TASKLISTS LEFT JOIN BAS_SKU ON TSK_TASKLISTS.CUSTOMERID = BAS_SKU.CUSTOMERID
+AND TSK_TASKLISTS.SKU = BAS_SKU.SKU
+WHERE FMID = ? AND (ALTERNATE_SKU1 = ? OR ALTERNATE_SKU2 = ? OR ALTERNATE_SKU3 = ?)
+AND TASKPROCESS = '00' AND TASKTYPE = 'PA' GROUP BY FMID,FMLOTNUM
+SQL;
+        $tasks = DB::connection("oracle")->select(DB::raw($sql),[$track,$barCode,$barCode,$barCode]);
+        $result = ["count"=>count($tasks)];
+        if (count($tasks)>1){
+            $lotNums = "";
+            foreach ($tasks as $task)$lotNums .= "'".$task->fmlotnum."',";
+            $lotNums = rtrim($lotNums,",");
+            $sql = <<<SQL
+SELECT * FROM INV_LOT_ATT WHERE LOTNUM IN ({$lotNums});
+SQL;
+            $result["lots"] = DB::connection("oracle")->select(DB::raw($sql));
+        }
+        if (count($tasks)==1)$result["lots"] = $tasks[0]->fmlotnum;
+        $this->success($result);
+    }
+
+    /**
+     * 改变ASN许可规则
+     */
+    public function changeAsnRule()
+    {
+        $ids = request("ids");
+        $val = request("val");
+        $this->success(Owner::query()->whereIn("id",$ids)->update(["is_check_asn"=>$val ? 0 : 1]));
+    }
 }

+ 3 - 1
app/Http/Controllers/StoreController.php

@@ -19,6 +19,7 @@ use Illuminate\Http\RedirectResponse;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
 use Illuminate\Routing\Redirector;
+use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Gate;
 use Illuminate\Support\Facades\Validator;
@@ -35,7 +36,8 @@ class StoreController extends Controller
         $storeService=app(StoreService::class);
         $stores=$storeService->paginate($request->input());
         $warehouses=Warehouse::query()->get();
-        $owners=app("OwnerService")->getIntersectPermitting();
+        $ownerIds=app('UserService')->getPermittingOwnerIds(Auth::user());
+        $owners=Owner::query()->select(["id","name","is_check_asn"])->whereIn('id', $ownerIds)->whereNull('deleted_at')->get();
         return view('store.inStorage.index',compact('stores','warehouses','owners','paginateParams'));
     }
     /**

Dosya farkı çok büyük olduğundan ihmal edildi
+ 10 - 432
app/Http/Controllers/TestController.php


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

@@ -1036,6 +1036,7 @@ class WaybillController extends Controller
         $waybill = $waybills->first();
         $destroys = [];
         $owner = [$waybill->owner_id];
+        if (array_search($waybill->status,["未审核","已审核"])===false)$this->error("运单禁止合并");
         for ($i=1;$i<$waybills->count();$i++){
             //信息一致性校验
             $identical = ($waybill->order && ($waybills[$i]->order->consignee_name!=$waybill->order->consignee_name
@@ -1056,6 +1057,7 @@ class WaybillController extends Controller
             $waybill->warehouse_weight += (double)$waybills[$i]->warehouse_weight;
             $owner[] = $waybills[$i]->owner_id;
         }
+        if (strlen($waybill->source_bill)>191 || strlen($waybill->wms_bill_number)>191)$this->error("单号超长,无法合并");
         $owner = array_unique($owner);
         if (count($owner)>1)$waybill->merge_owner = implode(',',$owner);
         $waybill->update();
@@ -1067,4 +1069,52 @@ class WaybillController extends Controller
         ]);
         $this->success($waybill->waybill_number);
     }
+
+    /**
+     * 运单拆分
+     */
+    public function waybillSplit(Request $request)
+    {
+        $this->gate("运输管理-编辑");
+        $ids = $request->input("ids");
+        DB::beginTransaction();
+        try {
+            /** @var Collection $waybills */
+            $waybills = Waybill::query()->whereHas("waybillAuditLogs",function ($query){
+                $query->where("audit_stage","合并运单");
+            })->whereIn("id",$ids)->get();
+            if ($waybills->count()==0)$this->error("运单不存在或非合并运单");
+            foreach ($waybills as $waybill){
+                $codes = explode(",",$waybill->wms_bill_number);
+                $bills = explode(",",$waybill->source_bill);
+                if (!$codes)continue;
+                /** @var Collection $destroys */
+                foreach (Waybill::onlyTrashed()->whereIn("wms_bill_number",$codes)->get() as $obj){
+                    unset($codes[array_search($obj->wms_bill_number,$codes)]);
+                    unset($bills[array_search($obj->source_bill,$bills)]);
+                    $waybill->charge -= (double)$obj->charge;
+                    $waybill->collect_fee -= (double)$obj->collect_fee;
+                    $waybill->other_fee -= (double)$obj->other_fee;
+                    $waybill->warehouse_weight_other -= (double)$obj->warehouse_weight_other;
+                    $waybill->warehouse_weight -= (double)$obj->warehouse_weight;
+                }
+                Waybill::onlyTrashed()->whereIn("wms_bill_number",explode(",",$waybill->wms_bill_number))->restore();
+                $waybill->merge_owner = null;
+                $waybill->source_bill = implode(",",$bills);
+                $waybill->wms_bill_number = implode(",",$codes);
+                $waybill->update();
+                WaybillAuditLog::query()->create([
+                    'waybill_id'=>$waybill->id,
+                    'audit_stage'=>'拆单返回',
+                    'user_id'=>Auth::id(),
+                ]);
+
+            }
+            DB::commit();
+        }catch (\Exception $e){
+            DB::rollBack();
+            $this->error($e->getMessage());
+        }
+        $this->success(count($ids)==$waybills->count() ? '运单拆单完毕' : '部分运单不符合拆单条件');
+    }
 }

+ 17 - 11
app/Http/Controllers/api/thirdPart/flux/WaybillController.php

@@ -27,7 +27,6 @@ class WaybillController extends Controller
         (new Controller())->log(__METHOD__,__FUNCTION__,'WMS requesting:.'.'|'.json_encode($request->all()));
         $errors=$this->validatorForNew($request->all())->errors();
         if(count($errors)>0){
-            app('LogService')->log(__METHOD__, 'error_' . __FUNCTION__, json_encode($request->getContent()));
             (new Controller())->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]]])
@@ -63,6 +62,8 @@ class WaybillController extends Controller
             $owner=Owner::query()->where('code',$receiveInputting['CustomerID'])->first();
             if (!$owner){$owner=new Owner(['name'=>$receiveInputting['CustomerID'],'code'=>$receiveInputting['CustomerID']]);$owner->save();}
             $zfList=config('merchantsInfo.waybill.ZFList');
+            $type = substr($receiveInputting['CarrierID'],0,2) == 'DB' ? '德邦物流' :
+                (isset($zfList[$receiveInputting['CarrierID']])&&$zfList[$receiveInputting['CarrierID']]?"直发车":"专线");
             $bswasCustomer=OracleBasCustomer::query()->where("customerid",$receiveInputting['CustomerID'])->first();
             if ($bswasCustomer){
                 $origination=$bswasCustomer->address1;
@@ -73,11 +74,11 @@ class WaybillController extends Controller
             }
             $recipient_mobile=trim($receiveInputting['C_Tel1'],',');
             $waybill=new Waybill([
-                'type'=>isset($zfList[$receiveInputting['CarrierID']])&&$zfList[$receiveInputting['CarrierID']]?"直发车":"专线",
+                'type'=>$type,
                 'waybill_number'=>Uuid::uuid1(),
                 'owner_id'=>$owner->id,
                 'wms_bill_number'=>$receiveInputting['OrderNo']??'',
-                'origination'=>isset($origination)?$origination:"",
+                'origination'=>$origination ?? "",
                 'destination'=>$receiveInputting['C_Address1']??'',
                 'recipient'=>$receiveInputting['ConsigneeName']??'',
                 'recipient_mobile'=>$recipient_mobile??'',
@@ -109,15 +110,20 @@ class WaybillController extends Controller
                 'audit_stage'=>'创建',
                 'user_id'=>Auth::id() ?? 0,
             ]);
-            if ($waybill->type=='直发车'){
-                $waybill_number='BSZF'.date ("ymd").str_pad($waybill->id>99999?$waybill->id%99999:$waybill->id,4,"0",STR_PAD_LEFT);
-                $waybill->waybill_number=$waybill_number;
-                $waybill->update();
-            }else{
-                $waybill_number='BSZX'.date ("ymd").str_pad($waybill->id>99999?$waybill->id%99999:$waybill->id,4,"0",STR_PAD_LEFT);
-                $waybill->waybill_number=$waybill_number;
-                $waybill->update();
+            switch ($waybill->type){
+                case "直发车":
+                    $prefix = "BSZF";
+                    break;
+                case "专线":
+                    $prefix = "BSZX";
+                    break;
+                default:
+                    $prefix = "BSDB";
+                    break;
             }
+            $waybill_number=$prefix.date ("ymd").str_pad($waybill->id>99999?$waybill->id%99999:$waybill->id,4,"0",STR_PAD_LEFT);
+            $waybill->waybill_number=$waybill_number;
+            $waybill->update();
             if (!$waybill->order_id && $waybill->wms_bill_number)dispatch(new HandleExceptionWaybill($waybill))->delay(now()->addMinutes(15));
             //回传FLUX
             $this->accomplishToWMS($waybill);

+ 2 - 1
app/Http/Controllers/api/thirdPart/haiq/HaiRoboticsController.php

@@ -25,7 +25,8 @@ class HaiRoboticsController
             'errorMsg'=>'波次任务不能为空'
         ];
         $batchTask=StationTaskBatch::query()->find($request['station_task_batch_id']);
-        $batchesFailed=$this->stationTaskBatchService->runMany(collect([$batchTask]));//执行波次任务
+        $batchesFailed=$this->stationTaskBatchService->runMany(collect([$batchTask]),
+            $request->input("isCacheShelf") ? 'OUTBIN-CACHE-SHELF' : 'OUTBIN-U-SHAPE-LINE');//执行波次任务
         if($batchesFailed && $batchesFailed->isNotEmpty()){
             return [
                 'success'=>false,

+ 2 - 14
app/Http/Controllers/api/thirdPart/haiq/LightController.php

@@ -3,15 +3,11 @@
 
 namespace App\Http\Controllers\api\thirdPart\haiq;
 
-
-
-
 use App\Services\CacheShelfService;
 use App\Services\ForeignHaiRoboticsService;
 use App\Station;
 use App\Traits\TestableInstant;
 use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Log;
 
 class LightController
 {
@@ -20,14 +16,6 @@ class LightController
 
     /** @var ForeignHaiRoboticsService $service */
     private $foreignHaiRoboticsService;
-    public function __construct(){
-        $this->foreignHaiRoboticsService=null;
-    }
-
-    public function lightOn($post){
-    }
-    public function lightOff(Request $request){
-    }
 
     /**
      * @param Request $request {"areaCode":"1004","locCode":"HAIB2-02-03","displayInfo":null,"PTLAction":0,"PTLSettings":null}
@@ -51,12 +39,12 @@ class LightController
                 }
                 /** @var CacheShelfService $cacheShelfService */
                 $cacheShelfService = app(CacheShelfService::class);
-                $result =   $cacheShelfService->lightOffTask($request['locCode'],$request['PTLAction']);
+                $result =   $cacheShelfService->lightOffTask($request['locCode']);
                 $response['location']=$result['success']??'';
                 $response['errMsg']=$result['errMsg']??'';
                 return $response;
             case 'U型线拍灯':
-//                $this->foreignHaiRoboticsService->uLineLightPat($station);
+//                废弃此入口 U型线拍灯口迁移至 PickStationController:processed
         }
 
         return $response;

+ 9 - 0
app/Http/Controllers/api/thirdPart/jianshang/RejectedController.php

@@ -4,6 +4,7 @@
 namespace App\Http\Controllers\api\thirdPart\jianshang;
 
 
+use App\Components\ErrorPush;
 use App\Http\Controllers\Controller;
 use App\Logistic;
 use App\QualityLabel;
@@ -17,6 +18,8 @@ use Zttp\ZttpResponse;
 
 class RejectedController extends Controller
 {
+    use ErrorPush;
+
     function sendRejected($rejected){
         $amount = $rejected['amount'] ?? '';
         $created_at = $rejected['created_at'] ?? '';
@@ -201,6 +204,12 @@ class RejectedController extends Controller
             $forSign = $str . $timestamp . $nonce . $signKey;
             return strtolower(md5($forSign));
         };
+        if (!$data){
+            app('LogService')->log(__METHOD__,'笕尚接口参数异常',json_encode(array($created_at,$fee_collected,$goodses,
+                $logistic_name_return,$logistic_number,$logistic_number_return,$order_number,
+                $sender_mobile,$sender_name)));
+            return false;
+        }
         $timestamp=intval(microtime(true)*1000);
         $nonce=md5(microtime(true));
         $sign=$sortParamsAndMd5(json_decode($data,true),$timestamp,$nonce,config('api.sign_key_rejected_send_jianshang'));

+ 4 - 2
app/Imports/DischargeTaskImport.php

@@ -31,7 +31,9 @@ class DischargeTaskImport implements ToCollection, WithHeadingRow
             $message = '';
             $owner = Owner::query()->where('name', trim($item['货主']))->first();
             $waveHouse = Warehouse::query()->where('name', trim($item['仓库']))->first();
+
             $type = array_search(trim($item['作业名称']), DischargeTask::types);
+
             $unit = array_search(trim($item['单位']), DischargeTask::units);
 
             if (trim($item['单位']) == 'm3'){
@@ -52,7 +54,7 @@ class DischargeTaskImport implements ToCollection, WithHeadingRow
 
             if (!$item['单位'] || strlen(trim('单位')) == 0) $message .= '未输入单位;';
 
-            if (isset($type) && $type != 0) $message .= '指定作业类型错误;';
+            if (!isset($type)) $message .= '指定作业类型错误;';
 
             if (!$item['作业名称']) $message .= '未指定作业类型';
 
@@ -72,7 +74,7 @@ class DischargeTaskImport implements ToCollection, WithHeadingRow
                 'income_unit' => $unit,
                 'income_total_cost' => $item['数量'] * $item['单价'],
                 'status' => 0,
-                'income_remark' => $item['备注'],
+                'income_remark' => $item['备注'] ?? '',
                 'income_at' => $item['预约日期'] ?formatExcelDateTime($item['预约日期']): Carbon::now()->format(Carbon::DEFAULT_TO_STRING_FORMAT)
             ];
             try {

+ 87 - 12
app/Jobs/CacheShelfTaskJob.php

@@ -2,18 +2,22 @@
 
 namespace App\Jobs;
 
+use App\Components\ErrorPush;
 use App\Services\ForeignHaiRoboticsService;
+use App\Station;
 use App\StationTaskMaterialBox;
+use App\TaskTransaction;
 use Illuminate\Bus\Queueable;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Foundation\Bus\Dispatchable;
 use Illuminate\Queue\InteractsWithQueue;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
 
 class CacheShelfTaskJob implements ShouldQueue
 {
-    use Dispatchable, InteractsWithQueue, Queueable;
+    use Dispatchable, InteractsWithQueue, Queueable, ErrorPush;
 
     protected $key;
     protected $count;
@@ -32,21 +36,92 @@ class CacheShelfTaskJob implements ShouldQueue
      * Execute the job.
      *
      * @return void
+     * @throws
      */
     public function handle()
     {
         /** @var ForeignHaiRoboticsService $service */
         $service = app("ForeignHaiRoboticsService");
-        if (!Cache::has($this->key))return;
-        /** @var Collection $task */
-        list($task,$location) = Cache::get($this->key);
-        if ($this->count!==$task->count())return;
-        $dataToPost = $service->makeJson_move_multi($task, '缓存架入立架', $location);
-        $controlSuccess = $service->controlHaiRobot($dataToPost,$task,'缓存架入立架');
-        $tIds = [];
-        $task->each(function ($t)use(&$tIds){$tIds[] = $t->id;});
-        StationTaskMaterialBox::query()->where("id",$tIds)
-            ->where("status","待处理")->update(['status' => $controlSuccess ? '处理中' : '异常']);
-        Cache::forget($this->key);
+        switch ($this->key){
+            case "CACHE_SHELF_AVAILABLE"://出库呼叫
+                DB::beginTransaction();
+                try {
+                    $available = Cache::get($this->key,function (){return [];});
+                    if ($this->count!==count($available))return;
+                    $tasks = TaskTransaction::query()->with("task")
+                        ->where("type","出库")->whereHas("task",function ($query){
+                            $query->where("status","待处理");
+                        })->where("status",3)->lockForUpdate()
+                        ->where("mark",2)->groupBy("task_id")->get(); //检索等待的队列事务来获取对应任务
+                    if (!$tasks->count())return;
+                    $tasks = $tasks->where("task.station_task_batch_id",$tasks[0]->task->station_task_batch_id);//仅处理同波次
+                    if ($tasks->count()>count($available))$tasks = $tasks->slice(0,count($available));//事务过多切割部分处理
+                    $toLocation = collect();
+                    $task = collect();
+                    $availableTemp = array_keys($available);
+                    $map = app("StationService")->getStationMapping($availableTemp);//获取库位映射信息
+                    $updateTask = [["id","station_id","updated_at"]];
+                    $updateTransaction = [["id","to_station_id","status","updated_at"]];
+                    $time = date("Y-m-d H:i:s");
+                    foreach ($tasks as $index=>$obj){
+                        $loc = $availableTemp[$index];
+                        $toLocation->push($loc);
+                        $obj->task->station_id = $map[$loc];
+                        $task->push($obj->task);
+                        unset($available[$loc]);
+                        $updateTask[] = ["id"=>$obj->task->id,"station_id"=>$map[$loc],"updated_at"=>$time];
+                        $updateTransaction[] = ["id"=>$obj->id,"to_station_id"=>$map[$loc],"status"=>0,"updated_at"=>$time];
+                    }
+                    app("BatchUpdateService")->batchUpdate("station_task_material_boxes",$updateTask);
+                    app("BatchUpdateService")->batchUpdate("task_transactions",$updateTransaction);
+                    $result = $service->fetchGroup_multiLocation($toLocation,$task,$tasks[0]->station_task_batch_id,'立架出至缓存架',20);
+                    if ($result){
+                        Cache::forever($this->key,$available);
+                        foreach ($toLocation as $value){
+                            app("CacheShelfService")->lightUp($value,'3','2');
+                            Cache::forever("CACHE_SHELF_OCCUPANCY_{$map[$value]}",true);
+                        }
+                        app("StationService")->locationOccupyMulti($toLocation->toArray());
+                        DB::commit();
+                    }else{
+                        DB::rollBack();
+                        $this->push(__METHOD__."->".__LINE__,"出库队列执行失败","库位信息:".json_encode($toLocation)."  任务信息:".json_encode($task));
+                    }
+                }catch (\Exception $e){
+                    DB::rollBack();
+                    $this->push(__METHOD__."->".__LINE__,"出库队列执行错误",$e->getMessage());
+                }
+                break;
+            default://入库呼叫
+                if (!Cache::has($this->key))return;
+                /** @var Collection $task */
+                list($task,$location) = Cache::get($this->key);
+                if ($this->count!==$task->count())return;
+                $dataToPost = $service->makeJson_move_multi($task, '缓存架入立架', $location);
+                $controlSuccess = $service->controlHaiRobot($dataToPost,$task,'缓存架入立架');
+                $tIds = [];
+                $task->each(function ($t)use(&$tIds){$tIds[] = $t->id;});
+                StationTaskMaterialBox::query()->where("id",$tIds)
+                    ->where("status","待处理")->update(['status' => $controlSuccess ? '处理中' : '异常']);
+                Cache::forget($this->key);
+                if ($controlSuccess)$this->materialBoxMappingCacheShelf($task,$location);
+        }
+    }
+
+    /**
+     * 料箱映射缓存架,因为建立的入立架任务源库位是立库,无法获取真实源库位,所以在此拿到映射库位
+     * 在料箱被取走时通过任务料箱号获取对应库位,来标记该缓存架库位可以被执行任务了 StationTaskMaterialBoxService:markHasTaken
+     * 出库会启用库位占用逻辑  入库分为:人工入库与系统自动入库 人工控制入库由人工自己辨识库位可用度,而系统入库只能通过此映射来拿到可用库位信息
+     *
+     * @param Collection $task
+     * @param Collection $location
+     *
+     * @return void
+     */
+    public function materialBoxMappingCacheShelf(Collection $task,Collection $location)
+    {
+        $map = Cache::get("CACHE_SHELF_MAPPING",function (){return [];});
+        foreach ($task as $key=>$obj)$map[$obj->material_box_id] = $location[$key];
+        Cache::forever("CACHE_SHELF_MAPPING",$map);
     }
 }

+ 2 - 3
app/Jobs/ProcurementCheckConfirmInform.php

@@ -34,8 +34,8 @@ class ProcurementCheckConfirmInform implements ShouldQueue
     {
         if (empty($this->procurementTotalBills)) return;
         foreach ($this->procurementTotalBills as $procurementTotalBill){
-            foreach ($procurementTotalBill->supplier as $supplier) {
-                foreach ($supplier->user as $user){
+            if (!$procurementTotalBill->supplier||!$procurementTotalBill->supplier->user) return;
+                foreach ($procurementTotalBill->supplier->user as $user){
                    if($user->userDetail->procurement_wechat_open_id){
                        $param['touser'] =$user->userDetail->procurement_wechat_open_id;
                        $param['mp_template_msg'] =[
@@ -74,5 +74,4 @@ class ProcurementCheckConfirmInform implements ShouldQueue
 
         }
 
-    }
 }

+ 3 - 5
app/Jobs/RejectedBillCreateInstantBill.php

@@ -2,17 +2,16 @@
 
 namespace App\Jobs;
 
+use App\Components\ErrorPush;
 use App\RejectedBill;
-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 RejectedBillCreateInstantBill implements ShouldQueue
 {
-    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+    use Dispatchable, InteractsWithQueue, Queueable, ErrorPush;
 
     protected $rejected;
     /**
@@ -38,8 +37,7 @@ class RejectedBillCreateInstantBill implements ShouldQueue
         try{
             app("RejectedBillService")->buildInstantBill($this->rejected);
         }catch(\Exception $exception){
-            LogService::log(__CLASS__,"退货单建立即时账单",$exception->getMessage()." | ".json_encode($this->rejected));
-            throw new \Exception($e->getMessage());
+            $this->push(__METHOD__."->".__LINE__,"退货单建立即时账单",$exception->getMessage()." | ".json_encode($this->rejected));
         }
     }
 }

+ 1 - 1
app/Logistic.php

@@ -22,7 +22,7 @@ class Logistic extends Model
     const TAGS=[
         0 => "专线",
         1 => "直发车",
-        2 => "德邦",
+        2 => "德邦物流",
     ];
 
     static function nameById($id){

+ 6 - 0
app/MaterialBox.php

@@ -34,6 +34,12 @@ class MaterialBox extends Model
         parent::__construct($attributes);
     }
 
+
+    public function performTask():HasOne
+    {
+        return $this->hasOne(StationTaskMaterialBox::class,"material_box_id")
+            ->whereNotIn("status",["完成","取消"]);
+    }
     public function station():HasOne
     {
         return $this->hasOne(Station::class);

+ 18 - 0
app/OracleBasLocation.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App;
+
+use App\Traits\ModelTimeFormat;
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class OracleBasLocation extends Model
+{
+    use ModelTimeFormat;
+    use ModelLogChanging;
+
+    protected $connection="oracle";
+    protected $table="BAS_Location";
+    //
+}

+ 6 - 1
app/Owner.php

@@ -38,7 +38,8 @@ class Owner extends Model
         "relevance",            //关联模型的JSON数组
         'subjection',           //主体公司
         'is_tax_exist',         //是否必填税率
-        'model_sequence'        //调箱序列(优先级匹配)
+        'model_sequence',       //调箱序列(优先级匹配)
+        'is_check_asn'          //是否校验ASN(收货时检查此项)
     ];
     //relevance说明 0:仓储 1:作业 2:快递 3:物流 4:直发 5:系统 存储示例:["0","1"]存在仓储与作业计费
     protected $casts = [
@@ -49,6 +50,10 @@ class Owner extends Model
         1 => "宝时物流",
         2 => "宝时供应链",
     ];
+    const IS_CHECK_ASN=[
+        0 => "否",
+        1 => "是"
+    ];
 
     public static function filterAuthorities(){
         $user=Auth::user();

+ 24 - 49
app/Services/CacheShelfService.php

@@ -4,12 +4,10 @@ namespace App\Services;
 
 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\Traits\ServiceAppAop;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Collection;
@@ -45,30 +43,36 @@ class   CacheShelfService
     /**
      * 拍灯触发任务
      * @param $locCode
-     * @param $PTLAction
+     *
      * @return array|bool[]
      * @throws \Exception
      */
-    public function lightOffTask($locCode, $PTLAction): array
+    public function lightOffTask($locCode): array
     {
-        $station = Station::query()->with(['pendingStationTask.stationTaskMaterialBoxes.materialBox','storage'=>function($query){
-            $query->whereNotNull("material_box_id")->orderByDesc("updated_at");
-        }])->where('code', $locCode)->first();
-        //站存在 站为缓存架2 站为蓝灯状态
+        $station = Station::query()->with('materialBox')->where('code', $locCode)->first();
+        if (Cache::has("CACHE_SHELF_OCCUPANCY_{$station->id}")){
+            //缓存存在 不允许灭灯 灭了再点开
+            app("CacheShelfService")->lightUp($station->code,'3','2',["title"=>"库位预定,禁止操作"]);
+            return ['success' => true];
+        }
+        //站存在 站为缓存架
         if (app("StationService")->isHalfBoxLocation($station)){
-            if (!app("StorageService")->checkStorage($station)){
+            $result = app("StorageService")->checkStorage($station);
+            if ($result===false){//任务存在且失败 红灯
                 $this->lightUp($station->code,'0','1',["title"=>"上架失败,联系管理员"]);
                 return ['success' => false,'errMsg' => '上架任务失败'];
             };
+            if ($result===true){//任务存在且成功 绿灯
+                $this->lightUp($station->code);
+                return ['success' => true];
+            }
         }
         try {
             $bool = $this->putBinToStore($station);                         // 推送任务
             if ($bool) {
                 LogService::log(__CLASS__, 'lightOffTask', 'code' . ' true' . $locCode . json_encode($station));
                 return ['success' => true];
-            } else {
-                return ['success' => false, 'errMsg' => '机器人推送失败'];
-            }
+            }else return ['success' => false, 'errMsg' => '机器人推送失败'];
         } catch (ErrorException $e) {
             LogService::log(__FUNCTION__, '缓存架推送任务失败', json_encode($e->getMessage()));
             return ['success' => false, 'errMsg' => $e->getMessage()];
@@ -78,50 +82,21 @@ class   CacheShelfService
     /**
      * 推任务至海柔机器人
      * @param  $station
-     * @return array
+     * @return bool
      * @throws ErrorException
      * @throws \Exception
      */
-    public function putBinToStore($station): array
+    public function putBinToStore($station): bool
     {
         $this->instant($this->foreignHaiRoboticsService, 'ForeignHaiRoboticsService');
         $this->instant($this->stationService, 'StationService');
 
-        /** @var MaterialBox $materialbox */
-        $materialBox = $station->storage->materialbox;
-
-        $formStation = $this->stationService->getStation_byType('立库');          // 立库
-
-        $stationTask = StationTask::query()->create(['station_id' => $formStation['id'], 'status' => '待处理']);   // 生成任务
+        if (!$station->materialBox)return false;
 
         /** @var StationTaskMaterialBox $stationTaskMaterialBox */
-        $stationTaskMaterialBox = StationTaskMaterialBox::query()->create([
-            'station_id' => $formStation['id'],
-            'material_box_id' => $materialBox['id'],
-            'status' => '待处理',
-            'station_task_id' => $stationTask['id'],
-            'type' => '放',
-        ]);
-
-        StationTaskChildren::query()->create([
-            'station_task_id' => $stationTask['id'],
-            'station_taskable_type' => StationTaskMaterialBox::class,
-            'station_taskable_id' => $stationTaskMaterialBox['id']
-        ]);
-
-        $bool = $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($stationTaskMaterialBox, $station);
-        return $bool ? ['success' => true] : ['success' => false];
-    }
+        $stationTaskMaterialBox = app("StorageService")->createWarehousingTask($this->stationService->getStation_byType('立库')["id"],$station->materialBox->id);
 
-    /**
-     * 缓存架和料箱的绑定
-     * @param $stationCode
-     * @param $materialBoxCode
-     * @return array
-     */
-    public function bindMaterialBox($stationCode, $materialBoxCode): array
-    {
-        return ['success' => false,'message' => "接口废弃"];
+        return $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($stationTaskMaterialBox, $station);
     }
 
     /**
@@ -141,8 +116,8 @@ class   CacheShelfService
             "detail03" => "",
             "qrCode" => "",
             "qty00" => "",
-            "qty01" => 0,
-            "qty02" => 0,
+            "qty01" => "",
+            "qty02" => "",
             "title" => '',
             "uomDesc01" => "",
             "uomDesc02" => ""

+ 8 - 10
app/Services/DbOpenService.php

@@ -21,7 +21,7 @@ class DbOpenService
      * 创建德邦订单,生成快递单号
      * @param array $params
      */
-    public function getDbOrderNo($params = [])
+    public function getDbOrderNo(array $params = []):array
     {
         //获取系统无快递单号订单信息
         $order_info = Waybill::query()
@@ -33,7 +33,6 @@ class DbOpenService
             ->first();
         //请求德邦API 生成新订单
         $model = new OrderLogistic();
-        $uri = "http://dpsanbox.deppon.com/sandbox-web/dop-standard-ewborder/createOrderNotify.action";
         $header = [
             'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
             "Accept" => "application/json"
@@ -108,18 +107,18 @@ class DbOpenService
                         'key' => ''
                     ]
                 ];
-                $param = json_encode($data, true);
+                $param = json_encode($data,1);
                 $dd["params"] = $param;
                 $dd["timestamp"] = (integer)getMillisecond();
                 $dd["digest"] = base64_encode(md5($param . config('api_logistic.DB.prod.app_key') . $dd['timestamp']));
                 $dd["companyCode"] = config('api_logistic.DB.prod.company_code');
-                $return = httpPost($uri, $dd, $header);
+                $return = httpPost(config('api_logistic.DB.prod.uri')['create_order'], $dd, $header);
                 unset($data);
+                $id = $params['id'];
+                $order_no = $order_info->wms_bill_number;
                 if (array_key_exists('result', $return)) {
                     //请求成功  快递单号 $return['mailNo']   请求编号 $return['uniquerRequestNumber']
                     //返回日志记录
-                    $id = $params['id'];
-                    $order_no = $order_info->wms_bill_number;
                     $mail_no = $return['mailNo']??'';
                     $add_data = [
                         'order_id' => $order_info->order->id,
@@ -159,10 +158,9 @@ class DbOpenService
      * @param array $params
      * @return array
      */
-    public function getOrderStatus($params = [])
+    public function getOrderStatus(array $params = []):array
     {
         if ( ($params['mailNo']??'') == '') return ['code' => 0 , 'msg' => '德邦运单号不能为空'];
-        $uri = "http://dpsanbox.deppon.com/sandbox-web/standard-order/newTraceQuery.action";
         $header = [
             'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
             "Accept" => "application/json"
@@ -170,12 +168,12 @@ class DbOpenService
         $data = [
             'mailNo' => $params['mailNo']??''
         ];
-        $param = json_encode($data, true);
+        $param = json_encode($data, 1);
         $dd["params"] = $param;
         $dd["timestamp"] = (integer)getMillisecond();
         $dd["digest"] = base64_encode(md5($param . config('api_logistic.DB.prod.app_key') . $dd['timestamp']));
         $dd["companyCode"] = config('api_logistic.DB.prod.company_code');
-        $return = httpPost($uri, $dd, $header);
+        $return = httpPost(config('api_logistic.DB.prod.uri')['order_locus'], $dd, $header);
         if (array_key_exists('result', $return) && $return['result'] == 'true' && array_key_exists('resultCode', $return) && $return['resultCode'] == '1000'){
            return ['code'=> 1, 'msg'=> '正在加载中。。。', 'data' => $return['responseParam']];
         }

+ 17 - 1
app/Services/DeliveryAppointmentService.php

@@ -4,6 +4,7 @@ namespace App\Services;
 
 use App\CommodityBarcode;
 use App\DeliveryAppointmentDetail;
+use App\Owner;
 use App\Services\common\QueryService;
 use App\Traits\ServiceAppAop;
 use App\DeliveryAppointment;
@@ -36,7 +37,7 @@ class DeliveryAppointmentService
             "owner_id"=>['multi' => ','],
             "asn_number"=>['like' => '','timeLimit' => 15],
             "id"=>['multi' => ','],
-        ])->orderByDesc("id")->whereIn("owner_id",$owners)->with(["cars.car","details.commodity.barcodes"]);
+        ])->whereIn("owner_id",$owners)->with(["cars.car","details.commodity.barcodes"]);
     }
 
     /**
@@ -206,4 +207,19 @@ class DeliveryAppointmentService
         $total = $warehouse->production_capacity*DeliveryAppointment::HOUR[$period];
         return $total-$result->capacity;
     }
+
+    /**
+     * 检查可操作ASN
+     *
+     * @param string $asn
+     * @param string $ownerCode
+     * @return bool
+     */
+    public function checkOperableAsn(string $asn,string $ownerCode):bool
+    {
+        if (!Owner::query()->where("code",$ownerCode)->where("is_check_asn",1)->first())return true;
+        return !!DeliveryAppointment::query()->selectRaw("1")->where("status",'!=',1)
+            ->where("appointment_date",date("Y-m-d"))
+            ->where("asn_number",'like',"%{$asn}%")->first();
+    }
 }

+ 4 - 22
app/Services/ForeignHaiRoboticsService.php

@@ -22,7 +22,6 @@ use App\Traits\ServiceAppAop;
 class ForeignHaiRoboticsService
 {
     use ServiceAppAop;
-//    protected $modelClass=ForeignHaiRobotics::class;
 
     /** @var  $stationTaskMaterialBoxService StationTaskMaterialBoxService */
     private $stationTaskMaterialBoxService;
@@ -142,24 +141,21 @@ class ForeignHaiRoboticsService
      * @param string $groupIdPrefix
      * @param string $mode
      * @return bool
-     * @throws ErrorException
+     * @throws ErrorException|Exception
      */
-    public function fetchGroup_multiLocation(Collection $toLocations, Collection $taskMaterialBoxes, $groupIdPrefix='',$mode='立架出至输送线'): bool
+    public function fetchGroup_multiLocation(Collection $toLocations, Collection $taskMaterialBoxes, $groupIdPrefix='', $mode='立架出至输送线', int $priority = 10): bool
     {
         $dataToPost=$this->makeJson_move_multi(
             $taskMaterialBoxes,
             $mode,
             null,
             $toLocations,
-            $groupIdPrefix
+            $groupIdPrefix,
+            $priority
         );
         return $this->controlHaiRobot($dataToPost,$taskMaterialBoxes,$mode);
     }
 
-    public function moveBin(){
-
-    }
-
     public function markBinProcessed(
         $workStation,
         $binCode,
@@ -184,17 +180,9 @@ class ForeignHaiRoboticsService
                 throw new ErrorException('海柔任务失败:'.$exception);
             LogService::log('海柔请求','markBinProcessed1.3',
                 $failed);
-//            if($NotInPlan
-//                =!$is_in_plan)
-//                throw new ErrorException('海柔认为是计划外的料箱:'.$exception);
-
-            LogService::log('海柔请求','markBinProcessed1.4',
-                '$NotInPlan');
 
             $materialBox=
                 $this->materialBoxService->get(['code'=>$binCode])->first();
-            LogService::log('海柔请求','markBinProcessed1.5',
-                json_encode($materialBox));
             /** @var StationTaskMaterialBox $stationTaskMaterialBox */
             $stationTaskMaterialBox
                 =(function()use($materialBox){
@@ -206,13 +194,9 @@ class ForeignHaiRoboticsService
                         ->orderBy('id','desc')
                     ->first();
             })();
-            LogService::log('海柔请求','markBinProcessed1.6',
-                json_encode($stationTaskMaterialBox).'|'.$binCode);
             if(!$stationTaskMaterialBox){
                 throw new ErrorException($binCode.'该料箱没有安排在处理队列中.');
             }
-            LogService::log('海柔请求','markBinProcessed1.7',
-                json_encode($stationTaskMaterialBox).'|'.$binCode);
 
             DB::transaction(function ()use($stationTaskMaterialBox,$binCode){
                 $stationTaskMaterialBox_next=
@@ -235,8 +219,6 @@ class ForeignHaiRoboticsService
                         json_encode($stationTaskMaterialBox['stationTaskBatch']).'|'.$binCode);
                     $stationTaskMaterialBox->loadMissing('stationTaskBatch');
                     $this->stationTaskBatchService->markProcessed($stationTaskMaterialBox['stationTaskBatch']);
-                    LogService::log('海柔请求','markBinProcessed1.82',
-                        json_encode($stationTaskMaterialBox['stationTaskBatch']).'|'.$binCode);
                     $this->stationTaskService->markProcessed($stationTaskMaterialBox['stationTask']);
                 }
                 $this->storeBox($stationTaskMaterialBox)

+ 191 - 41
app/Services/HandInStorageService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\CommodityBarcode;
 use App\OracleBasCode;
 use App\OracleBasSKU;
 use App\OracleDOCASNDetail;
@@ -10,6 +11,7 @@ use App\OracleInvLotAtt;
 use App\Traits\ServiceAppAop;
 use App\ValueStore;
 use Carbon\Carbon;
+use Doctrine\DBAL\Schema\AbstractAsset;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Database\Eloquent\Model;
@@ -21,27 +23,72 @@ class HandInStorageService
 {
     use ServiceAppAop;
 
+
+    public function checkAsnOperation(array $info)
+    {
+        if (!$info['customerid']||!$info['asntype']){
+            $asn=OracleDOCASNHeader::query()
+            ->select(['asnno','asnreference1','asnstatus','addtime','customerid','asntype'])
+            ->where('asnno',$info['asnno'])
+            ->whereIn('asnstatus',['00','30'])
+            ->first();
+            if (!$asn)return 1; //无效asn单号
+            return $this->whetherDeliver($asn);
+        }
+        return $this->whetherDeliver($info);
+    }
+
+    private function whetherDeliver($asn)
+    {
+        if ($asn['asntype']!='XNRK' && $asn['asntype']!='THRK' && $asn['asntype']!='F31'){
+            $res=app(DeliveryAppointmentService::class)->checkOperableAsn($asn['asnno'],$asn['customerid']);
+            if ($res) return $asn;
+            else return 2; //当前asn单号无预约记录
+        }
+        return $asn;
+    }
+
     /**
      * @param $asn
      * @return Builder[]|Collection
-     * 获取富勒asn_header
+     * 获取富勒asn_header  根据货主,asn,或者条码
      *
      */
     public function selectAsn($asn)
     {
-        if ($asn) return OracleDOCASNHeader::query()
-            ->with('asnStatus')
-            ->select(['asnno','asnreference1','asnstatus','addtime','customerid'])
-            ->where('asnno',$asn)
-            ->get();
-
-        return OracleDOCASNHeader::query()
-            ->select(['asnno','asnreference1','asnstatus','addtime','customerid'])
-            ->with('asnStatus')
+        if (!$asn) return OracleDOCASNHeader::query()
+            ->select(['asnno','asnreference1','asnstatus','addtime','customerid','asntype'])
             ->where('asnstatus','00')
             ->orderByDesc('addtime')
             ->limit(50)
             ->get();
+
+        if (strpos(strtoupper($asn),'ASN')!==false){
+            return OracleDOCASNHeader::query()
+                ->select(['asnno','asnreference1','asnstatus','addtime','customerid','asntype'])
+                ->where('asnno',$asn)
+                ->whereIn('asnstatus',['00','30'])
+                ->get();
+        }else {
+            $asns=OracleDOCASNHeader::query()
+                ->select(['asnno','asnreference1','asnstatus','addtime','customerid','asntype'])
+                ->where('customerid',strtoupper($asn))
+                ->whereIn('asnstatus',['00','30'])
+                ->get();
+            if ($asns->count()>0){
+                return $asns;
+            }else{
+                $sql = <<<SQL
+ SELECT DOC_ASN_HEADER.ASNNO,DOC_ASN_HEADER.addtime,DOC_ASN_HEADER.asnreference1,DOC_ASN_HEADER.customerid,DOC_ASN_HEADER.asnstatus,DOC_ASN_HEADER.asntype FROM DOC_ASN_HEADER
+                  LEFT JOIN DOC_ASN_DETAILS ON DOC_ASN_HEADER.ASNNO = DOC_ASN_DETAILS.ASNNO
+                  LEFT JOIN BAS_SKU ON DOC_ASN_DETAILS.CUSTOMERID = BAS_SKU.CUSTOMERID AND DOC_ASN_DETAILS.SKU = BAS_SKU.SKU
+WHERE DOC_ASN_HEADER.ASNSTATUS in ('00','30') and (BAS_SKU.ALTERNATE_SKU1 = ? OR BAS_SKU.ALTERNATE_SKU2 = ?  OR BAS_SKU.ALTERNATE_SKU3 = ?)
+group by DOC_ASN_HEADER.ASNNO,DOC_ASN_HEADER.addtime,DOC_ASN_HEADER.asnreference1,DOC_ASN_HEADER.customerid,DOC_ASN_HEADER.asnstatus,DOC_ASN_HEADER.asntype
+SQL;
+                return DB::connection("oracle")->select(DB::raw($sql),[$asn,$asn,$asn]);
+            }
+        }
+
     }
 
     /**
@@ -51,24 +98,38 @@ class HandInStorageService
      */
     public function selectAsnDetails($asnno)
     {
-        return OracleDOCASNDetail::query()
-            ->select(['sku','expectedqty','skudescrc','asnlineno','asnno','receivedqty'])
-            ->where('asnno',$asnno)
-            ->get();
+        $sql = <<<sql
+ SELECT DOC_ASN_DETAILS.sku,DOC_ASN_DETAILS.expectedqty,DOC_ASN_DETAILS.skudescrc,DOC_ASN_DETAILS.asnlineno,DOC_ASN_DETAILS.asnno,
+       DOC_ASN_DETAILS.receivedqty,BAS_SKU.alternate_sku1
+FROM DOC_ASN_DETAILS LEFT JOIN BAS_SKU ON DOC_ASN_DETAILS.CUSTOMERID = BAS_SKU.CUSTOMERID AND DOC_ASN_DETAILS.SKU = BAS_SKU.SKU
+WHERE asnno = ? AND linestatus IN ('00','30')
+sql;
+        $asn_details = DB::connection("oracle")->select(DB::raw($sql),[$asnno]);
+        if (count($asn_details)>0)return $asn_details;
+        else return array();
     }
 
     /**
      * @param $asnno
-     * @param $sku
+     * @param $skuOrBarcode
      * @return Builder|Model|object|null
-     *
+     *根据sku 或者条码获取asn_detail
      */
-    public function getAsnDetail($asnno,$sku)
+    public function getAsnDetail($asnno,$skuOrBarcode)
     {
-        return OracleDOCASNDetail::query()
+        $sql = <<<sql
+SELECT DOC_ASN_DETAILS.sku,DOC_ASN_DETAILS.expectedqty,DOC_ASN_DETAILS.skudescrc,
+       DOC_ASN_DETAILS.asnlineno,DOC_ASN_DETAILS.asnno,DOC_ASN_DETAILS.receivedqty FROM DOC_ASN_DETAILS
+         LEFT JOIN BAS_SKU ON DOC_ASN_DETAILS.CUSTOMERID = BAS_SKU.CUSTOMERID AND DOC_ASN_DETAILS.SKU = BAS_SKU.SKU
+WHERE ASNNO = ? AND LINESTATUS IN ('00','30') AND (ALTERNATE_SKU1 = ? OR ALTERNATE_SKU2 = ?  OR ALTERNATE_SKU3 = ?)
+sql;
+        $asn_detail = DB::connection("oracle")->selectOne(DB::raw($sql),[$asnno,$skuOrBarcode,$skuOrBarcode,$skuOrBarcode]);
+        if ($asn_detail)return $asn_detail;
+        else return OracleDOCASNDetail::query()
             ->select(['sku','expectedqty','skudescrc','asnlineno','asnno','receivedqty'])
             ->where('asnno',$asnno)
-            ->where('sku',$sku)
+            ->where('sku',$skuOrBarcode)
+            ->whereIn('linestatus',['00','30'])
             ->first();
     }
 
@@ -115,8 +176,87 @@ class HandInStorageService
         });
     }
 
+    /**
+     * @param string $barCode
+     * @return array
+     * 根据商品条码  获取完全收货状态  部分收货状态的 PA任务
+     */
+    public function getTsk(string $trackNumber,string $barCode): array
+    {
+        $sql = <<<sql
+SELECT TSK_TASKLISTS.CustomerID,TSK_TASKLISTS.Sku,TSK_TASKLISTS.PlanToLotNum,TSK_TASKLISTS.PlanToID,DOC_ASN_DETAILS.SKUDESCRC,sum(TSK_TASKLISTS.PlanToQty) AS QTY
+FROM DOC_ASN_DETAILS
+         LEFT JOIN TSK_TASKLISTS ON DOC_ASN_DETAILS.ASNNO = TSK_TASKLISTS.DOCNO AND
+                                    DOC_ASN_DETAILS.ASNLINENO = TSK_TASKLISTS.DOCLINENO
+WHERE
+      ASNNO in (SELECT asnno FROM DOC_ASN_DETAILS
+                                      LEFT JOIN BAS_SKU ON DOC_ASN_DETAILS.CUSTOMERID = BAS_SKU.CUSTOMERID AND DOC_ASN_DETAILS.SKU = BAS_SKU.SKU
+                WHERE LINESTATUS in ('30','40') and (ALTERNATE_SKU1 = ? OR ALTERNATE_SKU2 = ?  OR ALTERNATE_SKU3 = ?))
+  AND TSK_TASKLISTS.TASKPROCESS = '00'
+  AND TSK_TASKLISTS.TASKTYPE = 'PA'
+  AND TSK_TASKLISTS.PlanToID= ?
+  group by TSK_TASKLISTS.CustomerID,TSK_TASKLISTS.Sku,TSK_TASKLISTS.PlanToLotNum,TSK_TASKLISTS.PlanToID,DOC_ASN_DETAILS.SKUDESCRC
+sql;
+        $tasks = DB::connection("oracle")->select(DB::raw($sql),[$barCode,$barCode,$barCode,$trackNumber]);
+        if (!$tasks)return [];
+        else return $tasks;
+    }
+
+    /**
+     * @throws \Throwable
+     * flux手持端 上架
+     */
+    public function fluxHandPa(array $info, array $taskParam): bool
+    {
+        $tasks=$this->selectFluxTask($taskParam,$info['amount']);
+        if (!$tasks)return false; //获取任务失败
+        return DB::connection("oracle")->transaction(function ()use($tasks,$info){ //单体嵌套事务 回滚FLUX失败任务
+            foreach ($tasks as $task){
+                if (!app("StorageService")->fluxPA($task,$info['location'])){
+                    DB::connection("oracle")->rollBack();
+                    return false; //上架失败
+                }
+            }
+            return true; //上架成功
+        });
+    }
+
+    /**
+     * @param $taskParam
+     * @param $amount
+     * @return array
+     * 根据跟踪号,货主,sku,批次 获取任务列表   再通过数量 进行任务的重组(拆分或选定)
+     */
+    public function selectFluxTask($taskParam,$amount): array
+    {
+        /** @var StorageService $storageService  */
+        $storageService=app('StorageService');
+        $sql = <<<sql
+select * from TSK_TASKLISTS where customerid = ? AND sku = ? AND plantoid = ? AND plantolotnum = ? AND TASKPROCESS = '00' AND TASKTYPE = 'PA'
+sql;
+        $tasks = DB::connection("oracle")->select(DB::raw($sql),[$taskParam['customerid'],$taskParam['sku'],$taskParam['plantoid'],$taskParam['plantolotnum']]);
+        if (!$tasks)return [];
+        $nums = [];
+        $sum = 0;
+        $maxIndex = null;
+        foreach ($tasks as $i => $task){
+            if ((int)$task->fmqty == $amount)return [$task];
+            $nums[] = (int)$task->fmqty;
+            $sum += (int)$task->fmqty;
+            if ((int)$task->fmqty>$amount)$maxIndex = $i;
+        }
+        if ($sum<$amount)return []; //上架数大于入库数
+        $result = $storageService->getMatch($nums,$amount);
+        if (!$result)return $storageService->splitTask($tasks,$maxIndex,$amount);
+        $arr = [];
+        foreach ($result as $index)$arr[] = $tasks[$index];
+        return $arr;
+    }
+
+
     /**
      * @throws \Throwable
+     * fulx 手持收货
      */
     public function fluxHandIn(array $info)
     {
@@ -132,22 +272,26 @@ class HandInStorageService
         }
         $who= 'WAS'.(Auth::user() ? '-'.Auth::user()["name"] : '');
         $time=Carbon::now()->toDateTimeString();
-//        return DB::connection("oracle")->transaction(function ()use ($info,$invlotatt,$who,$time){
+        return DB::connection("oracle")->transaction(function ()use ($info,$invlotatt,$who,$time){
             //flux 批次号
-//            $lotNum=$this->getOrCreateLotNum($info,$invlotatt,$who,$time);
-//            if (!$lotNum) return false;
+            $lotNum=$this->getOrCreateLotNum($info,$invlotatt,$who,$time);
+            if (!$lotNum){
+                DB::connection("oracle")->rollBack();
+                return false;
+            }
             //flux 创建入库事务
-//            $actTransactionLog=$this->setFluxActTransactionLog($info,$lotNum,$who,$time);
-//            if (!$actTransactionLog)return false;
+            $actTransactionLog=$this->setFluxActTransactionLog($info,$lotNum,$who,$time);
+            if (!$actTransactionLog){
+                DB::connection("oracle")->rollBack();
+                return false;
+            }
             //flux 创建上架任务
-//            $this->setFluxTskTaskListPA($info,$invlotatt, $actTransactionLog, $who, $time);
+            $this->setFluxTskTaskListPA($info,$invlotatt, $actTransactionLog, $who, $time);
             //flux 完善库存余量
-//            $this->updateFluxInv($info,$lotNum,$who,$time,$actTransactionLog);
+            $this->updateFluxInv($info,$lotNum,$who,$time,$actTransactionLog);
             //flux 更新asn_detail 和 asn_header 状态
-            $re=$this->updateFluxAsn($info,$invlotatt,$time,$who);
-            dd($re);
-//            return true;
-//        });
+            return $this->updateFluxAsn($info,$invlotatt,$time,$who);
+        });
 
     }
 
@@ -171,26 +315,32 @@ class HandInStorageService
                 $asnDetail['customerid']==$info['customerid'] &&
                 $asnDetail['sku']==$info['sku']) $receiveAsn=$asnDetail;
         }
-        return $db->transaction(function ()use($db,$info,$receiveAsn,$invlotatt,$time,$who){
+        return $db->transaction(function ()use($db,$info,$receiveAsn,$invlotatt,$time,$who,$asn){
             if ($receiveAsn && (int)$receiveAsn['receivedqty']+(int)$info['amount']<(int)$receiveAsn['expectedqty']){
                 //asn_detail 收货数量+已收数量<预期数量
-                $db->update(DB::raw("UPDATE DOC_ASN_DETAILS SET linestatus = '30',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ?,
-             lotatt01=?,lotatt02=?,lotatt03=?,lotatt04=?,lotatt05=?,lotatt06=?,lotatt07=?,lotatt08=? WHERE asnno = ?"),
-                    [$time,$who,$invlotatt['lotatt01'],$invlotatt['lotatt02'],$invlotatt['lotatt03'],$invlotatt['lotatt04'],
-                        $invlotatt['lotatt05'],$invlotatt['lotatt06'],$invlotatt['lotatt07'],$invlotatt['lotatt08'],$info['asnno']]);
+                $db->update(DB::raw("UPDATE DOC_ASN_DETAILS SET receivedqty = receivedqty + ?,receivedqty_each = receivedqty_each + ?,linestatus = '30',holdrejectcode ='OK',
+                reserve_flag ='Y',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),receivedtime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ?,
+             lotatt01 =?,lotatt02 =?,lotatt03 =?,lotatt04 =?,lotatt05 =?,lotatt06 =?,lotatt07 =?,lotatt08=? WHERE asnno = ? and asnlineno = ?"),
+                    [(int)$info['amount'],(int)$info['amount'],$time,$time,$who,$invlotatt['lotatt01'],$invlotatt['lotatt02'],$invlotatt['lotatt03'],$invlotatt['lotatt04'],
+                        $invlotatt['lotatt05'],$invlotatt['lotatt06'],$invlotatt['lotatt07'],$invlotatt['lotatt08'],$info['asnno'],$info['asnlineno']]);
                 //asn_header 部分收货状态
                 $db->update(DB::raw("UPDATE DOC_ASN_HEADER SET asnstatus = '30',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ?"),
                     [$time,$who,$info['asnno']]);
             }elseif ($receiveAsn && (int)$receiveAsn['receivedqty']+(int)$info['amount']==(int)$receiveAsn['expectedqty']){
                 //asn_detail 收货数量+已收数量=预期数量
-                $db->update(DB::raw("UPDATE DOC_ASN_DETAILS SET linestatus = '40',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ?,
-             lotatt01=?,lotatt02=?,lotatt03=?,lotatt04=?,lotatt05=?,lotatt06=?,lotatt07=?,lotatt08=? WHERE asnno = ?"),
-                    [$time,$who,$invlotatt['lotatt01'],$invlotatt['lotatt02'],$invlotatt['lotatt03'],$invlotatt['lotatt04'],
-                        $invlotatt['lotatt05'],$invlotatt['lotatt06'],$invlotatt['lotatt07'],$invlotatt['lotatt08'],$info['asnno']]);
+                $db->update(DB::raw("UPDATE DOC_ASN_DETAILS SET receivedqty=receivedqty+?,receivedqty_each=receivedqty_each+?,linestatus = '40',
+                edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),receivedtime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ?,holdrejectcode='OK',
+                reserve_flag='Y',lotatt01=?,lotatt02=?,lotatt03=?,lotatt04=?,lotatt05=?,lotatt06=?,lotatt07=?,lotatt08=? WHERE asnno = ? and asnlineno = ?"),
+                    [(int)$info['amount'],(int)$info['amount'],$time,$time,$who,$invlotatt['lotatt01'],$invlotatt['lotatt02'],$invlotatt['lotatt03'],$invlotatt['lotatt04'],
+                        $invlotatt['lotatt05'],$invlotatt['lotatt06'],$invlotatt['lotatt07'],$invlotatt['lotatt08'],$info['asnno'],$info['asnlineno']]);
                 //当asn_detail 所有状态都为完全收货是  asn_header 状态修改为 完全收货(asnstatus=40)
                 if (OracleDOCASNDetail::query()->where('asnno',$info['asnno'])->where('linestatus',40)->count()==$asn->asn_details_count){
                     $db->update(DB::raw("UPDATE DOC_ASN_HEADER SET asnstatus = '40',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ?"),
                         [$time,$who,$info['asnno']]);
+                }else {
+                    //asn_header 部分收货状态
+                    $db->update(DB::raw("UPDATE DOC_ASN_HEADER SET asnstatus = '30',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ?"),
+                        [$time,$who,$info['asnno']]);
                 }
             }
             return true;
@@ -348,7 +498,7 @@ sql;
      * 获取批次号
      * @return array
      */
-    private function getLtNum()
+    private function getLtNum(): array
     {
         $val = ValueStore::query()->select("value")->where("name","flux_lt_number")->lockForUpdate()->first();
         if (!$val)$val = ValueStore::query()->create(["name"=>"flux_lt_number","value"=>'0']);
@@ -371,7 +521,7 @@ sql;
      * 获取批次号
      * @return array
      */
-    private function getTsNum()
+    private function getTsNum(): array
     {
         $val = ValueStore::query()->select("value")->where("name","flux_ts_number")->lockForUpdate()->first();
         if (!$val)$val = ValueStore::query()->create(["name"=>"flux_ts_number","value"=>'0']);

+ 22 - 0
app/Services/MaterialBoxService.php

@@ -8,6 +8,7 @@ use App\MaterialBox;
 use App\MaterialBoxModel;
 use App\StationTaskMaterialBox;
 use App\Traits\ServiceAppAop;
+use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\DB;
 
 
@@ -103,4 +104,25 @@ sql;
         if (StationTaskMaterialBox::query()->select(DB::raw(1))->whereNotIn("status",['完成','取消'])->where("material_box_id",$boxId)->first())return false;
         return true;
     }
+
+    /**
+     * 获取某个型号下的可用料箱
+     *
+     * @param integer $modelId
+     *
+     * @return Collection|string|null
+     */
+    public function getModelAvailableBox(int $modelId, bool $sqlQuery = false, array $blacklist = [])
+    {
+        $query = MaterialBox::query()->where("material_box_model_id",$modelId)->where("status",4);
+        $boxes = $query->whereNotIn("id",$query->whereHas("performTask"))
+            ->whereNotIn("id",$blacklist)->get();
+        if (!$sqlQuery)return $boxes;
+        if ($boxes->count()==0)return null;
+        $boxCodes = "";
+        foreach ($boxes as $box){
+            $boxCodes .= "'".$box->code."',";
+        }
+        return rtrim($boxCodes,",");
+    }
 }

+ 0 - 3
app/Services/NewOrderCountingRecordService.php

@@ -487,9 +487,6 @@ class NewOrderCountingRecordService
         return $ttl;
     }
 
-
-    //TODO 控制台重构
-
     public function getWareHouseRecordsApi($start, $end, $ownerIds): array
     {
         $orderCountingRecords = OrderCountingRecord::query()

+ 2 - 1
app/Services/OwnerPriceOperationService.php

@@ -545,7 +545,8 @@ class OwnerPriceOperationService
             $units = app("UnitService")->getUnitMapping(["件","单","箱","m³","T","kg"]); //获取单位映射集
             $exe = function ($mapping,$object,$detail)use($rule,$units,$owner,$discountIndex){
                 $money = $this->matchItem($rule,$mapping,$object,$units,$owner,[$discountIndex=>true]);
-                if ($money>0)$detail->update(["work_fee"=>$money,"work_tax_fee"=>$money*($rule->taxRate->value/100)]);
+                $rate = $rule->taxRate ?: (Owner::query()->with("taxRate")->find($owner)->taxRate ?? null);
+                if ($money>0)$detail->update(["work_fee"=>$money,"work_tax_fee"=>$rate ? ($money*($rate->value/100)) : null]);
                 else $this->push(__METHOD__."->".__LINE__,"处理历史即时账单时发生匹配错误","账单主键:".$detail->id."; 错误代码".$money.";参数列表:".json_encode(array($rule, $owner, $discountIndex)));
             };
             if ($rule->operation_type=='入库'){

+ 32 - 3
app/Services/StationService.php

@@ -13,6 +13,7 @@ use Exception;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Support\Facades\Cache;
 use App\Traits\ServiceAppAop;
+use Illuminate\Support\Facades\DB;
 
 
 class StationService
@@ -134,10 +135,29 @@ class StationService
      *
      * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
      */
-    public function getCacheShelf()
+    public function getCacheShelf($onlyAvailable = false)
     {
-        return Station::query()->where("station_type_id",5)
-            ->whereNotNull("parent_id")->get();
+        $stations = Station::query()->where("station_type_id",5)
+            ->whereNotNull("parent_id");
+        if ($onlyAvailable)$stations->where("status",0)
+            ->whereNotIn("id",Station::query()->select("id")->whereHas("task",function ($query){
+                $query->whereNotIn("status",["完成","取消"]);
+            }))->lockForUpdate();
+        return $stations->get();
+    }
+
+    /**
+     * @param array $codes
+     *
+     * @return array
+     */
+    public function getStationMapping(array $codes):array
+    {
+        $mapping = [];
+        foreach (Station::query()->whereIn("code",$codes)->get() as $station){
+            $station[$station->code] = $station->id;
+        }
+        return $mapping;
     }
 
     /**
@@ -155,6 +175,15 @@ class StationService
         if ($boxId)$update["material_box_id"]=$boxId;
         return Station::query()->where("code",$location)->update($update);
     }
+    /**
+     * 多库位占用
+     * @param array $location
+     * @return bool
+     */
+    public function locationOccupyMulti(array $location):bool
+    {
+        return !!Station::query()->whereIn("code",$location)->update(["status"=>1]);
+    }
 
     /**
      * 库位释放

+ 90 - 23
app/Services/StationTaskBatchService.php

@@ -6,6 +6,8 @@ namespace App\Services;
 
 use App\Exceptions\ErrorException;
 use App\StationTaskBatch;
+use App\StationTaskCommodity;
+use App\TaskTransaction;
 use Carbon\Carbon;
 use Exception;
 use Illuminate\Support\Collection;
@@ -129,18 +131,19 @@ class StationTaskBatchService
 
     /**
      * @param Collection|null $stationTaskBatches
+     * @param string $locationType
      * @return Collection|\Tightenco\Collect\Support\Collection|null 返回执行失败的记录
      * @throws ErrorException
      */
-    function runMany(?Collection $stationTaskBatches):?Collection
+    function runMany(?Collection $stationTaskBatches, $locationType = 'OUTBIN-U-SHAPE-LINE'):?Collection
     {
         LogService::log(__METHOD__,'runMany','波次任务分配6.1:'.json_encode($stationTaskBatches));
         $stationTaskBatches_failed = null;
-        ($execute = function(Collection $stationTaskBatches, &$stationTaskBatches_failed){
+        ($execute = function(Collection $stationTaskBatches, &$stationTaskBatches_failed)use($locationType){
                 if ($stationTaskBatches->isEmpty()) return; //波次任务不存在 跳出
                 $stationTaskBatches_failed = collect();
-                foreach ($stationTaskBatches as $stationTaskBatch) {
-                    $failed = !$this->run($stationTaskBatch); //运行波次 获取执行结果
+                foreach ($stationTaskBatches as $stationTaskBatch){
+                    $failed = !$this->run($stationTaskBatch, $locationType); //运行波次 获取执行结果
                     if ($failed) $stationTaskBatches_failed->push($stationTaskBatch);//执行失败  记录失败波次
                 }
         })($stationTaskBatches, $stationTaskBatches_failed);
@@ -159,13 +162,21 @@ class StationTaskBatchService
         return  $stationTaskBatches_failed;
     }
 
-    function run(StationTaskBatch $stationTaskBatch): bool
+    /**
+     * 解析波次任务 任务下发海柔
+     *
+     * @param StationTaskBatch $stationTaskBatch
+     * @param string $locationType
+     * @return bool
+     * @throws ErrorException
+     */
+    function run(StationTaskBatch $stationTaskBatch, $locationType): bool
     {
         $this->instant($this->foreignHaiRoboticsService,'ForeignHaiRoboticsService');
         $this->instant($this->stationService,'StationService');
         $stationTaskBatch->loadMissing(['station','stationTask.stationTaskMaterialBoxes']);
         LogService::log(__METHOD__,'runMany','波次任务分配6.r2:'.json_encode($stationTaskBatch));
-        $toLocation         = $this->stationService->getULineEntrance($stationTaskBatch['station'])['code'];//获取放线入口
+
         $groupPrefix        = $stationTaskBatch['id'];//将波次任务ID当作组前缀
         $taskMaterialBoxes  = $stationTaskBatch['stationTask']['stationTaskMaterialBoxes'] ??
             (function () use ($stationTaskBatch) {
@@ -173,8 +184,28 @@ class StationTaskBatchService
                 throw new Exception('找不到料箱:' . json_encode($stationTaskBatch));
             })();//存在任务返回任务 否则抛出无料箱异常
         try{
-            $isFetchedFromRobotics = $this->foreignHaiRoboticsService->
+            //获取放线入口
+            switch ($locationType){
+                case 'OUTBIN-U-SHAPE-LINE'://U型线
+                    $toLocation         = $this->stationService->getULineEntrance($stationTaskBatch['station'])['code'];
+                    $isFetchedFromRobotics = $this->foreignHaiRoboticsService->
                     fetchGroup($toLocation, $taskMaterialBoxes, $groupPrefix);//执行料箱任务
+                    break;
+                case 'OUTBIN-CACHE-SHELF'://缓存架
+                    list($toLocation, $taskMaterialBoxes, $map) = $this->apportionLocation($taskMaterialBoxes);
+                    if ($toLocation->count()>0){
+                        $isFetchedFromRobotics = $this->foreignHaiRoboticsService->
+                        fetchGroup_multiLocation($toLocation, $taskMaterialBoxes, $groupPrefix, '立架出至缓存架',20);
+                        foreach ($toLocation as $value){
+                            app("CacheShelfService")->lightUp($value,'3','2');
+                            Cache::forever("CACHE_SHELF_OCCUPANCY_{$map[$value]}",true);
+                        }
+                        app("StationService")->locationOccupyMulti($toLocation->toArray());
+                    }else $isFetchedFromRobotics = true;
+                    break;
+                default:
+                    $isFetchedFromRobotics = false;
+            }
             LogService::log(__METHOD__,'runMany','波次任务分配6.r6:'.json_encode($stationTaskBatch));
         }catch(Exception $e){
             throw new ErrorException('$stationTaskBatch运行波次机器人任务失败,获取组失败: '.$stationTaskBatch->toJson() . $e->getMessage());
@@ -194,7 +225,7 @@ class StationTaskBatchService
         }
         $taskIds = data_get($stationTaskBatch_orCollection, '*.id');
         $this->markProcessing_byIds($taskIds);
-        app("StorageService")->handleStorage($stationTaskBatch_orCollection);
+        //app("StorageService")->handleStorage($stationTaskBatch_orCollection);
     }
     function markProcessing_byIds($ids)
     {
@@ -233,24 +264,60 @@ class StationTaskBatchService
             ->update(['status'=>'完成']);
     }
 
-//    function markFinished($stationTaskBatches)
-//    {
-//        if (get_class($stationTaskBatches)==StationTaskBatch::class){
-//            $stationTaskBatches = collect($stationTaskBatches);
-//        }
-//        StationTaskBatch::query()
-//            ->whereIn('id', data_get($stationTaskBatches, '*.id'))
-//            ->update(['status'=>'完成']);
-//
-//        $this->stationTaskService
-//            ->markProcessing_byId(
-//                data_get($stationTaskBatches, '*.station_id')
-//            );
-//    }
-
     function markExcepted(StationTaskBatch $stationTaskBatch)
     {
         $stationTaskBatch['status'] = '异常';
         $stationTaskBatch           ->update();
     }
+
+    /**
+     * 为任务分配缓存架库位
+     *
+     * @param \Illuminate\Database\Eloquent\Collection $taskMaterialBoxes
+     *
+     * @return array
+     */
+    public function apportionLocation(Collection $taskMaterialBoxes):array
+    {
+        $taskMaterialBoxes->loadMissing(["stationTaskCommodities.order","stationTaskCommodities.commodity.barcodes"]);
+        //获取可用的库位 加行锁
+        $stations = app("StationService")->getCacheShelf(true);
+        $location = [];
+        $map = [];
+        foreach ($stations as $station){
+            $location[] = $station->code;
+            $map[$station->code] = $station->id;
+        }
+        /** @var Collection $handleTask */
+        $handleTask = $taskMaterialBoxes->splice(0,count($location));
+        $toLocation = collect();
+        $updateTask = [["id","station_id"]];
+        $insertTransaction = [];
+        $exeInsert = function ($task,$taskCommodity,$status)use(&$insertTransaction){
+            $insertTransaction[] = [
+                "doc_code" => $taskCommodity->order->code ?? "",
+                "bar_code" => $taskCommodity->commodity->barcodes[0]->code ?? "",
+                "to_station_id" => $task->station_id,
+                "material_box_id" => $task->material_box_id,
+                "task_id" => $task->id,
+                "commodity_id" => $taskCommodity->commodity_id,
+                "amount" => $taskCommodity->amount,
+                "type" => "出库",
+                "status" => $status,
+                "mark" => 2,
+                "bin_number"=>$taskCommodity->bin_number,
+            ];
+        };
+        foreach ($handleTask as $index=>$task){
+            $task->station_id = $map[$location[$index]];
+            $toLocation->push($location[$index]);
+            $handleTask->offsetSet($index,$task);
+            $updateTask[] = ["id"=>$task->id,"station_id"=>$task->station_id];
+            foreach ($task->stationTaskCommodities as $taskCommodity)$exeInsert($task,$taskCommodity,0);
+        }
+        if ($handleTask->count()>0)app("BatchUpdateService")->batchUpdate("station_task_material_boxes",$updateTask);
+        foreach ($taskMaterialBoxes as $obj)foreach ($obj->stationTaskCommodities as $taskCommodity)$exeInsert($obj,$taskCommodity,3);
+        TaskTransaction::query()->insert($insertTransaction);
+        return array($toLocation, $handleTask, $map);
+    }
 }

+ 29 - 38
app/Services/StationTaskMaterialBoxService.php

@@ -5,14 +5,11 @@ namespace App\Services;
 
 
 use App\Batch;
-use App\Events\BroadcastToStation;
 use App\Exceptions\ErrorException;
-use App\Exceptions\Exception;
+use App\Jobs\CacheShelfTaskJob;
 use App\MaterialBox;
 use App\OrderCommodity;
-use App\StationCacheShelfGrid;
 use App\StationTask;
-use App\StationTaskBatch;
 use App\StationTaskMaterialBox;
 use Carbon\Carbon;
 use Illuminate\Support\Collection;
@@ -109,7 +106,7 @@ class StationTaskMaterialBoxService
         $this->instant($this->orderCommodityService,'OrderCommodityService');
         $stationMaterialBoxes_toCreate=new Collection();
         $order_ids=data_get($batch['orders'],'*.id');
-        $orderCommodities=OrderCommodity::query()->orderByRaw("commodity_id,amount desc")//同商品多条 数量最小优先
+        $orderCommodities=OrderCommodity::query()->orderByRaw("commodity_id,amount")//同商品多条 数量最小优先
             ->with('orderBin')->whereIn('order_id',$order_ids)->get();
         //$orderCommodities=$this->orderCommodityService->correctLocation_fromWMS($orderCommodities);
         if($orderCommodities->isEmpty())return $stationMaterialBoxes_toCreate;
@@ -175,14 +172,14 @@ class StationTaskMaterialBoxService
                 case '入立库':
                     $stationTaskMaterialBox->materialBox['status']='在立库';
                     $stationTaskMaterialBox->materialBox->update();
-                    $stationTaskMaterialBox->loadMissing("station");    //提前加载站,后续都需要站信息来处理
-                    $this->storageService->releaseOccupation($stationTaskMaterialBox); //释放库位占用
-                    $this->storageService->checkMark($stationTaskMaterialBox); //检查标记并做一些特殊处理
+                    //$this->storageService->checkMark($stationTaskMaterialBox); //检查标记并做一些特殊处理
                     break;
                 case '入缓存架':
                     $stationTaskMaterialBox->materialBox['status']='在缓存架';
                     $stationTaskMaterialBox->materialBox->update();
+                    $stationTaskMaterialBox->loadMissing("station");    //提前加载站,后续都需要站信息来处理
                     $this->storageService->putCacheShelf($stationTaskMaterialBox);
+                    $this->storageService->releaseOccupation($stationTaskMaterialBox); //释放库位占用
                     break;
                 default:;
             }
@@ -206,20 +203,24 @@ class StationTaskMaterialBoxService
             ->update(["status"=>"完成"]);
     }
 
-    // TODO 料箱处理
+    /**
+     * 取出料箱通知
+     *
+     * @param $stationTaskMaterialBox
+     * @throws \Exception
+     */
     function markHasTaken($stationTaskMaterialBox)
     {
-        //TODO: 标记 料箱位置(需要其字段存在)$stationTaskMaterialBox['materialBox']['position']
         $this->instant($this->cacheShelfService,'CacheShelfService');
-
-        // 料箱从缓存架上拿走
-        if($stationTaskMaterialBox['station']['stationType']['name']=='缓存架'
-            &&$stationTaskMaterialBox['type']=='取'){
-
-            $stationTaskMaterialBox['status'] = '完成';
-            $result = $this->cacheShelfService->lightOffTask($stationTaskMaterialBox['station']['code'],0);
-            if($result['success'])
-                $this->markProcessed($stationTaskMaterialBox);
+        //维护缓存架可用度
+        $map = Cache::get("CACHE_SHELF_MAPPING",function (){return [];});
+        if (isset($map[$stationTaskMaterialBox->material_box_id])){
+            $available=Cache::get("CACHE_SHELF_AVAILABLE",function (){return [];});
+            $available[$map[$stationTaskMaterialBox->material_box_id]] = true;
+            Cache::forever("CACHE_SHELF_AVAILABLE",$available);
+            CacheShelfTaskJob::dispatch("CACHE_SHELF_AVAILABLE",count($available))->delay(now()->addSeconds(config("haiRou.cacheShelf.outBinAwait")));
+            unset($map[$stationTaskMaterialBox->material_box_id]);
+            Cache::forever("CACHE_SHELF_MAPPING",$map);
         }
     }
 
@@ -331,25 +332,15 @@ class StationTaskMaterialBoxService
     function getServingTaskType(StationTaskMaterialBox $stationTaskMaterialBox): string
     {
         $stationTaskMaterialBox->load('station.stationType');
-        if($isBatching=(
-            $stationTaskMaterialBox['station_task_batch_id'] &&
-            $stationTaskMaterialBox['station']['stationType']['name'] == '料箱监视器')
-        ){
-            return '分波次';
-        }
-        if($isPuttingBack=(
-            $stationTaskMaterialBox['station']['stationType']['name'] == '立库')
-        ){
-            return '入立库';
-        }
-        if($isCacheShelf=(
-            $stationTaskMaterialBox['station']['stationType']['name'] == '缓存架')
-        ){
-            return '入缓存架';
+        switch ($stationTaskMaterialBox['station']['stationType']['name']){
+            case "立库":
+                return '入立库';
+            case "缓存架":
+                return '入缓存架';
+            case "料箱监视器":
+                if ($stationTaskMaterialBox['station_task_batch_id'])return "分波次";
+            default:
+                throw new ErrorException('当前类型找不到');
         }
-//        if($isStoring=false){
-//            return '入库';
-//        }
-        throw new ErrorException('当前类型找不到');
     }
 }

+ 178 - 68
app/Services/StorageService.php

@@ -5,6 +5,7 @@ namespace App\Services;
 use App\CommodityMaterialBoxModel;
 use App\Components\ErrorPush;
 use App\MaterialBoxCommodity;
+use App\Order;
 use App\Station;
 use App\StationTask;
 use App\StationTaskMaterialBox;
@@ -16,6 +17,7 @@ use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Str;
 
@@ -33,24 +35,69 @@ class StorageService
     {
         DB::beginTransaction();
         try{
-            Station::query()->where("id",$stationTaskMaterialBox->station_id)
-                ->update(["material_box_id"=>$stationTaskMaterialBox->material_box_id,"status"=>0]);
             $stationTaskMaterialBox->loadMissing("station");
             //如果为半箱位置 清理原有任务
             if ($stationTaskMaterialBox->station && app("StationService")->isHalfBoxLocation($stationTaskMaterialBox->station)){
-                $task = TaskTransaction::query()->selectRaw("1")->with("materialBox")->where("fm_station_id",$stationTaskMaterialBox->station_id)
-                    ->where("status",0)->first();
-                if ($task)app("CacheShelfService")->lightUp($stationTaskMaterialBox->station->code,'1','0',[
-                    "title"=>$task->materialBox->code ?? '',
-                    "detail01"=>"{$task->doc_code}",
-                    "detail02"=>"商品条码:{$task->bar_code}",
-                    "detail03"=>"上架数量:{$task->amount}",
-                ]);
-                else $this->clearTask([$stationTaskMaterialBox->station->code]);
+                app("StationService")->locationFreed($stationTaskMaterialBox->station->code,$stationTaskMaterialBox->material_box_id);
+                //清除海柔库位信息
+                $this->clearTask([$stationTaskMaterialBox->station->code]);
+                $stationId = $stationTaskMaterialBox->station_id;
+                $tasks = TaskTransaction::query()->with("materialBox")->where(function ($query)use($stationId){
+                    $query->where("fm_station_id",$stationId)->orWhere("to_station_id",$stationId);
+                })->where("status",0)->get();
+                if ($tasks->count()!=0){
+                    $options = [];
+                    switch ($tasks[0]->mark){
+                        case 1:
+                            $options["title"] = '上架任务';
+                            break;
+                        case 2:
+                            $options["title"] = '出库任务';
+                            break;
+                        default:
+                            $options["title"] = '未知类型';
+                    }
+                    switch ($tasks->count()){
+                        case 1:
+                            $task = $tasks[0];
+                            $options["detail01"] = $task->materialBox->code ?? '';
+                            $options["detail02"] = $task->doc_code ?: $task->track_num;
+                            $options["detail03"] = $task->bar_code;
+                            $options["qty01"] = $task->amount;
+                            $options["uomDesc01"] = '件';
+                            $options["qty02"] = $task->bin_number;
+                            $options["uomDesc02"] = '号';
+                            break;
+                        default:
+                            $count = count(array_unique(array_column($tasks->toArray(),"commodity_id")));
+                            if ($count==1){
+                                $options["detail01"] = $tasks[0]->bar_code;
+                                $options["detail02"] = "";
+                                $options["detail03"] = "";
+                                foreach ($tasks as $task){
+                                    if (mb_strlen($options["detail02"])>20){
+                                        $options["detail03"] .= $task->bin_number."号-".$task->amount."件,";
+                                    }else $options["detail02"] .= $task->bin_number."号-".$task->amount."件,";
+                                }
+                                $options["detail02"] = rtrim($options["detail02"],",");
+                                $options["detail03"] = rtrim($options["detail03"],",");
+                            }else{
+                                $task = $tasks[0];
+                                $options["detail01"] = $task->materialBox->code ?? '';
+                                $options["detail02"] = "货品过多请自行核对";
+                                $options["detail03"] = "波次:".$task->doc_code ?
+                                    (Order::query()->with("batch")->where("code",$task->doc_code)->first()->batch->code ?? '无') : '无';
+                            }
+                            break;
+                    }
+                    app("CacheShelfService")->lightUp($stationTaskMaterialBox->station->code,'2','0',$options);
+                    Cache::forget("CACHE_SHELF_OCCUPANCY_{$stationTaskMaterialBox->station->id}");//关闭无限亮灯
+                }
             }
             DB::commit();
         }catch (\Exception $e){
             DB::rollBack();
+            $this->push(__METHOD__."->".__LINE__,"清除任务亮灯失败","错误信息:".$e->getMessage()."  执行任务信息:".json_encode($stationTaskMaterialBox));
         }
     }
 
@@ -61,7 +108,7 @@ class StorageService
      */
     public function releaseOccupation($stationTaskMaterialBox)
     {
-        if (!app("StationService")->isCacheShelfLocation($stationTaskMaterialBox->station))return;
+        if (!app("StationService")->isHalfBoxLocation($stationTaskMaterialBox->station))return;
         app("StationService")->locationFreed($stationTaskMaterialBox->station->code);
     }
 
@@ -75,8 +122,8 @@ class StorageService
         $task = TaskTransaction::query()->where("material_box_id",$stationTaskMaterialBox->material_box_id)
             ->where("status",0)->first();
         if (!$task)return;
-        //灯闪烁
-        if ($task->type == '入库' && $task->mark == 1)app("CacheShelfService")->lightUp($stationTaskMaterialBox->station->code,'2','2',["title"=>'机器人取箱中,禁止操作',]);
+        //灯闪烁
+        if ($task->type == '入库' && $task->mark == 1)app("CacheShelfService")->lightUp($stationTaskMaterialBox->station->code,'3','2',["title"=>'机器人取箱中,禁止操作',]);
     }
 
     /**
@@ -88,47 +135,88 @@ class StorageService
      *
      * @throws
      */
-    public function checkStorage(Station $station)
+    public function checkStorage(Station $station):?bool
     {
-        $task = TaskTransaction::query()->with("materialBox")->where("fm_station_id",$station->id)
-            ->where("status",0)->first();
-        if (!$task)return true;
-        //建立入库任务,通知入库,完善库存
-        if ($task->type == '入库' && $task->mark == 1){
-            DB::beginTransaction();
+        $stationId = $station->id;
+        $task = TaskTransaction::query()->with("materialBox")->where(function ($query)use($stationId){
+            $query->where("fm_station_id",$stationId)->orWhere("to_station_id",$stationId);
+        })->where("status",0)->first();
+        if (!$task)return null;
+        switch ($task->type){
+            case "入库":
+                switch ($task->mark){
+                    case 1:
+                        return $this->handlePaTransaction($task, $station);
+                }
+                break;
+            case "出库":
+                switch ($task->mark){
+                    case 2:
+                        return $this->handleOutTransaction($station);
+                }
+        }
+        return null;
+    }
+
+    /**
+     * 处理出货交易
+     *
+     * @param Station|\stdClass $station
+     *
+     * @return bool
+     */
+    private function handleOutTransaction($station):bool
+    {
+        return TaskTransaction::query()->with("materialBox")->orWhere("to_station_id",$station->id)
+            ->where("status",0)->update([
+                "status" => 1,
+            ]) > 0;
+    }
+
+    /**
+     * 处理上架交易
+     *
+     * @param TaskTransaction|\stdClass $task
+     * @param Station|\stdClass $station
+     *
+     * @return bool
+     * @throws
+     */
+    private function handlePaTransaction($task, $station):bool
+    {
+        DB::beginTransaction();
+        try{
+            //get flux
+            $tasks = $this->getFluxTask($task->track_num,$task->lot_num,$task->bar_code,$task->amount);
+            if (!$tasks)return false;
+            $ide = $task->materialBox->code;
+            DB::connection("oracle")->beginTransaction();
             try{
-                //get flux
-                $tasks = $this->getFluxTask($task->doc_code,$task->bar_code,$task->amount);
-                if (!$tasks)return false;
-                $ide = $task->materialBox->code;
-                DB::connection("oracle")->beginTransaction();
-                try{
-                    foreach ($tasks as $t)if (!$this->fluxPA($t,$ide)){
-                        DB::connection("oracle")->rollBack();
-                        return false;
-                    };
-                }catch(\Exception $e){
+                foreach ($tasks as $t)if (!$this->fluxPA($t,$ide)){
                     DB::connection("oracle")->rollBack();
                     return false;
-                }
-                $taskMaterialBox = $this->createWarehousingTask($station->id,$task->material_box_id);//建立入库任务
-                //2021-07-27 取消WAS库存维护
-                //if (!$this->enterWarehouse($task->material_box_id,$task->commodity_id,$task->amount))throw new \Exception("库存异常"); //处理库存
-                $task->update([
-                    "task_id" => $taskMaterialBox->id,
-                    "status" => 1,
-                ]);//标记事务完成
-                app("ForeignHaiRoboticsService")->putBinToStore_fromCacheShelf($taskMaterialBox,$station); //呼叫机器人入库
-                DB::commit();
-                DB::connection("oracle")->commit();
-                return true;
+                };
             }catch(\Exception $e){
-                DB::rollBack();
                 DB::connection("oracle")->rollBack();
                 return false;
             }
+            //$taskMaterialBox = $this->createWarehousingTask($station->id,$task->material_box_id);//建立入库任务
+            //2021-07-27 取消WAS库存维护
+            //if (!$this->enterWarehouse($task->material_box_id,$task->commodity_id,$task->amount))throw new \Exception("库存异常"); //处理库存
+            $task->update([
+                //"task_id" => $taskMaterialBox->id,
+                "status" => 1,
+            ]);//标记事务完成
+            //返回亮灯 此处不入库 再下一次按时入库
+            //app("ForeignHaiRoboticsService")->putBinToStore_fromCacheShelf($taskMaterialBox,$station); //呼叫机器人入库
+            DB::commit();
+            DB::connection("oracle")->commit();
+            return true;
+        }catch(\Exception $e){
+            DB::rollBack();
+            DB::connection("oracle")->rollBack();
+            return false;
         }
-        return true;
     }
 
     /**
@@ -200,21 +288,23 @@ class StorageService
     /**
      * 获取FLUX上架任务列表
      *
-     * @param string $asn
+     * @param string $trace
+     * @param string $lotNum
      * @param string $barCode
      * @param int $amount
      *
      * @return array|null
      */
-    public function getFluxTask(string $asn,string $barCode,int $amount):array
+    public function getFluxTask(string $trace, string $lotNum, string $barCode,int $amount):array
     {
-        $sql = <<<sql
-SELECT TSK_TASKLISTS.* FROM DOC_ASN_DETAILS LEFT JOIN BAS_SKU ON DOC_ASN_DETAILS.CUSTOMERID = BAS_SKU.CUSTOMERID AND DOC_ASN_DETAILS.SKU = BAS_SKU.SKU
-LEFT JOIN TSK_TASKLISTS ON DOC_ASN_DETAILS.ASNNO = TSK_TASKLISTS.DOCNO AND DOC_ASN_DETAILS.ASNLINENO = TSK_TASKLISTS.DOCLINENO
-WHERE ASNNO = ? AND (ALTERNATE_SKU1 = ? OR ALTERNATE_SKU2 = ? OR ALTERNATE_SKU3 = ?) AND RECEIVEDQTY >= ?
-  AND TASKPROCESS = '00' AND TASKTYPE = 'PA'
-sql;
-        $tasks = DB::connection("oracle")->select(DB::raw($sql),[$asn,$barCode,$barCode,$barCode,$amount]);
+        $sql = <<<SQL
+SELECT TSK_TASKLISTS.* FROM TSK_TASKLISTS LEFT JOIN BAS_SKU ON TSK_TASKLISTS.CUSTOMERID = BAS_SKU.CUSTOMERID
+AND TSK_TASKLISTS.SKU = BAS_SKU.SKU
+WHERE FMID = ? AND FMLOTNUM = ? AND (ALTERNATE_SKU1 = ? OR ALTERNATE_SKU2 = ? OR ALTERNATE_SKU3 = ?)
+AND TASKPROCESS = '00' AND TASKTYPE = 'PA'
+SQL;
+
+        $tasks = DB::connection("oracle")->select(DB::raw($sql),[$trace,$lotNum,$barCode,$barCode,$barCode,$amount]);
         if (!$tasks)return [];
         $nums = [];
         $sum = 0;
@@ -242,7 +332,7 @@ sql;
      * @return array
      * @throws
      */
-    private function splitTask($tasks,$maxIndex,$amount):array
+    public function splitTask($tasks, $maxIndex, $amount):array
     {
         $result = [];
         if ($maxIndex===null){
@@ -324,7 +414,7 @@ sql;
      * @param Integer $target
      * @return Integer[]|null
      */
-    protected function getMatch(array $nums,int $target) :?array
+    public function getMatch(array $nums, int $target) :?array
     {
         $map=[];
         foreach ($nums as $index=>$val){
@@ -420,8 +510,7 @@ sql;
         }
     }
 
-    private function
-    checkAsn($task)
+    private function checkAsn($task)
     {
         $sql = <<<SQL
 SELECT 1 FROM DOC_ASN_DETAILS WHERE ASNNO = ? AND LINESTATUS != '40'
@@ -432,8 +521,7 @@ SQL;
         $sql = <<<SQL
 SELECT 1 FROM TSK_TASKLISTS WHERE TASKPROCESS != '99' AND TASKTYPE = 'PA' AND DOCNO = ?
 SQL;
-        $task = DB::connection("oracle")->selectOne(DB::raw($sql),[$task->docno]);
-        if ($task)return;
+        if (DB::connection("oracle")->selectOne(DB::raw($sql),[$task->docno]))return;
 
         DB::connection("oracle")->update(DB::raw("UPDATE DOC_ASN_HEADER SET asnstatus = '99',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ?"),
             [date("Y-m-d H:i:s"),$task->who,$task->docno]);
@@ -508,7 +596,27 @@ SQL;
     }
 
     /**
-     * 获取半箱库位库存信息
+     * 获取指定型号的半箱库位
+     *
+     * @param CommodityMaterialBoxModel $model
+     * @param string $lotNum
+     * @return string|null
+     */
+    public function getMaxAvailableHalfBoxLocation(CommodityMaterialBoxModel $model, string $lotNum, array $blacklist = []):?string
+    {
+        $boxCodes = app("MaterialBoxService")->getModelAvailableBox($model->material_box_model_id,true,$blacklist);
+        if (!$boxCodes)return null;
+        $sql = <<<SQL
+SELECT LOCATIONID,({$model->maximum}-QTY) AS QTY FROM INV_LOT_LOC_ID WHERE LOTNUM = '{$lotNum}'
+AND LOCATIONID IN ({$boxCodes}) AND TRACEID = '*' AND {$model->maximum}-QTY > 0 ORDER BY (CASE QTY WHEN 0 THEN 1 ELSE 0 END),{$model->maximum}-QTY
+SQL;
+        $res = DB::connection("oracle")->selectOne(DB::raw($sql));
+        if ($res)return $res;
+        return null;
+    }
+
+    /**
+     * 获取半箱库位库存信息  废弃
      *
      * @param CommodityMaterialBoxModel|\stdClass $model
      * @param StoreItem|\stdClass $item
@@ -567,22 +675,24 @@ sql;
     /**
      * 检查可上架数量
      *
-     * @param string $asn
+     * @param string $track
      * @param string $barCode
+     * @param string $lotNum
      *
      * @return int
      */
-    public function checkPutAmount(string $asn,string $barCode):int
+    public function checkPutAmount(string $track, string $barCode, string $lotNum):int
     {
         $sql = <<<SQL
 SELECT SUM(FMQTY) qty FROM TSK_TASKLISTS
 LEFT JOIN BAS_SKU ON TSK_TASKLISTS.CUSTOMERID = BAS_SKU.CUSTOMERID AND TSK_TASKLISTS.SKU = BAS_SKU.SKU
-WHERE DOCNO = ? AND (ALTERNATE_SKU1 = ? OR ALTERNATE_SKU2 = ? OR ALTERNATE_SKU3 = ?) AND TASKTYPE = 'PA'
+WHERE FMID = ? AND FMLOTNUM = ? AND (ALTERNATE_SKU1 = ? OR ALTERNATE_SKU2 = ? OR ALTERNATE_SKU3 = ?) AND TASKTYPE = 'PA'
 AND TASKPROCESS = '00'
 SQL;
-        $tsk = DB::connection("oracle")->selectOne(DB::raw($sql),[$asn,$barCode,$barCode,$barCode]);
-        if (!$tsk)return  0;
-        $trk = TaskTransaction::query()->select(DB::raw("SUM(amount) amount"))->where("doc_code",$asn)->where("bar_code",$barCode)
+        $tsk = DB::connection("oracle")->selectOne(DB::raw($sql),[$track,$lotNum,$barCode,$barCode,$barCode]);
+        if (!$tsk)return 0;
+        $trk = TaskTransaction::query()->select(DB::raw("SUM(amount) amount"))->where("track_num",$track)
+            ->where("lot_num",$lotNum)->where("bar_code",$barCode)
             ->where("type","入库")->where("status",0)->first();
         if (!$trk)return $tsk->qty;
         return $tsk->qty - $trk->amount;

+ 4 - 5
app/Services/common/BatchUpdateService.php

@@ -3,15 +3,14 @@
 
 namespace App\Services\common;
 
-
-use App\Services\LogService;
+use App\Components\ErrorPush;
 use Illuminate\Support\Facades\DB;
 use App\Traits\ServiceAppAop;
 
 
 class BatchUpdateService
 {
-    use ServiceAppAop;
+    use ServiceAppAop,ErrorPush;
     public function batchUpdate($tableName = '', $multipleData = array(), $connection = 'mysql')
     {
         if (count($multipleData) == 1) {
@@ -76,7 +75,7 @@ class BatchUpdateService
             }
             return $bool;
         } catch (\Exception $e) {
-            app('LogService')->log(__METHOD__, __FUNCTION__, '批量更新失败' . $tableName . ' | '.json_encode($multipleData).' | 溯源:'.json_encode($debug) . $e->getMessage() . $e->getTraceAsString());
+            $this->push(__METHOD__."->".__LINE__,"批量更新失败",$tableName . ' | '.json_encode($multipleData).' | 溯源:'.json_encode($debug) . $e->getMessage() . $e->getTraceAsString());
             return false;
         }
     }
@@ -94,7 +93,7 @@ class BatchUpdateService
             app('LogService')->log(__METHOD__, __FUNCTION__, '批量更新本身' .$sql);
             return $bool;
         }catch (\Exception $e){
-            app('LogService')->log(__METHOD__, __FUNCTION__, '批量更新失败 SQL:(' . $sql .") 堆栈:". $e->getMessage() . $e->getTraceAsString());
+            $this->push(__METHOD__."->".__LINE__,"批量更新失败",'SQL:(' . $sql .") 堆栈:". $e->getMessage() . $e->getTraceAsString() . $e->getMessage() . $e->getTraceAsString());
             return false;
         }
     }

+ 12 - 3
app/Station.php

@@ -19,7 +19,16 @@ class Station extends Model
         0 => "正常",
         1 => "占用",
     ];
+    /*站相关 CACHE说明
+     * CACHE_SHELF_OCCUPANCY_{ID}   //bool:缓存架占用标记,开启此标记后连续排灯无效
+     * CACHE_SHELF_MAPPING          //array(map):缓存架映射标记,用来映射入库任务的真实库位 CacheShelfTaskJob:materialBoxMappingCacheShelf详细描述此流程
+     * CACHE_SHELF_AVAILABLE        //array(map):缓存架可用标记,映射缓存架是否可以被下达出库任务
+     * */
 
+    public function task()
+    {
+        return $this->hasOne(StationTaskMaterialBox::class,"station_id","id");
+    }
     public function materialBox():BelongsTo
     {
         return $this->belongsTo(MaterialBox::class);
@@ -41,14 +50,14 @@ class Station extends Model
         return $this->hasMany(StationTask::class)
             ->where('created_at','>=',now()->format('Y-m-d'))
             ->orderBy('status')
-            ->orderByDesc('id')
-            ;
+            ->orderByDesc('id');
     }
     public function stationTasks()
     {   //站任务
         return $this->hasMany(StationTask::class,"id","station_type_id");
     }
-    public function stationTypeBinMonitor(){
+    public function stationTypeBinMonitor()
+    {
         return $this->hasOne(StationTypeBinMonitor::class);
     }
 

+ 4 - 0
app/StationTaskCommodity.php

@@ -25,4 +25,8 @@ class StationTaskCommodity extends Model
     {
         return $this->belongsTo(StationTask::class);
     }
+    public function order()
+    {
+        return $this->belongsTo(Order::class);
+    }
 }

+ 24 - 14
app/TaskTransaction.php

@@ -11,32 +11,42 @@ class TaskTransaction extends Model
     use ModelLogChanging;
 
     protected $fillable = [
-        "doc_code",
-        "bar_code",
-        "fm_station_id",
-        "to_station_id",
-        "material_box_id",
-        "task_id",
-        "commodity_id",
-        "amount",
-        "type",
-        "status",
-        "user_id",
-        "mark"
+        "doc_code",     //单号
+        "bar_code",     //条码
+        "fm_station_id",//来源库位
+        "to_station_id",//目标库位
+        "material_box_id",//料箱
+        "task_id",      //机器人任务
+        "commodity_id", //商品
+        "amount",       //数量
+        "type",         //类型
+        "status",       //状态
+        "user_id",      //操作人
+        "mark",         //标记
+        "bin_number",   //格口号
+        "lot_num",      //批号
+        "track_num",    //跟踪号
     ];
 
     const STATUS = [
         0 => "待做",
         1 => "完成",
-        2 => "失败"
+        2 => "失败",
+        3 => "队列",
     ];
     const MARK = [
         0 => "无",
-        1 => "缓存架半箱入库"
+        1 => "缓存架半箱入库",
+        2 => "料箱出至缓存架"
     ];
 
     public function materialBox()
     {   //料箱
         return $this->belongsTo(MaterialBox::class);
     }
+
+    public function task()
+    {   //任务
+        return $this->belongsTo(StationTaskMaterialBox::class,"task_id");
+    }
 }

+ 4 - 4
bashupMysql.sh

@@ -1,11 +1,11 @@
 #!/bin/bash
 #设置mysql的备份保存目录
-folder=/etc/bashupMysql
-cd $folder
+#folder=/etc/bashupMysql
+#cd $folder
 #当前日期
 time_now=$(date  "+%Y-%m-%d")
 #当前时间的前30天 %H:%M:%S
-time_30day_ago=$(date -d"25 day ago" "+%Y-%m-%d 00:00:00")
+time_30day_ago=$(date -d"20 day ago" "+%Y-%m-%d 00:00:00")
 #数据库服务器ip
 host="was.baoshi56.com"
 test_host="101.133.135.193"
@@ -19,7 +19,7 @@ test_password="123456"
 db="bswas"
 test_db="bswas_test"
 #执行备份语句 --single-transaction 是在导出数据时不锁表
-mysqldump -h$host -u$user -p$password --single-transaction $db --ignore-table=$db.orders --ignore-table=$db.stores --ignore-table=$db.packages --ignore-table=$db.store_items --ignore-table=$db.commodities --ignore-table=$db.commodity_barcodes --ignore-table=$db.logs --ignore-table=$db.order_commodities --ignore-table=$db.order_bins --ignore-table=$db.w_m_s_waybill_orders --ignore-table=$db.rejected_bills --ignore-table=$db.rejected_bill_items --ignore-table=$db.w_m_s_reflect_packages --ignore-table=$db.w_m_s_reflect_receive_skus --ignore-table=$db.w_m_s_reflect_receives --ignore-table=$db.order_counting_records --ignore-table=$db.order_package_commodities --ignore-table=$db.order_packages --ignore-table=$db.packages> $time_nowall.sql
+mysqldump -h$host -u$user -p$password --single-transaction $db --ignore-table=$db.orders --ignore-table=$db.failed_jobs --ignore-table=$db.stores --ignore-table=$db.packages --ignore-table=$db.store_items --ignore-table=$db.commodities --ignore-table=$db.commodity_barcodes --ignore-table=$db.logs --ignore-table=$db.order_commodities --ignore-table=$db.order_bins --ignore-table=$db.w_m_s_waybill_orders --ignore-table=$db.rejected_bills --ignore-table=$db.rejected_bill_items --ignore-table=$db.w_m_s_reflect_packages --ignore-table=$db.w_m_s_reflect_receive_skus --ignore-table=$db.w_m_s_reflect_receives --ignore-table=$db.order_counting_records --ignore-table=$db.order_package_commodities --ignore-table=$db.order_packages --ignore-table=$db.packages> $time_nowall.sql
 mysql  -u$test_user -p$test_password  $test_db< $time_nowall.sql
 mysqldump -h$host -u$user -p$password --single-transaction -q -e $db orders --where="created_at>='$time_30day_ago'" > $time_noworders.sql
 mysql  -u$test_user -p$test_password  $test_db< $time_noworders.sql

+ 2 - 0
config/api_logistic.php

@@ -183,6 +183,7 @@ return [
             'passwordSigning' => 'N', //是否口令签收 仅适用于快递,Y:需要 N: 不需要;若为Y,必须收货人提供验证码给快递员才能签收,该服务是有偿的,具体费用请让我司收货营业部联系张宁(491407),请慎重使用!
             'uri' => [
                 'create_order' => 'http://dpsanbox.deppon.com/sandbox-web/dop-standard-ewborder/createOrderNotify.action',
+                'order_locus' => 'http://dpsanbox.deppon.com/sandbox-web/standard-order/newTraceQuery.action',
             ]
         ],
         'prod'=>[
@@ -200,6 +201,7 @@ return [
             'passwordSigning' => 'N', //是否口令签收 仅适用于快递,Y:需要 N: 不需要;若为Y,必须收货人提供验证码给快递员才能签收,该服务是有偿的,具体费用请让我司收货营业部联系张宁(491407),请慎重使用!
             'uri' => [
                 'create_order' => 'http://dpsanbox.deppon.com/sandbox-web/dop-standard-ewborder/createOrderNotify.action',
+                'order_locus' => 'http://dpsanbox.deppon.com/sandbox-web/standard-order/newTraceQuery.action',
             ]
         ]
     ],

+ 2 - 0
config/haiRou.php

@@ -9,5 +9,7 @@ return [
     "cacheShelf" => [
         /* call await time/second */
         "callAwait" => 3,
+        /* outbound waiting time/second */
+        "outBinAwait" => 60,
     ],
 ];

+ 0 - 7
config/sync,php.php

@@ -1,7 +0,0 @@
-<?php
-return [
-    'order_tracking_import' => [
-        'import' => 20,
-        'start_at'=> '',
-    ],
-];

+ 0 - 2
database/migrations/2021_07_02_092716_add_owner_price_operation_id_to_owner_store_out_fee_details.php

@@ -16,7 +16,6 @@ class AddOwnerPriceOperationIdToOwnerStoreOutFeeDetails extends Migration
         Schema::table('owner_store_out_fee_details', function (Blueprint $table) {
             $table->integer('owner_price_operation_id')->comment('计费模型');
             $table->string('price_remark')->comment('费用描述');
-            $table->string('step')->comment('阶梯');
         });
     }
 
@@ -30,7 +29,6 @@ class AddOwnerPriceOperationIdToOwnerStoreOutFeeDetails extends Migration
         Schema::table('owner_store_out_fee_details', function (Blueprint $table) {
             $table->dropColumn('owner_price_operation_id');
             $table->dropColumn('work_name');
-            $table->dropColumn('step');
         });
     }
 }

+ 3 - 1
database/migrations/2021_07_07_103716_change_warehouses_table.php

@@ -28,7 +28,9 @@ class ChangeWarehousesTable extends Migration
     public function down()
     {
         Schema::table('warehouses', function (Blueprint $table) {
-            //
+            $table->dropColumn('province_id');
+            $table->dropColumn('city_id');
+            $table->dropColumn('county_id');
         });
     }
 }

+ 4 - 1
database/migrations/2021_07_07_164742_change_waybills_add_db_table.php

@@ -29,7 +29,10 @@ class ChangeWaybillsAddDbTable extends Migration
     public function down()
     {
         Schema::table('waybills', function (Blueprint $table) {
-            //
+            $table->dropColumn('cargo_name');
+            $table->dropColumn('total_number');
+            $table->dropColumn('total_weight');
+            $table->dropColumn('deliveryType_id');
         });
     }
 }

+ 7 - 1
database/migrations/2021_07_15_173811_alert_order_type_column_in_waybills_table.php

@@ -33,7 +33,13 @@ class AlertOrderTypeColumnInWaybillsTable extends Migration
     public function down()
     {
         Schema::table('waybills', function (Blueprint $table) {
-            //
+            $table->dropColumn('order_type');
+            $table->dropColumn('transport_type');
+            $table->dropColumn('pay_type');
+            $table->dropColumn('back_sign_bill');
+            $table->dropColumn('package_service');
+            $table->dropColumn('total_number');
+            $table->dropColumn('deliveryType_id');
         });
     }
 }

+ 0 - 2
database/migrations/2021_07_16_092933_add_work_name_and_drop_other_to_owner_store_out_fee_details_table.php

@@ -18,7 +18,6 @@ class AddWorkNameAndDropOtherToOwnerStoreOutFeeDetailsTable extends Migration
             $table->string('sku')->comment('商家编码');
             $table->decimal('packingMaterialFee')->comment('耗材费');
             $table->string('barcode')->comment('商品条码');
-            $table->string('work_name')->comment('作业名称');
             $table->decimal('fee')->comment('费用');
 
             $table->dropColumn('owner_price_operation_id');
@@ -37,7 +36,6 @@ class AddWorkNameAndDropOtherToOwnerStoreOutFeeDetailsTable extends Migration
             $table->dropColumn('sku');
             $table->dropColumn('packingMaterialFee');
             $table->dropColumn('barcode');
-            $table->dropColumn('work_name');
             $table->dropColumn('fee');
 
             $table->integer('owner_price_operation_id');

+ 1 - 3
database/migrations/2021_07_28_115218_create_requirements_table.php

@@ -19,13 +19,11 @@ class CreateRequirementsTable extends Migration
             $table->decimal('score')->comment('');
             $table->timestamp('began_at')->nullable()->comment('任务开始时间');
             $table->timestamp('finished_at')->nullable()->comment('完结时间');
-            $table->text('title')->nullable()->comment('标题');
+            $table->string('title')->nullable()->index()->comment('标题');
             $table->text('content')->nullable()->comment('内容');
             $table->tinyInteger('status')->comment('状态');
             $table->softDeletes();
             $table->timestamps();
-
-            $table->index(['title']);
         });
     }
 

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

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeTaskTransactionsTableAddBinNumberColumn extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('task_transactions', function (Blueprint $table) {
+            $table->integer("bin_number")->nullable()->comment("格口");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('task_transactions', function (Blueprint $table) {
+            $table->dropColumn("bin_number");
+        });
+    }
+}

+ 34 - 0
database/migrations/2021_07_29_153104_change_waybills_wms_number_length.php

@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeWaybillsWmsNumberLength extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('waybills', function (Blueprint $table) {
+            $table->string('wms_bill_number')->nullable()->comment('WMS单号')->change();
+            $table->string('origination')->comment('始发地')->change();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('waybills', function (Blueprint $table) {
+            $table->string('wms_bill_number',50)->unique()->nullable()->comment('WMS单号')->change();
+            $table->string('origination',50)->comment('始发地')->change();
+        });
+    }
+}

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

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeNameColumnInOrderPackageCountingRecordsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('order_package_counting_records', function (Blueprint $table) {
+            $table->string('name')->nullable()->comment('称 名称');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('order_package_counting_records', function (Blueprint $table) {
+            $table->dropColumn('name');
+        });
+    }
+}

+ 34 - 0
database/migrations/2021_08_03_092749_change_task_transactions_add_column_lotnum.php

@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeTaskTransactionsAddColumnLotnum extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('task_transactions', function (Blueprint $table) {
+            $table->string("lot_num")->nullable()->comment("批次号");
+            $table->string("track_num")->nullable()->comment("跟踪号");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('task_transactions', function (Blueprint $table) {
+            $table->dropColumn("lot_num");
+            $table->dropColumn("track_num");
+        });
+    }
+}

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

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeOwnersTableChangeIsCheckAsnColumn extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('owners', function (Blueprint $table) {
+            $table->tinyInteger("is_check_asn")->default(0)->comment("是否校验ASN");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('owners', function (Blueprint $table) {
+            $table->dropColumn("is_check_asn");
+        });
+    }
+}

+ 5 - 0
resources/sass/text.scss

@@ -296,3 +296,8 @@
     box-shadow: 0px 0px 0px 1px #ddd;
     color: inherit;
 }
+
+//文本颜色
+.text-greed{
+    color: #27864f !important;
+}

+ 33 - 32
resources/views/control/panel.blade.php

@@ -344,18 +344,22 @@
                     <div class="card">
                         <div class="card-header">
                             <div class="row">
-                                <el-date-picker size="small" class="col-6 date" @blur="loadWeightInfo()"
+                                <el-date-picker size="small" class="col-4 date" @blur="loadWeightInfo()"
                                                 type="daterange" align="right"
                                                 v-model="searchOption.weightDate" unlink-panels range-separator="-"
                                                 start-placeholder="开始日期" end-placeholder="结束日期"
                                                 value-format="yyyy-MM-dd">
                                 </el-date-picker>
-                                <label class="col-3 offset-3">
+                                <label class="col-3">
                                     <select class="form-control rounded" v-model="searchOption.weightSelect"
                                             @change="switchWeightDate()">
                                         <option v-for="(date,i) in dateOptions" :value="i">@{{ date.text }}</option>
                                     </select>
                                 </label>
+                                <el-select class="col-3"  placeholder="请选择对应货主" multiple v-model="selectWeightOwners" size="small" style="width: 50%"  @change="loadWeightInfo()">
+                                    <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>
                             </div>
                         </div>
                         <div class="card-body row">
@@ -434,6 +438,7 @@
                 owners:{!! $owners !!},
                 selectOrderOwners: [],
                 selectLogisticsOwners: [],
+                selectWeightOwners: [],
                 selectExceptionTypeOwners: [],
                 warehousesOrders:{!! $warehousesOrders !!},
                 orderCountingRecords:{},
@@ -959,7 +964,7 @@
                     }
                     this.cardPool.weight.showLoading('default',{text:"加 载 中",color:'#C0C0C0'});
                     let url = "{{url('apiLocal/control/panel/menu/weightApi')}}";
-                    let params = {start:this.searchOption.weightDate[0],end:this.searchOption.weightDate[1]};
+                    let params = {start:this.searchOption.weightDate[0],end:this.searchOption.weightDate[1],owner_ids:this.selectWeightOwners};
                     window.tempTip.postBasicRequest(url,params,res=>{
                         this.cardPool.weight.hideLoading();
                         this.cardPool.weight.setOption(this._setWeightData(res.title,res.data));
@@ -1017,37 +1022,33 @@
                     this.loadExceptionTypeInfo();
                 },
                 _setWeightData(title, data){
-                    return {
-                        title: {
-                            text: '已称重包裹占比',
-                            left: 'left'
+                    let temp = [];
+                    for (let i=1;i<data.length; i++){
+                        temp.push({type: 'line', smooth: true, seriesLayoutBy: 'row', emphasis: {focus: 'series'}});
+                    }
+                    temp.push({type: 'pie', id: 'pie', radius: '30%', center: ['50%', '25%'], emphasis: {focus: 'data'},
+                        label: {
+                            formatter: '{b}: {@'+title+'} ({d}%)'
                         },
+                        encode: {
+                            itemName: 'product',
+                            value: title,
+                            tooltip: title
+                        }
+                    })
+                    return {
+                        legend: {},
                         tooltip: {
-                            trigger: 'item',
-                            formatter: function (params) {
-                                return params.data.date + "<br>" + "总量:<span class='text-success font-weight-bold'>" + params.data.total + "</span><br>" + "已称:<span class='text-info font-weight-bold'>" + params.data.count + "</span>";
-                            }
-                        }, xAxis: {
-                            data: title
-                        }, yAxis: {
-                            axisLabel: {
-                                show: true,
-                                interval: 'auto',
-                                formatter: '{value} %'
-                            },
-                            max: 100
-                        }, label: {
-                            show: true,
-                            position: 'top',
-                            formatter: '{c}%',
-                            color: "red"
-                        }, series: [{
-                            type: "bar",
-                            data: data,
-                            itemStyle: {
-                                color: "RGB(62,157,231)",
-                            }
-                        }]
+                            trigger: 'axis',
+                            showContent: false
+                        },
+                        dataset: {
+                            source: data
+                        },
+                        xAxis: {type: 'category'},
+                        yAxis: {gridIndex: 0},
+                        grid: {top: '55%'},
+                        series: temp
                     };
                 },
                 _setOrderPackageReceivedSyncRecordData(title,data){

+ 5 - 5
resources/views/customer/project/part/_three.blade.php

@@ -58,7 +58,7 @@
                         @can("项目管理-项目-计费模型-审核")<button class="btn btn-sm btn-success" type="button" @click="auditOrRecoverModel('operation')">审核</button>
                         <button class="btn btn-sm btn-danger" type="button" @click="auditOrRecoverModel('operation',false)">恢复</button>@endcan
                     </div>
-                </div>  
+                </div>
                 <div class="col-3 pull-right small mb-0 text-secondary" v-if="selectedModel.operation.length>0">双击下方已添加内容可编辑</div>
             </div>
             <div class="card-body" id="operation">
@@ -186,7 +186,7 @@
                 </div>
                 <div class="col-3 pull-right small mb-0 text-secondary" v-if="selectedModel.express.length>0">双击下方已添加内容可编辑</div>
             </div>
-            <div class="card-body" id="express">
+            <div class="card-body w-100 overflow-auto" id="express">
                 <table class="table table-sm">
                     <tr>
                         <th>承运商</th>
@@ -200,7 +200,7 @@
                     <tbody v-for="(express,i) in selectedModel.express" @dblclick="editExpress(i)" style="cursor: pointer">
                         <tr>
                             <td>
-                                <div class="text-overflow-warp-100 small">
+                                <div class="small">
                                     <label v-for="(logistic,j) in express.logistics" class="m-0">@{{ poolMapping.logistics ? poolMapping.logistics[logistic] : '' }}<br></label>
                                 </div>
                             </td>
@@ -281,7 +281,7 @@
                 </div>
                 <div class="col-3 pull-right small mb-0 text-secondary" v-if="selectedModel.logistic.length>0">双击下方已添加内容可编辑</div>
             </div>
-            <div class="card-body" id="logistic">
+            <div class="card-body w-100 overflow-auto" id="logistic">
                 <table class="table table-sm">
                     <tr>
                         <th>承运商</th>
@@ -300,7 +300,7 @@
                     <tbody v-for="(logistic,i) in selectedModel.logistic" @dblclick="editLogistic(i)" style="cursor: pointer">
                         <tr>
                             <td>
-                                <div class="text-overflow-warp-100 small">
+                                <div class="small">
                                     <label v-for="(logistic,j) in logistic.logistics" class="m-0">@{{ poolMapping.logistics ? poolMapping.logistics[logistic] : '' }}</label>
                                 </div>
                             </td>

+ 5 - 5
resources/views/maintenance/carType/create.blade.php

@@ -11,7 +11,7 @@
                         <label for="name" class="col-2 col-form-label text-right">车辆名称</label>
                         <div class="col-8">
                             <input type="text" class="form-control @error('CarType.name') is-invalid @enderror"
-                                   name="CarType[name]" autocomplete="off" value="{{ old('CarType')['name'] }}">
+                                   name="CarType[name]" autocomplete="off" value="{{ old('CarType')['name'] ?? '' }}">
                             @error('CarType.name')
                             <span class="invalid-feedback" role="alert">
                                         <strong>{{ $errors->first('CarType.name') }}</strong>
@@ -23,7 +23,7 @@
                         <label for="model" class="col-2 col-form-label text-right">车辆型号</label>
                         <div class="col-8">
                             <input type="text" class="form-control @error('CarType.model') is-invalid @enderror"
-                                   name="CarType[model]" autocomplete="off" value="{{ old('CarType')['model'] }}">
+                                   name="CarType[model]" autocomplete="off" value="{{ old('CarType')['model'] ?? '' }}">
                             @error('CarType.model')
                             <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('CarType.model') }}</strong>
@@ -35,7 +35,7 @@
                         <label for="length" class="col-2 col-form-label text-right">车辆长度(米)</label>
                         <div class="col-8">
                             <input type="text" class="form-control @error('CarType.length') is-invalid @enderror"
-                                   name="CarType[length]" autocomplete="off" value="{{ old('CarType')['length'] }}">
+                                   name="CarType[length]" autocomplete="off" value="{{ old('CarType')['length'] ?? '' }}">
                             @error('CarType.length')
                             <span class="invalid-feedback" role="alert">
                                         <strong>{{ $errors->first('CarType.length') }}</strong>
@@ -47,7 +47,7 @@
                         <label for="load" class="col-2 col-form-label text-right">车辆载重(吨)</label>
                         <div class="col-8">
                             <input type="text" class="form-control @error('CarType.load') is-invalid @enderror"
-                                   name="CarType[load]" autocomplete="off" value="{{ old('CarType')['load'] }}">
+                                   name="CarType[load]" autocomplete="off" value="{{ old('CarType')['load'] ?? '' }}">
                             @error('CarType.load')
                             <span class="invalid-feedback" role="alert">
                                          <strong>{{ $errors->first('CarType.load') }}</strong>
@@ -59,7 +59,7 @@
                         <label for="remark" class="col-2 col-form-label text-right">备注</label>
                         <div class="col-8">
                             <textarea type="text" class="form-control"
-                                      name="CarType[remark]" autocomplete="off" >{{ old('CarType')['remark'] }}</textarea>
+                                      name="CarType[remark]" autocomplete="off" >{{ old('CarType')['remark'] ?? '' }}</textarea>
                         </div>
                     </div>
                     <div class="form-group row">

+ 0 - 1
resources/views/maintenance/log/index.blade.php

@@ -7,7 +7,6 @@
         <div class="card">
             <div id="form_div"></div>
             <div class="card-body">
-                {{--TODO 错误信息提示 待抽离成为模板--}}
                 @foreach (['danger', 'warning', 'success', 'info'] as $msg)
                     @if(session()->has($msg))
                         <div class="flash-message">

+ 7 - 1
resources/views/station/monitor/show.blade.php

@@ -59,6 +59,10 @@
                                             <span v-if="current_stationTaskBatch.runningStatus==='请求成功'">(请求成功)重新执行</span>
                                             <span v-if="current_stationTaskBatch.runningStatus==='请求异常'">(请求异常)重新执行</span>
                                         </button>
+                                        <label class="align-bottom mb-0 p-0">
+                                            <input content="col-4" type="checkbox" class="switch" v-model="isCacheShelf"></input><br>
+                                            <small class="mb-0 h6">缓存架</small>
+                                        </label>
                                     </div>
                                 </div>
                                 <div class="text-center my-2" style="overflow-y: scroll;max-height:200px;">
@@ -329,6 +333,7 @@
                 allTaskBroadcastName : "{{config('database.redis.options.prefix').'station-0'}}",
                 channelName : ".App\\Events\\BroadcastToStation",
                 error:"",
+                isCacheShelf:false,
                 station:{!! $station !!},
                 inputs:{
                     manuallyTakeBox:{
@@ -423,6 +428,7 @@
                     });
                 },
                 selectBatch(stationTaskBatch){
+                    if (this.current_stationTaskBatch!==stationTaskBatch)this.isCacheShelf = false;
                     this.current_stationTaskBatch=stationTaskBatch;
                     if(typeof(this.current_stationTaskBatch.runningStatus)==='undefined')
                         this.current_stationTaskBatch.runningStatus=''
@@ -452,7 +458,7 @@
                     let _this=this;
                     _this.current_stationTaskBatch.runningStatus='请求中';
                     _this.$forceUpdate();
-                    axios.post('{{url('/api/thirdPart/haiq/runTaskBatch')}}',{station_task_batch_id:_this.current_stationTaskBatch.id})
+                    axios.post('{{url('/api/thirdPart/haiq/runTaskBatch')}}',{station_task_batch_id:_this.current_stationTaskBatch.id,isCacheShelf:this.isCacheShelf})
                         .then(function(response){
                             if(!response.data.success){
                                 _this.current_stationTaskBatch.runningStatus='请求失败';

+ 0 - 213
resources/views/station/monitor/show_bak.blade.php

@@ -1,213 +0,0 @@
-@extends('layouts.app')
-@section('title'){{$station->name}} - 监视器 - 站@endsection
-
-@section('content')
-    <div class="container-fluid body" id="container">
-        <div class="card">
-            <div class="card-body">
-                <div class="row border" style="opacity: 0.75">
-                    <div class="col-4 text-center h3 py-2 font-weight-bold text-info">宝时云仓</div>
-                    <div class="col text-center  h3 py-2 text-muted">智能分拣</div>
-                </div>
-                <div class="row pt-3">
-                    <div class="col-4">
-                        <div class="row">
-                            <div class="col py-3 h4">
-                                <div>波次号:</div>
-                                <div class=" text-center">
-                                    <b>@{{ task.taskBatch.batch.code }}</b>
-                                </div>
-                            </div>
-                        </div>
-                        <div class="row">
-                            <div class="col py-3 text-muted text-center">
-                                <img id="barcode" alt="">
-                            </div>
-                        </div>
-                        <div class="row">
-                            <div class="col py-3 h4">
-                                料箱号:<b v-if="task.currentCommodityIndex && task.currentCommodityIndex!==-1">@{{task.taskCommodities[task.currentCommodityIndex]['materialBox']['code']}}</b>
-                            </div>
-                        </div>
-                        <div class="row pt-2">
-                            <div class="col">
-                                {{--                                @include("station.monitor._svg")--}}
-                                <img src="{{asset('images/demoBin.png')}}" alt="" class="img">
-                            </div>
-                        </div>
-                    </div>
-                    <div class="col text-center">
-                        <div class="row">
-                            <div class="col py-3 h4" v-for="stationTypeBinMonitor in stationTypeBinMonitors">
-                                <table class="table border">
-                                    <tr v-for="row in stationTypeBinMonitor">
-                                        <td class="border p-0"
-                                            v-for="column in row"
-                                            :class="
-                                                task.currentCommodityIndex
-                                                && task.currentCommodityIndex!==-1
-                                                && task.taskCommodities[task.currentCommodityIndex]['binNumber'] === column
-                                                    ? 'bg-info'
-                                                    : ''
-                                        ">
-                                            <span style="opacity:0.25">@{{ column }}</span></td>
-                                    </tr>
-                                </table>
-                            </div>
-                        </div>
-                        <div class="row mb-1">
-                            <div class="col-1 text-left font-weight-bold">数量:</div>
-                            <div class="col-2 text-left">@{{ task.currentSum }}/@{{ task.sum }}</div>
-                            <div class="col-1 offset-2 text-muted" v-if="error">异常:</div>
-                            <div class="col-6" v-if="error">@{{ error }}</div>
-                        </div>
-                        <div class="row">
-                            <div class="col py-1">
-                                <table class="table table-hover border">
-                                    <tr class="text-muted">
-                                        <th class="py-2">序号</th>
-                                        <th class="py-2">商品</th>
-                                        <th class="py-2">数量</th>
-                                        <th class="py-2">条码</th>
-                                    </tr>
-                                    <tr class="text-muted" v-for="(taskCommodity,i) in task.taskCommodities" :class="taskCommodity.bg">
-                                        <td>@{{ i+1 }}</td>
-                                        <td>@{{ taskCommodity.name }}</td>
-                                        <td>@{{ taskCommodity.amount }}</td>
-                                        <td><small class="text-dark font-weight-bold" v-for="barcode in taskCommodity.barcodes">@{{ barcode.code }}</small><br></td>
-                                    </tr>
-                                </table>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-@endsection
-
-@section('lastScript')
-    <script type="text/javascript" src="{{mix('js/utilities/barcode.js')}}"></script>
-    <script>
-        $vue=new Vue({
-            el:"#container",
-            data:{
-                {{--broadcastName : "{{config('database.redis.options.prefix').'presence-station-'.$station->id}}",--}}
-                broadcastName : "{{config('database.redis.options.prefix').'station-'.$station->id}}",
-                channelName : ".App\\Events\\BroadcastToStation",
-                task : {
-                    currentCommodityIndex : -1,
-                    taskCommodities:[
-                        /*{amount:"",binNumber:"",name:"",barcodes:[]},*/
-                    ],
-                    taskBatch:{
-                        batch:{
-                            code:"",
-                        },
-                    },
-                    box:{},
-                    sum : 0,
-                    currentSum : 0,
-                },
-                boxes:[],
-                stationTypeBinMonitors:[],
-                stationTypeBinMonitor:{
-                    row:Number("{{$stationTypeBinMonitor->bin_row_length}}"),
-                    column:Number("{{$stationTypeBinMonitor->bin_column_length}}"),
-                    amount:Number("{{$stationTypeBinMonitor->bin_wall_amount}}"),
-                },
-                color:"red",
-                error:"",
-            },
-            mounted() {
-                $('.navbar,.nav1,.nav2').hide();
-                $('.nav3').on('mouseenter', function () {
-                    $('.navbar,.nav1,.nav2').show();
-                });
-                $('.body').on('mouseenter', function () {
-                    $('.navbar,.nav1,.nav2').hide();
-                });
-                this._broadcast();
-                console.log(this.stationTypeBinMonitor);
-                this._renderingstationTypeBinMonitor(this.stationTypeBinMonitor.amount,this.stationTypeBinMonitor.row,this.stationTypeBinMonitor.column);
-                /* this._renderingBox(3,5);*/
-            },
-            methods:{
-                _broadcast(){
-                    initEcho();
-                    window.Echo.channel(this.broadcastName).listen(this.channelName,(msg)=> {
-                        console.log(1231,msg)
-                        let json = JSON.parse(msg.json);
-                        console.log(json)
-                        this._refreshData(json);
-                    });
-                },
-                //刷新数据
-                _refreshData(obj){
-                    let task={};
-                    task.taskCommodities = [];
-                    task.sum = 0;
-                    task.currentSum = 0;
-                    task.currentCommodityIndex = "";
-                    obj.station_task_commodities.forEach((taskCommodity,i)=> {
-                        task.sum += Number(taskCommodity.amount);
-                        if (taskCommodity.status === '完成') task.currentSum += Number(taskCommodity.amount);
-                        if (taskCommodity.status === '处理中') task.currentCommodityIndex = i;
-                        task.taskCommodities.push({
-                            bg:this._setColor(taskCommodity.status),
-                            amount:taskCommodity.amount,
-                            binNumber:taskCommodity.bin_number,
-                            name:taskCommodity.commodity?taskCommodity.commodity.name:'',
-                            barcodes:taskCommodity.commodity?taskCommodity.commodity.barcodes:[],
-                            materialBox:taskCommodity.material_box,
-                        });
-                    });
-                    task.taskBatch=obj.station_task_batches[0];
-                    setBarcode(task.taskBatch.batch.code,"#barcode",1,50,false);
-                    console.log(task)
-                    this.task = task;
-                },
-                //渲染墙格口
-                _renderingstationTypeBinMonitor(amount, row, column){
-                    for (let i=0;i<amount;i++){
-                        this.stationTypeBinMonitors.push(this._createstationTypeBinMonitor(row, column, i*(row*column)));
-                    }
-                },
-                _setColor(status){
-                    switch (status) {
-                        case "待处理":return "";
-                        case "挂起"  :return "bg-white";
-                        case "处理中"  :return "bg-primary";
-                        case "完成"  :return "bg-success";
-                        case "异常"  :return "bg-danger";
-                        case "取消"  :return "bg-dark text-white";
-                    }
-                    return "";
-                },
-                //生成墙格口
-                _createstationTypeBinMonitor(row, column, increment){
-                    let stationTypeBinMonitor = [];
-                    for (let i=1;i<=row;i++){
-                        let columns = [];
-                        for (let j=((i-1)*column)+1;j<=i*column;j++){
-                            columns.push(j+increment);
-                        }
-                        stationTypeBinMonitor.unshift(columns);
-                    }
-                    return stationTypeBinMonitor;
-                },
-                //渲染料箱格口
-                _renderingBox(row, column, x=79, y=72, width=21, height=12){
-                    let boxes = [];
-                    for (let i=0;i<column;i++){
-                        for (let j=row-1;j>=0;j--){
-                            if (boxes.length===5) boxes.push({x:((i+j)*width)+x,y:(y+(i*height))-(j*height),sign:true});
-                            else boxes.push({x:((i+j)*width)+x,y:(y+(i*height))-(j*height),sign:false});
-                        }
-                    }
-                    this.boxes = boxes;
-                },
-            },
-        });
-    </script>
-@endsection

+ 96 - 12
resources/views/station/monitor/visual.blade.php

@@ -7,15 +7,19 @@
             <div class="col-6 offset-3 row">
                 <b>总占有率:</b>
                 <div class="progress w-75">
-                    <div class="progress-bar bg-danger" :style="{width:val+'%'}">@{{ val+'%' }}</div>
-                    <div class="progress-bar bg-success" :style="{width:(100-val)+'%'}">@{{val|reduce}}</div>
+                    <div class="progress-bar bg-danger" :style="{width:statistic.np1+'%'}">@{{ statistic.np1+'%' }}</div>
+                    <div class="progress-bar bg-warning text-dark" :style="{width:statistic.np2+'%'}">@{{ statistic.np2+'%' }}</div>
+                    <div class="progress-bar bg-success" :style="{width:statistic.np3+'%'}">@{{ statistic.np3+'%' }}</div>
                 </div>
             </div>
             <div class="col-6 offset-3 row mt-5">
-                <div class="col-1 bg-success"></div>
-                <div class="col-1">空箱</div>
-                <div class="col-1 bg-danger offset-5"></div>
+                <b>共:@{{ this.statistic.sum }}</b>
+                <div class="col-1 bg-danger text-white ml-2 font-weight-bold">@{{ this.statistic.number1 }}</div>
                 <div class="col-1">非空</div>
+                <div class="col-1 bg-warning offset-2 text-dark font-weight-bold">@{{ this.statistic.number2 }}</div>
+                <div class="col-1">空架</div>
+                <div class="col-1 bg-success offset-2 text-white  font-weight-bold">@{{ this.statistic.number3 }}</div>
+                <div class="col-1">空箱</div>
             </div>
         </div>
         <div class="row bg-dark">
@@ -26,8 +30,9 @@
                             <div class="w-100 text-center d-inline-block"><i class="fa fa-spinner fa-pulse"></i></div>
                         </div>
                         <div class="progress mr-2" style="cursor: pointer" v-else @click="loadDetail(i,j)">
-                            <div class="progress-bar bg-danger" :style="{width:val+'%'}">@{{ val+'%' }}</div>
-                            <div class="progress-bar bg-success" :style="{width:(100-val)+'%'}">@{{val | reduce}}</div>
+                            <div class="progress-bar bg-danger" :style="{width:val[0]+'%'}">@{{ val[0]+'%' }}</div>
+                            <div class="progress-bar bg-warning" :style="{width:val[1]+'%'}">@{{ val[1]+'%' }}</div>
+                            <div class="progress-bar bg-success" :style="{width:val[2]+'%'}">@{{ val[2]+'%' }}</div>
                         </div>
                     </div>
                 </div>
@@ -55,6 +60,41 @@
                 sum:0,
                 quantity:0,
                 val:0,
+                statistic:{
+                    sum : 0,//总量
+                    number1 : 0,//空架
+                    number2 : 0,//非空箱
+                    number3 : 0,//空箱
+                    np1:100,
+                    np2:0,
+                    np3:0,
+                },
+                blacklist:{
+                    "HAI01-045-%":[
+                        "HAI01-045-01",
+                        "HAI01-045-02",
+                        "HAI01-045-03",
+                        "HAI01-045-04",
+                    ],
+                    "HAI01-046-%":[
+                        "HAI01-046-01",
+                        "HAI01-046-02",
+                        "HAI01-046-03",
+                        "HAI01-046-04",
+                    ],
+                    "HAI01-047-%":[
+                        "HAI01-047-01",
+                        "HAI01-047-02",
+                        "HAI01-047-03",
+                        "HAI01-047-04",
+                    ],
+                    "HAI01-048-%":[
+                        "HAI01-048-01",
+                        "HAI01-048-02",
+                        "HAI01-048-03",
+                        "HAI01-048-04",
+                    ],
+                },
             },
             mounted() {
                 let data = [];
@@ -88,13 +128,36 @@
                         if (i%this.columnSize===0){arr.push(temp);temp = [];}
                     }
                     this.mapping.push(arr);
+                    let max = this.columnSize * this.heightSize;
                     window.tempTip.postBasicRequest("{{url('station/monitor/visual/getData')}}",{arr:arr},res=>{
-                        this.$set(this.data,index-1,res);
-                        res.forEach(val=>{
-                            this.sum += 100;
-                            this.quantity += Number(val);
+                        let sub = {};
+                        arr.forEach((ar,i)=>{
+                            for (let key in this.blacklist){
+                                if (ar.indexOf(key)!==-1){
+                                    if (!sub['_'+i])sub['_'+i] = this.blacklist[key].length;
+                                    else sub['_'+i] += this.blacklist[key].length;
+                                }
+                            }
+                        });
+                        res.forEach((ar,i)=>{
+                            let amount = max;
+                            if (sub['_'+i])amount -= sub['_'+i];
+                            let sum = Number(ar[0]);
+                            let quantity = Number(ar[1]);
+                            let number2 = Number(this.accSubtr(amount,sum));
+                            let number3 = Number(this.accSubtr(sum,quantity));
+                            let q1 = this.accDivCoupon(quantity,amount)
+                            let q2 = this.accDivCoupon(number2,amount)
+                            let q3 = this.accDivCoupon(number3,amount)
+                            this.$set(this.data[index-1],i,[q1,q2,q3]);
+                            this.statistic.sum += amount;
+                            this.statistic.number1 += quantity;
+                            this.statistic.number2 += number2;
+                            this.statistic.number3 += number3;
+                            this.statistic.np1 = this.accDivCoupon(this.statistic.number1,this.statistic.sum);
+                            this.statistic.np2 = this.accDivCoupon(this.statistic.number2,this.statistic.sum);
+                            this.statistic.np3 = this.accDivCoupon(this.statistic.number3,this.statistic.sum);
                         });
-                        this.val = Math.round((this.quantity/this.sum)*10000)/100;
                     });
                 },
                 loadDetail(index,j){
@@ -117,6 +180,7 @@
                         let suffix = i.toString().length<maxLen ? before.substr(0,maxLen-i.toString().length)+i.toString() : i.toString();
                         for (let k=arr.length-1;k>=0;k--){
                             let val = arr[k].substr(0,arr[k].length-1)+suffix;
+                            if (this.blacklist[arr[k]] && this.blacklist[arr[k]].indexOf(val)!==-1)continue;
                             res.push(val);
                             detailTemp.push({location:val,status:undefined});
                             mapping[val] = [rowIndex,columnIndex];
@@ -143,6 +207,26 @@
                         this.loadStatus = false;//加载完毕
                     });
                 },
+
+                 accSubtr(arg1,arg2){
+                    let r1,r2,m,n;
+                    try{r1=arg1.toString().split(".")[1].length;}catch(e){r1=0;}
+                    try{r2=arg2.toString().split(".")[1].length;}catch(e){r2=0;}
+                    m=Math.pow(10,Math.max(r1,r2));
+                    //动态控制精度长度
+                    n=(r1>=r2)?r1:r2;
+                    return ((arg1*m-arg2*m)/m).toFixed(n);
+                },
+                 accDivCoupon(arg1,arg2){
+                    let t1=0,t2=0,r1,r2;
+                    try{t1=arg1.toString().split(".")[1].length;}catch(e){}
+                    try{t2=arg2.toString().split(".")[1].length;}catch(e){}
+                    with(Math){
+                        r1=Number(arg1.toString().replace(".",""));
+                        r2=Number(arg2.toString().replace(".",""));
+                        return Math.round((r1/r2)*pow(10,t2-t1)*10000)/100;
+                    }
+                },
             },
             filters:{
                 reduce(val){

+ 74 - 52
resources/views/store/deliveryAppointment/appointment.blade.php

@@ -6,51 +6,51 @@
         <div class="card">
             <div class="card-body row">
                 <div class="offset-2 col-8">
-                    <div class="card">
-                        <div class="card-header">
-                            <div class="row">
-                                <label class="col-2">
-{{--                                    <label class="text-danger font-weight-bold ml-2 h4">*</label>--}}
-                                </label>
-                                <label class="col-2">车牌号</label>
-                                <label class="col-2">车型</label>
-                                <label class="col-2">司机姓名</label>
-                                <label class="col-3">司机电话</label>
-                                {{--<label class="col-1">
-                                    <span class="fa fa-plus cursor-pointer text-primary" @click="addCar()">增加</span>
-                                </label>--}}
-                            </div>
-                        </div>
-                        <div class="card-body">
-                            <div class="row" v-for="(car,i) in model.cars">
-                                <label class="col-2">车辆-@{{ i+1 }}</label>
-                                <label class="col-2">
-                                    <input type="text" class="form-control" v-model="car.license_plate_number" :class="errors['cars.'+i+'.license_plate_number'] ? 'is-invalid' : ''">
-                                </label>
-                                <label class="col-2">
-                                    <div class="dropdown">
-                                        <input type="text" class="form-control" v-model="car.car_name" :id="'car-'+i" @input="searchCar(car.car_name)"
-                                               data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" @click="searchInit()">
-                                        <div class="dropdown-menu" :aria-labelledby="'car-'+i" v-show="haystack.length>0">
-                                            <span class="row offset-1 text-secondary" v-for="c in haystack" @click.stop="selectCar(c,i)">@{{ c.name }}<br></span>
-                                        </div>
-                                    </div>
-                                </label>
-                                <label class="col-2">
-                                    <input type="text" class="form-control" v-model="car.driver_name">
-                                </label>
-                                <label class="col-3">
-                                    <input type="text" class="form-control" v-model="car.driver_phone">
-                                </label>
-                                {{--<label class="col-1" v-if="i!==0">
-                                    <span class="h4 font-weight-bold cursor-pointer text-danger" @click="delCar(i)">&times;</span>
-                                </label>--}}
-                                <label v-if="errors['cars.'+i+'.license_plate_number']" class="col-2 offset-2 text-danger font-weight-bold small">
-                                    @{{ errors['cars.'+i+'.license_plate_number'][0] }}
-                                </label>
-                            </div>
-                        </div>
-                    </div>
+                    <!--                   <div class="card">
+                                           <div class="card-header">
+                                               <div class="row">
+                                                   <label class="col-2">
+                                                       <label class="text-danger font-weight-bold ml-2 h4">*</label>
+                                                   </label>
+                                                   <label class="col-2">车牌号</label>
+                                                   <label class="col-2">车型</label>
+                                                   <label class="col-2">司机姓名</label>
+                                                   <label class="col-3">司机电话</label>
+                                                   <label class="col-1">
+                                                       <span class="fa fa-plus cursor-pointer text-primary" @click="addCar()">增加</span>
+                                                   </label>
+                                               </div>
+                                           </div>
+                                           <div class="card-body">
+                                               <div class="row" v-for="(car,i) in model.cars">
+                                                   <label class="col-2">车辆-@{{ i+1 }}</label>
+                                                   <label class="col-2">
+                                                       <input type="text" class="form-control" v-model="car.license_plate_number" :class="errors['cars.'+i+'.license_plate_number'] ? 'is-invalid' : ''">
+                                                   </label>
+                                                   <label class="col-2">
+                                                       <div class="dropdown">
+                                                           <input type="text" class="form-control" v-model="car.car_name" :id="'car-'+i" @input="searchCar(car.car_name)"
+                                                                  data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" @click="searchInit()">
+                                                           <div class="dropdown-menu" :aria-labelledby="'car-'+i" v-show="haystack.length>0">
+                                                               <span class="row offset-1 text-secondary" v-for="c in haystack" @click.stop="selectCar(c,i)">@{{ c.name }}<br></span>
+                                                           </div>
+                                                       </div>
+                                                   </label>
+                                                   <label class="col-2">
+                                                       <input type="text" class="form-control" v-model="car.driver_name">
+                                                   </label>
+                                                   <label class="col-3">
+                                                       <input type="text" class="form-control" v-model="car.driver_phone">
+                                                   </label>
+                                                   <label class="col-1" v-if="i!==0">
+                                                       <span class="h4 font-weight-bold cursor-pointer text-danger" @click="delCar(i)">&times;</span>
+                                                   </label>
+                                                   <label v-if="errors['cars.'+i+'.license_plate_number']" class="col-2 offset-2 text-danger font-weight-bold small">
+                                                       @{{ errors['cars.'+i+'.license_plate_number'][0] }}
+                                                   </label>
+                                               </div>
+                                           </div>
+                                       </div>-->
                     <div class="row ml-1">
                         <div class="col-6">
                             <div class="row mt-4">
@@ -94,14 +94,36 @@
                         </div>
                         <div class="col-5 offset-1">
                             <div class="row mt-4">
-                                <label class="col-3" for="logistic">快递公司</label>
-                                <select id="logistic" v-model="model.logistic_id" class="col-6 form-control" :class="errors.logistic_id ? 'is-invalid' : ''">
-                                    <option v-for="logistic in logistics" :value="logistic.id">@{{ logistic.name }}</option>
-                                </select>
+                                <label class="col-3" for="isToC">输入车型</label>
+                                <input content="col-4" id="isToC" type="checkbox" class="switch" v-model="model.isToC">
                             </div>
-                            <div class="row mt-2">
-                                <label class="col-3" for="logistic_number">快递单号</label>
-                                <input class="col-9 form-control" type="text" id="logistic_number" v-model="model.logistic_number" :class="errors.logistic_number ? 'is-invalid' : ''">
+                            <div v-if="model.isToC">
+                                <div class="row mt-2">
+                                    <label class="col-3" for="car_name">车型</label>
+                                    <div class="dropdown col-6 d-inline-block p-0">
+                                        <input type="text" class="form-control" v-model="model.cars[0].car_name" id="car-0" @input="searchCar(model.cars[0].car_name)"
+                                               data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" @click="searchInit()">
+                                        <div class="dropdown-menu" aria-labelledby="car-0" v-show="haystack.length>0">
+                                            <span class="row offset-1 text-secondary" v-for="c in haystack" @click.stop="selectCar(c,0)">@{{ c.name }}<br></span>
+                                        </div>
+                                    </div>
+                                </div>
+                                <div class="row mt-2">
+                                    <label class="col-3" for="license_plate_number">车牌号</label>
+                                    <input type="text" id="license_plate_number" class="col-9 form-control" v-model="model.cars[0].license_plate_number" :class="errors['cars.0.license_plate_number'] ? 'is-invalid' : ''">
+                                </div>
+                            </div>
+                            <div v-else>
+                                <div class="row mt-2">
+                                    <label class="col-3" for="logistic">快递公司</label>
+                                    <select id="logistic" v-model="model.logistic_id" class="col-6 form-control" :class="errors.logistic_id ? 'is-invalid' : ''">
+                                        <option v-for="logistic in logistics" :value="logistic.id">@{{ logistic.name }}</option>
+                                    </select>
+                                </div>
+                                <div class="row mt-2">
+                                    <label class="col-3" for="logistic_number">快递单号</label>
+                                    <input class="col-9 form-control" type="text" id="logistic_number" v-model="model.logistic_number" :class="errors.logistic_number ? 'is-invalid' : ''">
+                                </div>
                             </div>
                             <div class="row mt-2">
                                 <label class="col-3" for="box_amount">箱数</label>

+ 160 - 57
resources/views/store/deliveryAppointment/list.blade.php

@@ -5,7 +5,7 @@
     <div class="container-fluid d-none" id="container">
         <div id="form"></div>
         <div class="mt-1">
-            <button type="button" class="btn btn-outline-dark btn-sm form-control-sm dropdown-toggle tooltipTarget" :class="[checkData.length>0?'btn-dark text-light':'']"
+            <button type="button" class="btn btn-outline-dark btn-sm form-control-sm dropdown-toggle tooltipTarget"
                     data-toggle="dropdown" title="导出所有页将会以搜索条件得到的筛选结果,将其全部记录(每一页)导出">
                 导出Excel
             </button>
@@ -15,8 +15,8 @@
             </div>
             @can("入库管理-入库预约-质检")<button type="button" class="btn btn-outline-primary" @click="qualityInspectionMark()">质检</button>@endcan
         </div>
-        <table class="table table-striped table-hover text-nowrap td-min-width-80" id="table">
-            <tr class="text-center">
+        <table class="table table-striped table-bordered table-hover text-nowrap td-min-width-80" id="table">
+<!--            <tr class="text-center">
                 <th>
                     <label for="all" id="cloneCheckAll">
                         <input id="all" type="checkbox" @click="checkAll($event)">全选
@@ -25,9 +25,19 @@
                 <th>序号</th>
                 <th>操作</th>
                 <th>状态</th>
-                <th>货主</th>
+                <th>预约号</th>
+                <th>ASN单号</th>
                 <th>预约时间</th>
-                <th>仓库</th>
+                <th>创建时间</th>
+                <th>操作/送达时间</th>
+                <th>货主</th>
+                <th>重量/吨</th>
+                <th>体积/立方</th>
+                <th>箱数</th>
+                <th>备注</th>
+                <th>车号/快递公司</th>
+                <th>车型/快递单号</th>-->
+<!--                <th>仓库</th>
                 <th>
                     <div class="row" style="min-width: 800px">
                         <div class="col-12">车辆信息</div>
@@ -41,13 +51,9 @@
                         <div class="col-3">操作/送达时间</div>
                     </div>
                 </th>
-                <th>吨</th>
-                <th>立方</th>
-                <th>箱数</th>
                 <th>快递公司</th>
                 <th>快递单号</th>
                 <th>采购单号</th>
-                <th>ASN单号</th>
                 <th>
                     <div class="row">
                         <div class="col-12 text-center">明细单</div>
@@ -57,49 +63,74 @@
                         <div class="col-4 text-center">条码</div>
                         <div class="col-2 text-center">数量</div>
                     </div>
-                </th>
-                <th>预约备注</th>
-                <th>创建时间</th>
-            </tr>
-            <tr v-for="(info,i) in list">
-                <td>
-                    <label>
-                        <input class="checkItem" type="checkbox" :value="info.id" v-model="checkData">
-                    </label>
-                </td>
+                </th>-->
+<!--            </tr>-->
+            <tr v-for="(info,i) in list" :id="'info-'+i">
+                <td><input class="checkItem" type="checkbox" :value="list.id"></td>
                 <td>@{{ i+1 }}</td>
                 <td>
-                    @can("入库管理-入库预约-预约管理-签到")<span v-if="(info.status==0 || info.appointment_date==today) && info.cars[0].status==0"><button class="btn btn-sm btn-outline-success" @click="signIn(i,0)">签到</button><br></span>@endcan
-                    <span v-if="info.status==0">
-                        <button type="button" @click="cancel(info.id,i)" class="btn btn-sm btn-outline-danger">取消预约</button><br>
-                        <button type="button" @click="updateDeliveryDate(info,i)" class="btn btn-sm btn-outline-primary">修改预约</button>
-                    </span>
-                    <span v-if="info.status==2">
-                        <button type="button" @click="printReceipt(info)" class="btn btn-sm btn-outline-success"><i class="fa fa-print"></i>&nbsp;打印</button>
+                    <span>
+                         @can("入库管理-入库预约-预约管理-签到")<span v-if="(info.status==0 && info.appointment_date==today) && info.cars[0].status==0"><button class="btn btn-sm btn-outline-success" @click="signIn(i,0)">签到</button><br></span>@endcan
+                        <span v-if="info.status==0">
+                            <button type="button" @click="cancel(info.id,i)" class="btn btn-sm btn-outline-danger">取消预约</button><br>
+                            <button type="button" @click="updateDeliveryDate(info,i)" class="btn btn-sm btn-outline-primary">修改预约</button>
+                        </span>
+                        <span v-if="info.status==2">
+                            <button type="button" @click="printReceipt(info)" class="btn btn-sm btn-outline-success"><i class="fa fa-print"></i>&nbsp;打印</button>
+                        </span>
+                         <span v-if="info.status==3">
+                             <button type="button" @click="reschedule(info,i)" class="btn btn-sm btn-outline-primary">重新预约</button>
+                         </span>
+                         <span v-if="info.details.length>0">
+                             <br>
+                             <button class="btn btn-sm btn-dark" v-if="currentIndex===i" @click="openDetails(i,true);">关闭明细</button>
+                             <button class="btn btn-sm btn-outline-info" v-else  @click="openDetails(i);">查看明细</button>
+                         </span>
                     </span>
                 </td>
                 <td>
-                    <span v-if="info.status==0 && info.cars.length>0 && info.cars[0].status==1">
+                    <span>
+                        <span v-if="info.status==0 && info.cars.length>0 && info.cars[0].status==1">
                         <span class="fa fa-circle text-primary">作业中</span>
+                        </span>
+                        <span v-else>
+                            <label v-if="!poolMapping.status">
+                                <span class="fa fa-circle text-secondary">未知</span>
+                            </label>
+                            <label v-else>
+                                <small><span class="fa fa-circle" :class="info.status==0 ? 'text-info' : (info.status==2 ? 'text-success' : (info.status==4 ? 'text-greed' : 'text-danger'))"></span></small>
+                                @{{ poolMapping.status[info.status] }}
+                                <span v-if="info.type_mark==0" class="badge badge-primary">质检单</span>
+                            </label>
+                        </span>
                     </span>
-                    <span v-else>
-                        <label v-if="!poolMapping.status">
-                            <span class="fa fa-circle text-secondary">未知</span>
-                        </label>
-                        <label v-else>
-                            <small><span class="fa fa-circle" :class="info.status==0 ? 'text-info' : (info.status==2 ? 'text-success' : 'text-danger')"></span></small>
-                            @{{ poolMapping.status[info.status] }}
-                            <span v-if="info.type_mark==0" class="badge badge-primary">质检单</span>
-                        </label>
-                    </span>
-
                 </td>
-                <td>
-                    <label v-if="!poolMapping.owners"></label>
-                    <label v-else>@{{ poolMapping.owners[info.owner_id] }}</label>
+                <td class="font-weight-bold">
+                    @{{ info.cars[0].appointment_number }}
                 </td>
+                <td><span v-html="warpText(info.asn_number)"></span></td>
                 <td class="text-primary">@{{ info.appointment_date }}&nbsp;&nbsp;@{{ info.period }}</td>
+                <td>@{{ info.created_at }}</td>
                 <td>
+                    <div>
+                        @can("入库管理-入库预约-预约管理-卸货完成")<button class="btn btn-sm btn-outline-success" @click="unloading(i,0)" v-if="info.cars[0].status==1">卸货完成</button>@endcan
+                        <div v-if="info.cars[0].status==2">@{{ info.cars[0].delivery_time }}</div>
+                    </div>
+                </td>
+                <td>
+                    <div>
+                        <label v-if="!poolMapping.owners"></label>
+                        <label v-else>@{{ poolMapping.owners[info.owner_id] }}</label>
+                    </div>
+                </td>
+                <td>@{{ info.tonne>0 ? info.tonne : '-' }}</td>
+                <td>@{{ info.cubic_meter>0 ? info.cubic_meter : '-' }}</td>
+                <td>@{{ info.box_amount>0 ? info.box_amount : '-' }}</td>
+                <td><div class="text-overflow-replace-200">@{{ info.remark }}</div></td>
+                <td>@{{ info.logistic ? info.logistic.name : info.cars[0].license_plate_number }}</td>
+                <td>@{{ info.logistic ? info.logistic_number : (info.cars[0].car ? info.cars[0].car.name : '') }}</td>
+
+<!--                <td>
                     <label v-if="!poolMapping.warehouses"></label>
                     <label v-else>@{{ poolMapping.warehouses[info.warehouse_id] }}</label>
                 </td>
@@ -136,13 +167,9 @@
                         </div>
                     </div>
                 </td>
-                <td>@{{ info.tonne>0 ? info.tonne : '-' }}</td>
-                <td>@{{ info.cubic_meter>0 ? info.cubic_meter : '-' }}</td>
-                <td>@{{ info.box_amount>0 ? info.box_amount : '-' }}</td>
                 <td>@{{ info.logistic ? info.logistic.name : '' }}</td>
                 <td>@{{ info.logistic_number }}</td>
                 <td><span v-html="warpText(info.procurement_number)"></span></td>
-                <td><span v-html="warpText(info.asn_number)"></span></td>
                 <td>
                     <div v-if="info.details.length>0">
                         <div class="row">
@@ -163,9 +190,24 @@
                             <span v-else>展开其余@{{ info.details.length-1 }}条</span>
                         </div>
                     </div>
+                </td>-->
+            </tr>
+            <tr v-if="currentIndex!==undefined" id="await">
+                <td colspan="2"></td>
+                <td colspan="13">
+                    <table class="table table-sm table-bordered table-condensed">
+                        <tr>
+                            <th>商品名称</th>
+                            <th>条码</th>
+                            <th>数量</th>
+                        </tr>
+                        <tr v-for="(detail,i) in list[currentIndex].details">
+                            <td>@{{ detail.commodity_id ? (detail.commodity ? detail.commodity.name : '') : detail.name }}</td>
+                            <td>@{{ detail | getCommodity }}</td>
+                            <td>@{{ detail.amount }}</td>
+                        </tr>
+                    </table>
                 </td>
-                <td>@{{ info.remark }}</td>
-                <td>@{{ info.created_at }}</td>
             </tr>
         </table>
         {{$list->appends($params)->links()}}
@@ -178,6 +220,7 @@
 @section("lastScript")
     <script type="text/javascript" src="{{mix('js/queryForm/export.js')}}"></script>
     <script type="text/javascript" src="{{mix('js/queryForm/queryForm.js')}}"></script>
+    <script type="text/javascript" src="{{mix('js/queryForm/header.js')}}"></script>{{--新版2--}}
     <script>
         new Vue({
             el:"#container",
@@ -186,7 +229,7 @@
                 status:[],
                 warehouses:[],
                 owners:[@foreach($owners as $owner){name:"{{$owner->id}}",value:"{{$owner->name}}"},@endforeach],
-                checkData:[],
+               /* checkData:[],*/
                 poolMapping:{},
                 upList:{},
                 upListDetail:{},
@@ -199,6 +242,8 @@
                 infoShow:false,
                 printInfo:{},
                 today:"",
+                currentIndex:undefined,
+                isShowAwait:false,
             },
             mounted(){
                 let status = [];
@@ -239,15 +284,27 @@
                 let dd = now.getDate();
                 this.today = yy+'-'+(mm<10 ? '0'+mm : mm)+'-'+(dd<10 ? '0'+dd : dd);
             },
-            watch:{
+            /*watch:{
                 checkData:{
                     handler(){
                         document.querySelector('#all').checked = this.checkData.length === this.list.length;
                     },
                     deep:true
                 },
-            },
+            },*/
             methods: {
+                openDetails(index,isClose = false){
+                    if (isClose){
+                        this.currentIndex=undefined;
+                        this.isShowAwait = false;
+                    }else{
+                        this.currentIndex = index;
+                        setTimeout(function (){
+                            $("#info-"+index).after($("#await"));
+                            this.isShowAwait = true;
+                        },100);
+                    }
+                },
                 exePrint(){
                     if (!this.printInfo.signer){
                         window.tempTip.setIndex(1099);
@@ -298,6 +355,36 @@
                         condition:data,
                     });
                     form.init();
+                    let column = [
+                        {name:'index',value: '序号', neglect: true, class:"td-warm"},
+                        {name:'operation',value: '操作', neglect: true, class:"td-warm"},
+                        {name:'status',value: '状态', class:"td-warm"},
+                        {name:'appointment_number',value: '预约号', neglect: true, class:"td-warm"},
+                        {name:'asn_number',value: 'ASN单号', class:"td-warm"},
+                        {name:'appointment_date',value: '预约时间', class:"td-warm"},
+                        {name:'created_at',value: '创建时间', class:"td-warm"},
+                        {name:'delivery_time',value: '操作/送达时间', neglect: true, class:"td-warm"},
+                        {name:'owner_id',value: '货主', class:"td-warm"},
+                        {name:'tonne',value: '重量/吨', class:"td-warm"},
+                        {name:'cubic_meter',value: '体积/立方', class:"td-warm"},
+                        {name:'box_amount',value: '箱数', class:"td-warm"},
+                        {name:'remark',value: '备注', class:"td-warm"},
+                        {name:'logistic_id',value: '车号/快递公司', class:"bg-info"},
+                        {name:'logistic_number',value: '车型/快递单号', class:"bg-info"},
+                    ];
+                    new Header({
+                        el: "table",
+                        name: "deliveryAppointment",
+                        column: column,
+                        data: this.list,
+                        restorationColumn: 'id',
+                        fixedTop:($('#form').height())+2,
+                        before : [
+                            {colspan:'1',value: ''},
+                            {colspan:'13',value: '订单信息', class:"td-warm"},
+                            {colspan:'14',value: '物流信息', class:"bg-info"},
+                        ],
+                    }).init();
                 },
                 upAll(id){
                     let dom = "#item-"+id;
@@ -339,18 +426,18 @@
                         })
                     })
                 },
-                checkAll(e){
+                /*checkAll(e){
                     if (e.target.checked){
                         this.checkData = [];
                         this.list.forEach((el)=>{
                             this.checkData.push(el.id);
                         });
                     }else this.checkData = [];
-                },
+                },*/
                 executeExport(isAll){
                     let url = '{{url('store/deliveryAppointment/export')}}';
                     let token='{{ csrf_token() }}';
-                    excelExport(isAll,this.checkData,url,this.sum,token);
+                    excelExport(isAll,checkData,url,this.sum,token);
                 },
                 updateDeliveryDate(info,index){
                     for (let i=0;i<info.cars.length;i++){
@@ -370,6 +457,18 @@
                         });
                     }
                 },
+                reschedule(info,index){
+                    this.index = index;
+                    let param = {
+                        model:info,
+                        detail_amount:info.details.length,
+                        postpone : 1,
+                    };
+                    window.tempTip.postBasicRequest("{{url('store/deliveryAppointment/getCapacity')}}",param,res=>{
+                        this.capacities = res;
+                        $("#modal").modal("show");
+                    });
+                },
                 submitAppointment(){
                     window.tempTip.setDuration(3000);
                     window.tempTip.setIndex(1099);
@@ -403,6 +502,10 @@
                         this.list[this.index].date_period = this.selectDate.time;
                         this.list[this.index].period = this.periods[this.selectDate.time];
                         $("#modal").modal("hide");
+                        if (this.list[this.index].status == 3){
+                            this.list[this.index].status = 0;
+                            return "重新预约成功";
+                        }
                         return "修改预约时间成功";
                     },true);
                 },
@@ -410,15 +513,15 @@
                     if (isSelect) this.selectDate = {date:date,time:time};
                 },
                 qualityInspectionMark(){
-                    if (this.checkData.length<1){
+                    if (checkData.length<1){
                         window.tempTip.setDuration("3000");
                         window.tempTip.show("未勾选记录");
                         return;
                     }
                     let url = "{{url('store/deliveryAppointment/qualityInspectionMark')}}";
-                    window.tempTip.postBasicRequest(url,{ids:this.checkData},()=>{
+                    window.tempTip.postBasicRequest(url,{ids:checkData},()=>{
                         this.list.forEach(data=>{
-                            if (this.checkData.indexOf(data.id)!==-1){
+                            if (checkData.indexOf(data.id)!==-1){
                                 data.type_mark = 0;
                             }
                         });
@@ -441,7 +544,7 @@
                 },
                 warpText(code){
                     if (!code)return code;
-                    code = code.split(/[,, ]+/is);
+                    code = code.split(/[,\/, ]+/is);
                     let str = "";
                     for (let i=0;i<code.length;i++){
                         str += code[i]+"<br>";

+ 2 - 2
resources/views/store/handInStorage/androidIndex.blade.php

@@ -19,8 +19,8 @@
     <div class="text-center h-75">
         <div class="w-100 center h-75 row align-items-center justify-content-center">
             <div class="w-100">
-                <a href="{{url('')}}"><button class="btn btn-info w-75 text-white" style="height: 60px"><h4>收货</h4></button></a>
-                <a href="{{url('')}}"><button class="btn btn-info w-75 mt-3 text-white" style="height: 60px"><h4>上架</h4></button></a>
+                <a  href="{{url('store/handInStorage/receive')}}"><button class="btn btn-info w-75 text-white" style="height: 60px"><h4>收货</h4></button></a>
+                <a  href="{{url('store/handInStorage/putaway')}}"><button class="btn btn-info w-75 mt-3 text-white" style="height: 60px"><h4>上架</h4></button></a>
             </div>
         </div>
     </div>

+ 262 - 0
resources/views/store/handInStorage/putaway.blade.php

@@ -0,0 +1,262 @@
+@extends('layouts.app')
+@section('title')手持入库-上架@endsection
+
+@section('content')
+    <div class="d-none" id="container">
+        <div class="card offset-md-3 col-md-6">
+            <div class="card-header text-center mt-2 bg-transparent" id="header_title">
+                <span class="font-weight-bold h4">上架</span>
+            </div>
+            <div class="card-body">
+                <div class="form-group row m-1">
+                        <span class="text-right">
+                            <label for="trackNumber" class="text-right font-weight-bold">容器号:</label>
+                        </span>
+                    <input type="text" class="form-control form-control-sm col-8" id="trackNumber" autocomplete="off"
+                           :class="errors.trackNumber ? 'is-invalid' : ''" @keydown.enter="enterVal($event)"
+                           v-model="info.trackNumber">
+                    <span class="invalid-feedback offset-3" role="alert" v-if="errors.trackNumber">
+                            <strong>@{{ errors.trackNumber[0] }}</strong>
+                    </span>
+                </div>
+                <div class="form-group row m-1">
+                        <span class="text-right">
+                            <label for="barCode" class="text-right font-weight-bold">商品条码:</label>
+                        </span>
+                    <input type="text" class="form-control form-control-sm col-8" id="barCode" autocomplete="off"
+                           :class="errors.barCode ? 'is-invalid' : ''" @keydown.enter="enterVal($event)"
+                           v-model="info.barCode" @blur="getTsk()">
+                    <span class="invalid-feedback offset-3" role="alert" v-if="errors.barCode">
+                            <strong>@{{ errors.barCode[0] }}</strong>
+                    </span>
+                </div>
+                <div class="card border-bottom-0">
+                    <div class="card-body">
+                        <div class="form-group row m-1">
+                            <label for="name" class="text-right">商品品名:</label>
+                            <span id="name">@{{ info.name }}</span>
+                        </div>
+                        <div class="form-group row m-1">
+                            <label for="amount" class="text-right">上架总数:</label>
+                            <input type="text" class="form-control form-control-sm col-4" style="width: 10px"
+                                   id="amount" autocomplete="off"
+                                   :class="errors.amount ? 'is-invalid' : ''"
+                                   @keydown.enter="enterVal($event)" v-model="info.amount"><span id="paTotal"
+                                                                                                 v-if="info.paTotal">&nbsp;&nbsp;/&nbsp;&nbsp;@{{ info.paTotal }}</span>
+                            <span class="invalid-feedback offset-3" role="alert" v-if="errors.amount">
+                            <strong>@{{ errors.amount[0] }}</strong>
+                    </span>
+                        </div>
+                        <div class="form-group row m-1">
+                            <label for="location" class="text-right">目标库位:</label>
+                            <input type="text" class="form-control form-control-sm col-8" id="location"
+                                   autocomplete="off"
+                                   :class="errors.location ? 'is-invalid' : ''"
+                                   @keydown.enter="enterVal($event)" v-model="info.location">
+                            <span class="invalid-feedback offset-3" role="alert" v-if="errors.location">
+                            <strong>@{{ errors.location[0] }}</strong>
+                    </span>
+                        </div>
+                    </div>
+                </div>
+                <div style="overflow: auto;overflow-x: hidden" id="cardTable" v-if="tasks.length>0">
+                    <table class="table-sm table-striped table-bordered table-hover mb-3"
+                           style="background: rgb(255, 255, 255);">
+                        <tr v-for="(task,i) in tasks">
+                            <td style="filter:grayscale(30%);">
+                                <div>
+                                    <div style="transform:scale(1)" class="pl-0">
+                                        <span><span class="text-black">货主:</span><span
+                                                class="text-black font-weight-bold">@{{ task.customerid }}</span></span>
+                                        <span><span class="text-black">批次:</span><span
+                                                class="text-danger">@{{ task.plantolotnum }}</span></span>
+                                        <span class="text-right float-right">选中:<input type="checkbox" :id="'task_'+i"
+                                                                                       @click="checked($event,task)"></span>
+                                        <br>
+                                        <span><span>容器号:</span><span class="">@{{ task.plantoid }} </span></span>
+                                        <span><span class="text-lowercase">数量:</span><span
+                                                class="text-lowercase">@{{ task.qty }} </span></span>
+                                        <span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                        <span><span class="text-black">商品名:</span><span class="text-black">@{{ task.skudescrc }}</span></span>
+                                    </div>
+                                </div>
+                            </td>
+                        </tr>
+                    </table>
+                </div>
+
+                <div class="card-footer bg-transparent">
+                    <button type="button" id="confirm" class="btn btn-sm btn-outline-success float-right"
+                            @click="ensure()">确定
+                    </button>
+                    <button type="button" id="cancel" class="btn btn-sm btn-outline-info float-left" @click="cancel()">
+                        取消
+                    </button>
+                </div>
+            </div>
+        </div>
+        @stop
+
+        @section('lastScript')
+            <script type="text/javascript">
+                new Vue({
+                    el: "#container",
+                    data: {
+                        height: 0,//屏幕高度
+                        info: {},
+                        errors: {},
+                        tasks: [],
+                        checkData: [],
+                        selectTr: '',
+                        isAndroid: false,
+                        element: [
+                            "trackNumber","barCode", "amount", "location",
+                        ],
+                    },
+                    mounted() {
+                        if (navigator.userAgent.indexOf("Android") !== -1) this.isAndroid = true;
+                        this.pageInit();
+                        $("#container").removeClass("d-none");
+                        document.getElementById("trackNumber").focus();
+                    },
+                    methods: {
+                        //页面初始化
+                        pageInit() {
+                            if (!this.isAndroid) return;
+                            let element = document.getElementById("navbarSupportedContent").parentElement;
+                            element.className = "row";
+                            element.children[0].className += " col-5";
+                            element.innerHTML = element.children[0].outerHTML;
+                            let e1 = document.getElementById("menu");
+                            let e2 = document.getElementById("demand-div");
+                            if (e1) e1.remove();
+                            if (e2) e2.remove();
+                        },
+                        checked(e, task, element = undefined) {
+                            if (!element)element = e.target;
+                            let _this = this;
+                            if (element.checked) {
+                                if (_this.checkData.length === 0) {
+                                    _this.checkData.push(task);
+                                    _this.fillInfo(task);
+                                } else if (_this.checkData.length > 0) {
+                                    this.checkData.some(function (item, i) {
+                                        if (item.customerid == task.customerid
+                                            && item.plantolotnum == task.plantolotnum
+                                            && item.sku == task.sku) {
+                                            _this.checkData.push(task)
+                                            _this.fillInfo(task);
+                                            return true;
+                                        } else {
+                                            $('#'+element.id).prop('checked', false);
+                                            window.tempTip.setDuration(2000);
+                                            window.tempTip.show('货主,批次不同,不可同时上架');
+                                        }
+                                    });
+                                }
+                            }else {
+                                _this.checkData.some(function (item, i) {
+                                    if (item.taskid == task.taskid
+                                    && item.taskid_sequence == task.taskid_sequence) {
+                                        _this.checkData.splice(i, 1);
+                                        _this.updateInfo(task);
+                                        return true;
+                                    }
+                                });
+                            }
+                            _this.$forceUpdate();
+                        },
+                        fillInfo(task){
+                            this.info.name=task.skudescrc;
+                            if (this.info.paTotal==''||this.info.paTotal==null||this.info.paTotal==undefined){this.info.paTotal=0;}
+                            this.info.paTotal+=Number(task.qty);
+                            // this.info.location=task.plantolocation;
+                        },
+                        updateInfo(task){
+                            this.info.name=task.skudescrc;
+                            this.info.paTotal-=Number(task.qty);
+                            // this.info.location=task.plantolocation;
+                        },
+                        getTsk() {
+                            let _this=this;
+                            _this.clearChecked();
+                            if (!this.info.barCode)return;
+                            let url = '{{url('store/handInStorage/getTsk')}}';
+                            window.axios.post(url, {trackNumber:this.info.trackNumber,barCode: this.info.barCode})
+                                .then(res => {
+                                    if (res.data.success) {
+                                        this.tasks = res.data.data;
+                                        this.$forceUpdate();
+                                        setTimeout(function () {
+                                            document.getElementById("task_0").checked=true;
+                                            let element={};
+                                            element.checked=true;
+                                            _this.checked(1,_this.tasks[0],element)
+                                        }, 100);
+                                        return;
+                                    }
+                                    window.tempTip.setDuration(2000);
+                                    window.tempTip.show(res.data.data);
+                                }).catch(err => {
+                                window.tempTip.setDuration(2000);
+                                window.tempTip.show("网络错误:" + err);
+                            })
+                        },
+                        clearChecked(){
+                            this.checkData=[];
+                            this.info.paTotal=0;//设置上架总数
+                            $('input[type=checkbox]').each(function() {
+                                let self = $(this);
+                                self.prop('checked', false);
+                            });
+                        },
+                        ensure() {
+                            this.errors={};//初始errors状态
+                            this.verifyInfoAndCheckData();
+                            let url = '{{url('store/handInStorage/handFluxPa')}}';
+                            if (JSON.stringify(this.errors)==='{}') window.axios.post(url,{info:this.info,checkData:this.checkData})
+                                .then(res=>{
+                                    if (res.data.success){
+                                        window.tempTip.setDuration(2000);
+                                        window.tempTip.showSuccess(res.data.data);
+                                        this.info={};
+                                        this.checkData=[];
+                                        this.tasks=[];
+                                        this.$forceUpdate()
+                                        document.getElementById("trackNumber").focus();
+                                        return;
+                                    }
+                                    window.tempTip.setDuration(2000);
+                                    window.tempTip.show(res.data.data);
+                                }).catch(err=>{
+                                window.tempTip.setDuration(2000);
+                                window.tempTip.show("网络错误:"+err);
+                            })
+
+                        },
+                        cancel() {
+                            setTimeout(function () {
+                                window.location.reload();
+                                document.getElementById("trackNumber").focus();
+                            }, 100);
+                        },
+                        enterVal(e) {
+                            let index = this.element.indexOf(e.target.id) + 1;
+                            let element = document.getElementById(this.element[index]);
+                            if (element) element.focus();
+                            e.preventDefault();
+                            return false;
+                        },
+                        verifyInfoAndCheckData(){
+                            let error = {};
+                            if (!this.info.trackNumber) error.trackNumber = ["容器号必填"];
+                            if (!this.info.barCode) error.barCode = ["条码必填"];
+                            if (!this.info.amount) error.amount = ["上架数量必填"];
+                            if (Number(this.info.paTotal)!==0 && Number(this.info.amount)>Number(this.info.paTotal)) error.amount = ["上架数量不能超过上架总数必填"];
+                            if (!this.info.location) error.location = ["目标库位必填"];
+                            if (JSON.stringify(error) !== '{}') {this.errors = error;return;}
+                        },
+                    },
+                });
+            </script>
+@stop

+ 89 - 14
resources/views/store/handInStorage/receive.blade.php

@@ -8,17 +8,18 @@
                 <span class="font-weight-bold h4">收货</span>
             </div>
             <div class="card-body" >
-                <div class="offset-2">
-                    <span class="font-weight-bold">ASN号:</span>
+                <div class="offset-1">
+                    <span class="font-weight-bold">ASN号:</span><br>
+                    <p class="small font-weight-light">可输入条码,ASN号,货主编号(如:YOUWU)_搜索</p>
                     <div class="form-group row mt-2">
                         <label for="asn"></label>
-                        <input type="text" class="form-control col-8" id="asn"
-                               :class="errors.asn ? 'is-invalid' : ''" @keydown.enter="selectCustomerid($event)" v-model="info.asn">
+                        <input type="text" class="form-control col-8" id="asn" autocomplete="off"
+                               :class="errors.asnno ? 'is-invalid' : ''" v-model="info.asnno">
                         <span class="ml-2">
                              <button type="button" id="select" class="btn btn-info" @click="selectAsn()">搜索</button>
                         </span>
-                        <span class="invalid-feedback" role="alert" v-if="errors.asn">
-                            <strong>@{{ errors.asn[0] }}</strong>
+                        <span class="invalid-feedback" role="alert" v-if="errors.asnno">
+                            <strong>@{{ errors.asnno[0] }}</strong>
                         </span>
                     </div>
                 </div>
@@ -29,10 +30,31 @@
                             <td style="filter:grayscale(30%);">
                                 <div>
                                     <div style="transform:scale(1)" class="pl-0">
-                                        <span><span class="text-danger font-weight-bold">ASN编号:</span><span class="text-black">@{{ asn.asnno }}</span></span>
-                                        <span><span class="font-weight-bold">交接状态:</span><span class="text-lowercase" v-if="asn.asn_status">@{{ asn.asn_status.codename_c }}</span></span>
+                                        <span><span class="text-danger">ASN编号:</span><span class="text-black font-weight-bold">@{{ asn.asnno }}</span></span><br>
+                                        <span>
+                                            <span >状态:</span>
+                                            <span class="text-lowercase small" v-if="asn.asnstatus==='00'">订单创建</span>
+                                            <span class="text-lowercase small" v-if="asn.asnstatus==='30'">部分收货</span>
+                                        </span>
+                                        <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                        <span><span>货主:</span><span class="text-black font-weight-bold small">@{{ asn.customerid }}</span></span><br>
                                         <span><span class="text-lowercase">客户订单号1:</span><span class="text-lowercase">@{{ asn.asnreference1 }} </span></span>
                                         <span><span class="text-black">创建时间:</span><span class="text-black-50">@{{ asn.addtime }}</span></span>
+                                        <span>
+                                            <span class="btn btn-success btn-sm" v-if="!asn.up"  @click.stop="getAsnDetails(asn)">明细</span>
+                                            <span class="btn btn-secondary btn-sm" v-if="asn.up" @click.stop="closeDetail(asn)">收起</span>
+                                        </span>
+                                        <table class="table-sm table-borderless" v-if="asns.length>0 && asn.asnDetails && asn.up">
+                                            <tr  v-for="(asnDetail,i) in asn.asnDetails">
+                                                <td>
+                                                    <span><span class="small">产品:</span><span class="text-black small">@{{ asnDetail.sku }}</span></span>
+                                                    <span><span class="small">条码:</span><span class="text-black font-weight-bold small">@{{ asnDetail.alternate_sku1 }}</span></span>
+                                                    <span><span class="small">品名:</span><span class="text-black small">@{{ asnDetail.skudescrc }}</span></span>
+                                                    <span><span class="small">预期数量:</span><span class="text-black font-weight-bold small">@{{ asnDetail.expectedqty }}</span></span>
+                                                    <span><span class="small">已收数量:</span><span class="text-black font-weight-bold small">@{{ asnDetail.receivedqty }}</span></span>
+                                                <td/>
+                                            </tr>
+                                        </table>
                                     </div>
                                 </div>
                             </td>
@@ -66,7 +88,8 @@
                 this.pageInit();
                 $("#container").removeClass("d-none");
                 this.height=window.screen.availHeight;
-                document.getElementById('cardTable').style.height=this.height*0.50+'px';
+                document.getElementById('cardTable').style.height=this.height*0.35+'px';
+                document.getElementById("asn").focus();
             },
             methods:{
                 //页面初始化
@@ -82,8 +105,9 @@
                     if (e2)e2.remove();
                 },
                 selectAsn(){
+                    this.selectTr='';
                     let url = '{{url('store/handInStorage/selectAsn')}}';
-                    window.axios.post(url,{asnno:this.info.asn})
+                    window.axios.post(url,{asnno:this.info.asnno})
                         .then(res=>{
                             if (res.data.success){
                                 this.asns=res.data.data;
@@ -97,25 +121,76 @@
                         window.tempTip.show("网络错误:"+err);
                     })
                 },
+                getAsnDetails(asn){
+                    if (!asn)return;
+                    let url = '{{url('store/handInStorage/selectAsnDetails')}}';
+                    window.axios.post(url,{asnno:asn.asnno})
+                        .then(res=>{
+                            if (res.data.success){
+                                this.asns.forEach(function (Asn){
+                                    if (Asn.asnno==asn.asnno){
+                                        Asn.up=true;
+                                        Asn.asnDetails=res.data.data;
+                                    }
+                                })
+                                this.$forceUpdate()
+                                return;
+                            }
+                            window.tempTip.setDuration(2000);
+                            window.tempTip.show(res.data.data);
+                        }).catch(err=>{
+                        window.tempTip.setDuration(2000);
+                        window.tempTip.show("网络错误:"+err);
+                    })
+                },
+                closeDetail(asn){
+                    this.asns.forEach(function (Asn){
+                        if (Asn.asnno==asn.asnno){
+                            Asn.up=false;
+                        }
+                    })
+                    this.$forceUpdate()
+                },
                 selectTrOne(i,asn){
                     if (this.selectTr===i+1){
                         this.selectTr=0
                     }else {
                         this.selectTr=i+1;
-                        this.info.asn=asn.asnno;
+                        this.info.asnno=asn.asnno;
                         this.info.customerid=asn.customerid;
+                        this.info.asntype=asn.asntype;
                     }
                 },
+                onfocus(){
+                    document.getElementById("asn").focus();
+                },
                 ensure(){
                     let error = {};
-                    if (!this.info.asn)error.asn = ["ASN号必填"];
-                    if (this.info.asn && this.info.asn.length!==13)error.asn = ["无效ASN号"];
+                    if (!this.info.asnno)error.asnno = ["ASN号必填"];
+                    if (this.info.asnno && this.info.asnno.length!==13)error.asnno = ["无效ASN号"];
                     if (JSON.stringify(error)!=='{}'){this.errors = error;return;}
-                    window.location.href="{{url('store/handInStorage/receiveDetailPage')}}/" + this.info.asn+'/'+ this.info.customerid;
+                    if (!this.info.customerid||!this.info.asntype){this.info.customerid='';this.info.asntype='';}
+                    this.checkAsnOperation();
+                },
+                checkAsnOperation(){
+                    let url = '{{url('store/handInStorage/checkAsnOperation')}}';
+                    window.axios.post(url,{info:this.info})
+                        .then(res=>{
+                            if (res.data.success){
+                                window.location.href="{{url('store/handInStorage/receiveDetailPage')}}/" + res.data.data.asnno+'/'+ res.data.data.customerid;
+                            }else {
+                                window.tempTip.setDuration(2000);
+                                window.tempTip.show(res.data.data);
+                            }
+                        }).catch(err=>{
+                        window.tempTip.setDuration(2000);
+                        window.tempTip.show("网络错误:"+err);
+                    })
                 },
                 cancel(){
                     setTimeout(function () {
                         window.location.reload();
+                        this.onfocus();
                     },100);
                 },
             },

+ 40 - 30
resources/views/store/handInStorage/receiveDetailPage.blade.php

@@ -11,9 +11,9 @@
                 <div class="form-group row m-1">
                         <span class="text-right">
                             <span class="fa fa-search fa-lg" aria-hidden="true" @click="selectAsnDetails()"></span>
-                            <label for="sku" class="text-right text-danger font-weight-bold">条码:</label>
+                            <label for="sku" class="text-right text-danger font-weight-bold">产品:</label>
                         </span>
-                    <input type="text" class="form-control form-control-sm col-8" id="sku"
+                    <input type="text" class="form-control form-control-sm col-8" id="sku" autocomplete="off" placeholder="输入商品sku或商品条码"
                            :class="errors.sku ? 'is-invalid' : ''" @keydown.enter="enterVal($event)" v-model="info.sku" @blur="checkedSku()">
                     <span class="invalid-feedback offset-3" role="alert" v-if="errors.sku">
                             <strong>@{{ errors.sku[0] }}</strong>
@@ -31,21 +31,24 @@
                     </div>
                     <div class="form-group row m-1">
                         <label for="amount" class="text-right text-danger font-weight-bold">实收数量:</label>
-                        <input type="number" class="form-control form-control-sm col-8" id="amount"
+                        <input type="number" class="form-control form-control-sm col-8" id="amount" autocomplete="off"
                                :class="errors.amount ? 'is-invalid' : ''" v-model="info.amount" @keydown.enter="enterVal($event)">
                         <span class="invalid-feedback offset-3" role="alert" v-if="errors.amount">
                             <strong>@{{ errors.amount[0] }}</strong>
                         </span>
                     </div>
+{{--                    <div class="form-group row m-1">--}}
+{{--                        <label for="location" class="text-right">目标库位:</label>--}}
+{{--                        <input type="text" class="form-control form-control-sm col-8" id="location" autocomplete="off"--}}
+{{--                               @keydown.enter="enterVal($event)" v-model="info.location">--}}
+{{--                    </div>--}}
                     <div class="form-group row m-1">
-                        <label for="location" class="text-right">目标库位:</label>
-                        <input type="text" class="form-control form-control-sm col-8" id="location"
-                               @keydown.enter="enterVal($event)" v-model="info.location">
-                    </div>
-                    <div class="form-group row m-1">
-                        <label for="trackNumber" class="text-right">托盘号:</label>
-                        <input type="text" class="form-control form-control-sm col-8" id="trackNumber"
-                               @keydown.enter="enterVal($event)" v-model="info.trackNumber">
+                        <label for="trackNumber" class="text-right text-danger font-weight-bold">容器号:</label>
+                        <input type="text" class="form-control form-control-sm col-8" id="trackNumber" autocomplete="off"
+                               @keydown.enter="enterVal($event)" :class="errors.trackNumber ? 'is-invalid' : ''" v-model="info.trackNumber">
+                        <span class="invalid-feedback offset-3" role="alert" v-if="errors.trackNumber">
+                            <strong>@{{ errors.trackNumber[0] }}</strong>
+                        </span>
                     </div>
                 </div>
                 <div style="overflow: auto;overflow-x: hidden" id="cardTable" v-if="!isInit">
@@ -55,11 +58,12 @@
                             <td style="filter:grayscale(30%);">
                                 <div>
                                     <div style="transform:scale(1)" class="pl-0">
-                                        <span><span class="text-danger font-weight-bold">条码:</span><span class="text-black">@{{ asnDetail.sku }}</span></span>
+                                        <span><span class="text-danger font-weight-bold">产品:</span><span class="text-black">@{{ asnDetail.sku }}</span></span>
                                         <span><span class="font-weight-bold">行号:</span><span class="text-lowercase" >@{{ asnDetail.asnlineno }}</span></span>
                                         <span class="text-right float-right">选中:<input type="checkbox" @click="checked(asnDetail)"></span>
                                         <span><span class="text-lowercase">品名:</span><span class="text-lowercase">@{{ asnDetail.skudescrc }} </span></span>
                                         <span><span class="text-black">预期数量:</span><span class="text-black-50">@{{ asnDetail.expectedqty }}</span></span>
+                                        <span><span class="text-black">已收数量:</span><span class="text-black-50">@{{ asnDetail.receivedqty }}</span></span>
                                     </div>
                                 </div>
                             </td>
@@ -89,7 +93,7 @@
                 <div class="form-group row">
                     <span class="col-6" v-if="basSku.lot_id.lotkey04==='Y'">
                         <label for="lotatt04" class=" text-right text-danger">批号:</label><br>
-                        <input type="text" class="form-control form-control-sm" :class="errors.lotatt04 ? 'is-invalid' : ''"
+                        <input type="text" class="form-control form-control-sm" :class="errors.lotatt04 ? 'is-invalid' : ''" autocomplete="off"
                                id="lotatt04" v-model="info.lotatt04">
                          <span class="invalid-feedback offset-3" role="alert" v-if="errors.lotatt04">
                             <strong>@{{ errors.lotatt04[0] }}</strong>
@@ -154,15 +158,15 @@
                 isAndroid:false,
                 isInit:true,
                 element:[
-                    "sku","amount","location","trackNumber"
+                    "sku","amount",/*"location",*/"trackNumber"
                 ],
                 selectTr:'',
             },
             mounted(){
                 if (navigator.userAgent.indexOf("Android")!==-1)this.isAndroid = true;
-                this.codeFocus();
                 this.pageInit();
                 $("#container").removeClass("d-none");
+                document.getElementById("sku").focus();
             },
             methods:{
                 //页面初始化
@@ -182,10 +186,10 @@
                         this.selectTr=0
                     }else {
                         this.selectTr=i+1;
-                        // this.info.sku=sku;
                     }
                 },
                 checkedSku(){
+                    if (!this.info.sku)return;
                     let url = '{{url('store/handInStorage/getBasSkuWithLot')}}';
                     window.axios.post(url,{asnno:this.asnno,customerid:this.customerid,sku:this.info.sku})
                         .then(res=>{
@@ -232,16 +236,14 @@
                     this.info.name=asnDetail.skudescrc;
                     this.info.expectedqty=asnDetail.expectedqty;
                     this.info.receivedqty=asnDetail.receivedqty;
+                    this.info.amount=Number(this.info.expectedqty)-Number(this.info.receivedqty);
                     this.info.asnlineno=asnDetail.asnlineno;
                 },
-                //聚焦 白名单
-                codeFocus(){
-                    document.getElementById("sku").focus();
-                },
                 checkInfo(){
                     let error = {};
                     if (!this.info.sku)error.sku = ["条码必填"];
                     if (!this.info.amount)error.amount = ["实收数量必填"];
+                    if (!this.info.trackNumber)error.trackNumber = ["容器号必填"];
                     if (this.info.amount && ((Number(this.info.amount)+Number(this.info.receivedqty))>Number(this.info.expectedqty)))error.amount = ["总数不能超过预期数"];
                     if (this.basSku.lot_id && this.basSku.lot_id.lotkey01==='Y' && !this.info.lotatt01) error.lotatt01=["生产日期为选"];
                     if (this.basSku.lot_id && this.basSku.lot_id.lotkey02==='Y' && !this.info.lotatt02) error.lotatt02=["失效日期为选"];
@@ -249,8 +251,7 @@
                     if (this.basSku.lot_id && this.basSku.lot_id.lotkey04==='Y' && !this.info.lotatt04) error.lotatt04=["批号未填"];
                     if (this.basSku.lot_id && this.basSku.lot_id.lotkey05==='Y' && !this.info.lotatt05) error.lotatt05=["属性仓未选"];
                     if (this.basSku.lot_id && this.basSku.lot_id.lotkey08==='Y' && !this.info.lotatt08) error.lotatt08=["质量状态未选"];
-                    if (JSON.stringify(error)!=='{}'){this.errors = error;return;}
-                    if (!this.info.amount && this.info.maximum)this.info.amount = this.info.maximum;
+                    if (JSON.stringify(error)!=='{}'){this.errors = error;}
                 },
                 enterVal(e){
                     let index = this.element.indexOf(e.target.id)+1;
@@ -278,21 +279,24 @@
                     })
                 },
                 ensure(){
+                    this.errors={};//初始errors状态
                     this.checkInfo();
                     this.info.customerid=this.customerid;
                     this.info.asnno=this.asnno;
-                    console.log( this.info.trackNumber,this.info.location)
-                    if (this.info.trackNumber==''||this.info.trackNumber==null||this.info.trackNumber==undefined)this.info.trackNumber='';
+                    // if (this.info.trackNumber==''||this.info.trackNumber==null||this.info.trackNumber==undefined)this.info.trackNumber='';
                     if (this.info.location==''||this.info.location==null||this.info.location==undefined)this.info.location='';
-                    // this.info.trackNumber='';
-                    // this.info.location='';
-                    console.log(this.info)
+                    if (Number(this.info.receivedqty)===Number(this.info.expectedqty)){
+                        window.tempTip.setDuration(2000); window.tempTip.show("收货已完成");
+                    }
                     let url = '{{url('store/handInStorage/fluxHandIn')}}';
-                    window.axios.post(url,{info:this.info})
+                    if (JSON.stringify(this.errors)==='{}') window.axios.post(url,{info:this.info})
                         .then(res=>{
                             if (res.data.success){
-                                // this.asnDetails=res.data.data;
-                                // this.$forceUpdate()
+                                window.tempTip.setDuration(2000);
+                                window.tempTip.showSuccess(res.data.data);
+                                this.info={};
+                                this.$forceUpdate();
+                                document.getElementById("sku").focus();
                                 return;
                             }
                             window.tempTip.setDuration(2000);
@@ -302,6 +306,12 @@
                         window.tempTip.show("网络错误:"+err);
                     })
                 },
+                cancel(){
+                    setTimeout(function () {
+                        window.location.reload();
+                        document.getElementById("sku").focus();
+                    },100);
+                },
             },
         });
     </script>

+ 1 - 1
resources/views/store/inStorage/_commodities.blade.php

@@ -14,7 +14,7 @@
                        <th></th>
                     </tr>
                     <tr v-for="(commodity,index) in commodities">
-                        <td>@{{ commodity.owner.name }}</td>
+                        <td>@{{ commodity.owner ? commodity.owner.name : '未知' }}</td>
                         <td>@{{ commodity.name }}</td>
                         <td>@{{ commodity.sku }}</td>
                         <td>

+ 36 - 0
resources/views/store/inStorage/_lotModal.blade.php

@@ -0,0 +1,36 @@
+<div class="modal fade" tabindex="-1" role="dialog" id="commodities">
+    <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="font-weight-bold h4">多批次选择</div>
+                <button type="button" class="close" data-dismiss="modal">&times;</button>
+            </div>
+            <div class="modal-body">
+                <table class="w-100 h-100 table table-bordered table-striped">
+                    <tr>
+                        <th>货主</th>
+                        <th>生产日期</th>
+                        <th>失效日期</th>
+                        <th>入库日期</th>
+                        <th>属性仓</th>
+                        <th>批号</th>
+                        <th>质量</th>
+                        <th></th>
+                    </tr>
+                    <tr v-for="(lot,index) in lots">
+                        <td>@{{ lot.customerid }}</td>
+                        <td>@{{ lot.lotatt01 }}</td>
+                        <td>@{{ lot.lotatt02 }}</td>
+                        <td>@{{ lot.lotatt03 }}</td>
+                        <td>@{{ lot.lotatt04 }}</td>
+                        <td>@{{ lot.lotatt05 }}</td>
+                        <td>@{{ lot.lotatt08 }}</td>
+                        <td>
+                            <button class="btn btn-sm btn-primary" @click="selectedLot(index)">选定</button>
+                        </td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+    </div>
+</div>

+ 25 - 0
resources/views/store/inStorage/_setCommodityMaximum.blade.php

@@ -0,0 +1,25 @@
+<div class="modal fade" tabindex="-1" role="dialog" id="maximumModal">
+    <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="font-weight-bold h4">单品料箱设置</div>
+                <button type="button" class="close" data-dismiss="modal">&times;</button>
+            </div>
+            <div class="modal-body">
+                <div class="row mt-2" v-for="commodity in commodities">
+                    <div class="col-6" style="overflow: hidden">
+                        @{{ commodity.name }}
+                    </div>
+                    <div class="col-6">
+                        <input class="form-control" type="number" step="1" min="1" placeholder="最大上限"
+                               v-model="commodity.maximum">
+                    </div>
+                    <hr class="w-100">
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-success" @click="settingCommodityMaximum()">提交</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 50 - 0
resources/views/store/inStorage/_settingAsnRule.blade.php

@@ -0,0 +1,50 @@
+<div class="modal fade" tabindex="-1" role="dialog" id="modal">
+    <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="font-weight-bold h4">ASN规则</div>
+                <button type="button" class="close" data-dismiss="modal">&times;</button>
+            </div>
+            <div class="modal-body row">
+                <div class="col-5 h-100 card p-0">
+                    <div class="card-header">
+                        <div class="custom-control custom-checkbox">
+                            <input type="checkbox" class="custom-control-input" id="owner" @change="selectAll(false)">
+                            <label class="custom-control-label" for="owner">未设定货主</label>
+                        </div>
+                    </div>
+                    <div class="card-body list-group p-0 overflow-y-scrollbar-200">
+                        <div class="list-group-item" v-for="owner in owners" v-if="!owner.is_show">
+                            <div class="custom-control custom-checkbox">
+                                <input type="checkbox" class="custom-control-input" :id="'owner-'+owner.name" v-model="owner.is_check_asn">
+                                <label class="custom-control-label" :for="'owner-'+owner.name">@{{ owner.value }}</label>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-2 d-flex align-items-center h-100">
+                    <div class="w-100 text-center cursor-pointer">
+                        <span class="fa fa-angle-double-right fa-3x w-100" @click="changeAsnRule(false)"></span>
+                        <span class="fa fa-angle-double-left fa-3x w-100" @click="changeAsnRule(true)"></span>
+                    </div>
+                </div>
+                <div class="col-5 h-100 card p-0">
+                    <div class="card-header">
+                        <div class="custom-control custom-checkbox">
+                            <input type="checkbox" class="custom-control-input" id="ownerNo" @change="selectAll(true)">
+                            <label class="custom-control-label" for="ownerNo">已设定货主</label>
+                        </div>
+                    </div>
+                    <div class="card-body list-group p-0 overflow-y-scrollbar-200">
+                        <div class="list-group-item" v-for="owner in owners" v-if="owner.is_show">
+                            <div class="custom-control custom-checkbox">
+                                <input type="checkbox" class="custom-control-input" :id="'owner-'+owner.name" v-model="owner.is_check_asn">
+                                <label class="custom-control-label" :for="'owner-'+owner.name">@{{ owner.value }}</label>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 2 - 0
resources/views/store/inStorage/androidIndex.blade.php

@@ -20,6 +20,8 @@
         <div class="w-100 center h-75 row align-items-center justify-content-center">
             <div class="w-100">
 <!--                <a href="{{url('store/inStorage/cacheRackStorage')}}"><button class="btn btn-info w-75 text-white" style="height: 60px"><h4>整箱入库</h4></button></a>-->
+                <a href="{{url('store/handInStorage/receive')}}"><button class="btn btn-info w-75 mt-3 text-white" style="height: 60px"><h4>收货</h4></button></a>
+                <a href="{{url('store/handInStorage/putaway')}}"><button class="btn btn-info w-75 mt-3 text-white" style="height: 60px"><h4>上架</h4></button></a>
                 <a href="{{url('store/inStorage/halfChestStorage')}}"><button class="btn btn-info w-75 mt-3 text-white" style="height: 60px"><h4>半箱入库</h4></button></a>
                 <a href="{{url('store/inStorage/boxBindShelf')}}"><button class="btn btn-info w-75 mt-3 text-white" style="height: 60px"><h4>新箱上架</h4></button></a>
                 <a href="{{url('store/inStorage/boxBindModel')}}"><button class="btn btn-info w-75 mt-3 text-white" style="height: 60px"><h4>料箱型号</h4></button></a>

+ 8 - 10
resources/views/store/inStorage/commodityBindModel.blade.php

@@ -51,25 +51,23 @@
                 searchBarCode(){
                     if(!this.barCode)return;
                     window.tempTip.postBasicRequest("{{url('store/inStorage/searchBarCode')}}",{barCode:this.barCode},res=>{
-                        console.log(res)
                         this.commodities = res;
                         if (res.length>1){
                             $("#commodities").modal("show");
                             return;
                         }
-                        $("#maximumModal").modal("show");
+                        this.selectedCommodity(0);
                     },true)
                 },
-                submitBind(){
-                    window.tempTip.postBasicRequest("{{url('store/inStorage/boxBindModel')}}",this.info,()=>{
-                        this.info = {};
-                        return "绑定成功";
-                    })
-                },
                 selectedCommodity(index){
                     this.commodityIndex = index;
-                    $("#commodities").modal("hide");
-                    $("#maximumModal").modal("show");
+                    window.tempTip.postBasicRequest("{{url('store/inStorage/searchModel')}}",{id:this.commodities[this.commodityIndex].id},res=>{
+                        this.models.forEach((model,i)=>{
+                            this.$set(this.models[i],"maximum",res ? (res[model.id] ? res[model.id] : null) : null);
+                        });
+                        $("#commodities").modal("hide");
+                        $("#maximumModal").modal("show");
+                    });
                 },
                 settingModelMaximum(){
                     let models = [];

+ 61 - 47
resources/views/store/inStorage/halfChestStorage.blade.php

@@ -11,17 +11,16 @@
                         <a class="small" href="#" @click="openModal()">溢出减量</a>
                     </div>
                     <div class="form-group row">
-                        <label for="asn" class="col-sm-2 col-3 text-right">ASN号:</label>
-                        <input type="text" class="form-control col-8" id="asn" placeholder="只需填写后几位,自动补充"
-                             @change="downSign()" :class="errors.asn ? 'is-invalid' : ''" @keydown.enter="enterVal($event)" v-model="info.asn" @blur="checkAsn()">
-                        <span class="invalid-feedback offset-3" role="alert" v-if="errors.asn">
-                            <strong>@{{ errors.asn[0] }}</strong>
+                        <label for="track" class="col-sm-2 col-3 text-right">跟踪号:</label>
+                        <input type="text" class="form-control col-8" id="track" :class="errors.track ? 'is-invalid' : ''" @keydown.enter="enterVal($event)" v-model="info.track" @blur="check()">
+                        <span class="invalid-feedback offset-3" role="alert" v-if="errors.track">
+                            <strong>@{{ errors.track[0] }}</strong>
                         </span>
                     </div>
                     <div class="form-group row">
                         <label for="station" class="col-sm-2 col-3 text-right">库位:</label>
                         <input type="text" class="form-control col-8" id="station" placeholder="扫描货架条码"
-                               :class="errors.station ? 'is-invalid' : ''" v-model="info.station" @blur="checkMaximum()" @keydown.enter="enterVal($event)">
+                               :class="errors.station ? 'is-invalid' : ''" v-model="info.station" @blur="check()" @keydown.enter="enterVal($event)">
                         <span class="invalid-feedback offset-3" role="alert" v-if="errors.station">
                             <strong>@{{ errors.station[0] }}</strong>
                         </span>
@@ -29,7 +28,7 @@
                     <div class="form-group row">
                         <label for="barCode" class="col-sm-2 col-3 text-right">条码:</label>
                         <input type="text" class="form-control col-8" id="barCode" placeholder="扫描商品条码"
-                               @change="downSign()" :class="errors.barCode ? 'is-invalid' : ''" v-model="info.barCode" @blur="checkMaximum()" @keydown.enter="enterVal($event)">
+                               :class="errors.barCode ? 'is-invalid' : ''" v-model="info.barCode" @blur="check()" @keydown.enter="enterVal($event)">
                         <span class="invalid-feedback offset-3" role="alert" v-if="errors.barCode">
                             <strong>@{{ errors.barCode[0] }}</strong>
                         </span>
@@ -37,7 +36,7 @@
                     <div class="form-group row">
                         <label for="amount" class="col-sm-2 col-3 text-right">数量:</label>
                         <input type="number" class="form-control col-8" id="amount"
-                               @keydown.enter="enterVal($event)" :class="errors.amount ? 'is-invalid' : ''" @blur="checkMaximum()" v-model="info.amount" :placeholder="info.maximum!==undefined ? '最大可上:'+info.maximum : ''" :max="info.maximum" step="1">
+                               @keydown.enter="enterVal($event)" :class="errors.amount ? 'is-invalid' : ''" @blur="check()" v-model="info.amount" :placeholder="info.maximum!==undefined ? '最大可上:'+info.maximum : ''" :max="info.maximum" step="1">
                         <span class="invalid-feedback offset-3" role="alert" v-if="errors.amount">
                             <strong>@{{ errors.amount[0] }}</strong>
                         </span>
@@ -87,6 +86,7 @@
                 </div>
             </div>
             @include("store.inStorage._setMaximum")
+            @include("store.inStorage._lotModal")
         </div>
     </div>
 @stop
@@ -97,19 +97,16 @@
             el:"#container",
             data:{
                 permissionList:[ //允许聚焦许可列表
-                    "asn","station","amount","location","ov_amount"
+                    "track","station","amount","location","ov_amount"
                 ],
                 info:{},
                 mount:false,
-                before:{
-                    asn:"",
-                },
+                /*before:{},*/
                 focus:"",
                 errors:{},
                 ov:{},//溢出减量数值
-                checkSign:false,
                 element:[
-                    "asn","station","barCode","amount","submit"
+                    "track","station","barCode","amount","submit"
                 ],
                 isAndroid:false,
                 shelfOccupy:{},
@@ -127,16 +124,17 @@
                     ],
                 ],
                 models:null,
+                oldInfo:{},
+                lots:[],
             },
             mounted(){
                 if (navigator.userAgent.indexOf("Android")!==-1)this.isAndroid = true;
                 @foreach($stations as $station)this.$set(this.shelfOccupy,"{{$station->code}}",!!{{$station->material_box_id}});@endforeach
                 //this.codeFocus();
                 //this.globalClick();
-                this.createBefore();
+                //this.createBefore();
                 this.pageInit();
                 $("#container").removeClass("d-none");
-                this.showMaximumModal();
             },
             methods:{
                 //页面初始化
@@ -171,7 +169,7 @@
                         document.getElementById("location").focus();
                     },500);
                 },
-                //聚焦 白名单
+                /*//聚焦 白名单
                 codeFocus(){
                     if (!this.permissionList.includes(document.activeElement.id)) document.getElementById("barCode").focus();
                 },
@@ -181,12 +179,11 @@
                     this.mount = turn;//防止重复挂载事件
                     if (turn) window.addEventListener("click",this.codeFocus);
                     else window.removeEventListener("click",this.codeFocus);
-                },
+                },*/
 
                 checkInfo(){
                     let error = {};
-                    if (!this.info.asn)error.asn = ["ASN号必填"];
-                    if (this.info.asn && this.info.asn.length!==13)error.asn = ["非法ASN号"];
+                    if (!this.info.track)error.track = ["跟踪号必填"];
                     if (!this.info.barCode)error.barCode = ["商品条码必填"];
                     if (!this.info.station)error.station = ["库位必填"];
                     if (!this.info.amount && !this.info.maximum)error.amount = ["数量必填"];
@@ -196,12 +193,19 @@
                 },
                 _exeTask(){
                     window.tempTip.postBasicRequest("{{url('store/inStorage/acquireBox')}}",this.info,()=>{
-                        this.info = {asn:this.info.asn};
+                        if (!this.status){
+                            window.tempTip.show("调取失败,内部错误");
+                            return;
+                        }
+                        if (this.amount>0){
+                            this.info.station = "";
+                            this.info.amount = "";
+                        }else this.info = {track:this.info.track};
                         this.errors = {};
                         return "上架成功!";
                     });
                 },
-                createBefore(){
+  /*              createBefore(){
                     let now = new Date();
                     let yy = now.getFullYear().toString().substr(2, 2);
                     let mm = now.getMonth() + 1;
@@ -209,32 +213,43 @@
                     let dd = now.getDate();
                     dd = dd <10 ? '0'+dd : dd.toString();
                     this.before.asn = 'ASN'+yy+mm+dd+'000';
-                },
-                checkAsn(){
-                    if(!this.info.asn)return;
-                    let len = this.info.asn.length;
-                    if (len<13)this.info.asn = this.before.asn.substr(0,13-len)+this.info.asn;
-                    if (!this.checkSign)this.checkMaximum(e,'');
-                },
-                downSign(){
-                    this.checkSign = false;
-                },
+                },*/
                 checkMaximum(){
-                    if (!this.info.asn || !this.info.barCode || this.checkSign)return;
                     window.tempTip.postBasicRequest("{{url('store/inStorage/checkMaximum')}}",this.info,res=>{
                         if (!res.material_box_model_id){
+                            this.info.commodity_id = res.commodity_id;
                             this.showMaximumModal();
                             return;
                         }
-                        this.info.maximum = res.maximum;
-                        this.info.material_box_id = res.material_box_id;
+                        this.info.maximum = res.need;
+                        this.info.location = res.location;
                         this.info.material_box_model_id = res.material_box_model_id;
                         this.info.commodity_id = res.commodity_id;
-                        if(!this.info.amount)this.info.amount = res.maximum;
-                        return "该库位最大可上数为"+res.maximum;
+                        if(!this.info.amount)this.info.amount = res.need;
+                        return "该库位最大可上数为"+res.need;
                     });
-                    this.checkSign = true;
                 },
+                check(){
+                    if (!this.info.track || !this.info.barCode)return;
+                    if (!this.info.lotNum || this.info.track !== this.oldInfo.track || this.info.barCode !== this.oldInfo.barCode){
+                        window.tempTip.postBasicRequest("{{url('store/inStorage/checkTask')}}",this.info,res=>{
+                            this.oldInfo = {track:this.info.track,barCode:this.info.barCode};
+                            switch (res.count){
+                                case 0:
+                                    window.tempTip.show("无此上架信息");
+                                    break;
+                                case 1:
+                                    this.info.lotNum = res.lots;
+                                    this.checkMaximum();
+                                    break;
+                                default:
+                                    this.lots = res.lots;
+                                    $("#lotModal").modal("show");
+                            }
+                        });
+                    }
+                },
+                //回车向下TAB
                 enterVal(e){
                     let index = this.element.indexOf(e.target.id)+1;
                     let element = document.getElementById(this.element[index]);
@@ -305,16 +320,15 @@
                         return;
                     }
                     window.tempTip.postBasicRequest("{{url('store/inStorage/setMaximum')}}",
-                        {models:models,asn:this.info.asn,barCode:this.info.barCode},res=>{
-                        this.info.maximum = res.maximum;
-                        this.info.material_box_id = res.material_box_id;
-                        this.info.material_box_model_id = res.material_box_model_id;
-                        this.info.commodity_id = res.commodity_id;
-                        if(!this.info.amount)this.info.amount = res.maximum;
-                        $("#maximumModal").modal("hide");
-                        return "该库位最大可上数为"+res.maximum;
+                        {models:models,commodityId:this.info.commodity_id},res=>{
+                        this.checkMaximum();
                     },true);
-                }
+                },
+                selectedLot(index){
+                    this.info.lotNum = this.lots[index].lotnum;
+                    this.checkMaximum();
+                    $("#lotModal").modal("hide");
+                },
             },
         });
     </script>

+ 25 - 2
resources/views/store/inStorage/index.blade.php

@@ -6,6 +6,7 @@
         <div id="form_div"></div>
         <div class="ml-2">
             <button class="btn btn-sm btn-primary" @click="syncStorage()">同步FLUX部分库存</button>
+            <button class="btn btn-sm btn-outline-info" @click="settingAsnRule()">设定ASN收货规则</button>
         </div>
         <table class="table table-striped table-sm text-nowrap table-hover td-min-width-80" id="table">
             <tr v-for="(store,i) in stores" :id="'data-'+store.id" @click="selectTableRow(i,$event)">
@@ -53,6 +54,7 @@
                             </td>
                         </tr>
         </table>
+        @include("store.inStorage._settingAsnRule")
         <div class="text-info h5 btn btn">{{$stores->count()}}/{{$stores->total()}}</div>
         <div>{{$stores->appends($paginateParams)->links()}}</div>
     </div>
@@ -71,8 +73,8 @@
                     @endforeach
                 ],
                 owners:[
-                        @foreach($owners as $owner)
-                    {name:'{{$owner->id}}',value:'{{$owner->name}}'},
+                    @foreach($owners as $owner)
+                    {name:'{{$owner->id}}',value:'{{$owner->name}}',is_show:Boolean({!! $owner->is_check_asn !!})},
                     @endforeach
                 ],
                 warehouses:[
@@ -163,6 +165,27 @@
                         })
                     })
                 },
+                settingAsnRule(){
+                    $("#modal").modal("show");
+                },
+                selectAll(show){
+                    let val = event.target.checked;
+                    this.owners.forEach((owner,index)=>{
+                        if (owner.is_show===show)this.$set(this.owners[index],"is_check_asn",val);
+                    })
+                },
+                changeAsnRule(show){
+                    let pool = [];
+                    this.owners.forEach((owner,index)=>{
+                        if (owner.is_show===show && owner.is_check_asn){
+                            owner.is_show = !owner.is_show;
+                            owner.is_check_asn = !owner.is_check_asn;
+                            this.$set(this.owners,index,owner);
+                            pool.push(owner.name);
+                        }
+                    });
+                    window.tempTip.postBasicRequest("{{url('store/inStorage/changeAsnRule')}}",{ids:pool,val:show},()=>{});
+                }
             }
         });
     </script>

+ 53 - 0
resources/views/store/inStorage/quickPutStorage.blade.php

@@ -0,0 +1,53 @@
+@extends('layouts.app')
+@section('title')商品绑定型号-入库管理@endsection
+
+@section('content')
+    <div class="container-fluid d-none" id="container">
+        <div class="mt-3 col-8 offset-2">
+            <div class="form-group row">
+                <label for="asn">ASN号</label>
+                <input id="asn" type="text" class="form-control" v-model="asn"></input>
+            </div>
+            <div class="input-group row mt-5">
+                <button type="submit" id="submit" class="btn btn-info offset-2 col-10" @click="searchAsn()">检索</button>
+            </div>
+        </div>
+        @include("store.inStorage._setCommodityMaximum")
+        @include("store.inStorage._commodities")
+    </div>
+@stop
+
+@section('lastScript')
+    <script>
+        new Vue({
+            el:"#container",
+            data:{
+                asn:"",
+                commodities:[],
+                model:{},
+            },
+            methods:{
+                searchAsn(){
+                    if (!this.asn)return;
+                    window.tempTip.postBasicRequest("{{url('store/inStorage/searchAsn')}}",{asn:this.asn},res=>{
+                        this.commodities = res.commodities;
+                        this.model = res.model;
+                    })
+                },
+                settingCommodityMaximum(){
+                    this.commodities.forEach(commodity=>{
+                        if (!commodity.maximum){
+                            window.tempTip.setDuration(2000);
+                            window.tempTip.show("'"+commodity.name+"'未设定上限");
+                            return;
+                        }
+                    });
+                    window.tempTip.postBasicRequest("{{url('store/inStorage/settingCommodityMaximum')}}",
+                        {commodities:this.commodities,modelId:this.model.id},res=>{
+                        return "设定完毕";
+                    })
+                },
+            },
+        });
+    </script>
+@stop

+ 27 - 29
resources/views/transport/waybill/edit.blade.php

@@ -57,7 +57,16 @@
                                     <strong class="">@{{ errors['logistic_id'][0] }}</strong>
                                 </div>
                             </div>
-
+                            <div class="form-group row">
+                                <label for="deliver_at" class="col-2 col-form-label text-right text-muted">发货时间</label>
+                                <div class="col-8 form-inline">
+                                    <input  id="deliver_at_date" @input="spliceDeliverAt" name="deliver_at_date" type="date" class="form-control col-4 @error('deliver_at_date') is-invalid @enderror"
+                                            value="@if(old('deliver_at_date')){{ old('deliver_at_date') }}@else{{$waybill->deliver_at_date}}@endif">
+                                    <input  id="deliver_at_time" @input="spliceDeliverAt" name="deliver_at_time" type="time" class="form-control col-4 @error('deliver_at_date') is-invalid @enderror"
+                                            value="@if(old('deliver_at_time')){{ old('deliver_at_time') }}@else{{$waybill->deliver_at_time}}@endif">
+                                    <input hidden id="deliver_at"  name="deliver_at" type="text" class="form-control col-4">
+                                </div>
+                            </div>
                             <div v-if="waybill.logistic_id == 15 || waybill.type=='德邦物流'" style="background: black">
                                 <div class="form-group row">
                                     <label for="cargo_name" class="col-2 col-form-label text-right text-primary">货物名称 *</label>
@@ -329,16 +338,6 @@
                                     </div>
                                 </div>
                             </div>
-                            <div class="form-group row">
-                                <label for="deliver_at" class="col-2 col-form-label text-right text-muted">发货时间</label>
-                                <div class="col-8 form-inline">
-                                    <input  id="deliver_at_date" @input="spliceDeliverAt" name="deliver_at_date" type="date" class="form-control col-4"
-                                            value="@if(old('deliver_at_date')){{ old('deliver_at_date') }}@else{{$waybill->deliver_at_date}}@endif">
-                                    <input  id="deliver_at_time" @input="spliceDeliverAt" name="deliver_at_time" type="time" class="form-control col-4"
-                                            value="@if(old('deliver_at_time')){{ old('deliver_at_time') }}@else{{$waybill->deliver_at_time}}@endif">
-                                    <input hidden id="deliver_at"  name="deliver_at" type="text" class="form-control col-4">
-                                </div>
-                            </div>
                             <div class="form-group row">
                                 <label for="dispatch_remark" class="col-2 col-form-label text-right text-muted">调度备注</label>
                                 <div class="col-8">
@@ -621,15 +620,13 @@
                 is_waybillPriceModel(logistic_id,carrier_weight,carrier_weight_unit_id,destination_city_id,carrier_weight_other,carrier_weight_unit_id_other,cargo_name,total_number,total_weight,deliveryType_id,order_type,transport_type,pay_type,back_sign_bill,package_service){
                     this.errors=[];
                     let url='{{url('transport/waybill/is/waybillPriceModel')}}';
-
                     let _this=this;
                     axios.post(url,{logistic_id:logistic_id,carrier_weight:[carrier_weight,carrier_weight_other],
                             carrier_weight_unit_id:[carrier_weight_unit_id,carrier_weight_unit_id_other],destination_city_id:destination_city_id,
                             cargo_name:cargo_name, total_number:total_number,total_weight:total_weight, deliveryType_id:deliveryType_id
                             ,order_type:order_type, transport_type: transport_type, pay_type:pay_type, back_sign_bill:back_sign_bill,package_service:package_service
-                    }) .then(
+                    }).then(
                             function (response) {
-
                                 if (response.data.error){
                                     _this.errors=response.data.error;return;}
 
@@ -659,7 +656,7 @@
                     let  logistic_id=document.getElementById('logistic_id').value;
                     let carrier_weight = '',carrier_weight_unit_id='',destination_city_id='',carrier_weight_other='',carrier_weight_unit_id_other='',
                         cargo_name = '',total_number='',total_weight='',deliveryType_id='',order_type='',transport_type='',pay_type='',back_sign_bill='',package_service='';
-                    if ( logistic_id == 15 ){
+                    if ( logistic_id == 15 || type === '德邦物流'){
                         cargo_name=document.getElementById('cargo_name').value;
                         total_number=document.getElementById('total_number').value;
                         total_weight=document.getElementById('total_weight').value;
@@ -669,22 +666,23 @@
                         pay_type=document.getElementById('pay_type').value;
                         back_sign_bill=document.getElementById('back_sign_bill').value;
                         package_service=document.getElementById('package_service').value;
-                    }
-                    if (type==='专线'){
-                        carrier_weight=document.getElementById('carrier_weight').value;
-                        carrier_weight_unit_id=document.getElementById('carrier_weight_unit_id').value;
-                        destination_city_id=document.getElementById('destination_city_id').value;
-                        carrier_weight_other=document.getElementById('carrier_weight_other').value;
-                        carrier_weight_unit_id_other=document.getElementById('carrier_weight_unit_id_other').value;
-                        this.is_waybillPriceModel(logistic_id,carrier_weight,carrier_weight_unit_id,destination_city_id,
-                            carrier_weight_other,carrier_weight_unit_id_other,cargo_name,total_number,total_weight,
-                            deliveryType_id,order_type,transport_type,pay_type,back_sign_bill,package_service
+                        destination_city_id = 0;
+                        this.is_waybillPriceModel(logistic_id, carrier_weight, carrier_weight_unit_id, destination_city_id,
+                            carrier_weight_other, carrier_weight_unit_id_other, cargo_name, total_number, total_weight,
+                            deliveryType_id, order_type, transport_type, pay_type, back_sign_bill, package_service
                         );
-                    } else {
-                        this.is_waybillPriceModel(logistic_id,carrier_weight,carrier_weight_unit_id,destination_city_id,
-                            carrier_weight_other,carrier_weight_unit_id_other,cargo_name,total_number,total_weight,
-                            deliveryType_id,order_type,transport_type,pay_type,back_sign_bill,package_service
+                    }
+                    if (type==='专线') {
+                        carrier_weight = document.getElementById('carrier_weight').value;
+                        carrier_weight_unit_id = document.getElementById('carrier_weight_unit_id').value;
+                        destination_city_id = document.getElementById('destination_city_id').value;
+                        carrier_weight_other = document.getElementById('carrier_weight_other').value;
+                        carrier_weight_unit_id_other = document.getElementById('carrier_weight_unit_id_other').value;
+                        this.is_waybillPriceModel(logistic_id, carrier_weight, carrier_weight_unit_id, destination_city_id,
+                            carrier_weight_other, carrier_weight_unit_id_other, cargo_name, total_number, total_weight,
+                            deliveryType_id, order_type, transport_type, pay_type, back_sign_bill, package_service
                         );
+                    }else if(type === '直发车') {
                         document.getElementById('deliver_at').value= document.getElementById('deliver_at_date').value+' '+ document.getElementById('deliver_at_time').value;
                         this.executeSubmit();
                     }

+ 30 - 4
resources/views/transport/waybill/index.blade.php

@@ -13,13 +13,13 @@
                             <a target="transport/waybill/index" class="nav-link @if($uriType=='') active @endif" href="{{url('transport/waybill/index')}}">全部</a>
                         </li>
                         <li class="nav-item">
-                            <a target="transport/waybill/index" class="nav-link @if($uriType=='专线') active @endif" href="{{url('transport/waybill/index?uriType=专线')}}">专线</a>
+                            <a target="transport/waybill/index" class="nav-link @if($uriType=='专线') active @endif" href="{{url('transport/waybill/index?uriType=专线&status=未审核')}}">专线</a>
                         </li>
                         <li class="nav-item">
-                            <a target="transport/waybill/index" class="nav-link @if($uriType=='直发车') active @endif" href="{{url('transport/waybill/index?uriType=直发车')}}">直发车</a>
+                            <a target="transport/waybill/index" class="nav-link @if($uriType=='直发车') active @endif" href="{{url('transport/waybill/index?uriType=直发车&status=未审核')}}">直发车</a>
                         </li>
                         <li class="nav-item">
-                            <a target="transport/waybill/index" class="nav-link @if($uriType=='德邦物流') active @endif" href="{{url('transport/waybill/index?uriType=德邦物流')}}">德邦物流</a>
+                            <a target="transport/waybill/index" class="nav-link @if($uriType=='德邦物流') active @endif" href="{{url('transport/waybill/index?uriType=德邦物流&status=未审核')}}">德邦物流</a>
                         </li>
                     </ul>
                 </div>
@@ -43,7 +43,10 @@
                             title="计算指定日期下的所有专线费,不考虑有无货主权限">按日输入专线费</button>@endcan
             @endif
             @can('运输管理-编辑')<button class="btn btn-sm btn-outline-info tooltipTarget"
-                        title="合并多条运单至一条,已填写信息将被累加处理" @click="waybillMerge()">运单合并</button>@endcan
+                        title="合并多条运单至一条,已填写信息将被累加处理" @click="waybillMerge()">运单合并</button>
+            <button class="btn btn-sm btn-outline-info tooltipTarget"
+                    title="将已合并运单拆分返回原状态" @click="waybillSplit()">拆单返回</button>
+            @endcan
             <div>
                 @if(Session::has('successTip'))
                     <div class="alert alert-success h1">{{Session::get('successTip')}}</div>
@@ -449,7 +452,11 @@
                         return;
                     }
                     window.tempTip.confirm("确定要合并选中运单吗?",()=>{
+                        window.tempTip.setDuration(99999);
+                        window.tempTip.waitingTip("合并中,请稍等...");
                         window.tempTip.postBasicRequest("{{url('transport/waybill/waybillMerge')}}",{ids:checkData},res=>{
+                            window.tempTip.cancelWaitingTip();
+                            window.tempTip.setDuration(2000);
                             setTimeout(function (){
                                 location.reload();
                             },1000);
@@ -457,6 +464,25 @@
                         });
                     })
                 },
+                waybillSplit(){
+                    if (checkData.length<1){
+                        window.tempTip.setDuration(2000);
+                        window.tempTip.show("未选择任何记录");
+                        return;
+                    }
+                    window.tempTip.confirm("确定要拆分选中合并单吗?",()=>{
+                        window.tempTip.setDuration(99999);
+                        window.tempTip.waitingTip("拆分中,请稍等...");
+                        window.tempTip.postBasicRequest("{{url('transport/waybill/waybillSplit')}}",{ids:checkData},res=>{
+                            window.tempTip.cancelWaitingTip();
+                            window.tempTip.setDuration(2000);
+                            setTimeout(function (){
+                                location.reload();
+                            },1000);
+                            return res;
+                        });
+                    })
+                },
                 rendingFloatBtn(){
                     let parent = $('.pick-btn :visible');
                     if (parent.length<1)return;

+ 0 - 3
routes/apiLocal.php

@@ -207,9 +207,6 @@ 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('getChildStation/{id}','CacheShelfController@getChildStationApi')->name('station.cacheShelf.getChildStationApi');
     });
 
     /** 栈规则 */

+ 11 - 3
routes/web.php

@@ -30,7 +30,7 @@ Route::post('package/weigh/measureMonitor/data','MeasureMonitorController@data')
 //称重显示
 Route::get('package/measureMonitor','MeasureMonitorController@index');
 Route::resource('package/weigh/measureMonitor','MeasureMonitorController');
-Route::resource('package/measureMonitor','MeasureMonitorController');
+
 //入库预约终端
 Route::get('store/deliveryAppointment/exhibition','DeliveryAppointmentController@exhibition');
 //入库预约预约码输入
@@ -377,6 +377,7 @@ Route::group(['middleware'=>'auth'],function ($route){
             Route::post('dailyBilling','WaybillController@dailyBilling');
             Route::post('countPickUpFee','WaybillController@countPickUpFee');
             Route::post('waybillMerge','WaybillController@waybillMerge');
+            Route::post('waybillSplit','WaybillController@waybillSplit');
             Route::resource('waybillFinancialSnapshot','WaybillFinancialSnapshotsController');
             Route::resource('waybillFinancialExcepted','WaybillFinancialExceptedController');
         });
@@ -467,7 +468,6 @@ Route::group(['middleware'=>'auth'],function ($route){
             Route::get('halfChestStorage','StoreController@halfChestStorage');
             Route::post('putShelf','StorageController@putShelf');
             Route::post('resetCacheShelf','StorageController@resetCacheShelf');
-            Route::post('setMaximum','StorageController@setMaximum');
             Route::post('checkMaximum','StorageController@checkMaximum');
             Route::post('overflowRevision','StorageController@overflowRevision');
             Route::post('acquireBox','StorageController@acquireBox');
@@ -484,15 +484,23 @@ Route::group(['middleware'=>'auth'],function ($route){
             Route::post('getModels','StorageController@getModels');
             Route::post('setMaximum','StorageController@settingModelMaximum');
             Route::post('searchBarCode','StorageController@searchBarCode');
+            Route::post('searchModel','StorageController@searchModel');
+            Route::post('searchAsn','StorageController@searchAsn');
+            Route::post('settingCommodityMaximum','StorageController@settingCommodityMaximum');
+            Route::post('checkTask','StorageController@checkTask');
+            Route::post('changeAsnRule','StorageController@changeAsnRule');
         });
         Route::group(['prefix'=>'handInStorage'],function() {
             Route::get('receive',function (){return view('store.handInStorage.receive');});//收货页面
             Route::get('putaway',function (){return view('store.handInStorage.putaway');});//上架页面
             Route::get('android.index',function (){return view('store.handInStorage.androidIndex');});
             Route::post('selectAsn','HandInStorageController@selectAsn');
+            Route::post('checkAsnOperation','HandInStorageController@checkAsnOperation');
             Route::post('selectAsnDetails','HandInStorageController@selectAsnDetails');
             Route::post('getBasSkuWithLot','HandInStorageController@getBasSkuWithLot');
-            Route::post('fluxHandIn','HandInStorageController@fluxHandIn');
+            Route::any('fluxHandIn','HandInStorageController@fluxHandIn');
+            Route::post('getTsk','HandInStorageController@getTsk');
+            Route::post('handFluxPa','HandInStorageController@handFluxPa');
             Route::get('receiveDetailPage/{asnno}/{customerid}','HandInStorageController@receiveDetailPage');
         });
         Route::group(['prefix'=>'fast'],function() {

+ 1 - 1
syncProject.sh

@@ -3,7 +3,7 @@ Ip="was.baoshi56.com"
 username="haozi"
 password="haozi"
 files=("app" "config" "database" "public" "resources" "routes" "webpack.mix.js" "composer.json" "tests")
-src=/var/www/bswas_test_
+src=/var/www/bswas_test
 dsc=/var/www/was
 cd $src
 for i in ${files[*]}

+ 5 - 0
yarn.lock

@@ -4351,6 +4351,11 @@ map-visit@^1.0.0:
   dependencies:
     object-visit "^1.0.0"
 
+marked@^2.1.3:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/marked/-/marked-2.1.3.tgz#bd017cef6431724fd4b27e0657f5ceb14bff3753"
+  integrity sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==
+
 md5.js@^1.3.4:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"

+ 44 - 1
文档/SystemHandBook.md

@@ -2,6 +2,8 @@
 > 客户ERP 》 FLUX应用系统 》 <font color=#1E90FF>**WAS后台管理系统**</font> 》 HAIQ机器人系统
 ***
 ## 全局功能
+* **数据**  
+  可视数据与个人账户权限挂钩,仅可见对应的(货主,工作组...),如发觉权限不足找对应主管反馈开通对应权限
 * **搜索**
 > 对于文本类搜索可以在前后加<kbd>%</kbd>进行模糊匹配
 > > 例:搜索快递单号为123456的订单可以写为:```%456``` 或 ```123%```,推荐使用后者,在内容前加<kbd>%</kbd>会使得搜索变慢
@@ -18,4 +20,45 @@
 * **复制**  
   应用场景:复制页面信息粘贴到通讯软件(QQ,VX,TIM)中防止信息换行显示
 > > 点击打开左下角的设置栏 》 表头设置 》 禁止复制换行   
-> 同上,针对本机记录,更换设备重置  
+> 同上,针对本机记录,更换设备重置
+* **导出**  
+  一般分为两种导出方式:
+    * 导出所有页
+      根据当前查询条件,导出所有符合当前查询条件的数据
+    * 导出勾选
+      仅导出勾选的数据
+  > > 部分模块可以格式化导出:大多导出行为如果同数据多子项会在一个Excel单元格内进行合并  
+  > > 例如订单管理:格式化导出  勾选此选项执行导出时可以进行合并单元格操作
+
+## 退货管理
+* **查询**
+    * 一般退货数据   
+      审核:审核退货单,标记审核号  
+      完结:完结退货单,收录数据  
+      修改入库:修改退单入库状态或方式  
+      批量填充订单号:去往导入页  
+      复制快递单号:将选中退单的快递单号换行复制  
+      取消审核:删除审核号,回滚审核状态
+    * 货主退货统计数据
+    * 导入
+* **录入**
+* **回收站**
+
+## 控制台
+* **功能**
+
+    1. 最近常用功能:显示用户近期使用的功能,包含一级二级菜单
+    2. 实时待处理订单:分仓库显示当日订单数量
+    3. 订单量趋势:根据时间、货主搜索
+    4. 快递分布:根据时间、货主搜索
+    5. 仓库分布:根据时间货主搜索
+    6. 临时工趋势:根据时间搜索
+    7. 临时工小组分布:根据时间搜索
+    8. 已称重包裹占比:根据时间搜索
+    9. 异常分布:显示包裹异常比例,可根据时间、货主搜索
+    10. 快递信息同步成功失败占比:可根据时间搜索
+
+
+* **权限**
+
+  根据用户所有权限不同,上述功能可能有部分缺少

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor