do_set_material_input_by_item_code($post); } /* 装配段设备物料投料出现以下场景: 一、一个或多个原材料+裸电芯半成品 => 单个成品电池 例子:铝塑膜+焊接裸电芯 => 包装成品电池 接口api示例 { "action": "set_material_input_by_item_code", "param": { "batch": "batch1", "workingsubclass": "BZ", "device_code": "BZ-1", "in": [{ "item_code":"tongbo", "item_batch": "fengezi-1", "item_quantity":"345.34", "item_id": "-1" }] } } */ /* * 通过batch->flow->model->bom->workingsubclass->BomRelationship对应的bom结构 * 1.获取请求体设备编码参数 * 2.判断工序单元、设备编码是存在?根据设备编码查询批次工序日志表,判断该设备是否已经存在生产中物料信息 * 3.获取生产批次关联工艺流程,工艺流程关联型号,型号关联bom,bom关联bom关系,bom关系关联物料信息 * 4.通过以上关联信息查询物料编码 * 4.1.获取bom的物料编码 * 4.2.获取param_in结构的物料编码 * 5.检查上传param参数中in结构是否缺少物料 * 6.剔除上传param参数中in结构多余物料信息,获取最终需要处理param_in * 7.判断原材料或半成品是否已经投入批次工序日志缓存表,不允许重复再投,只能先把上一次投入物料结束,才能允许再投入; * 8.拼接存储结构,上传数据到批次工序日志缓存表;原材料新增数据,半成品更改半成品状态为0 * 9.半成品更改半成品状态为0,表示进行设备投料 * 10.原材料数组数据写入缓存表 */ private function do_set_material_input_by_item_code($post) { // 验证数据 $param = $post['param']; try{ if(empty($param["workingsubclass"])){ throw new Exception("缺少workingsubclass参数"); } if(empty($param["device_code"])){ throw new Exception("缺少device_code参数"); } if(empty($param["in"]) || count($param["in"]) < 0){ throw new Exception("缺少in参数"); } //1.获取请求体设备编码参数 $workingsubclass = $param["workingsubclass"]; $batch = $param["batch"]; $device_code = $param["device_code"]; $param_in = $param["in"]; // 缓存wip的item_id,为后续通过item_id获取batch $wip_item_id = ''; // 判断in结构参数是否上传 foreach($param_in as $key=>$values){ if(empty($values["item_code"])){ throw new Exception("上传的in结构内,第".($key+1)."个item_code参数缺少数据"); } if(empty($values["item_batch"])){ throw new Exception("上传的in结构内,第".($key+1)."个item_batch参数缺少数据"); } if(!isset($values["item_quantity"]) && $values["item_quantity"]==""){ throw new Exception("上传的in结构内,第".($key+1)."个item_quantity参数缺少数据"); } if(empty($values["item_id"])){ throw new Exception("上传的in结构内,第".($key+1)."个item_id参数缺少数据"); } } // 判断in结构内item_code、item_id是否有重复值,同时忽略键值对[['key'=> 'item_id','value'=> '-1'] // 指定需要校验的键名 $check_keys = ['item_code','item_id']; // 忽略条件,可能存在多个原材料投入,所以需要忽略item=-1 $ignore_key_value_pairs = [ ['key' => 'item_id', 'value' => '-1'], ]; $duplicates = findDuplicates($param_in, $check_keys, $ignore_key_value_pairs); if (!empty($duplicates)) { $duplicates_str = '上传的in结构内,'; foreach($duplicates as $key=>$value){ $duplicates_str .= '参数'.$key.'存在重复值【'.implode("、",$value).'】,'; } throw new Exception($duplicates_str); } //2.判断工序单元、设备编码是存在?根据设备编码查询批次工序日志表,判断该设备是否已经存在生产中物料信息 $sql = "SELECT id FROM hf_mes_process_workingsubclass WHERE code='".$workingsubclass."'"; $ret = Db::fetch($sql); if(empty($ret)){ throw new Exception("工序单元[$workingsubclass]不存在"); } $sql = "SELECT id FROM hf_mes_device WHERE code='".$device_code."'"; $ret = Db::fetch($sql); if(empty($ret)){ throw new Exception("设备编码[$device_code]不存在"); } //判断是否存在已经上料的物料 $param_in_item_code = array_column($param_in,'item_code'); $sql = "SELECT item_code FROM hf_mes_bkv_batch_process_log WHERE item_code IN ('". implode("','",$param_in_item_code)."') AND status=0"; $ret = Db::fetchAll($sql); if($ret){ throw new Exception('工序单元['.$workingsubclass.']下设备编码['.$device_code.']已经存在投入['. implode(',',array_column($ret,'item_code')).']物料生产批次信息'); } //3.获取生产批次关联工艺流程,工艺流程关联型号,型号关联bom,bom关联bom关系,bom关系关联物料信息 $subbatch = ''; $process_code = ''; $sql = "SELECT b.subbatch,c.process FROM hf_mes_production_planning_management_batch a INNER JOIN hf_mes_production_planning_management_subbatch b ON a.id = b.batch_id INNER JOIN hf_mes_technology_flow c ON b.flow_id = c.id WHERE batch='".$batch."' ORDER BY b.id DESC LIMIT 1"; $ret = Db::fetch($sql); if(empty($ret)){ throw new Exception("批次[".$batch."]不存在子批次信息,请检查批次是否已创建"); } $subbatch = $ret['subbatch']; // 拿到工序编码 foreach(json_decode($ret['process'],true) as $val){ if($val[4] == $workingsubclass){ $process_code = $val[2]; } } //4.通过以上关联信息查询物料编码 $sql = "SELECT e.code as bom_source_code,d.bom_source_id,e.name as bom_source_name,d.bom_id,f.code as bom_source_category_code FROM hf_mes_production_planning_management_batch a INNER JOIN hf_mes_technology_flow b ON a.flow_id = b.id INNER JOIN hf_mes_product_bom c ON b.product_model_id = c.product_model_id INNER JOIN hf_mes_product_bom_relationship d ON c.id = d.bom_id INNER JOIN hf_mes_product_bom_source e ON d.bom_source_id = e.id INNER JOIN hf_mes_product_bom_source_category f ON e.bom_source_category_id = f.id WHERE a.batch='".$batch."' AND d.in_workingsubclass='".$workingsubclass."'"; $ret = Db::fetchAll($sql); if(empty($ret)){ throw new Exception('批次'.$batch.'下的工序单元'.$workingsubclass.',bom关系不存在in结构物料编码'); } //4.1获取bom的物料编码 $bom_relationship_array = $ret; $bom_relationship_item_code = array_column($ret,'bom_source_code'); //4.2获取param_in结构的物料编码 $param_in_item_code = array_column($param_in, 'item_code'); $missing_material = []; foreach($param_in_item_code as $key=>$val){ if(!in_array($val,$bom_relationship_item_code) ){ $missing_material[]=$val; } } if(count($missing_material)>0){ throw new Exception("上传param中in结构的item_code物料[".implode(',',$missing_material)."]不在本生产批次[$batch]的[$workingsubclass]工序中投料"); } $uuid = []; $wip_uuid = []; $pid = []; // 6、剔除上传param参数中in结构多余物料信息,获取最终需要处理param_in foreach($param_in as $key=>$value){ if(!in_array($value['item_code'],$bom_relationship_item_code)){ unset($param_in[$key]); }else{ // 7、判断原材料或半成品是否已经投入批次工序日志缓存表,不允许重复再投,只能先把上一次投入物料结束,才能允许再投入; // 如果是某一物料追加再投,用其他接口进行处理 #物料虚拟码,当item_id=-1时,代表原材料;当item_id!=-1,代表半成品(wip) if($value['item_id'] == '-1'){ // 判断原材料是否已投入但还未结束,如果是则报警不给投入 $sql = "SELECT id FROM hf_mes_bkv_batch_process_log WHERE workingsubclass='".$workingsubclass."' AND item_device_code='".$device_code."' AND item_code='".$value['item_code']."' AND status=0 ORDER BY id DESC LIMIT 1"; $ret = Db::fetch($sql); if(!empty($ret)){ throw new Exception("工序单元[$workingsubclass]下设备[$device_code]已有正在生产中的物料[".$value['item_code']."],如需投料请先结束生产中的物料"); } }else{ // 判断半成品是否存在,且状态是未结束;如果不存在或状态是结束,则报警不给投入 $sql = "SELECT id,uuid,status FROM hf_mes_bkv_batch_process_log WHERE item_id='".$value['item_id']."' ORDER BY id DESC LIMIT 1"; $ret = Db::fetch($sql); if(empty($ret)){ throw new Exception("物料[".$value['item_code']."]不存在半成品信息[".$value['item_id']."],请检查半成品信息是否存在批次工序日志缓存表"); } if($ret['status'] != '-1' && $ret['status'] != '-2'){ throw new Exception("物料[".$value['item_code']."]对应半成品信息[".$value['item_id']."已投料或已生产完成,不允许重复投料,请检查物料状态信息"); } $uuid = array_merge($uuid, json_decode($ret["uuid"])); $wip_uuid[$value['item_id']] = $ret["uuid"]; $pid[$value['item_id']] = $ret["pid"]; } // 把bom_source_id、bom_id、bom_source_category_code加进param,为后续拼接insert sql做准备 foreach ($bom_relationship_array as $k => $v) { if($v['bom_source_code'] == $value['item_code']){ $param_in[$key]['bom_source_id'] = $v['bom_source_id']; $param_in[$key]['bom_source_name'] = $v['bom_source_name']; $param_in[$key]['bom_id'] = $v['bom_id']; $param_in[$key]['bom_source_category_code'] = $v['bom_source_category_code']; } } // 冻结解冻列表设置拦截工序调用该接口就会反馈给class和classname到设备 if ($value['item_id'] != '-1') { $freeze_data = Event::emit('FreezeInterceptionEvent.handle', [ 'battery_id' => $v['item_id'], 'workingsubclass' => $ret['next_workingsubclass'], 'ropes_time' => date("Y-m-d H:i:s"), ]); $h = $k + 1; if (!empty($freeze_data)) { // 检查 status 是否为 5 和 workingsubclass为ALLPROCESS if ($freeze_data['status'] == 5 && $freeze_data['workingsubclass'] = 'ALLPROCESS') { throw new Exception("(!!!紧急冻结全工序!!!)第[{$h}]位置半成品物料{$value['item_id']}在工序[{$workingsubclass}]已被标记[{$freeze_data['classname']}]冻结,需要设备排出或人工取出!!!"); // 检查 status 是否为 1 } elseif ($freeze_data['status'] == 1) { throw new Exception("(!!!请先解冻再复投!!!)第[{$h}]位置半成品物料{$value['item_id']}在工序[{$workingsubclass}]已被标记[{$freeze_data['classname']}]冻结,需要设备排出或人工取出!!!"); } // 默认冻结报错逻辑 throw new Exception("第[{$h}]位置半成品物料{$value['item_id']}在工序[{$workingsubclass}]已被标记[{$freeze_data['classname']}]冻结,需要设备排出或人工取出!!!"); } } } } // 如果存在半成品uuid,则用半成品uuid,否则默认为[] $uuid = json_encode(array_unique($uuid)); $finish_time = date("Y-m-d H:i:s"); }catch(Exception $e){ throw new Exception($e->getMessage()); } // 开启事务 Db::beginTrans(); try { // 8、拼接存储结构,上传数据到批次工序日志缓存表;原材料新增数据,半成品更改半成品状态为0 $material_insert_sql_head = 'INSERT INTO "hf_mes_bkv_batch_process_log" (item_id, batch, subbatch, workingsubclass, process_code, device_code, item_device_code, status, start_time, finish_time, bom_source_id, item_batch, item_quantity, pid, uuid, bom_id, item_code,item_name, lot, tray) VALUES' ; $material_insert_sql_val = []; foreach($param_in as $key=>$value){ $item_id = $value['item_id']; if($value['item_id'] == '-1'){ // 生成MES内部item_id $item_id = generate_material_item_id($workingsubclass, $value['bom_source_category_code'], $value['item_code']); } $material_insert_sql_val[] = sprintf( "('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s')", $item_id, $batch, $subbatch, $workingsubclass, $process_code, $device_code, $device_code, 0, $finish_time, $finish_time, $value['bom_source_id'], $value['item_batch'], $value['item_quantity'], $value['item_id'] == '-1' ? -1 : $pid[$value['item_id']], $value['item_id'] == '-1' ? $uuid : $wip_uuid[$value['item_id']], $value['bom_id'], $value['item_code'], $value['bom_source_name'], strtotime(date('Y-m-d H:i:s')), '-1' ); } //10.原材料数组数据写入缓存表 $sql = $material_insert_sql_head . implode(',', $material_insert_sql_val); $row = Db::query($sql); if ($row === NULL) { throw new Exception("原材料新增批次工序日志缓存表失败"); } } catch (Exception $e) { Db::rollBackTrans(); throw new Exception($e->getMessage()); } Db::commitTrans(); return ''; } }