Accept Merge Request #1222: (feature/优化制造功能 -> develop)

Merge Request: 运行日志数据接入;大屏对接

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1222
This commit is contained in:
马广威
2024-08-20 11:28:33 +08:00
committed by Coding
12 changed files with 299 additions and 5887 deletions

View File

@@ -30,6 +30,7 @@
'views/machine_info_present.xml', 'views/machine_info_present.xml',
'views/delivery_record.xml', 'views/delivery_record.xml',
'views/res_config_settings_views.xml', 'views/res_config_settings_views.xml',
'views/maintenance_views.xml',
], ],
'assets': { 'assets': {

View File

@@ -1,11 +1,45 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import re
import ast import ast
import json import json
import logging import logging
from datetime import datetime
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
def convert_to_seconds(time_str):
# 修改正则表达式,使 H、M、S 部分可选
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 Sf_Dashboard_Connect(http.Controller): class Sf_Dashboard_Connect(http.Controller):
@http.route('/api/get_machine_datas/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False, @http.route('/api/get_machine_datas/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
@@ -18,6 +52,11 @@ class Sf_Dashboard_Connect(http.Controller):
""" """
res = {'status': 1, 'message': '成功', 'data': []} res = {'status': 1, 'message': '成功', 'data': []}
logging.info('前端请求机床数据的参数为:%s' % kw) logging.info('前端请求机床数据的参数为:%s' % kw)
# 获取当前时间的时间戳
current_timestamp = datetime.now().timestamp()
print(current_timestamp)
# tem_list = [ # tem_list = [
# "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-1", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-3", # "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-1", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-3",
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-4", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-5", # "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-4", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-5",
@@ -33,10 +72,24 @@ class Sf_Dashboard_Connect(http.Controller):
machine_list = ast.literal_eval(kw['machine_list']) machine_list = ast.literal_eval(kw['machine_list'])
for item in machine_list: for item in machine_list:
machine_data = equipment_obj.search([('code', '=', item)]) machine_data = equipment_obj.search([('code', '=', item)])
# 机床上线时间段
first_online_duration = current_timestamp - int(machine_data.first_online_time.timestamp())
power_off_time = None
power_off_rate = None
if machine_data.machine_power_on_time:
power_off_time = first_online_duration - convert_to_seconds(machine_data.machine_power_on_time)
power_off_rate = round((power_off_time / first_online_duration), 3)
else:
power_off_time = False
power_off_rate = False
if machine_data: if machine_data:
res['data'].append({ res['data'].append({
'active': machine_data.status,
'id': machine_data.id, 'id': machine_data.id,
'name': machine_data.name, 'name': machine_data.name,
'brand': machine_data.type_id.name,
'code': machine_data.code, 'code': machine_data.code,
'status': machine_data.status, 'status': machine_data.status,
'run_status': machine_data.run_status, 'run_status': machine_data.run_status,
@@ -88,6 +141,16 @@ class Sf_Dashboard_Connect(http.Controller):
'alarm_time': machine_data.alarm_time, 'alarm_time': machine_data.alarm_time,
'alarm_msg': machine_data.alarm_msg, 'alarm_msg': machine_data.alarm_msg,
'clear_time': machine_data.clear_time, 'clear_time': machine_data.clear_time,
# 计算出来的数据
# 开动率:运行时间/通电时间
'run_rate': machine_data.run_rate,
# 关机时长:初次上线时间 - 通电时间
'power_off_time': power_off_time,
# 关机率:关机时长/初次上线时间
'power_off_rate': power_off_rate,
'first_online_duration': first_online_duration,
# 停机时间:关机时间 - 运行时间
# 停机时长:关机时间 - 初次上线时间
}) })
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
@@ -96,3 +159,126 @@ class Sf_Dashboard_Connect(http.Controller):
res['status'] = -1 res['status'] = -1
res['message'] = '前端请求机床数据失败,原因:%s' % e res['message'] = '前端请求机床数据失败,原因:%s' % e
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
# @http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
# cors="*")
# def logs_list(self, **kw):
# """
# 拿到日志数据返回给大屏展示
# :param kw:
# :return:
# """
# res = {'status': 1, 'message': '成功', 'data': []}
# logging.info('前端请求日志数据的参数为:%s' % kw)
#
# try:
# # 获取请求的日志数据
# logs_obj = request.env['maintenance.equipment.oee.log.detail'].sudo()
# # 获取请求的机床数据
# machine_list = ast.literal_eval(kw['machine_list'])
# begin_time_str = kw['begin_time'].strip('"')
# end_time_str = kw['end_time'].strip('"')
#
# begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
# end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
#
# print('begin_time: %s' % begin_time)
# for item in machine_list:
# log_datas = logs_obj.search(
# [('equipment_code', '=', item), ('time', '>=', begin_time), ('time', '<=', end_time)])
# print('log_datas: %s' % log_datas)
# for log_data in log_datas:
# res['data'].append({
# 'equipment_code': log_data.equipment_code,
# 'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'),
# 'state': log_data.state
#
# })
#
# return json.JSONEncoder().encode(res)
#
# except Exception as e:
# logging.info('前端请求日志数据失败,原因:%s' % e)
# res['status'] = -1
# res['message'] = '前端请求日志数据失败,原因:%s' % e
# return json.JSONEncoder().encode(res)
@http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
def logs_list(self, **kw):
"""
拿到日志数据返回给大屏展示
:param kw:
:return:
"""
res = {'status': 1, 'message': '成功', 'data': {}}
logging.info('前端请求日志数据的参数为:%s' % kw)
try:
# 获取请求的日志数据
logs_obj = request.env['maintenance.equipment.oee.log.detail'].sudo()
# 获取请求的机床数据
machine_list = ast.literal_eval(kw['machine_list'])
begin_time_str = kw['begin_time'].strip('"')
end_time_str = kw['end_time'].strip('"')
begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
print('begin_time: %s' % begin_time)
for item in machine_list:
log_datas = logs_obj.search(
[('equipment_code', '=', item), ('time', '>=', begin_time), ('time', '<=', end_time)])
print('log_datas: %s' % log_datas)
# 将数据按照 equipment_code 进行分组
if item not in res['data']:
res['data'][item] = []
for log_data in log_datas:
res['data'][item].append({
'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'),
'state': log_data.state,
'production_name': log_data.production_name,
})
return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode()
except Exception as e:
logging.info('前端请求日志数据失败,原因:%s' % e)
res['status'] = -1
res['message'] = '前端请求日志数据失败,原因:%s' % e
return json.dumps(res)
# 返回CNC机床列表
@http.route('/api/CNCList', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
cors="*")
def CNCList(self, **kw):
"""
获取CNC机床列表
:param kw:
:return:
"""
# logging.info('CNCList:%s' % kw)
try:
res = {'Succeed': True}
# cnc_list = request.env['sf.cnc.equipment'].sudo().search([])
# cnc_list = ["XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-1", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-3",
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-4", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-5",
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-6", "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-7",
# "XT-GNJC-LSZX-X800-Y550-Z550-T24-A3-8", "XT-GNJC-WZZX-X800-Y550-Z550-T24-A5-2",
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-9", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-10",
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-11", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-12",
# "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-13", "XT-GNJC-GSZG-X600-Y400-Z350-T21-A3-14"]
cnc_list_obj = request.env['maintenance.equipment'].sudo().search(
[('function_type', '!=', False), ('active', '=', True)])
cnc_list = list(map(lambda x: x.code, cnc_list_obj))
print('cnc_list: %s' % cnc_list)
res['CNCList'] = cnc_list
except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('CNCList error:%s' % e)
return json.JSONEncoder().encode(res)

View File

@@ -121,6 +121,13 @@ class Machine_ftp(models.Model):
""" """
_inherit = 'maintenance.equipment' _inherit = 'maintenance.equipment'
# 机床首次上线时间(默认取值2024年08月01日零点)
def _get_default_online_time(self):
return datetime(2024, 1, 1, 0, 0, 0)
first_online_time = fields.Datetime(string='首次上线时间', default=_get_default_online_time)
# workorder_ids = fields.One2many('mrp.workorder', 'machine_tool_id', string='工单') # workorder_ids = fields.One2many('mrp.workorder', 'machine_tool_id', string='工单')
# # 机床配置项目 # # 机床配置项目
@@ -275,7 +282,28 @@ class Machine_ftp(models.Model):
alarm_msg = fields.Char('故障报警信息', readonly=True) alarm_msg = fields.Char('故障报警信息', readonly=True)
clear_time = fields.Char('故障消除时间(复原时间)', readonly=True) clear_time = fields.Char('故障消除时间(复原时间)', readonly=True)
# 当前程序名, 机床累计运行时间, 机床系统日期, 机床系统时间, 当前刀具号, 机床循环时间 # # 开动率
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): class WorkCenterBarcode(models.Model):

View File

@@ -18,6 +18,7 @@
<field name="run_status"/> <field name="run_status"/>
<field name="run_time"/> <field name="run_time"/>
<field name="system_date"/> <field name="system_date"/>
<field name="first_online_time"/>
</group> </group>
<group> <group>
<field name="cut_status"/> <field name="cut_status"/>

View File

@@ -0,0 +1,17 @@
<?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>

View File

@@ -41,29 +41,32 @@ class SfMaintenanceEquipmentOEELog(models.Model):
_name = 'maintenance.equipment.oee.logs' _name = 'maintenance.equipment.oee.logs'
_description = '设备运行日志' _description = '设备运行日志'
equipment_id = fields.Many2one('maintenance.equipment', '机台号') equipment_id = fields.Many2one('maintenance.equipment', '机台号', readonly='True')
equipment_code = fields.Char('设备编码') equipment_code = fields.Char('设备编码', readonly='True')
name = fields.Char('设备名称', readonly='True') name = fields.Char('设备名称', readonly='True')
function_type = fields.Selection(
[("ZXJGZX", "钻铣加工中心"), ("CXJGZX", "车削加工中心"), ("FHJGZX", "复合加工中心")],
default="", string="功能类型")
machine_tool_picture = fields.Binary('设备图片') machine_tool_picture = fields.Binary('设备图片')
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号') type_id = fields.Many2one('sf.machine_tool.type', '品牌型号', reaonly='True')
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"), state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
("检修", "检修"), ("保养", "保养")], default="", string="实时状态") ("检修", "检修"), ("保养", "保养")], default="", string="实时状态")
online_time = fields.Char('开机时长') online_time = fields.Char('开机时长', reaonly='True')
offline_time = fields.Char('关机时长') offline_time = fields.Char('关机时长', reaonly='True')
offline_nums = fields.Integer('关机次数') offline_nums = fields.Integer('关机次数', reaonly='True')
# 待机时长 # 待机时长
idle_time = fields.Char('待机时长') idle_time = fields.Char('待机时长', reaonly='True')
# 待机率 # 待机率
idle_rate = fields.Char('待机率') idle_rate = fields.Char('待机率', reaonly='True')
work_time = fields.Char('加工时长') work_time = fields.Char('加工时长', reaonly='True')
work_rate = fields.Char('可用率') work_rate = fields.Char('可用率', reaonly='True')
fault_time = fields.Char('故障时长') fault_time = fields.Char('故障时长', reaonly='True')
fault_rate = fields.Char('故障率') fault_rate = fields.Char('故障率', reaonly='True')
fault_nums = fields.Integer('故障次数') fault_nums = fields.Integer('故障次数', reaonly='True')
detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情') detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情')
@@ -81,12 +84,15 @@ class SfMaintenanceEquipmentOEELog(models.Model):
class SfMaintenanceEquipmentOEELogDetail(models.Model): class SfMaintenanceEquipmentOEELogDetail(models.Model):
_name = 'maintenance.equipment.oee.log.detail' _name = 'maintenance.equipment.oee.log.detail'
_description = '设备运行日志详情' _description = '设备运行日志详情'
_order = 'time desc'
sequence = fields.Integer('序号') # sequence = fields.Integer('序号', related='id')
time = fields.Datetime('时间') time = fields.Datetime('时间')
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"), state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
("检修", "检修"), ("保养", "保养")], default="", string="事件/状态") ("检修", "检修"), ("保养", "保养")], default="", string="事件/状态")
production_id = fields.Many2one('mrp.production', '加工工单') production_name = fields.Char('加工工单')
log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志') log_id = fields.Many2one('maintenance.equipment.oee.logs', '日志')
# equipment_code = fields.Char('设备编码', related='log_id.equipment_code')
equipment_code = fields.Char('设备编码', readonly='True')

View File

@@ -159,6 +159,8 @@
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/> <field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
<field name="type_id"/> <field name="type_id"/>
<field name="state"/> <field name="state"/>
<field name="equipment_code"/>
<field name="function_type"/>
</group> </group>
</group> </group>
<group> <group>
@@ -202,10 +204,10 @@
<!-- <field name="detail_ids" domain="[('time','&lt;',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> --> <!-- <field name="detail_ids" domain="[('time','&lt;',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
<field name="detail_ids" domain="[('state','ilike','加工')]"> <field name="detail_ids" domain="[('state','ilike','加工')]">
<tree> <tree>
<field name="sequence"/> <!-- <field name="sequence"/> -->
<field name="time"/> <field name="time"/>
<field name="state"/> <field name="state"/>
<field name="production_id"/> <field name="production_name"/>
</tree> </tree>
<!-- <form> --> <!-- <form> -->
<!-- <field name="sequence"/> --> <!-- <field name="sequence"/> -->
@@ -219,10 +221,10 @@
<page string="历史日志详情"> <page string="历史日志详情">
<field name="detail_ids"> <field name="detail_ids">
<tree> <tree>
<field name="sequence"/> <!-- <field name="sequence"/> -->
<field name="time"/> <field name="time"/>
<field name="state"/> <field name="state"/>
<field name="production_id"/> <field name="production_name"/>
</tree> </tree>
<!-- <form> --> <!-- <form> -->
<!-- <field name="sequence"/> --> <!-- <field name="sequence"/> -->
@@ -263,10 +265,10 @@
<field name="model">maintenance.equipment.oee.log.detail</field> <field name="model">maintenance.equipment.oee.log.detail</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="sequence"/> <!-- <field name="sequence"/> -->
<field name="time"/> <field name="time"/>
<field name="state"/> <field name="state"/>
<field name="production_id"/> <field name="production_name"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -280,10 +282,10 @@
<group> <group>
<group> <group>
<field name="state"/> <field name="state"/>
<field name="production_id"/> <!-- <field name="production_id"/> -->
</group> </group>
<group> <group>
<field name="sequence"/> <!-- <field name="sequence"/> -->
<field name="time"/> <field name="time"/>
</group> </group>
</group> </group>

View File

@@ -135,6 +135,9 @@ class ResMrpWorkOrder(models.Model):
surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids') surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids')
surface_technics_purchase_count = fields.Integer("外协采购", compute='_compute_surface_technics_purchase_ids') surface_technics_purchase_count = fields.Integer("外协采购", compute='_compute_surface_technics_purchase_ids')
# 是否绑定托盘
is_trayed = fields.Boolean(string='是否绑定托盘', default=False)
@api.depends('name', 'production_id.name') @api.depends('name', 'production_id.name')
def _compute_surface_technics_picking_ids(self): def _compute_surface_technics_picking_ids(self):
for workorder in self: for workorder in self:
@@ -1248,6 +1251,18 @@ class ResMrpWorkOrder(models.Model):
record.production_id.button_mark_done1() record.production_id.button_mark_done1()
# record.production_id.state = 'done' # record.production_id.state = 'done'
# 解绑托盘
def unbind_tray(self):
self.write({
'rfid_code': False,
'tray_serial_number': False,
'tray_product_id': False,
'tray_brand_id': False,
'tray_type_id': False,
'tray_model_id': False,
'is_trayed': False
})
# 将FTP的检测报告文件下载到临时目录 # 将FTP的检测报告文件下载到临时目录
def download_reportfile_tmp(self, workorder, reportpath): def download_reportfile_tmp(self, workorder, reportpath):
@@ -1556,6 +1571,7 @@ class SfWorkOrderBarcodes(models.Model):
raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name)) raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name))
self.process_state = '待检测' self.process_state = '待检测'
self.date_start = datetime.now() self.date_start = datetime.now()
self.is_trayed = True
else: else:
raise UserError('没有找到Rfid为【%s】的托盘信息!!!' % barcode) raise UserError('没有找到Rfid为【%s】的托盘信息!!!' % barcode)
# stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)]) # stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)])

View File

@@ -1,15 +1,17 @@
var RFID = '' var RFID = ''
$(document).off('keydown') $(document).off('keydown')
console.log(2222) $(document).on('keydown', 'body.o_web_client', function (e) {
$(document).on('keydown', '.modal.d-block.o_technical_modal,body.o_web_client', function (e) {
const dom = $('.customRFID')
if(!dom.length) return
setTimeout(() => { setTimeout(() => {
RFID = '' RFID = ''
}, 200) }, 200)
if(e.key == 'Enter' && e.keyCode == 13 || e.key == 'Tab' && e.keyCode == 9){ if(e.key == 'Enter' && e.keyCode == 13 || e.key == 'Tab' && e.keyCode == 9){
console.log(RFID)
if(!RFID || RFID.length <= 3) return; if(!RFID || RFID.length <= 3) return;
dom.children('span').text(RFID) $('[name="button_start"]').trigger('click')
setTimeout(() => {
$('.o_dialog .modal-footer .btn-primary').trigger('click')
}, 50)
RFID = '' RFID = ''
return; return;
} }

View File

@@ -122,7 +122,7 @@
groups="sf_base.group_sf_mrp_user"/> groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<xpath expr="(//header//button[@name='button_scrap'])" position="replace"> <xpath expr="(//header//button[@name='button_scrap'])" position="replace">
<button name="button_scrap" invisible="0"/> <button name="button_scrap" invisible="1"/>
<button name="do_update_program" string="更新程序" type="object" groups="sf_base.group_sf_mrp_user" <button name="do_update_program" string="更新程序" type="object" groups="sf_base.group_sf_mrp_user"
confirm="是否确认更新程序" confirm="是否确认更新程序"
attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/> attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/>

View File

@@ -118,6 +118,9 @@
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/> <field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//form" position="inside">
<script src="sf_manufacturing/static/src/js/customRFID.js"/>
</xpath>
<xpath expr="//header/field[@name='state']" position="replace"> <xpath expr="//header/field[@name='state']" position="replace">
<field name="state" widget="statusbar" <field name="state" widget="statusbar"
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/> statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
@@ -146,6 +149,7 @@
<field name='name' invisible="1"/> <field name='name' invisible="1"/>
<field name='is_rework' invisible="1"/> <field name='is_rework' invisible="1"/>
<field name='is_delivery' invisible="1"/> <field name='is_delivery' invisible="1"/>
<field name="is_trayed" invisible="1"/>
<!-- <field name='is_send_program_again' invisible="1"/>--> <!-- <field name='is_send_program_again' invisible="1"/>-->
<!-- 工单form页面的开始停工按钮等 --> <!-- 工单form页面的开始停工按钮等 -->
<!-- <button name="button_start" type="object" string="开始" class="btn-success" --> <!-- <button name="button_start" type="object" string="开始" class="btn-success" -->
@@ -161,7 +165,9 @@
<!-- <button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"--> <!-- <button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"-->
<!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>--> <!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>-->
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始" <button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"
attrs="{'invisible': ['|', '|', '|', '|', ('routing_type', '=', '解除装夹'), ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/> attrs="{'invisible': ['|', '|', '|', '|', '|', ('routing_type', '=', '装夹预调'), ('routing_type', '=', '解除装夹'), ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>
<button name="button_start" type="object" string="开始" class="btn-success"
attrs="{'invisible': ['|', '|', '|', '|', ('routing_type', '!=', '装夹预调'), ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>
<button name="button_pending" type="object" string="暂停" class="btn-warning" <button name="button_pending" type="object" string="暂停" class="btn-warning"
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/> attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
<button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工" <button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
@@ -187,6 +193,9 @@
<button name="button_rework_pre" type="object" string="返工" <button name="button_rework_pre" type="object" string="返工"
class="btn-primary" class="btn-primary"
attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/> attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/>
<button name="unbind_tray" type="object" string="解绑托盘"
class="btn-primary"
attrs="{'invisible': ['|', '|', ('routing_type','!=','装夹预调'),('state','!=','progress'), ('is_trayed', '=', False)]}"/>
<button name="print_method" type="object" string="打印二维码" class="btn-primary" <button name="print_method" type="object" string="打印二维码" class="btn-primary"
attrs="{'invisible': ['|',('routing_type','!=','解除装夹'),('state','!=','done')]}"/> attrs="{'invisible': ['|',('routing_type','!=','解除装夹'),('state','!=','done')]}"/>
</xpath> </xpath>

File diff suppressed because it is too large Load Diff