SCTMES_V5/mes_in_sct/app/action/SetBatteryProcessResult.php
2025-06-14 18:55:09 +08:00

392 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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 '';
}
}