SCTMES_V5/mes_in_sct/app/action/SetWipOutput.php
hui 74d0818775
All checks were successful
Run Unit Tests / test (pull_request) Successful in 5s
🐎 ci(更新测试):
2025-06-16 10:48:33 +08:00

463 lines
24 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 libs\listener\Event;
use libs\db\Db;
use Exception;
// 半成品产出
class SetWipOutput
{
public function execute($post)
{
return $this->do_set_wip_output($post);
}
/*
制片段、装配段设备半成品产出出现以下场景:
一、1个生产批次下物料投入 => 产出当前生产批次半成品
例子:正极制片段物料 => 正极制片段半成品(生产批次用物料投入生产批次)
二、2个以上生产批次下物料投入 => 产出新生产批次半成品
例子:正极制片物料半成品 + 负极制片物料半成品 + 原材料 => 装配段半成品(用上传批次作为生产批次)
接口api示例
{
"action": "set_wip_output",
"param": {
"batch": "", #当batch不为空代表装配段第一个工序把正极制片段、负极制片段投入物料合并到装配段上当batch为空时代表正极制片段、负极制片段工序batch以投入物料batch为准
"workingsubclass": "ZJ", # 工序单元
"device_code": "FJZJ-1", # 设备编码
"item_quantity":"", # 半成品产出数量比如浆料产出500.234kg、卷料产出1000m等
"out": {
"START_TIME":"tongbo", # 开始时间
"FINISH_TIME": "fengezi-1", # 结束时间
"DEVICE_CODE": "fengezi-1" # 设备编码
}
}
}
*/
/*
* 通过batch->flow->model->bom->workingsubclass->BomRelationship对应的bom结构
* 1.获取请求体设备编码参数
* 2.判断工序单元、设备编码是存在?根据设备编码查询批次工序日志表,判断该设备是否已经存在生产中物料信息
* 3.获取生产批次关联工艺流程工艺流程关联型号型号关联bombom关联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_wip_output($post)
{
// 验证数据
$param = $post['param'];
$data_list = [];
try {
// 1.判断请求参数是否完整
if (empty($param["workingsubclass"])) {
throw new Exception("缺少workingsubclass参数");
}
if (empty($param["device_code"])) {
throw new Exception("缺少device_code参数");
}
if (!isset($param["cut_list"]) || $param["cut_list"] === '') {
throw new Exception("缺少cut_list分切卷号参数");
}
if (empty($param["item_quantity"])) {
throw new Exception("缺少item_quantity参数");
}
if (empty($param["out"])) {
throw new Exception("缺少out参数");
}
$batch = $param["batch"];
$workingsubclass = $param["workingsubclass"];
$cut_list = $param["cut_list"];
$device_code = $param["device_code"];
$item_quantity = $param["item_quantity"];
$param_out = $param["out"];
//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]不存在");
}
//3.获取生产批次关联工艺流程工艺流程关联型号型号关联bombom关联bom关系bom关系关联物料信息
if (empty($batch)) {
// 当batch为空时代表正极制片段、负极制片段工序batch以投入物料batch为准
$sql = "SELECT batch FROM hf_mes_bkv_batch_process_log WHERE workingsubclass='" . $workingsubclass . "' AND item_device_code='" . $device_code . "' AND status=0 ORDER BY id DESC LIMIT 1";
$ret = Db::fetch($sql);
if (empty($ret)) {
throw new Exception('工序单元[' . $workingsubclass . ']下设备编码[' . $device_code . ']找不到对应投入物料生产批次信息');
}
$batch = $ret['batch'];
}
$subbatch = '';
$process_code = '';
$next_process_code = '-1'; //下一工序编码
$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'];
// 拿到工序编码
$ret_process = json_decode($ret['process'], true);
// 拿到工序编码
foreach ($ret_process as $key => $val) {
if ($val[4] == $workingsubclass) {
if (isset($ret_process[$key + 1])) {
$next_process_code = $ret_process[$key + 1][2];
}
$process_code = $val[2];
}
}
//4.通过以上关联信息查询物料编码
$sql = "SELECT a.flow_id,e.code as bom_source_code,e.name as bom_source_name,d.bom_source_id,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
LEFT JOIN hf_mes_product_bom_source_category f ON e.bom_source_category_id = f.id
WHERE a.batch='" . $batch . "' AND d.out_workingsubclass='" . $workingsubclass . "'";
$ret = Db::fetch($sql);
if (empty($ret)) {
throw new Exception('批次' . $batch . '下的工序单元' . $workingsubclass . 'bom关系不存在out结构物料编码');
}
//4.1获取bom的物料编码
$bom_relationship_array = $ret;
$bom_id = $ret['bom_id'];
// 5.获取批次、工序单元对应process_code的结果参数对比工序结果参数与上传参数是否对应
$flow_id = $ret['flow_id'];
$flow_process_code = $flow_id . '_' . $workingsubclass;
$sql = "SELECT b.code,b.field_type FROM hf_mes_technology_process a
INNER JOIN hf_mes_technology_process_result_param b ON a.id = b.process_id
WHERE a.code='" . $flow_process_code . "'";
$ret = Db::fetchAll($sql);
if (empty($ret)) {
throw new Exception('工序编码' . $flow_process_code . '不存在结果参数');
}
// 6.检查上传的结果参数是否缺少,并拼接结果参数
$sql_key_out_result_param = [];
$sql_val_out_result_param = [];
$result_param_out = array_keys($param_out);
foreach ($ret as $key => $val) {
if (!in_array($val['code'], $result_param_out)) {
throw new Exception("上传的结果参数里不含有该参数: " . $val["code"]);
}
// 上传结果参数值
$param_out_val = $param_out[$val['code']];
// 数据类型
$field_type = $val['field_type'];
// 验证上传结果参数值与数据类型是否一致
$verify_result = verify_data_type($val['code'], $param_out_val, $field_type);
if ($verify_result != '') {
throw new Exception($verify_result);
}
$sql_key_out_result_param[] = '"' . $flow_process_code . "." . $val["code"] . '"';
if ($param_out_val === "") {
$sql_val_out_result_param[] = 'NULL';
} else {
$sql_val_out_result_param[] = "'" . $param_out_val . "'";
}
}
// 7.获取设备投入物料信息为后续追加battery_map、bkv表做准备
$sql = "SELECT * FROM hf_mes_bkv_batch_process_log WHERE workingsubclass='" . $workingsubclass . "' AND item_device_code='" . $device_code . "' AND status=0";
$material_input_ret = Db::fetchAll($sql);
if (empty($material_input_ret)) {
throw new Exception('工序单元[' . $workingsubclass . ']下设备编码[' . $device_code . ']找不到对应投入物料信息');
}
$item_code_in_process_log = array_column($material_input_ret, "item_code");
//获取正向追溯的uuid
$forward_tracing_uuid_in_process_log = array_column($material_input_ret, "forward_tracing_uuid");
$forward_tracing_uuid = [];
foreach ($forward_tracing_uuid_in_process_log as $json_str) {
$decoded = json_decode($json_str, true); // 转成数组
if (is_array($decoded)) {
$forward_tracing_uuid = array_merge($forward_tracing_uuid, $decoded);
}
}
//对比物料信息是否与process_log表的item_code是否相同
$sql = "SELECT b.code,b.name as bom_source_name FROM hf_mes_product_bom_relationship as a
INNER JOIN hf_mes_product_bom_source b ON a.bom_source_id = b.id
WHERE a.in_workingsubclass ='$workingsubclass' AND bom_id=" . $bom_id . " ;";
$ret = Db::fetchAll($sql);
if (empty($ret)) {
throw new Exception('批次' . $batch . '下的工序单元' . $workingsubclass . 'bom关系不存在in结构物料编码');
}
$item_code_diff = array_diff(array_column($ret, "code"), $item_code_in_process_log);
if (count($item_code_diff) > 0) {
throw new Exception('工序单元[' . $workingsubclass . ']下设备编码[' . $device_code . ']找不到对应[' . implode(",", $item_code_diff) . ']投入物料生产批次信息');
}
$bom_source_name_array = array_column($ret, 'bom_source_name', 'code');
$pid = [];
$uuid = [];
$battery_map_sql_val = [];
$wip_uuid = [];
$bkv_sql_val = [];
$last_time = null;
// 8. 通过item_id判断物料是否已存在battery_map不存在则新增battery_map和bkv表如果存在不做处理
foreach ($material_input_ret as $key => $value) {
if (empty($last_time)) {
$last_time = $value['start_time'];
} else {
$last_time = strtotime($last_time) < strtotime($value['start_time']) ? $value['start_time'] : $last_time;
}
$battery_id = $value['item_id'];
$pid[] = $battery_id;
$uuid = array_merge($uuid, json_decode($value["uuid"]));
$wip_uuid = $value['pid'] != "-1" ? array_merge($wip_uuid, json_decode($value["uuid"])) : array_merge($wip_uuid, []);
$sql = "SELECT * FROM hf_mes_production_battery_map WHERE battery_id='" . $battery_id . "' ORDER BY id DESC LIMIT 1";
$material_input_battery_map_ret = Db::fetch($sql);
if (empty($material_input_battery_map_ret)) {
// 拼接插入battery_map_sql_val值
$battery_unique_value = "{$value['batch']}_{$value['subbatch']}_{$value['tray']}_{$value['lot']}_{$battery_id}";
$battery_map_sql_val[] = sprintf(
"('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
$value['bom_source_id'],
$battery_unique_value,
$battery_id,
$value['batch'],
$value['subbatch'],
$value['lot'],
$value['tray'],
$value['item_batch'],
$value['item_device_code'],
$value['pid'],
$value['uuid'],
$value['bom_id'],
$value['workingsubclass'],
$value['item_code'],
$bom_source_name_array[$value['item_code']]
);
$bkv_sql_val[] = sprintf(
"('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
$battery_id,
$value['tray'],
$value['lot'],
1,
$value['process_code'],
$next_process_code,
$value['item_code'],
$bom_source_name_array[$value['item_code']],
$value['item_batch'],
$value['item_device_code'],
$value['start_time'],
$value['pid'],
$value['uuid'],
$value['bom_source_id'],
$value['bom_id']
);
}
}
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
Db::beginTrans();
try {
// 标记最后一条数据的状态
if (!empty($pid)) {
Event::emit('SetProcessLogEvent.updateLastStatus', $pid);
}
// 9.投入物料新增数据到battery_map、bkv表
if (count($battery_map_sql_val) > 0) {
$battery_map_sql_head = 'INSERT INTO "hf_mes_production_battery_map" (bom_source_id, battery_unique_value, battery_id, batch, subbatch, lot, tray, item_batch, item_device_code, pid, uuid, bom_id, workingsubclass, item_code, item_name) VALUES';
$bkv_sql_head = 'INSERT INTO "hf_mes_tmp_bkv_' . $subbatch . '" (battery_id, tray, lot, active, process_code,next_process_code, item_code, item_name, item_batch, item_device_code, item_batch_start_time, pid, uuid, bom_source_id, bom_id) VALUES';
$sql = $battery_map_sql_head . implode(',', $battery_map_sql_val);
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("投入物料信息插入battery_map表失败");
}
$sql = $bkv_sql_head . implode(',', $bkv_sql_val);
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("投入物料信息插入bkv表失败");
}
}
// 10.产出半成品新增数据到process_log、battery_map、bkv表
// uuid如果为空数组则自动创建uuid否则用不为空数组做uuid
if (count($uuid) <= 0) {
$uuid[] = generateUniqueId();
$uuid = json_encode($uuid);
} else {
$uuid = json_encode(array_unique($uuid));
}
//保证每个正向追溯的uuid都是唯一的
$forward_tracing_uuid = json_encode(array_unique(array_merge($forward_tracing_uuid, [generateUniqueId()])));
$wip_uuid = count($wip_uuid) <= 0 ? $uuid : json_encode(array_values(array_unique($wip_uuid)));
$now_date = date('Y-m-d H:i:s');
$start_time = $last_time; //isset($param_out['START_TIME'])? $param_out['START_TIME'] : date('Y-m-d H:i:s');
$finish_time = isset($param_out['FINISH_TIME']) ? $param_out['FINISH_TIME'] : date('Y-m-d H:i:s');
$lot = strtotime($now_date);
$wip_msg = generate_material_item_id_wip($workingsubclass, $device_code, $batch, $cut_list);
if (!$wip_msg[0]) {
throw new Exception("获取物料批次条码失败!" . $wip_msg[1]);
} else {
$battery_id = $wip_msg[1];
}
//判断物料批次条码是否已经存在于生产批次中如果存在则提示失败
$sql = 'SELECT id FROM "hf_mes_tmp_bkv_' . $subbatch . '" WHERE battery_id = \'' . $wip_msg[1] . '\' AND active = 1';
$ret = Db::fetch($sql);
if (!empty($ret)) {
throw new Exception("产出批次【$wip_msg[1]】已经激活了,不要重复产出!");
}
// 新增数据到process_log表
//返回需要使用的数据
$data_list = array_merge($data_list, [$battery_id, $bom_relationship_array['bom_source_code'], $bom_relationship_array['bom_source_name'], $batch, $device_code]);
$wip_process_log_sql_head = 'INSERT INTO "hf_mes_bkv_batch_process_log" (item_id, batch, subbatch, workingsubclass, process_code, device_code, status, start_time, finish_time, bom_source_id, item_batch, item_quantity, pid, uuid, bom_id, item_code, item_name, lot, tray, last_status,forward_tracing_uuid) VALUES';
$wip_process_log_sql_val = sprintf(
"('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
$battery_id,
$batch,
$subbatch,
$workingsubclass,
$process_code,
$device_code,
-1,
$start_time,
$finish_time,
$bom_relationship_array['bom_source_id'],
$battery_id,
$item_quantity,
json_encode($pid),
$wip_uuid,
$bom_relationship_array['bom_id'],
$bom_relationship_array['bom_source_code'],
$bom_relationship_array['bom_source_name'],
$lot,
'-1',
1,
$forward_tracing_uuid
);
$sql = $wip_process_log_sql_head . $wip_process_log_sql_val;
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("半成品信息插入process_log表失败");
}
// 新增数据到battery_map表
$battery_unique_value = "{$batch}_{$subbatch}_-1_{$lot}_{$battery_id}";
$wip_battery_map_sql_head = 'INSERT INTO "hf_mes_production_battery_map" (bom_source_id, battery_unique_value, battery_id, batch, subbatch, lot, tray, item_batch, pid, uuid, bom_id, workingsubclass, item_code, item_name) VALUES ';
$wip_battery_map_sql_val = sprintf(
"('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
$bom_relationship_array['bom_source_id'],
$battery_unique_value,
$battery_id,
$batch,
$subbatch,
$lot,
'-1',
$battery_id,
json_encode($pid),
$wip_uuid,
$bom_relationship_array['bom_id'],
$workingsubclass,
$bom_relationship_array['bom_source_code'],
$bom_relationship_array['bom_source_name']
);
$sql = $wip_battery_map_sql_head . $wip_battery_map_sql_val;
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("半成品信息插入battery_map表失败");
}
// 新增数据到bkv表
$wip_bkv_sql_head = 'INSERT INTO "hf_mes_tmp_bkv_' . $subbatch . '" (battery_id, tray, lot, active, process_code, next_process_code, item_code, item_name, item_batch, item_quantity, item_batch_start_time, pid, uuid, bom_source_id, bom_id, ' . implode(',', $sql_key_out_result_param) . ') VALUES ';
$wip_bkv_sql_val = sprintf(
"('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s',%s)",
$battery_id,
'-1',
$lot,
1,
$process_code,
$next_process_code,
$bom_relationship_array['bom_source_code'],
$bom_relationship_array['bom_source_name'],
$battery_id,
$item_quantity,
$now_date,
json_encode($pid),
$wip_uuid,
$bom_relationship_array['bom_source_id'],
$bom_relationship_array['bom_id'],
implode(',', $sql_val_out_result_param)
);
$sql = $wip_bkv_sql_head . $wip_bkv_sql_val;
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("半成品信息插入bkv表失败");
}
// 如果不存在uuid证明是第一个工序第一次生成uuid需要把uuid写回到投入物料uuid信息上
foreach ($material_input_ret as $key => $value) {
if ($value['pid'] != '-1') {
continue;
}
$item_id = $value['item_id'];
$sql = "UPDATE hf_mes_bkv_batch_process_log SET uuid='$uuid' WHERE item_id='{$item_id}' AND item_device_code='" . $device_code . "' AND status=0";
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("更新process_log表中投入物料[$item_id]对应uuid数据失败");
}
$sql = "UPDATE hf_mes_production_battery_map SET uuid='$uuid' WHERE battery_id='{$item_id}' AND item_device_code='" . $device_code . "'";
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("更新battery_map表中投入物料[$item_id]对应uuid数据失败");
}
$sql = "UPDATE \"hf_mes_tmp_bkv_" . $subbatch . "\" SET uuid='$uuid' WHERE battery_id='{$item_id}' AND item_device_code='" . $device_code . "'";
$row = Db::query($sql);
if ($row === NULL) {
throw new Exception("更新bkv表中投入物料[$item_id]对应uuid数据失败");
}
}
} catch (Exception $e) {
Db::rollBackTrans();
throw new Exception($e->getMessage());
}
Db::commitTrans();
return $data_list;
}
}