Просмотр исходного кода

完善手持入库 收货上架调整

haozi 4 лет назад
Родитель
Сommit
ea78db5c0a

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

@@ -6,6 +6,7 @@ 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
@@ -20,7 +21,10 @@ class HandInStorageController extends Controller
         $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单');
@@ -50,7 +54,7 @@ class HandInStorageController extends Controller
     {
         $asnno= $request->input('asnno');
         $asnDetails =app('HandInStorageService')->selectAsnDetails($asnno);
-        if ($asnDetails->count()>0)$this->success($asnDetails);
+        if (count($asnDetails)>0)$this->success($asnDetails);
         else $this->error('未搜索到ASN详情单');
 
     }
@@ -61,26 +65,31 @@ 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)
     {
         $info=$request->input('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'])->first();
-            if (!$location)$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');
         $result=$handInStorageService->fluxHandIn($info);
@@ -88,5 +97,44 @@ class HandInStorageController extends Controller
         else $this->error("收货失败");
     }
 
+    /**
+     * @param Request $request
+     * 根据商品条码 获取要上架的任务列表
+     */
+    public function getTsk(Request $request)
+    {
+        $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)
+    {
+        $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];
+//        dd($info,$checkData);
+        $location=OracleBasLocation::query()
+                ->where('locationid',$info['location'])
+                ->where('status','OK')
+                ->first();
+        if (!$location)$this->error('目标库位不存在');
+        /** @var HandInStorageService $handInStorageService  */
+        $handInStorageService=app('HandInStorageService');
+        $result=$handInStorageService->fluxHandPa($info,$checkData);
+        if ($result)$this->success("上架成功");
+        else $this->error("上架失败");
+    }
+
 
 }

+ 23 - 17
app/Http/Controllers/TestController.php

@@ -151,22 +151,16 @@ class TestController extends Controller
     }
     public function test()
     {
-        $a = function ($a){
-          dump($a);
-        };
-        $a(true);
-        dd(2);
-        $fee = OwnerFeeDetail::query()->with(["order.logistic","order.shop",
-            "order.packages.commodities.commodity","order.batch"])
-            ->find(3183469);
-
-        $rule = OwnerPriceOperation::query()->with(["items"=>function($query){
-            /** @var Builder $query */
-            $query->orderByRaw("CASE strategy  WHEN '起步' THEN 1 WHEN '默认' THEN 2 WHEN '特征' THEN 3 END DESC,priority");
-        }])->find(82);dd($rule->toArray());
-        $units = app("UnitService")->getUnitMapping(["件","单","箱","m³","T","kg"]); //获取单位映射集
-        $money = app("OwnerPriceOperationService")->matchItem($rule,Feature::MAPPING["order"],$fee->order,$units,2,[0=>true]);
-        dd($money);
+        $who= 'WAS'.(Auth::user() ? '-'.Auth::user()["name"] : '');
+        $time=Carbon::now()->toDateTimeString();
+        $asnno='ASN2107280001';
+       $db = DB::connection("oracle");
+       $db->transaction(function ()use($db,$time,$who,$asnno){
+           $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,$asnno]);
+//           $db->rollBack();
+           return true;
+       });
     }
     public function orderCreateBill()
     {
@@ -1301,6 +1295,18 @@ TEXT;
 
     public function uuid()
     {
-        dd(md5( date("Y-m-d H:i:s")));
+        $asn='ASN2107210001';
+//        $barCode='450066';
+        $barCode='500087';
+        $amount=70;
+        $tasks = app("StorageService")->getFluxTask($asn,$barCode,$amount);
+//        $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]);
+        dd($tasks,'111');
     }
 }

+ 150 - 24
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;
@@ -29,19 +31,38 @@ class HandInStorageService
      */
     public function selectAsn($asn)
     {
-        if ($asn) return OracleDOCASNHeader::query()
-            ->with('asnStatus')
+        if (!$asn) return OracleDOCASNHeader::query()
             ->select(['asnno','asnreference1','asnstatus','addtime','customerid'])
-            ->where('asnno',$asn)
-            ->get();
-
-        return OracleDOCASNHeader::query()
-            ->select(['asnno','asnreference1','asnstatus','addtime','customerid'])
-            ->with('asnStatus')
             ->where('asnstatus','00')
             ->orderByDesc('addtime')
             ->limit(50)
             ->get();
+
+        if ($asn && strpos(strtoupper($asn),'ASN')!==false){
+            return OracleDOCASNHeader::query()
+                ->select(['asnno','asnreference1','asnstatus','addtime','customerid'])
+                ->where('asnno',$asn)
+                ->get();
+        }else {
+            $asns=OracleDOCASNHeader::query()
+                ->select(['asnno','asnreference1','asnstatus','addtime','customerid'])
+                ->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 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
+SQL;
+                return DB::connection("oracle")->select(DB::raw($sql),[$asn,$asn,$asn]);
+            }
+        }
+
     }
 
     /**
@@ -51,24 +72,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
      *
      */
-    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 +150,88 @@ 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']);
+//        dd($tasks);
+        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)
     {
@@ -135,10 +250,16 @@ class HandInStorageService
         return DB::connection("oracle")->transaction(function ()use ($info,$invlotatt,$who,$time){
             //flux 批次号
             $lotNum=$this->getOrCreateLotNum($info,$invlotatt,$who,$time);
-            if (!$lotNum) return false;
+            if (!$lotNum){
+                DB::connection("oracle")->rollBack();
+                return false;
+            }
             //flux 创建入库事务
             $actTransactionLog=$this->setFluxActTransactionLog($info,$lotNum,$who,$time);
-            if (!$actTransactionLog)return false;
+            if (!$actTransactionLog){
+                DB::connection("oracle")->rollBack();
+                return false;
+            }
             //flux 创建上架任务
             $this->setFluxTskTaskListPA($info,$invlotatt, $actTransactionLog, $who, $time);
             //flux 完善库存余量
@@ -169,14 +290,15 @@ class HandInStorageService
                 $asnDetail['customerid']==$info['customerid'] &&
                 $asnDetail['sku']==$info['sku']) $receiveAsn=$asnDetail;
         }
+//        dd($receiveAsn);
         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 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 = ?"),
+             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']]);
+                        $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']]);
@@ -184,13 +306,17 @@ class HandInStorageService
                 //asn_detail 收货数量+已收数量=预期数量
                 $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 = ?"),
+                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']]);
+                        $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 +474,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 +497,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']);

+ 2 - 2
app/Services/StorageService.php

@@ -293,7 +293,7 @@ sql;
      *
      * @return array
      */
-    private function splitTask($tasks,$maxIndex,$amount):array
+    public function splitTask($tasks, $maxIndex, $amount):array
     {
         $result = [];
         if ($maxIndex===null){
@@ -413,7 +413,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){

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

@@ -0,0 +1,257 @@
+@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");
+                    },
+                    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){
+                                        this.info={};
+                                        this.checkData=[];
+                                        this.$forceUpdate()
+                                        window.tempTip.setDuration(2000);
+                                        window.tempTip.showSuccess(res.data.data);
+                                    }
+                                    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();
+                            }, 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

+ 59 - 6
resources/views/store/handInStorage/receive.blade.php

@@ -8,12 +8,13 @@
                 <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" autocomplete="off"
-                               :class="errors.asn ? 'is-invalid' : ''" @keydown.enter="selectCustomerid($event)" v-model="info.asn">
+                               :class="errors.asn ? 'is-invalid' : ''" v-model="info.asn">
                         <span class="ml-2">
                              <button type="button" id="select" class="btn btn-info" @click="selectAsn()">搜索</button>
                         </span>
@@ -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,7 @@
                 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.45+'px';
             },
             methods:{
                 //页面初始化
@@ -82,6 +104,7 @@
                     if (e2)e2.remove();
                 },
                 selectAsn(){
+                    this.selectTr='';
                     let url = '{{url('store/handInStorage/selectAsn')}}';
                     window.axios.post(url,{asnno:this.info.asn})
                         .then(res=>{
@@ -97,6 +120,36 @@
                         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

+ 23 - 12
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" autocomplete="off"
+                    <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>
@@ -37,15 +37,18 @@
                             <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" autocomplete="off"
-                               @keydown.enter="enterVal($event)" v-model="info.location">
-                    </div>
-                    <div class="form-group row m-1">
-                        <label for="trackNumber" class="text-right">托盘号:</label>
+                        <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)" v-model="info.trackNumber">
+                               @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>
@@ -154,7 +158,7 @@
                 isAndroid:false,
                 isInit:true,
                 element:[
-                    "sku","amount","location","trackNumber"
+                    "sku","amount",/*"location",*/"trackNumber"
                 ],
                 selectTr:'',
             },
@@ -185,6 +189,7 @@
                     }
                 },
                 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=>{
@@ -242,6 +247,7 @@
                     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=["失效日期为选"];
@@ -281,7 +287,7 @@
                     this.checkInfo();
                     this.info.customerid=this.customerid;
                     this.info.asnno=this.asnno;
-                    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='';
                     if (Number(this.info.receivedqty)===Number(this.info.expectedqty)){
                         window.tempTip.setDuration(2000); window.tempTip.show("收货已完成");
@@ -303,6 +309,11 @@
                         window.tempTip.show("网络错误:"+err);
                     })
                 },
+                cancel(){
+                    setTimeout(function () {
+                        window.location.reload();
+                    },100);
+                },
             },
         });
     </script>

+ 3 - 1
routes/web.php

@@ -475,7 +475,9 @@ Route::group(['middleware'=>'auth'],function ($route){
             Route::post('selectAsn','HandInStorageController@selectAsn');
             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() {