Переглянути джерело

半箱入库,亮灯接口
计费模型前端BUG修复

Zhouzhendong 4 роки тому
батько
коміт
8ad9a08780

+ 27 - 146
app/Http/Controllers/StorageController.php

@@ -11,7 +11,6 @@ use App\StationTaskMaterialBox;
 use App\Storage;
 use App\StoreItem;
 use App\TaskTransaction;
-use App\ValueStore;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Auth;
@@ -35,30 +34,11 @@ class StorageController extends Controller
         if (!$box)$this->error("WAS无此料箱");
 
         //get flux
-        $sql = <<<sql
-SELECT * 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;
-        $asns = DB::connection("oracle")->select(DB::raw($sql),[$asn,$barCode,$barCode,$barCode,$amount]);
+        $asns = app("StorageService")->getFluxTask($asn,$barCode,$amount);
         if (!$asns)$this->error("ASN不存在或上架数量与入库数量不符");
-        $nums = [];
-        $result = null;
-        foreach ($asns as $index=>$asn){
-            if ((int)$asn->fmqty == $amount){$result=$index;break;}
-            $nums[] = (int)$asn->fmqty;
-        }
-        //flux上架
-        if ($result===null){
-            $result = $this->twoSum($nums,$amount);
-            if (!$result)$this->error("无法匹配入库记录,检查您的上架数量");
-            DB::connection("oracle")->transaction(function ()use($result,$asns,$ide){
-                foreach ($result as $index){
-                    $this->fluxPA($asns[$index],$ide,(int)$asns[$index]->fmqty);
-                }
-            });
-        } else $this->fluxPA($asns[$result],$ide,$amount);
+        DB::connection("oracle")->transaction(function ()use($asns,$ide){
+            foreach ($asns as $asn)app("StorageService")->fluxPA($asn,$ide,(int)$asn->fmqty);
+        });
         //亮灯
         app("CacheShelfService")->_stationCacheLightOn($fromLocation,$ide);
         //库存相关信息
@@ -117,128 +97,6 @@ sql;
         $this->success(["need"=>$models[0]->maximum,"material_box_model_id"=>$models[0]->material_box_model_id,"commodity_id"=>$item->commodity_id]);
     }
 
-    public function fluxPA($asn,$ide,$amount)
-    {
-        if (!$asn->taskid)$this->error("ASN单无此入库信息,禁止上架");
-
-        $sql = <<<sql
-SELECT * FROM inv_lot_loc_id  WHERE lotnum = ? AND traceid = ? AND customerid= ?  and sku = ?
-sql;
-        $inv = DB::connection("oracle")->select(DB::raw($sql),[$asn->fmlotnum,$asn->plantoid,$asn->customerid,$asn->sku]);
-        if (count($inv)==0)$this->error("余量与入库不符");
-        DB::connection("oracle")->transaction(function ()use($inv,$amount,$ide,$asn,&$who){
-            $db = DB::connection("oracle");
-            $qty = $amount;
-            foreach ($inv as $in){
-                if ($qty==0)break;
-                if ($in->qty > $qty){
-                    $db->update(DB::raw("update inv_lot_loc_id set qty = qty-?,qtymvout = qty-? where lotnum = ? and locationid = ? and traceid = ?"),[
-                        $qty,$qty,$in->lotnum,$in->locationid,$in->traceid
-                    ]);//TODO 遗留问题:对应生成分配库位上架数量未被变更
-                    $in->qty = $in->qty-$qty;
-                    $qty = 0;
-                }else{
-                    $db->delete(DB::raw("DELETE FROM inv_lot_loc_id WHERE lotnum = ? and locationid = ? and traceid = ?"),[
-                        $in->lotnum,$in->locationid,$in->traceid
-                    ]);
-                    $qty = $qty-$in->qty;
-                }
-            }
-            $db->delete(DB::raw("DELETE FROM inv_lot_loc_id WHERE lotnum = ? AND traceid = ? AND traceid != '*'  AND qty = 0"),[
-                $inv[0]->lotnum,$inv[0]->traceid
-            ]);
-            $invHistory = $db->selectOne(DB::raw("SELECT * FROM inv_lot_loc_id WHERE lotnum = ? AND locationid = ? AND customerid = ? AND sku = ? AND traceid = '*' FOR UPDATE"),[
-                $inv[0]->lotnum,$ide,$inv[0]->customerid,$inv[0]->sku
-            ]);
-            $who = 'WAS'.(Auth::user() ? '-'.Auth::user()["name"] : '');
-            if ($invHistory)$db->update(DB::raw("UPDATE inv_lot_loc_id SET qty = qty+? WHERE lotnum = ? AND locationid = ? AND traceid = '*'"),[
-                (int)$amount,$inv[0]->lotnum,$ide
-            ]);
-            else $db->insert(DB::raw("INSERT INTO inv_lot_loc_id VALUES(?,?,'*',?,?,?,0,0,0,0,0,0,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,0,0,0,0,0,'*',0,null)"),[
-                $inv[0]->lotnum,$ide,$inv[0]->customerid,$inv[0]->sku,$amount,date("Y-m-d H:i:s"),$who,
-                date("Y-m-d H:i:s"),$who
-            ]);
-            $sql = <<<sql
-INSERT INTO ACT_TRANSACTION_LOG VALUES(?,'PA',?,?,?,?,'ASN',?,?,?,?,?,?,?,?,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,
-TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,0,0,0,0,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,?,null,null,null,'*',?,?,?,?,?,?,?,
-?,?,?,?,?,'N',null,?,?,?,?,?,?,?,null,null)
-sql;
-            $trid = $this->getTrNumber();
-            $db->insert(DB::raw($sql),[
-                $trid,$asn->customerid,$asn->sku,
-                $asn->asnno,$asn->asnlineno,$inv[0]->lotnum,$asn->fmlocation,$asn->plantoid,$asn->packid,$asn->uom,$amount,$amount,'99',date("Y-m-d H:i:s"),$who,
-                date("Y-m-d H:i:s"),$who,date("Y-m-d H:i:s"),$asn->customerid,$asn->sku,$ide,$who,$asn->packid,$asn->uom,$amount,$amount,$inv[0]->lotnum,
-                '*','0','N','*',$asn->taskid_sequence,$asn->warehouseid,$asn->userdefine1,$asn->userdefine2,
-                $asn->userdefine3,$asn->userdefine4,$asn->userdefine5,'O'
-            ]);
-            $this->setTrNumber();
-            $sql = <<<sql
-update TSK_TASKLISTS set TASKPROCESS = '99',REASONCODE = 'OK',PLANTOLOCATION = ?,PLANLOGICALTOSEQUENCE = ?,
-CREATE_TRANSACTIONID = ?,OPENWHO = ?,OPENTIME = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),
- CLOSEWHO = ?,CLOSETIME = ?,EDITTIME = ?,EDITWHO = ?
- where taskid = ? AND TASKID_SEQUENCE = ?
-sql;
-            $db->update(DB::raw($sql),[
-                $ide,$ide,$trid,$who,date("Y-m-d H:i:s"),$who,date("Y-m-d H:i:s"),date("Y-m-d H:i:s"),$who,$asn->taskid,$asn->taskid_sequence
-            ]);
-        });
-        //成功后应去修改ASN状态及数量 暂时不知上架后ASN应为状态
-        /*        $sql = <<<sql
-        UPDATE doc_asn_details SET linestatus = ?,edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ? AND asnlineno = ?
-        sql;*/
-        //if ($asn->expectedqty>$asn->receivedqty && $asn->linestatus!='30')DB::connection("oracle")->update(DB::raw($sql),['30',date("Y-m-d H:i:s"),$who,$asn->asnno,$asn->asnlineno]);
-        if ($asn->expectedqty==$asn->receivedqty && $asn->linestatus=='40'){
-            //DB::connection("oracle")->update(DB::raw($sql),['40',date("Y-m-d H:i:s"),$who,$asn->asnno,$asn->asnlineno]);
-            $check = DB::connection("oracle")->selectOne(DB::raw("SELECT 1 FROM DOC_ASN_DETAILS WHERE ASNNO = ? AND LINESTATUS != '40'"),[$asn->asnno]);
-            if (!$check){
-                $logs = DB::connection("oracle")->select(DB::raw("SELECT SUM(FMQTY) qty,TRANSACTIONTYPE FROM ACT_TRANSACTION_LOG WHERE DOCNO = ? AND TRANSACTIONTYPE IN ('PA','IN') GROUP BY TRANSACTIONTYPE"),[$asn->asnno]);
-                $paQty = 0;
-                $inQty = 0;
-                foreach ($logs as $log){
-                    if ($log->transactiontype == 'IN')$inQty = $log->qty;
-                    else $paQty = $log->qty;
-                }
-                if ($paQty == $inQty){
-                    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"),$who,$asn->asnno]);
-                    DB::connection("oracle")->update(DB::raw("UPDATE DOC_ASN_DETAILS SET linestatus = '99',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ?"),
-                        [date("Y-m-d H:i:s"),$who,$asn->asnno]);
-                }
-            }
-        }
-    }
-
-    /**
-     * @param Integer[] $nums
-     * @param Integer $target
-     * @return Integer[]|null
-     */
-    function twoSum($nums, $target) {
-        $map=[];
-        for($i=0;$i<count($nums);$i++){
-            $complement=$target-$nums[$i];
-            if(array_key_exists($complement,$map)){
-                return [$map[$complement],$i];
-            }
-            $map[$nums[$i]]=$i;
-        }
-        return null;
-    }
-
-    function getTrNumber()
-    {
-        $val = ValueStore::query()->select("value")->where("name","flux_tr_number")->first();
-        if (!$val)$val = ValueStore::query()->create(["name"=>"flux_tr_number","value"=>'0']);
-        $max = $val->value+1;
-        $number = sprintf("%09d", $max);
-        return 'W'.$number;
-    }
-
-    function setTrNumber()
-    {
-        ValueStore::query()->select("value")->where("name","flux_tr_number")->update(["value"=>DB::raw("flux_tr_number+1")]);
-    }
-
     /**
      * 重置缓存架指定格口
      */
@@ -329,6 +187,8 @@ sql;
         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"),
@@ -341,4 +201,25 @@ sql;
         app("CacheShelfService")->stationLightUp($station->code,null,'2');
         $this->success();
     }
+
+    /**
+     * 溢出校正
+     */
+    public function overflowRevision()
+    {
+        $station = request("station");
+        $amount = request("amount");
+        //获取目标库位
+        $station = app("StationService")->getMirrorMappingLocation($station);
+        if (!$station)$this->error("未知库位");
+        $task = TaskTransaction::query()->with("materialBox")->where("fm_station_id",$station->id)->where("amount",">",$amount)
+            ->where("type","入库")->where("mark",1)->where("status",0)->first();
+        if (!$task)$this->error("无任务存在");
+        $task->update(["amount" => DB::raw("amount - {$amount}")]);
+        $storage = Storage::query()->where("material_box_id",$task->material_box_id)->first();
+        $maximum = (($storage->amount ?? 0)+$task->amount)-$amount;
+        CommodityMaterialBoxModel::query()->where("material_box_model_id",$task->materialBox->material_box_model_id)
+            ->where("commodity_id",$task->commodity_id)->update(["maximum"=>$maximum]);
+        $this->success("校正成功");
+    }
 }

+ 28 - 12
app/Http/Controllers/api/thirdPart/haiq/LightController.php

@@ -9,17 +9,19 @@ 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
 {
     protected $request;
+    use TestableInstant;
 
     /** @var ForeignHaiRoboticsService $service */
-    private $service;
+    private $foreignHaiRoboticsService;
     public function __construct(){
-        $this->service=app('ForeignHaiRoboticsService');
+        $this->foreignHaiRoboticsService=null;
     }
 
     public function lightOn($post){
@@ -32,18 +34,32 @@ class LightController
      * @return array
      */
     public function update(Request $request){// 拍灯以后的消息发至此处
-        $station = Station::query()->with('stationType')->where('code',$request['locCode'])->first();
-        if( ($station ?? false) && ($station->stationType->name ?? false) && $station->stationType->name == '缓存架' ){  // 拍灯 推送任务
-            if($request['PTLAction'] !== 0) return ['location' => 200,'errMsg' => 'is cacheShelf','data' => $request->all()];
-            /** @var CacheShelfService $cacheShelfService */
-            $cacheShelfService = app(CacheShelfService::class);
-            $result =   $cacheShelfService->lightOffTask($request['locCode'],$request['PTLAction']);
-            return ['location'=>$result['success'] ? 200 :0,'errMsg'=>$result['errMsg'] ?? null,'data'=>$request->all()];
-        }
+        app('LogService')->log(__METHOD__,__FUNCTION__,'拍灯:'.json_encode($request->all()));
+        $this->instant($this->foreignHaiRoboticsService, 'ForeignHaiRoboticsService');
         $success = $request->input('success');
         $location = $success?200:0;
-        app('LogService')->log(__METHOD__,__FUNCTION__,'拍灯:'.json_encode($request->all()));
-        return ['location'=>$location,'errMsg'=>'','data'=>$request->all()];
+        /** @var Station $station */
+        $station = Station::query()->with('stationType')->where('code',$request['locCode'])->first();
+        $response = ['location' => $location, 'errMsg' => '', 'data' => $request->all()];
+        if(empty($station)
+            ||empty($station->stationType->name))return $response;
+
+        switch ($station->stationType->name) {
+            case '缓存架':     // 拍灯 推送任务
+                if($request['PTLAction'] !== 0){
+                    $response['errMsg']='灯条未开启';return $response;
+                }
+                /** @var CacheShelfService $cacheShelfService */
+                $cacheShelfService = app(CacheShelfService::class);
+                $result =   $cacheShelfService->lightOffTask($request['locCode'],$request['PTLAction']);
+                $response['location']=$result['success'];
+                $response['errMsg']=$result['errMsg'];
+                return $response;
+            case 'U型线拍灯':
+                $this->foreignHaiRoboticsService->uLineLightPat($station);
+        }
+
+        return $response;
     }
 
 }

+ 3 - 0
app/Providers/AuthServiceProvider.php

@@ -37,6 +37,9 @@ class AuthServiceProvider extends ServiceProvider
     public function boot()
     {
         $this->registerPolicies();
+        Gate::before(function ($user){
+            if (config("app.env") == 'local')return true;
+        });
         $isSuperAdmin = null;
         if(!Schema::hasTable('users')){return;}
         /** @var CacheService $cacheService */

+ 4 - 0
app/Services/CacheShelfService.php

@@ -53,6 +53,10 @@ class   CacheShelfService
     public function lightOffTask($locCode, $PTLAction): array
     {
         $station = Station::query()->with('pendingStationTask.stationTaskMaterialBoxes.materialBox')->where('code', $locCode)->first();
+        if (!app("StorageService")->checkStorage($station)){
+            $this->stationLightUp($station->code,null,'0','1','上架任务失败');
+            return ['success' => false,'errMsg' => '上架任务失败'];
+        };
         try {
             $bool = $this->putBinToStore($station);                         // 推送任务
             if($bool){

+ 1 - 12
app/Services/ForeignHaiRoboticsService.php

@@ -508,19 +508,8 @@ class ForeignHaiRoboticsService
         $station = Station::query()->select("id")->where("code",$fromLocation)->first();
         if (!$station)return null;
         if (StationTask::query()->select("id")->where("status","!=",'完成')->where("station_id",$station->id)->first())return null;
-        /** @var \stdClass $task */
-        $task = StationTask::query()->create([
-            'status' => "待处理",
-            'station_id' => $station->id,
-        ]);
         /** @var StationTaskMaterialBox|\stdClass $stmb */
-        $stmb = StationTaskMaterialBox::query()->create([
-            'station_id' => $station->id,
-            'material_box_id'=>$boxId,
-            'status'=>"待处理",
-            'type' => '放',
-            'station_task_id' => $task->id,
-        ]);
+        $stmb = app("StorageService")->createWarehousingTask($station->id,$boxId);
         return $stmb->id;
     }
 

+ 252 - 3
app/Services/StorageService.php

@@ -3,12 +3,16 @@
 namespace App\Services;
 
 use App\CommodityMaterialBoxModel;
+use App\Station;
 use App\StationTask;
 use App\StationTaskMaterialBox;
 use App\TaskTransaction;
 use App\Traits\ServiceAppAop;
 use App\Storage;
+use App\ValueStore;
+use Illuminate\Database\Eloquent\Model;
 use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
 
 class StorageService
@@ -78,15 +82,93 @@ class StorageService
     }
 
     /**
-     * 入库
+     * 检查存储 根据事务表做处理
+     *
+     * @param Station|\stdClass $station
+     *
+     * @return bool
+     *
+     * @throws
+     */
+    public function checkStorage($station)
+    {
+        $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();
+            try{
+                //get flux
+                $asns = app("StorageService")->getFluxTask($task->doc_code,$task->bar_code,$task->amount);
+                if (!$asns)return false;
+                $ide = $task->materialBox->code;
+                DB::connection("oracle")->beginTransaction();
+                try{
+                    foreach ($asns as $asn)if (!$this->fluxPA($asn,$ide,(int)$asn->fmqty)){
+                        DB::connection("oracle")->rollBack();
+                        return false;
+                    };
+                    DB::connection("oracle")->commit();
+                }catch(\Exception $e){
+                    DB::connection("oracle")->rollBack();
+                    return false;
+                }
+                $taskMaterialBox = $this->createWarehousingTask($station->id,$task->material_box_id);//建立入库任务
+                if (!$this->enterWarehouse($station->id,$task->material_box_id,$task->commodity_id,$task->amount))throw new \Exception("库存异常"); //处理库存
+                $task->update([
+                    "task_id" => $taskMaterialBox->id,
+                    "status" => 1,
+                    "user_id" => Auth::id(),
+                ]);//标记事务完成
+                $collection = new Collection([$taskMaterialBox]);
+                app("ForeignHaiRoboticsService")->fetchGroup($station->code,$collection,'','缓存架入立架'); //呼叫机器人入库
+                DB::commit();
+                return true;
+            }catch(\Exception $e){
+                DB::rollBack();
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 建立入库任务
+     *
+     * @param $stationId
+     * @param $boxId
+     *
+     * @return Model|\stdClass
+     */
+    public function createWarehousingTask($stationId,$boxId)
+    {
+        /** @var StationTask|\stdClass $task */
+        $task = StationTask::query()->create([
+            'status' => "待处理",
+            'station_id' => $stationId,
+        ]);
+        return StationTaskMaterialBox::query()->create([
+            'station_id' => $stationId,
+            'material_box_id'=>$boxId,
+            'status'=>"待处理",
+            'type' => '放',
+            'station_task_id' => $task->id,
+        ]);
+    }
+
+    /**
+     * 库存入库
      *
      * @param integer $stationId
      * @param integer $boxId
      * @param integer $commodityId
      * @param integer $amount
      * @param integer $modelId
+     *
+     * @return bool
      */
-    public function enterWarehouse($stationId, $boxId, $commodityId, $amount, $modelId)
+    public function enterWarehouse($stationId, $boxId, $commodityId, $amount, $modelId = null)
     {
         DB::beginTransaction();
         try{
@@ -103,7 +185,7 @@ class StorageService
                 $storage->update($obj);
                 $amount = (int)$storage->amount + (int)$amount;
             } else Storage::query()->create($obj);
-            if ($commodityId){
+            if ($commodityId && $modelId){
                 //维护料箱最大上限 用于半箱补货
                 $model = CommodityMaterialBoxModel::query()->select("maximum")->where("commodity_id",$commodityId)
                     ->where("material_box_model_id",$modelId)->first();
@@ -111,8 +193,175 @@ class StorageService
                 if ($model && $model->maximum < $amount)$model->update(["maximum"=>$amount]);
             }
             DB::commit();
+            return true;
         }catch(\Exception $e){
             DB::rollBack();
+            return false;
+        }
+    }
+
+    /**
+     * 获取FLUX上架任务列表
+     *
+     * @param string $asn
+     * @param string $barCode
+     * @param int $amount
+     *
+     * @return array|null
+     */
+    public function getFluxTask($asn,$barCode,$amount):?array
+    {
+        $sql = <<<sql
+SELECT * 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;
+        $asns = DB::connection("oracle")->select(DB::raw($sql),[$asn,$barCode,$barCode,$barCode,$amount]);
+        if (!$asns)return null;
+        $nums = [];
+        foreach ($asns as $index=>$asn){
+            if ((int)$asn->fmqty == $amount)return [$asn];
+            $nums[] = (int)$asn->fmqty;
+        }
+        $result = $this->twoSum($nums,$amount);
+        if ($result)return [$asns[$result[0]],$asns[$result[1]]];
+        return null;
+    }
+
+    /**
+     * 获取匹配数字
+     *
+     * @param Integer[] $nums
+     * @param Integer $target
+     * @return Integer[]|null
+     */
+    protected function twoSum($nums, $target) {
+        $map=[];
+        for($i=0;$i<count($nums);$i++){
+            $complement=$target-$nums[$i];
+            if(array_key_exists($complement,$map)){
+                return [$map[$complement],$i];
+            }
+            $map[$nums[$i]]=$i;
         }
+        return null;
+    }
+
+    /**
+     * flux上架
+     *
+     * @param $asn
+     * @param $ide
+     * @param $amount
+     * @return bool
+     * @throws \Throwable
+     */
+    public function fluxPA($asn,$ide,$amount)
+    {
+        if (!$asn->taskid)return false;//ASN单无此入库信息,禁止上架
+
+        $sql = <<<sql
+SELECT * FROM inv_lot_loc_id  WHERE lotnum = ? AND traceid = ? AND customerid= ?  and sku = ?
+sql;
+        $inv = DB::connection("oracle")->select(DB::raw($sql),[$asn->fmlotnum,$asn->plantoid,$asn->customerid,$asn->sku]);
+        if (count($inv)==0)return false;//余量与入库不符
+        DB::connection("oracle")->transaction(function ()use($inv,$amount,$ide,$asn,&$who){
+            $db = DB::connection("oracle");
+            $qty = $amount;
+            foreach ($inv as $in){
+                if ($qty==0)break;
+                if ($in->qty > $qty){
+                    $db->update(DB::raw("update inv_lot_loc_id set qty = qty-?,qtymvout = qty-? where lotnum = ? and locationid = ? and traceid = ?"),[
+                        $qty,$qty,$in->lotnum,$in->locationid,$in->traceid
+                    ]);//TODO 遗留问题:对应生成分配库位上架数量未被变更
+                    $in->qty = $in->qty-$qty;
+                    $qty = 0;
+                }else{
+                    $db->delete(DB::raw("DELETE FROM inv_lot_loc_id WHERE lotnum = ? and locationid = ? and traceid = ?"),[
+                        $in->lotnum,$in->locationid,$in->traceid
+                    ]);
+                    $qty = $qty-$in->qty;
+                }
+            }
+            $db->delete(DB::raw("DELETE FROM inv_lot_loc_id WHERE lotnum = ? AND traceid = ? AND traceid != '*'  AND qty = 0"),[
+                $inv[0]->lotnum,$inv[0]->traceid
+            ]);
+            $invHistory = $db->selectOne(DB::raw("SELECT * FROM inv_lot_loc_id WHERE lotnum = ? AND locationid = ? AND customerid = ? AND sku = ? AND traceid = '*' FOR UPDATE"),[
+                $inv[0]->lotnum,$ide,$inv[0]->customerid,$inv[0]->sku
+            ]);
+            $who = 'WAS'.(Auth::user() ? '-'.Auth::user()["name"] : '');
+            if ($invHistory)$db->update(DB::raw("UPDATE inv_lot_loc_id SET qty = qty+? WHERE lotnum = ? AND locationid = ? AND traceid = '*'"),[
+                (int)$amount,$inv[0]->lotnum,$ide
+            ]);
+            else $db->insert(DB::raw("INSERT INTO inv_lot_loc_id VALUES(?,?,'*',?,?,?,0,0,0,0,0,0,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,0,0,0,0,0,'*',0,null)"),[
+                $inv[0]->lotnum,$ide,$inv[0]->customerid,$inv[0]->sku,$amount,date("Y-m-d H:i:s"),$who,
+                date("Y-m-d H:i:s"),$who
+            ]);
+            $sql = <<<sql
+INSERT INTO ACT_TRANSACTION_LOG VALUES(?,'PA',?,?,?,?,'ASN',?,?,?,?,?,?,?,?,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,
+TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,0,0,0,0,TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),?,?,null,null,null,'*',?,?,?,?,?,?,?,
+?,?,?,?,?,'N',null,?,?,?,?,?,?,?,null,null)
+sql;
+            $trid = $this->getTrNumber();
+            $db->insert(DB::raw($sql),[
+                $trid,$asn->customerid,$asn->sku,
+                $asn->asnno,$asn->asnlineno,$inv[0]->lotnum,$asn->fmlocation,$asn->plantoid,$asn->packid,$asn->uom,$amount,$amount,'99',date("Y-m-d H:i:s"),$who,
+                date("Y-m-d H:i:s"),$who,date("Y-m-d H:i:s"),$asn->customerid,$asn->sku,$ide,$who,$asn->packid,$asn->uom,$amount,$amount,$inv[0]->lotnum,
+                '*','0','N','*',$asn->taskid_sequence,$asn->warehouseid,$asn->userdefine1,$asn->userdefine2,
+                $asn->userdefine3,$asn->userdefine4,$asn->userdefine5,'O'
+            ]);
+            $this->setTrNumber();
+            $sql = <<<sql
+update TSK_TASKLISTS set TASKPROCESS = '99',REASONCODE = 'OK',PLANTOLOCATION = ?,PLANLOGICALTOSEQUENCE = ?,
+CREATE_TRANSACTIONID = ?,OPENWHO = ?,OPENTIME = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),
+ CLOSEWHO = ?,CLOSETIME = ?,EDITTIME = ?,EDITWHO = ?
+ where taskid = ? AND TASKID_SEQUENCE = ?
+sql;
+            $db->update(DB::raw($sql),[
+                $ide,$ide,$trid,$who,date("Y-m-d H:i:s"),$who,date("Y-m-d H:i:s"),date("Y-m-d H:i:s"),$who,$asn->taskid,$asn->taskid_sequence
+            ]);
+        });
+        //成功后应去修改ASN状态及数量 暂时不知上架后ASN应为状态
+        /*        $sql = <<<sql
+        UPDATE doc_asn_details SET linestatus = ?,edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ? AND asnlineno = ?
+        sql;*/
+        //if ($asn->expectedqty>$asn->receivedqty && $asn->linestatus!='30')DB::connection("oracle")->update(DB::raw($sql),['30',date("Y-m-d H:i:s"),$who,$asn->asnno,$asn->asnlineno]);
+        if ($asn->expectedqty==$asn->receivedqty && $asn->linestatus=='40'){
+            //DB::connection("oracle")->update(DB::raw($sql),['40',date("Y-m-d H:i:s"),$who,$asn->asnno,$asn->asnlineno]);
+            $check = DB::connection("oracle")->selectOne(DB::raw("SELECT 1 FROM DOC_ASN_DETAILS WHERE ASNNO = ? AND LINESTATUS != '40'"),[$asn->asnno]);
+            if (!$check){
+                $logs = DB::connection("oracle")->select(DB::raw("SELECT SUM(FMQTY) qty,TRANSACTIONTYPE FROM ACT_TRANSACTION_LOG WHERE DOCNO = ? AND TRANSACTIONTYPE IN ('PA','IN') GROUP BY TRANSACTIONTYPE"),[$asn->asnno]);
+                $paQty = 0;
+                $inQty = 0;
+                foreach ($logs as $log){
+                    if ($log->transactiontype == 'IN')$inQty = $log->qty;
+                    else $paQty = $log->qty;
+                }
+                if ($paQty == $inQty){
+                    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"),$who,$asn->asnno]);
+                    DB::connection("oracle")->update(DB::raw("UPDATE DOC_ASN_DETAILS SET linestatus = '99',edittime = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),editwho = ? WHERE asnno = ?"),
+                        [date("Y-m-d H:i:s"),$who,$asn->asnno]);
+                }
+            }
+        }
+        return true;
+    }
+
+
+
+    private function getTrNumber()
+    {
+        $val = ValueStore::query()->select("value")->where("name","flux_tr_number")->first();
+        if (!$val)$val = ValueStore::query()->create(["name"=>"flux_tr_number","value"=>'0']);
+        $max = $val->value+1;
+        $number = sprintf("%09d", $max);
+        return 'W'.$number;
+    }
+
+    private function setTrNumber()
+    {
+        ValueStore::query()->select("value")->where("name","flux_tr_number")->update(["value"=>DB::raw("flux_tr_number+1")]);
     }
 }

+ 7 - 0
app/TaskTransaction.php

@@ -11,6 +11,8 @@ class TaskTransaction extends Model
     use ModelLogChanging;
 
     protected $fillable = [
+        "doc_code",
+        "bar_code",
         "fm_station_id",
         "to_station_id",
         "material_box_id",
@@ -32,4 +34,9 @@ class TaskTransaction extends Model
         0 => "无",
         1 => "缓存架半箱入库"
     ];
+
+    public function materialBox()
+    {   //料箱
+        return $this->belongsTo(MaterialBox::class);
+    }
 }

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

@@ -15,6 +15,8 @@ class CreateTaskTransactionsTable extends Migration
     {
         Schema::create('task_transactions', function (Blueprint $table) {
             $table->id();
+            $table->string("doc_code")->nullable()->comment("文档代码");
+            $table->string("bar_code")->nullable()->comment("商品条码");
             $table->string("fm_station_id")->nullable()->comment("来源库位");
             $table->string("to_station_id")->nullable()->comment("目标库位");
             $table->string("material_box_id")->nullable()->comment("料箱ID");

+ 7 - 4
resources/views/customer/project/create.blade.php

@@ -892,11 +892,14 @@
                         this.$set(this.errors,"surcharge_unit_id",["耗材附加费未填写"]);
                         return;
                     }
-                    let unit = this.model.operation.items[0].unit_id;
+                    let unit = null;
                     for (let i=1;i<this.model.operation.items.length;i++){
-                        if (this.model.operation.items[i]!==unit){
-                            this.$set(this.errors,'items.'+i+'.unit_id',["所有子项单位必须一致"]);
-                            return;
+                        if (this.model.operation.items[i].amount){
+                            if(!unit)unit = this.model.operation.items[i].unit_id;
+                            else if(unit !== this.model.operation.items[i].unit_id){
+                                this.$set(this.errors,'items.'+i+'.unit_id',["所有子项单位必须一致"]);
+                                return;
+                            }
                         }
                     }
                     if (!this.model.operation.isSingle){