Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/销售订单和工单逾期消息推送
# Conflicts: # sf_message/__manifest__.py # sf_message/data/bussiness_node.xml # sf_message/models/sf_message_sale.py
This commit is contained in:
@@ -321,7 +321,7 @@ class ToolInventory(models.Model):
|
||||
prefix = fields.Char('前缀')
|
||||
postfix = fields.Char('后缀')
|
||||
diameter = fields.Float('直径(mm)')
|
||||
angle = fields.Float('R角(mm)')
|
||||
angle = fields.Float('R角(mm)',default=0)
|
||||
tool_length = fields.Float('刀具总长(mm)')
|
||||
blade_length = fields.Float('避空长/刃长(mm)')
|
||||
knife_head_name = fields.Char('刀头名称')
|
||||
|
||||
@@ -23,7 +23,7 @@ class ToolMaterialsBasicParameters(models.Model):
|
||||
handle_length = fields.Float('柄部长度(mm)')
|
||||
blade_tip_diameter = fields.Float('刀尖直径(mm)')
|
||||
blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20)
|
||||
tip_r_size = fields.Float('刀尖R角(mm)')
|
||||
tip_r_size = fields.Float('刀尖R角(mm)',default=0)
|
||||
blade_tip_taper = fields.Integer('刀尖锥度(°)')
|
||||
blade_diameter = fields.Float('刃部直径(mm)')
|
||||
blade_length = fields.Float('刃部长度(mm)')
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
'views/machine_info_present.xml',
|
||||
'views/delivery_record.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/maintenance_views.xml',
|
||||
|
||||
],
|
||||
'assets': {
|
||||
|
||||
@@ -162,7 +162,7 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
# 关机时长:初次上线时间 - 通电时间
|
||||
'power_off_time': power_off_time,
|
||||
# 关机率:关机时长/初次上线时间
|
||||
'power_off_rate': power_off_rate,
|
||||
# 'power_off_rate': power_off_rate,
|
||||
'first_online_duration': first_online_duration,
|
||||
# 停机时间:关机时间 - 运行时间
|
||||
# 停机时长:关机时间 - 初次上线时间
|
||||
@@ -187,11 +187,11 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
"""
|
||||
res = {'status': 1, 'message': '成功', 'data': {}}
|
||||
logging.info('前端请求日志数据的参数为:%s' % kw)
|
||||
# 连接数据库
|
||||
conn = psycopg2.connect(**db_config)
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
# 连接数据库
|
||||
conn = psycopg2.connect(**db_config)
|
||||
cur = conn.cursor()
|
||||
machine_list = ast.literal_eval(kw['machine_list'])
|
||||
begin_time_str = kw['begin_time'].strip('"')
|
||||
end_time_str = kw['end_time'].strip('"')
|
||||
@@ -231,6 +231,12 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
res['message'] = '前端请求日志数据失败,原因:%s' % e
|
||||
return json.dumps(res)
|
||||
|
||||
finally:
|
||||
if cur:
|
||||
cur.close()
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
@http.route('/api/logs/page_data', type='http', auth='public', methods=['GET', 'POST'],
|
||||
csrf=False, cors="*")
|
||||
def logs_page_data(self, **kw):
|
||||
@@ -242,11 +248,10 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
res = {'status': 1, 'message': '成功', 'data': {}}
|
||||
logging.info('前端请求日志数据的参数为:%s' % kw)
|
||||
|
||||
# 连接数据库
|
||||
conn = psycopg2.connect(**db_config)
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
# 连接数据库
|
||||
conn = psycopg2.connect(**db_config)
|
||||
cur = conn.cursor()
|
||||
|
||||
# 获取并解析传递的参数
|
||||
machine_list = ast.literal_eval(kw.get('machine_list', '[]'))
|
||||
begin_time_str = kw.get('begin_time', '').strip('"')
|
||||
@@ -848,10 +853,10 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
'''
|
||||
|
||||
sql2 = '''
|
||||
SELECT DISTINCT ON (alarm_time) alarm_time, alarm_repair_time
|
||||
SELECT DISTINCT ON (alarm_start_time) alarm_time, alarm_start_time
|
||||
FROM device_data
|
||||
WHERE device_name = %s AND alarm_time IS NOT NULL
|
||||
ORDER BY alarm_time, time;
|
||||
WHERE device_name = %s AND alarm_start_time IS NOT NULL
|
||||
ORDER BY alarm_start_time, time;
|
||||
|
||||
'''
|
||||
# 执行SQL命令
|
||||
@@ -867,8 +872,11 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
res['data'][item] = {'idle_count': row[0]}
|
||||
alarm_count = []
|
||||
for row in result2:
|
||||
alarm_count.append(row[0])
|
||||
total_alarm_time += abs(float(row[0]))
|
||||
alarm_count.append(row[1])
|
||||
if row[0]:
|
||||
total_alarm_time += abs(float(row[0]))
|
||||
else:
|
||||
total_alarm_time += 0.0
|
||||
if len(list(set(alarm_count))) == 1:
|
||||
if list(set(alarm_count))[0] is None:
|
||||
alarm_count_num = 0
|
||||
@@ -1233,17 +1241,24 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
machine_list = ast.literal_eval(kw['machine_list'])
|
||||
time_threshold = datetime.now() - timedelta(days=1)
|
||||
|
||||
alarm_last_24_time = 0.0
|
||||
|
||||
def fetch_result_as_dict(cursor):
|
||||
"""辅助函数:将查询结果转为字典"""
|
||||
columns = [desc[0] for desc in cursor.description]
|
||||
return dict(zip(columns, cursor.fetchone())) if cursor.rowcount != 0 else None
|
||||
|
||||
# 获取当前时间的时间戳
|
||||
current_timestamp = datetime.now().timestamp()
|
||||
for item in machine_list:
|
||||
euipment_obj = request.env['maintenance.equipment'].sudo().search([('code', '=', item)])
|
||||
# 机床上线时间段
|
||||
first_online_duration = current_timestamp - euipment_obj.first_online_time.timestamp()
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("""
|
||||
SELECT * FROM device_data
|
||||
WHERE device_name = %s
|
||||
AND device_state != '离线'
|
||||
AND device_state != '离线' AND process_time IS NOT NULL
|
||||
ORDER BY time DESC
|
||||
LIMIT 1;
|
||||
""", (item,))
|
||||
@@ -1252,18 +1267,52 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
cur.execute("""
|
||||
SELECT * FROM device_data
|
||||
WHERE device_name = %s
|
||||
AND device_state != '离线' AND time >= %s
|
||||
AND device_state != '离线' AND time >= %s AND process_time IS NOT NULL
|
||||
ORDER BY time ASC
|
||||
LIMIT 1;
|
||||
""", (item, time_threshold))
|
||||
last_24_time = fetch_result_as_dict(cur)
|
||||
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("""
|
||||
SELECT COUNT(*)
|
||||
FROM (
|
||||
SELECT DISTINCT ON (idle_start_time) idle_start_time
|
||||
FROM device_data
|
||||
WHERE device_name = %s AND idle_start_time IS NOT NULL AND time >= %s
|
||||
ORDER BY idle_start_time, time
|
||||
) subquery;
|
||||
""", (item, time_threshold))
|
||||
idle_count = cur.fetchone()[0]
|
||||
|
||||
alarm_last_24_nums = []
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("""
|
||||
SELECT DISTINCT ON (alarm_start_time) alarm_time, alarm_start_time
|
||||
FROM device_data
|
||||
WHERE device_name = %s
|
||||
AND alarm_start_time IS NOT NULL AND time >= %s;
|
||||
""", (item, time_threshold))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
alarm_last_24_nums.append(result[1])
|
||||
if result[0]:
|
||||
if float(result[0]) >= 1000:
|
||||
continue
|
||||
alarm_last_24_time += float(result[0])
|
||||
else:
|
||||
alarm_last_24_time += 0.0
|
||||
# 返回数据
|
||||
res['data'][item] = {
|
||||
'wait_time': last_all_time['run_time'] if last_all_time['run_time'] is not None else 0,
|
||||
'cut_time': last_all_time['process_time'] if last_all_time['process_time'] is not None else 0,
|
||||
'cut_24_time': last_24_time['process_time'] if last_24_time['process_time'] is not None else 0,
|
||||
'power_on_time': last_all_time['power_on_time'] if last_all_time['power_on_time'] is not None else 0,
|
||||
'power_on_24_time': last_24_time['power_on_time'] if last_24_time['power_on_time'] is not None else 0
|
||||
'power_on_24_time': last_24_time['power_on_time'] if last_24_time['power_on_time'] is not None else 0,
|
||||
'alarm_last_24_time': alarm_last_24_time,
|
||||
'alarm_last_24_nums': len(list(set(alarm_last_24_nums))),
|
||||
'idle_count': idle_count,
|
||||
'first_online_time': first_online_duration,
|
||||
}
|
||||
|
||||
conn.close()
|
||||
|
||||
@@ -285,26 +285,6 @@ class Machine_ftp(models.Model):
|
||||
# # 开动率
|
||||
run_rate = fields.Char('开动率', readonly=True)
|
||||
|
||||
# 同步CNC设备到oee
|
||||
def sync_oee(self):
|
||||
"""
|
||||
同步CNC设备到oee
|
||||
:return:
|
||||
"""
|
||||
for record in self:
|
||||
record.ensure_one()
|
||||
cnc_oee_dict = {
|
||||
'equipment_id': record.id,
|
||||
'type_id': record.type_id.id,
|
||||
'machine_tool_picture': record.machine_tool_picture,
|
||||
'equipment_code': record.code,
|
||||
'function_type': record.function_type,
|
||||
}
|
||||
if self.env['maintenance.equipment.oee.logs'].search([('equipment_id', '=', record.id)]):
|
||||
self.env['maintenance.equipment.oee.logs'].write(cnc_oee_dict)
|
||||
else:
|
||||
self.env['maintenance.equipment.oee.logs'].create(cnc_oee_dict)
|
||||
|
||||
|
||||
class WorkCenterBarcode(models.Model):
|
||||
"""
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<group string='状态监控'>
|
||||
<group>
|
||||
<!-- <field name="timestamp"/> -->
|
||||
<field name="status"/>
|
||||
<!-- <field name="status"/> -->
|
||||
<field name="run_status"/>
|
||||
<field name="run_time"/>
|
||||
<field name="system_date"/>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
<!-- 修改设备列表视图-->
|
||||
<record id="sf_machine_hr_equipment_view_tree_inherit" model="ir.ui.view">
|
||||
<field name="name">sf.machine.hr.equipment.view.tree.inherit</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="inherit_id" ref="maintenance.hr_equipment_view_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree" position="inside">
|
||||
<header>
|
||||
<button name="sync_oee" type="object" string="同步设备至OEE"/>
|
||||
</header>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import json
|
||||
import datetime
|
||||
import requests
|
||||
@@ -6,6 +7,42 @@ from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
def convert_to_seconds(time_str):
|
||||
# 修改正则表达式,使 H、M、S 部分可选
|
||||
|
||||
if time_str is None:
|
||||
return 0
|
||||
|
||||
pattern = r"(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?"
|
||||
|
||||
match = re.match(pattern, time_str)
|
||||
|
||||
if match:
|
||||
# 提取各时间单位,如果某个单位缺失则默认设为0
|
||||
hours = int(match.group(1)) if match.group(1) else 0
|
||||
minutes = int(match.group(2)) if match.group(2) else 0
|
||||
seconds = int(match.group(3)) if match.group(3) else 0
|
||||
|
||||
# 计算总秒数
|
||||
total_seconds = hours * 3600 + minutes * 60 + seconds
|
||||
if total_seconds == 0:
|
||||
# return None
|
||||
pattern = r"(?:(\d+)小时)?(?:(\d+)分钟)?(?:(\d+)秒)?"
|
||||
match = re.match(pattern, time_str)
|
||||
if match:
|
||||
# 提取各时间单位,如果某个单位缺失则默认设为0
|
||||
hours = int(match.group(1)) if match.group(1) else 0
|
||||
minutes = int(match.group(2)) if match.group(2) else 0
|
||||
seconds = int(match.group(3)) if match.group(3) else 0
|
||||
|
||||
# 计算总秒数
|
||||
total_seconds = hours * 3600 + minutes * 60 + seconds
|
||||
return total_seconds
|
||||
else:
|
||||
return None
|
||||
return total_seconds
|
||||
|
||||
|
||||
class SfMaintenanceEquipmentOEE(models.Model):
|
||||
_name = 'maintenance.equipment.oee'
|
||||
_description = '设备OEE'
|
||||
@@ -22,18 +59,27 @@ class SfMaintenanceEquipmentOEE(models.Model):
|
||||
[("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"),
|
||||
("封存(报废)", "封存(报废)")],
|
||||
default='正常', string="机床状态", related='equipment_id.state')
|
||||
run_time = fields.Float('加工时长(h)')
|
||||
equipment_time = fields.Float('开机时长(h)')
|
||||
done_nums = fields.Integer('加工件数')
|
||||
utilization_rate = fields.Char('可用率')
|
||||
fault_time = fields.Float('故障时长')
|
||||
fault_nums = fields.Integer('故障次数')
|
||||
# 故障率
|
||||
fault_rate = fields.Char('故障率')
|
||||
|
||||
online_time = fields.Char('开机时长(小时)', reaonly='True')
|
||||
|
||||
offline_time = fields.Char('关机时长(小时)', reaonly='True')
|
||||
idle_nums = fields.Integer('待机次数', reaonly='True')
|
||||
# 待机时长
|
||||
|
||||
idle_time = fields.Char('待机时长(小时)', reaonly='True')
|
||||
|
||||
# 待机率
|
||||
idle_rate = fields.Char('待机率(%)', reaonly='True')
|
||||
|
||||
work_time = fields.Char('加工时长(小时)', reaonly='True')
|
||||
work_rate = fields.Char('可用率(%)', reaonly='True')
|
||||
fault_time = fields.Char('故障时长(小时)', reaonly='True')
|
||||
fault_rate = fields.Char('故障率(%)', reaonly='True')
|
||||
fault_nums = fields.Integer('故障次数', reaonly='True')
|
||||
|
||||
# 设备故障日志
|
||||
sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志',
|
||||
related='equipment_id.sf_maintenance_logs_ids')
|
||||
oee_logs = fields.One2many('maintenance.equipment.oee.logs', 'equipment_oee_id', string='运行日志')
|
||||
|
||||
day_logs_detail = fields.Html('日运行日志详情')
|
||||
history_logs_detail = fields.Html('历史运行日志详情')
|
||||
@@ -42,8 +88,13 @@ class SfMaintenanceEquipmentOEE(models.Model):
|
||||
|
||||
# 获取日志详情
|
||||
def get_day_logs(self):
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
print(base_url)
|
||||
config = self.env['ir.config_parameter'].sudo()
|
||||
url = 'http://172.16.10.112:8069/api/logs/list'
|
||||
# url = 'http://172.16.10.112:8069/api/logs/list'
|
||||
# url_time = 'http://localhost:9069/api/RunningTimeDetail'
|
||||
url = base_url + '/api/logs/list'
|
||||
url_time = base_url + '/api/RunningTimeDetail'
|
||||
machine_list = [self.equipment_code]
|
||||
begin_time = datetime.datetime.now().strftime('%Y-%m-%d') + ' 00:00:00'
|
||||
end_time = datetime.datetime.now().strftime('%Y-%m-%d') + ' 23:59:59'
|
||||
@@ -55,11 +106,41 @@ class SfMaintenanceEquipmentOEE(models.Model):
|
||||
"end_time": end_time
|
||||
}
|
||||
|
||||
data_time = {
|
||||
"machine_list": str(machine_list)
|
||||
}
|
||||
|
||||
print(data)
|
||||
|
||||
# 发送POST请求
|
||||
response = requests.post(url, json={}, data=data)
|
||||
print(response.json()) # 输出服务器返回的响应
|
||||
response_time = requests.post(url_time, json={}, data=data_time)
|
||||
# print(response.json()) # 输出服务器返回的响应
|
||||
print(response_time.json())
|
||||
if response_time.status_code == 200:
|
||||
result_time = response_time.json()
|
||||
real_dict = result_time['data'][self.equipment_code]
|
||||
print('=', result_time)
|
||||
if result_time['status'] == 1:
|
||||
self.online_time = round((convert_to_seconds(real_dict['power_on_time']) - convert_to_seconds(
|
||||
real_dict['power_on_24_time'])) / 3600, 2)
|
||||
self.work_time = round(
|
||||
(convert_to_seconds(real_dict['cut_time']) - convert_to_seconds(real_dict['cut_24_time'])) / 3600,
|
||||
2)
|
||||
self.offline_time = 24 - (float(self.online_time) if self.online_time else 0)
|
||||
self.idle_time = float(self.online_time) - float(
|
||||
self.work_time) if self.online_time and self.work_time else 0
|
||||
self.idle_rate = round(
|
||||
float(self.idle_time) / (float(self.online_time) if self.online_time else 1) * 100, 2)
|
||||
self.work_rate = round(
|
||||
float(self.work_time) / (float(self.online_time) if self.online_time else 1) * 100, 2)
|
||||
self.fault_time = (float(real_dict['alarm_last_24_time']) if real_dict[
|
||||
'alarm_last_24_time'] else 0) / 3600
|
||||
self.fault_rate = round(
|
||||
float(self.fault_time) / (float(self.online_time) if self.online_time else 1) * 100, 2)
|
||||
self.fault_nums = real_dict['alarm_last_24_nums']
|
||||
self.idle_nums = real_dict['idle_count']
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
print('============', result)
|
||||
@@ -94,7 +175,10 @@ class SfMaintenanceEquipmentOEE(models.Model):
|
||||
# 获取历史日志详情
|
||||
def get_history_logs(self):
|
||||
config = self.env['ir.config_parameter'].sudo()
|
||||
url = 'http://172.16.10.112:8069/api/logs/list'
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
# url = 'http://172.16.10.112:8069/api/logs/list'
|
||||
url = base_url + '/api/logs/list'
|
||||
url_time = base_url + '/api/RunningTimeDetail'
|
||||
machine_list = [self.equipment_code]
|
||||
if not self.begin_time:
|
||||
raise UserError('请选择开始时间')
|
||||
|
||||
@@ -67,6 +67,3 @@ access_sf_cutting_tool_type_admin_sf_group_equipment_user,sf_cutting_tool_type_a
|
||||
access_sf_cutting_tool_type_group_purchase_director_sf_group_equipment_user,sf_cutting_tool_type_group_purchase_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
access_sf_cutting_tool_type_group_sale_director_sf_group_equipment_user,sf_cutting_tool_type_group_sale_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
access_sf_cutting_tool_type_group_plan_director_sf_group_equipment_user,sf_cutting_tool_type_group_plan_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
|
||||
access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_maintenance.sf_group_equipment_manager,1,1,1,1
|
||||
access_maintenance_equipment_oee_log_detail,maintenance_equipment_oee_log_detail,model_maintenance_equipment_oee_log_detail,sf_maintenance.sf_group_equipment_manager,1,1,1,1
|
||||
|
@@ -8,13 +8,13 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="equipment_id"/>
|
||||
<field name="equipment_time"/>
|
||||
<field name="run_time"/>
|
||||
<field name="done_nums"/>
|
||||
<field name="utilization_rate"/>
|
||||
<field name="online_time"/>
|
||||
<field name="work_time"/>
|
||||
<field name="work_rate"/>
|
||||
<field name="fault_time"/>
|
||||
<field name="fault_nums"/>
|
||||
<field name="fault_rate"/>
|
||||
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -37,19 +37,48 @@
|
||||
|
||||
<group>
|
||||
<group>
|
||||
<field name="type_id" readonly="1"/>
|
||||
<field name="equipment_code"/>
|
||||
<field name="equipment_time"/>
|
||||
<field name="run_time"/>
|
||||
<field name="done_nums"/>
|
||||
<field name="utilization_rate"/>
|
||||
<field name="fault_time"/>
|
||||
<field name="fault_nums"/>
|
||||
<group>
|
||||
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
|
||||
<field name="type_id"/>
|
||||
<field name="state"/>
|
||||
<field name="equipment_code"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="machine_tool_picture" widget="image" readonly="1"/>
|
||||
<group>
|
||||
<!-- <field name="state" nolabel="1"/> -->
|
||||
<!-- <field name="state" string=""/> -->
|
||||
</group>
|
||||
<group>
|
||||
<field name="machine_tool_picture" widget="image" nolabel="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="online_time" readonly="1"/>
|
||||
<field name="offline_time" readonly="1"/>
|
||||
<field name="fault_rate" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="idle_nums" readonly="1"/>
|
||||
<field name="fault_time" readonly="1"/>
|
||||
<field name="fault_nums" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="idle_time"/>
|
||||
<field name="idle_rate"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="work_time"/>
|
||||
<field name="work_rate"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="24H日志详情">
|
||||
<group>
|
||||
@@ -81,28 +110,28 @@
|
||||
<!-- </div> -->
|
||||
<!-- </group> -->
|
||||
</page>
|
||||
<page string="历史日志详情">
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="begin_time"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="end_time"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<button name="get_history_logs" type="object" string="查看历史日志" t-attf-style="white-space:nowrap;"/>
|
||||
</group>
|
||||
<group>
|
||||
<button name="download_history_logs" type="object" string="下载历史日志" t-attf-style="white-space:nowrap;"/>
|
||||
</group>
|
||||
</group>
|
||||
<!-- <page string="历史日志详情"> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="begin_time"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="end_time"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <button name="get_history_logs" type="object" string="查看历史日志" t-attf-style="white-space:nowrap;"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <button name="download_history_logs" type="object" string="下载历史日志" t-attf-style="white-space:nowrap;"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- </group> -->
|
||||
|
||||
</group>
|
||||
<field name="history_logs_detail"/>
|
||||
</page>
|
||||
<!-- </group> -->
|
||||
<!-- <field name="history_logs_detail"/> -->
|
||||
<!-- </page> -->
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
|
||||
@@ -105,249 +105,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 设备运行日志 -->
|
||||
<record id="view_maintenance_logs_run_tree" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.tree</field>
|
||||
<field name="model">maintenance.equipment.oee.logs</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="equipment_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_maintenance_logs_run_form" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.form</field>
|
||||
<field name="model">maintenance.equipment.oee.logs</field>
|
||||
<field name="arch" type="xml">
|
||||
<!-- <form string="设备运行日志"> -->
|
||||
<!-- <header> -->
|
||||
<!-- <field name="equipment_id" readonly="1"/> -->
|
||||
<!-- </header> -->
|
||||
<!-- <sheet> -->
|
||||
<!-- <div class="oe_title"> -->
|
||||
<!-- <h1> -->
|
||||
<!-- <field name="start_time" readonly="1"/> -->
|
||||
<!-- </h1> -->
|
||||
<!-- </div> -->
|
||||
<!-- <group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="stop_time" readonly="1"/> -->
|
||||
<!-- <field name="duration" readonly="1"/> -->
|
||||
<!-- <field name="oee" readonly="1"/> -->
|
||||
<!-- </group> -->
|
||||
<!-- <group> -->
|
||||
<!-- <field name="note"/> -->
|
||||
<!-- </group> -->
|
||||
|
||||
<!-- </group> -->
|
||||
<!-- </sheet> -->
|
||||
<!-- </form> -->
|
||||
<form string="设备运行日志">
|
||||
<!-- <header> -->
|
||||
<!-- <field name="name" readonly="1"/> -->
|
||||
<!-- </header> -->
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
|
||||
<field name="type_id"/>
|
||||
<field name="state"/>
|
||||
<field name="equipment_code"/>
|
||||
<field name="function_type"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<!-- <field name="state" nolabel="1"/> -->
|
||||
<field name="state" string=""/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="machine_tool_picture" widget="image" nolabel="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="online_time" readonly="1"/>
|
||||
<field name="offline_time" readonly="1"/>
|
||||
<field name="fault_rate" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="offline_nums" readonly="1"/>
|
||||
<field name="fault_time" readonly="1"/>
|
||||
<field name="fault_nums" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="idle_time"/>
|
||||
<field name="idle_rate"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="work_time"/>
|
||||
<field name="work_rate"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="24H日志详情">
|
||||
<!-- 筛选出24小时内的日志 -->
|
||||
<!-- <field name="detail_ids" domain="[('time','<',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
|
||||
<field name="detail_ids" domain="[('state','ilike','加工')]">
|
||||
<tree>
|
||||
<!-- <field name="sequence"/> -->
|
||||
<field name="time"/>
|
||||
<field name="state"/>
|
||||
<field name="production_name"/>
|
||||
</tree>
|
||||
<!-- <form> -->
|
||||
<!-- <field name="sequence"/> -->
|
||||
<!-- <field name="time"/> -->
|
||||
<!-- <field name="state"/> -->
|
||||
<!-- <field name="production_id"/> -->
|
||||
<!-- </form> -->
|
||||
|
||||
</field>
|
||||
</page>
|
||||
<page string="历史日志详情">
|
||||
<field name="detail_ids">
|
||||
<tree>
|
||||
<!-- <field name="sequence"/> -->
|
||||
<field name="time"/>
|
||||
<field name="state"/>
|
||||
<field name="production_name"/>
|
||||
</tree>
|
||||
<!-- <form> -->
|
||||
<!-- <field name="sequence"/> -->
|
||||
<!-- <field name="time"/> -->
|
||||
<!-- <field name="state"/> -->
|
||||
<!-- <field name="production_id"/> -->
|
||||
<!-- </form> -->
|
||||
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- <record id="view_maintenance_logs_run_search" model="ir.ui.view"> -->
|
||||
<!-- <field name="name">maintenance.logs.run.search</field> -->
|
||||
<!-- <field name="model">maintenance.equipment.oee.logs</field> -->
|
||||
<!-- <field name="arch" type="xml"> -->
|
||||
<!-- <search> -->
|
||||
<!-- <field name="equipment_id"/> -->
|
||||
<!-- <field name="start_time"/> -->
|
||||
<!-- <field name="stop_time"/> -->
|
||||
<!-- <field name="duration"/> -->
|
||||
<!-- <field name="oee"/> -->
|
||||
<!-- <field name="note"/> -->
|
||||
<!-- </search> -->
|
||||
|
||||
<!-- </field> -->
|
||||
<!-- </record> -->
|
||||
|
||||
<!-- 设备运行日志详情 -->
|
||||
<record id="view_maintenance_logs_run_detail_tree" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.detail.tree</field>
|
||||
<field name="model">maintenance.equipment.oee.log.detail</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<!-- <field name="sequence"/> -->
|
||||
<field name="time"/>
|
||||
<field name="state"/>
|
||||
<field name="production_name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_maintenance_logs_run_detail_form" model="ir.ui.view">
|
||||
<field name="name">maintenance.logs.run.detail.form</field>
|
||||
<field name="model">maintenance.equipment.oee.log.detail</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="设备运行日志详情">
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="state"/>
|
||||
<!-- <field name="production_id"/> -->
|
||||
</group>
|
||||
<group>
|
||||
<!-- <field name="sequence"/> -->
|
||||
<field name="time"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record id="view_maintenance_logs_run_detail_search" model="ir.ui.view"> -->
|
||||
<!-- <field name="name">maintenance.logs.run.detail.search</field> -->
|
||||
<!-- <field name="model">maintenance.equipment.oee.logs.detail</field> -->
|
||||
<!-- <field name="arch" type="xml"> -->
|
||||
<!-- <search> -->
|
||||
<!-- <field name="equipment_id"/> -->
|
||||
<!-- <field name="start_time"/> -->
|
||||
<!-- <field name="stop_time"/> -->
|
||||
<!-- <field name="duration"/> -->
|
||||
<!-- <field name="oee"/> -->
|
||||
<!-- <field name="note"/> -->
|
||||
<!-- </search> -->
|
||||
<!-- </field> -->
|
||||
<!-- </record> -->
|
||||
|
||||
<!-- 设备运行日志详情action -->
|
||||
<!-- <record id="action_maintenance_logs_run_detail" model="ir.actions.act_window"> -->
|
||||
<!-- <field name="name">设备运行日志详情</field> -->
|
||||
<!-- <field name="type">ir.actions.act_window</field> -->
|
||||
<!-- <field name="res_model">maintenance.equipment.oee.logs.detail</field> -->
|
||||
<!-- <field name="view_mode">tree,form</field> -->
|
||||
<!-- <field name="view_id" ref="view_maintenance_logs_run_detail_tree"/> -->
|
||||
<!-- <field name="help" type="html"> -->
|
||||
<!-- <p class="oe_view_nocontent_create"> -->
|
||||
<!-- 设备运行日志详情 -->
|
||||
<!-- </p> -->
|
||||
<!-- </field> -->
|
||||
<!-- -->
|
||||
<!-- </record> -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<record id="action_maintenance_logs_run" model="ir.actions.act_window">
|
||||
<field name="name">设备运行日志</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">maintenance.equipment.oee.logs</field>
|
||||
<!-- <field name="search_view_id" ref="view_maintenance_logs_run_search"/> -->
|
||||
<field name="view_mode">tree,form</field>
|
||||
<!-- <field name="view_mode">form</field> -->
|
||||
<field name="view_id" ref="view_maintenance_logs_run_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
设备运行日志
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem name="设备运行日志" id="menu_maintenance_logs_run" parent="maintenance.menu_m_request"
|
||||
sequence="10" action="action_maintenance_logs_run"/>
|
||||
|
||||
|
||||
<!-- Action -->
|
||||
|
||||
<record id="action_maintenance_logs" model="ir.actions.act_window">
|
||||
|
||||
@@ -163,6 +163,19 @@ class ResWorkcenter(models.Model):
|
||||
else:
|
||||
record.effective_working_hours_day = 0
|
||||
|
||||
# 计算传入时间日有效工作时长
|
||||
def _compute_effective_working_hours_day1(self, date):
|
||||
effective_working_hours_day = 0
|
||||
for record in self:
|
||||
attendance_ids = [p for p in record.resource_calendar_id.attendance_ids if
|
||||
p.dayofweek == self.get_current_day_of_week(date)]
|
||||
if attendance_ids:
|
||||
for attendance_id in attendance_ids:
|
||||
if attendance_id.hour_from and attendance_id.hour_to:
|
||||
effective_working_hours_day += attendance_id.hour_to - attendance_id.hour_from
|
||||
|
||||
return effective_working_hours_day
|
||||
|
||||
# 获取传入时间是星期几
|
||||
def get_current_day_of_week(self, datetime):
|
||||
day_num = datetime.weekday()
|
||||
@@ -211,7 +224,8 @@ class ResWorkcenter(models.Model):
|
||||
('state', 'not in', ['draft', 'cancel'])])
|
||||
if plan_ids:
|
||||
sum_qty = sum([p.product_qty for p in plan_ids])
|
||||
if sum_qty >= self.default_capacity:
|
||||
date_planned_working_hours = self._compute_effective_working_hours_day1(date_planned)
|
||||
if sum_qty >= date_planned_working_hours:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@ class ResProductMo(models.Model):
|
||||
product_model_type_id = fields.Many2one('sf.model.type', string='产品模型类型')
|
||||
embryo_model_type_id = fields.Many2one('sf.model.type', string='坯料模型类型')
|
||||
materials_id = fields.Many2one('sf.production.materials', string='材料')
|
||||
# materials_type_id = fields.Many2one('sf.materials.model', string='材料型号',
|
||||
# domain="[('materials_id', '=', materials_id)]")
|
||||
materials_type_id = fields.Many2one(related='cutting_tool_model_id.material_model_id', string='材料型号',
|
||||
materials_type_id = fields.Many2one('sf.materials.model', string='材料型号',
|
||||
domain="[('materials_id', '=', materials_id)]")
|
||||
# materials_type_id = fields.Many2one(related='cutting_tool_model_id.material_model_id', string='材料型号',
|
||||
# domain="[('materials_id', '=', materials_id)]")
|
||||
# cutting_tool_model_id.material_model_id
|
||||
server_product_process_parameters_id = fields.Many2one('sf.production.process.parameter',
|
||||
string='表面工艺参数(服务产品)')
|
||||
@@ -58,10 +58,10 @@ class ResProductMo(models.Model):
|
||||
cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='型号名称')
|
||||
specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='物料号')
|
||||
|
||||
# cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型',
|
||||
# domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
|
||||
cutting_tool_type_id = fields.Many2one(related='cutting_tool_model_id.cutting_tool_type_id', string='类型',
|
||||
cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型',
|
||||
domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
|
||||
# cutting_tool_type_id = fields.Many2one(related='cutting_tool_model_id.cutting_tool_type_id', string='类型',
|
||||
# domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
|
||||
# brand_id = fields.Many2one('sf.machine.brand', '品牌')
|
||||
brand_id = fields.Many2one(related='cutting_tool_model_id.brand_id', string='品牌')
|
||||
# cutting_tool_model_id.brand_id
|
||||
@@ -630,14 +630,14 @@ class ResProductMo(models.Model):
|
||||
cutting_tool_installing_structure = fields.Char(related='specification_id.installing_structure',
|
||||
string='安装结构')
|
||||
# specification_id.installing_structure
|
||||
# cutting_tool_blade_id = fields.Many2one(
|
||||
# 'sf.cutting_tool.standard.library',
|
||||
# domain="[('cutting_tool_type', '=', '刀片')]",
|
||||
# string='适用刀片型号' # 使用空列表作为默认值
|
||||
# )
|
||||
cutting_tool_blade_id = fields.Many2one(related='specification_id.blade_id',
|
||||
domain="[('cutting_tool_type', '=', '刀片')]",
|
||||
string='适用刀片型号')
|
||||
cutting_tool_blade_id = fields.Many2one(
|
||||
'sf.cutting_tool.standard.library',
|
||||
domain="[('cutting_tool_type', '=', '刀片')]",
|
||||
string='适用刀片型号' # 使用空列表作为默认值
|
||||
)
|
||||
# cutting_tool_blade_id = fields.Many2one(related='specification_id.blade_id',
|
||||
# domain="[('cutting_tool_type', '=', '刀片')]",
|
||||
# string='适用刀片型号')
|
||||
# specification_id.blade_id
|
||||
# cutting_tool_tool_shim = fields.Char('适配刀垫型号', size=50)
|
||||
cutting_tool_tool_shim = fields.Char(related='specification_id.tool_shim',
|
||||
@@ -756,14 +756,14 @@ class ResProductMo(models.Model):
|
||||
# string='适用刀柄型号'
|
||||
# )
|
||||
|
||||
# cutting_tool_handle_id = fields.Many2one(
|
||||
# 'sf.cutting_tool.standard.library',
|
||||
# domain="[('cutting_tool_type', '=', '刀柄')]",
|
||||
# string='适用刀柄型号'
|
||||
# )
|
||||
cutting_tool_handle_id = fields.Many2one(related='cutting_tool_model_id.handle_id',
|
||||
domain="[('cutting_tool_type', '=', '刀柄')]",
|
||||
string='适用刀柄型号')
|
||||
cutting_tool_handle_id = fields.Many2one(
|
||||
'sf.cutting_tool.standard.library',
|
||||
domain="[('cutting_tool_type', '=', '刀柄')]",
|
||||
string='适用刀柄型号'
|
||||
)
|
||||
# cutting_tool_handle_id = fields.Many2one(related='cutting_tool_model_id.handle_id',
|
||||
# domain="[('cutting_tool_type', '=', '刀柄')]",
|
||||
# string='适用刀柄型号')
|
||||
# cutting_tool_model_id.handle_id
|
||||
|
||||
# 注册状态
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
from . import models
|
||||
from . import models
|
||||
from . import controllers
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
'data': [
|
||||
'data/bussiness_node.xml',
|
||||
'data/cron_data.xml',
|
||||
'data/template_data.xml',
|
||||
|
||||
|
||||
],
|
||||
'test': [
|
||||
],
|
||||
|
||||
1
sf_message/controllers/__init__.py
Normal file
1
sf_message/controllers/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import main
|
||||
40
sf_message/controllers/main.py
Normal file
40
sf_message/controllers/main.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import json
|
||||
import requests
|
||||
import logging
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class MessageSfMrsConnect(Sf_Mrs_Connect):
|
||||
|
||||
@http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def get_cnc_processing_create(self, **kw):
|
||||
res = super(MessageSfMrsConnect, self).get_cnc_processing_create(**kw)
|
||||
res = json.loads(res)
|
||||
if res.get('production_ids'):
|
||||
try:
|
||||
_logger.info('已编程的制造订单:%s' % res.get('production_ids'))
|
||||
productions = request.env['mrp.production'].sudo().search([('id', 'in', res.get('production_ids'))])
|
||||
# 过滤programming_state为已编程,tool_state为2的制造订单
|
||||
tool_state_valid_productions = productions.filtered(lambda x: x.programming_state == '已编程' and x.tool_state == '2')
|
||||
if tool_state_valid_productions:
|
||||
data = {
|
||||
'name': tool_state_valid_productions[0].programming_no
|
||||
}
|
||||
# 请求cloud接口,发送微信消息推送
|
||||
configsettings = request.env['res.config.settings'].sudo().get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/message/invalid_tool_state'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
data['token'] = configsettings['token']
|
||||
ret = requests.post(config_url, json=data, headers=config_header)
|
||||
ret = ret.json()
|
||||
_logger.info('无效用刀异常消息推送接口:%s' % ret)
|
||||
except Exception as e:
|
||||
_logger.info('无效用刀异常消息推送接口:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<field name="model">sale.order</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="transfer_inventory" model="jikimo.message.bussiness.node">
|
||||
<field name="name">调拨入库</field>
|
||||
<field name="model">stock.picking</field>
|
||||
@@ -49,6 +50,45 @@
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="bussiness_mrp_workorder_pre_overdue_warning" model="jikimo.message.bussiness.node">
|
||||
<field name="name">装夹预调工单逾期预警</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
<record id="bussiness_mrp_workorder_pre_overdue" model="jikimo.message.bussiness.node">
|
||||
<field name="name">装夹预调工单已逾期</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
|
||||
<record id="bussiness_mrp_workorder_cnc_overdue_warning" model="jikimo.message.bussiness.node">
|
||||
<field name="name">CNC工单逾期预警</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
<record id="bussiness_mrp_workorder_cnc_overdue" model="jikimo.message.bussiness.node">
|
||||
<field name="name">CNC工单已逾期</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
|
||||
<record id="bussiness_mrp_workorder_unclamp_overdue_warning" model="jikimo.message.bussiness.node">
|
||||
<field name="name">解除装夹工单逾期预警</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
|
||||
<record id="bussiness_mrp_workorder_unclamp_overdue" model="jikimo.message.bussiness.node">
|
||||
<field name="name">解除装夹工单已逾期</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
|
||||
<record id="bussiness_mrp_workorder_surface_overdue_warning" model="jikimo.message.bussiness.node">
|
||||
<field name="name">表面工艺工单逾期预警</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
|
||||
<record id="bussiness_mrp_workorder_surface_overdue" model="jikimo.message.bussiness.node">
|
||||
<field name="name">表面工艺工单已逾期</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
</record>
|
||||
|
||||
<record id="bussiness_mrp_workorder_pre_overdue_warning" model="jikimo.message.bussiness.node">
|
||||
<field name="name">装夹预调工单逾期预警</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
|
||||
110
sf_message/data/template_data.xml
Normal file
110
sf_message/data/template_data.xml
Normal file
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="template_pending_order" model="jikimo.message.template">
|
||||
<field name="name">待接单</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_pending_order"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 待接单提醒:
|
||||
单号:销售订单[{{name}}]({{url}})
|
||||
事项:请确认是否接单。
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="template_to_be_confirm" model="jikimo.message.template">
|
||||
<field name="name">确认接单</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_to_be_confirm"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 待排程提醒:
|
||||
单号:产品[{{product_id}}]({{url}})
|
||||
事项:{{mrp_production_count}}个制造订单待计划排程
|
||||
</field>
|
||||
</record>
|
||||
<record id="template_material_purchase_remind" model="jikimo.message.template">
|
||||
<field name="name">坯料采购提醒</field>
|
||||
<field name="model_id" ref="purchase.model_purchase_order"/>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_material_purchase_remind"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 坯料采购通知:
|
||||
单号:采购单[{{name}}]({{request_url}})
|
||||
事项:请确认坯料采购单并处理</field>
|
||||
</record>
|
||||
|
||||
<record id="template_material_picking_remind" model="jikimo.message.template">
|
||||
<field name="name">坯料发料提醒</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_material_picking_remind"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 坯料发料提醒:
|
||||
单号:产品[{{product_id}}]({{request_url}})
|
||||
事项:共{{number}}个生产发料单待确认处理</field>
|
||||
</record>
|
||||
|
||||
<record id="template_mrp_workorder_remind" model="jikimo.message.template">
|
||||
<field name="name">工单已下发通知</field>
|
||||
<field name="model_id" ref="mrp_workorder.model_mrp_workorder"/>
|
||||
<field name="model">mrp.workorder</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_mrp_workorder_remind"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 工单已下发通知:
|
||||
单号:产品[{{product_id}}]({{request_url}})
|
||||
事项:共{{number}}个工单已下发,请查收知悉</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<record id="template_transfer_inventory_remind" model="jikimo.message.template">
|
||||
<field name="menu_id" ref="stock.menu_stock_root"/>
|
||||
<field name="action_id" ref="stock.action_picking_tree_ready"/>
|
||||
<field name="name">调拨入库</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="bussiness_node_id" ref="transfer_inventory"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 调拨入库通知:
|
||||
单号:调拨入库单[{{name}}]({{request_url}})
|
||||
事项:完成刀具物料上架入库</field>
|
||||
</record>
|
||||
|
||||
<record id="template_tool_expired_remind" model="jikimo.message.template">
|
||||
<field name="menu_id" ref="mrp.menu_mrp_root"/>
|
||||
<field name="action_id" ref="sf_tool_management.sf_functional_tool_dismantle_view_act"/>
|
||||
<field name="name">功能刀具寿命到期</field>
|
||||
<field name="model_id" ref="sf_tool_management.model_sf_functional_tool_dismantle"/>
|
||||
<field name="model">sf.functional.tool.dismantle</field>
|
||||
<field name="bussiness_node_id" ref="tool_dismantle"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 功能刀具寿命到期提醒:
|
||||
单号:拆解单[{{code}}]({{request_url}})
|
||||
事项:{{functional_tool_id.tool_name_id.name}}寿命已到期,需拆解</field>
|
||||
</record>
|
||||
|
||||
<record id="template_tool_assembly_remind" model="jikimo.message.template">
|
||||
<field name="menu_id" ref="mrp.menu_mrp_root"/>
|
||||
<field name="action_id" ref="sf_tool_management.sf_functional_tool_assembly_view_act"/>
|
||||
<field name="name">功能刀具组装</field>
|
||||
<field name="model_id" ref="sf_tool_management.model_sf_functional_tool_assembly"/>
|
||||
<field name="model">sf.functional.tool.assembly</field>
|
||||
<field name="bussiness_node_id" ref="tool_assembly"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">normal</field>
|
||||
<field name="content">### 功能刀具组装通知:
|
||||
单号:组装任务单[{{name}}]({{request_url}})
|
||||
事项:{{use_tool_time}}前完成组装</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -6,4 +6,4 @@ from . import sf_message_cam_program
|
||||
from . import sf_message_functional_tool_assembly
|
||||
from . import sf_message_purchase
|
||||
from . import sf_message_workorder
|
||||
from . import sf_message_functional_tool_dismantle
|
||||
from . import sf_message_functional_tool_dismantle
|
||||
|
||||
@@ -41,26 +41,30 @@ class SFMessageSale(models.Model):
|
||||
|
||||
# 继承并重写jikimo.message.dispatch的_get_message()
|
||||
def _get_message(self, message_queue_ids):
|
||||
res = super(SFMessageSale, self)._get_message(message_queue_ids)
|
||||
new_res = []
|
||||
processed_messages = set() # 用于跟踪已经处理过的消息
|
||||
contents = []
|
||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
for item in message_queue_ids:
|
||||
if item.message_template_id.bussiness_node_id.name == '确认接单':
|
||||
# 待接单的处理
|
||||
if item.message_template_id.bussiness_node_id.name == '待接单':
|
||||
content = super(SFMessageSale, self)._get_message(item)
|
||||
action_id = self.env.ref('sale.action_quotations_with_onboarding').id
|
||||
url = f"{url}/web#id={item.res_id}view_type=form&action={action_id}"
|
||||
content = content[0].replace('{{url}}', url)
|
||||
contents.append(content)
|
||||
# 确认接单的处理
|
||||
elif item.message_template_id.bussiness_node_id.name == '确认接单':
|
||||
content = super(SFMessageSale, self)._get_message(item)
|
||||
sale_order_line = self.env['sale.order.line'].search([('order_id', '=', int(item.res_id))])
|
||||
if len(sale_order_line) == 1:
|
||||
product = sale_order_line[0].product_id.name
|
||||
elif len(sale_order_line) > 1:
|
||||
product = '%s...' % sale_order_line[0].product_id.name
|
||||
for message in res:
|
||||
message_text = message.replace('{{product_id}}', product)
|
||||
if message_text not in processed_messages:
|
||||
new_res.append(message_text)
|
||||
processed_messages.add(message_text)
|
||||
if new_res:
|
||||
res = new_res
|
||||
return res
|
||||
product = sale_order_line[0].product_id.name if len(sale_order_line) == 1 else '%s...' % \
|
||||
sale_order_line[
|
||||
0].product_id.name
|
||||
action_id = self.env.ref('sf_plan.sf_production_plan_action1').id
|
||||
url = f"{url}/web#view_type=list&action={action_id}"
|
||||
content = content[0].replace('{{product_id}}', product).replace('{{url}}', url)
|
||||
contents.append(content)
|
||||
return contents
|
||||
|
||||
# 销售订单逾期预警
|
||||
# # 销售订单逾期预警
|
||||
def _overdue_warning_func(self):
|
||||
sale_order_
|
||||
return 1
|
||||
@@ -68,3 +72,4 @@ class SFMessageSale(models.Model):
|
||||
# 销售订单已逾期
|
||||
def _overdue_func(self):
|
||||
return 1
|
||||
|
||||
|
||||
@@ -39,28 +39,6 @@ class SFMessageWork(models.Model):
|
||||
contents.append(content)
|
||||
return contents
|
||||
|
||||
@api.depends('cnc_ids.tool_state')
|
||||
def _compute_tool_state(self):
|
||||
# 将self的id与tool_state进行保存
|
||||
tool_state_dict = {record.id: record.tool_state for record in self}
|
||||
res = super(SFMessageWork, self)._compute_tool_state()
|
||||
data = {'name': []}
|
||||
for record in self:
|
||||
if tool_state_dict[record.id] != '2' and record.tool_state == '2':
|
||||
data['name'].append(record.production_id.programming_no)
|
||||
|
||||
if data['name']:
|
||||
# 请求cloud接口,发送微信消息推送
|
||||
configsettings = self.env['res.config.settings'].get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/message/invalid_tool_state'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
data['token'] = configsettings['token']
|
||||
ret = requests.post(config_url, json=data, headers=config_header)
|
||||
ret = ret.json()
|
||||
_logger.info('无效用刀异常消息推送接口:%s' % ret)
|
||||
return res
|
||||
|
||||
def request_url(self):
|
||||
we_config_info = self.env['we.config'].sudo().search([], limit=1)
|
||||
redirect_domain = self.env['we.app'].sudo().search([('id', '=', we_config_info.odoo_app_id.id)]).redirect_domain
|
||||
@@ -75,3 +53,4 @@ class SFMessageWork(models.Model):
|
||||
# 拼接URL
|
||||
full_url = full_url + "web#" + query_string
|
||||
return full_url
|
||||
|
||||
|
||||
@@ -93,6 +93,9 @@ class Sf_Mrs_Connect(http.Controller):
|
||||
pre_workorder.write(
|
||||
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||
res.update({
|
||||
'production_ids': productions.ids
|
||||
})
|
||||
return json.JSONEncoder().encode(res)
|
||||
else:
|
||||
res = {'status': 0, 'message': '该制造订单暂未开始'}
|
||||
|
||||
@@ -18,7 +18,6 @@ class OrderPrice(models.Model):
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
@api.depends('sale_order_id.remark')
|
||||
def _compute_bfm_amount_total(self):
|
||||
for record in self:
|
||||
amount_total = 0
|
||||
|
||||
@@ -3013,8 +3013,7 @@ class CuttingToolBasicParameters(models.Model):
|
||||
})
|
||||
if 'basic_parameters_cutter_head' in result['cutting_tool_basic_parameters_yesterday_list']:
|
||||
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']:
|
||||
basic_parameters_cutter_head_list = json.loads(
|
||||
result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head'])
|
||||
basic_parameters_cutter_head_list = result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']
|
||||
if basic_parameters_cutter_head_list:
|
||||
for cutter_head_item in basic_parameters_cutter_head_list:
|
||||
cutter_head = self.search(
|
||||
|
||||
@@ -95,16 +95,20 @@ class CNCprocessing(models.Model):
|
||||
# tool_state_remark1 = f'{key}无效刀:{data1.get(key)}'
|
||||
# 无效刀处理逻辑
|
||||
# 1、创建制造订单无效刀检测结果记录
|
||||
logging.info('创建制造订单无效刀检测结果记录!')
|
||||
production_id.detection_result_ids.create({
|
||||
'production_id': production_id.id,
|
||||
'processing_panel': key,
|
||||
'routing_type': 'CNC加工',
|
||||
'rework_reason': 'programming', # 原因:编程(programming)
|
||||
'detailed_reason': '无效功能刀具',
|
||||
'test_results': '返工',
|
||||
'handle_result': '待处理'
|
||||
})
|
||||
if not production_id.detection_result_ids.filtered(
|
||||
lambda a: (a.processing_panel == key and a.detailed_reason == '无效功能刀具'
|
||||
and a.handle_result == '待处理' and a.routing_type == 'CNC加工'
|
||||
and a.rework_reason == 'programming' and a.test_results == '返工')):
|
||||
logging.info('创建制造订单无效刀检测结果记录!')
|
||||
production_id.detection_result_ids.create({
|
||||
'production_id': production_id.id,
|
||||
'processing_panel': key,
|
||||
'routing_type': 'CNC加工',
|
||||
'rework_reason': 'programming', # 原因:编程(programming)
|
||||
'detailed_reason': '无效功能刀具',
|
||||
'test_results': '返工',
|
||||
'handle_result': '待处理'
|
||||
})
|
||||
# 修改当前面装夹预调工单的 is_rework 为 True
|
||||
# work_ids = production_id.workorder_ids.filtered(
|
||||
# lambda a: a.routing_type == '装夹预调' and a.processing_panel == key and not a.is_rework)
|
||||
|
||||
Reference in New Issue
Block a user