SCTMES_V5/mes_in_sct/app/action/SetBatteryProcessResult.php

392 lines
17 KiB
PHP
Raw Permalink Normal View History

2025-06-14 18:55:09 +08:00
<?php
namespace app\action;
use Exception;
use libs\db\Db;
use libs\listener\Event;
class SetBatteryProcessResult
{
public function execute($post)
{
// 验证数据
$param = check_valid($post['action'], [
['battery_ids', 'array', '电池条码数据'],
['workingsubclass', 'string', '工序单元'],
['device_code', 'string', '设备编码']
], $post['param']);
$date = date('Y-m-d H:i:s');
$param['DEVICE_CODE'] = [];
$param['FINISH_TIME'] = [];
list($battery_ids, $workingsubclass, $device_code) = [
$param['battery_ids'],
$param['workingsubclass'],
$param['device_code'],
];
try {
// 判断上传上来的device_code是否存在
$sql = sprintf(
"SELECT device_category_id,code,name
FROM hf_mes_device
WHERE code='%s' LIMIT 1;",
$device_code
);
$ret = Db::fetch($sql);
if (empty($ret)) {
throw new Exception("设备编码[{$device_code}]不存在,请检查");
}
$device_category_id = $ret['device_category_id'];
list($first_batch, $check_battery_ids) = ['', array()];
foreach ($battery_ids as $key => $battery_id) {
// 判断电池是否为空
if (empty($battery_id)) {
throw new Exception("电池条码数组第[{$key}]位置的电池条码不能是:[0, '0', '', null, NAN]等,请上传电池条码", 4006);
}
// 判断如果查询不到battery_map的数据pid赋予-2uuid赋予空数组
$pid = '-2';
$uuid = json_encode([]);
// 判断是否存在battery_map中
$sql = sprintf(
"SELECT batch,tray,lot,subbatch,pid,uuid
FROM hf_mes_production_battery_map
WHERE battery_id='%s' ORDER BY id DESC LIMIT 1;",
$battery_id
);
$ret = Db::fetch($sql);
if (empty($ret)) {
$key += 1;
throw new Exception("电池数组[battery_ids]第[{$key}]位置的电池[{$battery_id}]数据不存在系统中,请检查");
}
$pid = !empty($ret['pid']) ? $ret['pid'] : $pid;
$uuid = !empty($ret['uuid']) ? $ret['uuid'] : $uuid;
list($old_batch, $old_tray, $old_lot, $old_subbatch) = [
$ret['batch'],
$ret['tray'],
$ret['lot'],
$ret['subbatch']
];
if ($key == 0) {
$first_batch = $old_subbatch;
}
// 确认电池在之前托盘是激活状态
$sql = sprintf(
"SELECT next_process_code
FROM \"%s\"
WHERE battery_id='%s' AND tray='%s' AND lot='%s' AND active=1 LIMIT 1;",
'hf_mes_tmp_bkv_' . $old_subbatch,
$battery_id,
$old_tray,
$old_lot
);
$ret = Db::fetch($sql);
if (empty($ret)) {
$key += 1;
throw new Exception("电池数组[battery_ids]第[{$key}]位置的电池[{$battery_id}]在原托盘[{$old_tray}]中不是激活状态,请检查");
}
$next_process_code = $ret['next_process_code'];
// 所有录入的电池的批次必须是一样的
if ($first_batch != $old_subbatch) {
$key += 1;
throw new Exception("电池数组[battery_ids]第[{$key}]位置的电池[{$battery_id}]与第一个电池的批次不一致,请检查");
}
array_push($check_battery_ids, [
'battery_id' => $battery_id,
'tray' => $old_tray,
'lot' => $old_lot,
'next_process_code' => $next_process_code,
'pid' => $pid,
'uuid' => $uuid,
]);
}
// 判断所有电池的工序是否一致
$sql = sprintf(
"SELECT flow_id
FROM hf_mes_production_planning_management_subbatch
WHERE subbatch='%s' LIMIT 1;",
$first_batch
);
$ret = Db::fetch($sql);
$flow_id = $ret['flow_id'];
$current_process_code = "{$flow_id}_{$workingsubclass}";
// 验证所有电池的当前工序编码是否与当前的工序一致
foreach ($check_battery_ids as $item) {
if ($item['next_process_code'] != $current_process_code) {
throw new Exception("电池[{$item['battery_id']}]当前工序编码[{$item['next_process_code']}]与当前上传数据要求的设备工序编码[{$current_process_code}]不一致,请检查!");
}
}
// 判断结果参数是否都上传了
$sql = sprintf(
"SELECT a.id,b.process
FROM hf_mes_technology_process AS a
INNER JOIN hf_mes_technology_flow b ON b.id = a.flow_id
WHERE a.code='%s' LIMIT 1;",
$current_process_code
);
$ret = Db::fetch($sql);
list($flow_process, $process_id) = [
json_decode($ret['process'], true),
$ret['id']
];
// 根据电池数组赋予通道数据
$param['CHANNEL'] = array_map(function ($value) {
return $value + 1;
}, array_keys($battery_ids));
// 赋予设备结果参数数组
$param['DEVICE_CODE'] = array_pad($param['DEVICE_CODE'], count($battery_ids), $device_code);
// 赋予完成时间结果参数数组
$param['FINISH_TIME'] = array_pad($param['FINISH_TIME'], count($battery_ids), $date);
// 刷选出需要设备上传的结果参数
$sql = sprintf(
"SELECT code,field_type,is_upload
FROM hf_mes_technology_process_result_param
WHERE process_id=%s AND is_upload=1;",
$process_id
);
$result_param_need = Db::fetchAll($sql);
if (!empty($result_param_need)) {
$result_param_need_params = array_column($result_param_need, 'code');
// 验证提交的结果数据
// 1、验证是否上传了结果参数
$diff = array_diff($result_param_need_params, array_keys($param));
if (!empty($diff)) {
throw new Exception("结果参数:[{" . implode(',', $diff) . "}]没有上传");
}
// 1、验证结果参数是否是数组格式
// 2、验证结果参数的数组长度是否与电池数量一致
// 3、验证具体的结果数据有没有上传与数据的类型
foreach ($result_param_need as $item) {
// 1、验证结果参数是否是数组格式
if (!is_array($param[$item['code']])) {
throw new Exception("上传的结果参数[{$item['code']}] 需要是数组!结果数据均为数组格式,请检查!");
}
// 1、验证结果参数的数组长度是否与电池数量一致
if (count($param[$item['code']]) != count($battery_ids)) {
$count = count($battery_ids);
throw new Exception("结果参数[{$item['code']}]的数组长度与电池数量不相等,电池数量为:[{$count}],请检查");
}
// 结果参数数组
$p_vals = $param[$item['code']];
// 结果参数类型
$p_class = $item['field_type'];
// 2、验证具体的结果数据有没有上传与数据的类型
foreach ($p_vals as $p_key => $p_val) {
if ($p_class == 'TIMESTAMP') {
if ($p_val != "" && date('Y-m-d H:i:s', strtotime($p_val)) != $p_val) {
throw new Exception(sprintf(
"结果数据[%s]第[%s]位置的数据类型与系统[%s]类型要求不相符,请检查!【要求数据类型格式比如为:'2022-11-11 09:00:00'】",
$item['code'],
$p_key + 1,
$p_class
));
}
} elseif ($p_class == 'FLOAT') {
if ($p_val != "" && !is_numeric($p_val)) {
throw new Exception(sprintf(
"结果数据[%s]第[%s]位置的数据类型与系统[%s]类型要求不相符,请检查!【要求数据类型格式比如为: 12.8】",
$item['code'],
$p_key + 1,
$p_class
));
}
} elseif ($p_class == 'INT') {
if ($p_val != "" && !is_int($p_val)) {
throw new Exception(sprintf(
"结果数据[%s]第[%s]位置的数据类型与系统[%s]类型要求不相符,请检查!【要求数据类型格式比如为: 12】",
$item['code'],
$p_key + 1,
$p_class
));
}
}
}
}
} else {
$result_param_need = [];
}
// 把完成时间加入到结果参数上传之中
array_push(
$result_param_need,
['code' => 'FINISH_TIME', 'field_type' => 'TIMESTAMP', 'is_upload' => 0],
['code' => 'DEVICE_CODE', 'field_type' => 'VARCHAR', 'is_upload' => 0]
);
// 判断是否有下一工序
$current_process_idx = -1;
$next_next_process_code = '-1';
$flow_process_column = array_column($flow_process, null, '2');
if ($flow_process_column[$current_process_code][0] < (count($flow_process) - 1)) {
$next_next_process_code = $flow_process[$flow_process_column[$current_process_code][0] + 1][2];
} elseif ($flow_process_column[$current_process_code][0] == (count($flow_process) - 1)) {
$next_next_process_code = '-1';
} else {
$next_next_process_code = '-1';
}
$current_process_idx = $flow_process_column[$current_process_code][0];
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
// 开启事务
Db::beginTrans();
try {
// 标记最后一条数据的状态
Event::emit('SetProcessLogEvent.updateLastStatus', $battery_ids);
// 更新BKV数据
$common_update_str = sprintf(
"process_code='%s',process_idx=%s,next_process_code='%s'",
$current_process_code,
$current_process_idx,
$next_next_process_code
);
// 判断如果是最后一个工序,拼接取消激活的状态修改
if ($next_next_process_code == -1) {
$common_update_str = $common_update_str . ',active=0';
}
// process_log数据
$insert_process_log_data = [];
foreach ($check_battery_ids as $battery_index => $val) {
// 过滤0的数据
if ($val['battery_id'] === '0') {
continue;
}
$bkv_update_str = '';
$ng_code = '';
foreach ($result_param_need as $p_val) {
// 结果参数
$p_param = $p_val['code'];
// 结果参数类型
$p_class = $p_val['field_type'];
// 结果参数值
$p_param_val = trim($param[$p_param][$battery_index]);
if (in_array($p_class, ['FLOAT', 'INT'])) {
$bkv_update_str .= "\"{$current_process_code}.{$p_param}\"={$p_param_val},";
} else {
$bkv_update_str .= "\"{$current_process_code}.{$p_param}\"='{$p_param_val}',";
}
// 判断NG是否存在
if ($p_param == 'NG') {
if ($p_param_val != '') {
$ng_code = $p_param_val;
} else {
$ng_code = 0;
}
}
}
if (!empty($bkv_update_str)) {
$bkv_update_str = $bkv_update_str . $common_update_str;
} else {
$bkv_update_str = $common_update_str;
}
$sql = sprintf(
"UPDATE \"%s\" SET %s WHERE battery_id='%s' AND tray='%s' AND lot='%s'",
config('app.bkv_prefix') . $first_batch,
$bkv_update_str,
$val['battery_id'],
$val['tray'],
$val['lot']
);
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("PROCESS update failed:[tmp_bkv]");
}
$forward_tracing_uuid = [];
//读取这个电池在process_log表中最新一条记录的forward_tracing_uuid如果有的话没有的话则赋值uuid
$sql = "SELECT forward_tracing_uuid
FROM hf_mes_bkv_batch_process_log
WHERE item_id = '" . $val['battery_id'] . "'
ORDER BY id DESC
LIMIT 1";
$ret = Db::fetch($sql);
if (!empty($ret)) {
$forward_tracing_uuid = $ret['forward_tracing_uuid'];
}
// 组装process_log新增数据
array_push($insert_process_log_data, [
'item_id' => $val['battery_id'],
'batch' => $old_batch,
'subbatch' => $first_batch,
'tray' => $val['tray'],
'lot' => $val['lot'],
'process_code' => $current_process_code,
'workingsubclass' => $workingsubclass,
'device_code' => $device_code,
'device_category_id' => $device_category_id,
'channel' => $param['CHANNEL'][$battery_index],
'finish_time' => $param['FINISH_TIME'][$battery_index],
'input_finish_time' => $param['FINISH_TIME'][$battery_index],
'status' => -1,
'pid' => $val['pid'],
'uuid' => $val['uuid'],
'last_status' => 1,
'ng_code' => $ng_code ? $ng_code : 0,
'class' => $ng_code ? 'NG' : null,
'forward_tracing_uuid' => $forward_tracing_uuid ?: $val['uuid']
]);
}
// 写入process_log的数据(同步)
Event::emit('SetProcessLogEvent.handle', $insert_process_log_data);
// 写入曲线数据(同步)
Event::emit('CurveDataPathEvent.handle', ["end_time" => isset($param["end_time"]) ? $param["end_time"] : "", "workingsubclass" => $workingsubclass, "data" => $insert_process_log_data]);
// 结果参数转发到scada(异步)
Event::emit('SendProcessResultParamsToScadaEvent.handle', ["workingsubclass" => $workingsubclass, "device_code" => $device_code, "param" => $post['param'], "batch" => $old_batch]);
} catch (Exception $e) {
Db::rollBackTrans();
throw new Exception($e->getMessage());
}
Db::commitTrans();
$data['process_code'] = $current_process_code;
$data['class_name'] = get_class($this);
$data['log_data'] = $insert_process_log_data;
try {
// 写入process_log的数据(同步)
$response = Event::emit('ExtScriptEvent.extScriptEnd', $data);
if ($response['ext_script_code'] != 0) {
throw new Exception($response['ext_script_msg']);
}
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
return '';
}
}