Merge branch 'refs/heads/develop' into feature/tax_sync
This commit is contained in:
@@ -324,4 +324,4 @@ def unlink(self):
|
|||||||
|
|
||||||
|
|
||||||
BaseModel._create = _create
|
BaseModel._create = _create
|
||||||
BaseModel.unlink = unlink
|
# BaseModel.unlink = unlink
|
||||||
@@ -88,6 +88,7 @@ class MrsProductionProcess(models.Model):
|
|||||||
code = fields.Char("编码")
|
code = fields.Char("编码")
|
||||||
name = fields.Char('名称')
|
name = fields.Char('名称')
|
||||||
remark = fields.Text("备注")
|
remark = fields.Text("备注")
|
||||||
|
sequence = fields.Integer('排序')
|
||||||
# processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
|
# processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
|
||||||
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
||||||
active = fields.Boolean('有效', default=True)
|
active = fields.Boolean('有效', default=True)
|
||||||
@@ -96,7 +97,7 @@ class MrsProductionProcess(models.Model):
|
|||||||
# workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True)
|
# workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True)
|
||||||
processing_day = fields.Float('加工天数/d')
|
processing_day = fields.Float('加工天数/d')
|
||||||
travel_day = fields.Float('路途天数/d')
|
travel_day = fields.Float('路途天数/d')
|
||||||
|
sequence = fields.Integer('排序')
|
||||||
|
|
||||||
# class MrsProcessingTechnology(models.Model):
|
# class MrsProcessingTechnology(models.Model):
|
||||||
# _name = 'sf.processing.technology'
|
# _name = 'sf.processing.technology'
|
||||||
@@ -148,6 +149,7 @@ class MrsProductionProcessParameter(models.Model):
|
|||||||
processing_day = fields.Float('加工天数/d')
|
processing_day = fields.Float('加工天数/d')
|
||||||
travel_day = fields.Float('路途天数/d')
|
travel_day = fields.Float('路途天数/d')
|
||||||
active = fields.Boolean('有效', default=True)
|
active = fields.Boolean('有效', default=True)
|
||||||
|
processing_mm = fields.Char('加工厚度/mm')
|
||||||
|
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
result = []
|
result = []
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
diff a/sf_base/models/tool_base_new.py b/sf_base/models/tool_base_new.py (rejected hunks)
|
|
||||||
@@ -108,6 +108,4 @@
|
|
||||||
cutting_speed_ids = fields.One2many('sf.cutting.speed', 'standard_library_id', string='切削速度Vc')
|
|
||||||
- feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz',
|
|
||||||
- domain=[('cutting_speed', '!=', False)])
|
|
||||||
- feed_per_tooth_ids_3 = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz',
|
|
||||||
- domain=[('cutting_speed', '!=', False)])
|
|
||||||
+ feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz')
|
|
||||||
+ feed_per_tooth_ids_3 = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz')
|
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<record model="ir.ui.view" id="mrs_production_process_parameter_form">
|
<record model="ir.ui.view" id="mrs_production_process_parameter_form">
|
||||||
<field name="model">sf.production.process.parameter</field>
|
<field name="model">sf.production.process.parameter</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="表面工艺可选参数" create="0" delete="0">
|
<form string="表面工艺可选参数" create="0" delete="0" >
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
<h1>
|
<h1>
|
||||||
@@ -33,11 +33,12 @@
|
|||||||
<group>
|
<group>
|
||||||
<field name="processing_day" readonly="1"/>
|
<field name="processing_day" readonly="1"/>
|
||||||
<field name="travel_day" readonly="1"/>
|
<field name="travel_day" readonly="1"/>
|
||||||
|
<field name="processing_mm" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="适用材料">
|
<page string="适用材料">
|
||||||
<field name="materials_model_ids"></field>
|
<field name="materials_model_ids" readonly="1"></field>
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
@@ -52,7 +53,7 @@
|
|||||||
<search>
|
<search>
|
||||||
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
|
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
|
||||||
<field name="name" string="名称" filter_domain="[('name','ilike',self)]"/>
|
<field name="name" string="名称" filter_domain="[('name','ilike',self)]"/>
|
||||||
<field name="code" string="编码" filter_domain="[('codeNum','ilike',self)]"/>
|
<field name="code" string="编码" filter_domain="[('code','ilike',self)]"/>
|
||||||
<searchpanel class="account_root">
|
<searchpanel class="account_root">
|
||||||
<field name="process_id" icon="fa-filter"/>
|
<field name="process_id" icon="fa-filter"/>
|
||||||
</searchpanel>
|
</searchpanel>
|
||||||
@@ -140,7 +141,7 @@
|
|||||||
<field name="model">sf.production.process.category</field>
|
<field name="model">sf.production.process.category</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="表面工艺类别" default_order="sequence, id" create="0" edit="0" delete="1">
|
<tree string="表面工艺类别" default_order="sequence, id" create="0" edit="0" delete="1">
|
||||||
<field name="sequence" widget="handle" string="序号"/>
|
<field name="sequence" widget="handle" string="序号" readonly="1"/>
|
||||||
<field name="code"/>
|
<field name="code"/>
|
||||||
<field name="name" string="名称"/>
|
<field name="name" string="名称"/>
|
||||||
</tree>
|
</tree>
|
||||||
@@ -163,7 +164,8 @@
|
|||||||
<record model="ir.ui.view" id="sf_production_process_tree">
|
<record model="ir.ui.view" id="sf_production_process_tree">
|
||||||
<field name="model">sf.production.process</field>
|
<field name="model">sf.production.process</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="表面工艺" create="0" edit="0" delete="1">
|
<tree string="表面工艺" create="0" edit="0" delete="0">
|
||||||
|
<field name="sequence" widget="handle" string="序号" readonly="1"/>
|
||||||
<field name="code"/>
|
<field name="code"/>
|
||||||
<field name="name" string="名称"/>
|
<field name="name" string="名称"/>
|
||||||
<field name="remark"/>
|
<field name="remark"/>
|
||||||
@@ -174,7 +176,7 @@
|
|||||||
<record model="ir.ui.view" id="sf_production_process_form">
|
<record model="ir.ui.view" id="sf_production_process_form">
|
||||||
<field name="model">sf.production.process</field>
|
<field name="model">sf.production.process</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="表面工艺" create="0" edit="1" delete="1">
|
<form string="表面工艺" create="0" delete="0">
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
<h1>
|
<h1>
|
||||||
@@ -192,11 +194,11 @@
|
|||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="可选参数">
|
<page string="可选参数" >
|
||||||
<field name="parameter_ids">
|
<field name="parameter_ids" >
|
||||||
<tree force_save="1">
|
<tree force_save="1" create="0">
|
||||||
<field name="code" readonly="1" force_save="1"/>
|
<field name="code" readonly="1" force_save="1"/>
|
||||||
<field name="name"/>
|
<field name="name" readonly="1"/>
|
||||||
<field name="gain_way"/>
|
<field name="gain_way"/>
|
||||||
<field name='process_id' default="default"/>
|
<field name='process_id' default="default"/>
|
||||||
</tree>
|
</tree>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class StatusChange(models.Model):
|
|||||||
res = super(StatusChange, self).action_confirm()
|
res = super(StatusChange, self).action_confirm()
|
||||||
|
|
||||||
# 原有方法执行后,进行额外的操作(如调用外部API)
|
# 原有方法执行后,进行额外的操作(如调用外部API)
|
||||||
process_start_time = str(datetime.now())
|
process_start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
config = self.env['res.config.settings'].get_values()
|
config = self.env['res.config.settings'].get_values()
|
||||||
json1 = {
|
json1 = {
|
||||||
'params': {
|
'params': {
|
||||||
|
|||||||
3
sf_hr/__init__.py
Normal file
3
sf_hr/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import models
|
||||||
22
sf_hr/__manifest__.py
Normal file
22
sf_hr/__manifest__.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
{
|
||||||
|
'name': '机企猫智能工厂 员工管理',
|
||||||
|
'version': '1.0',
|
||||||
|
'summary': '智能工厂员工模块',
|
||||||
|
'sequence': 1,
|
||||||
|
'category': 'sf',
|
||||||
|
'website': 'https://www.sf.jikimo.com',
|
||||||
|
'depends': ['hr'],
|
||||||
|
'data': [
|
||||||
|
'views/hr_employee.xml',
|
||||||
|
],
|
||||||
|
'demo': [
|
||||||
|
],
|
||||||
|
'qweb': [
|
||||||
|
],
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
'installable': True,
|
||||||
|
'application': False,
|
||||||
|
'auto_install': False,
|
||||||
|
}
|
||||||
2
sf_hr/models/__init__.py
Normal file
2
sf_hr/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
0
sf_hr/security/ir.model.access.csv
Normal file
0
sf_hr/security/ir.model.access.csv
Normal file
|
|
15
sf_hr/views/hr_employee.xml
Normal file
15
sf_hr/views/hr_employee.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record id="view_form_employee_extend" model="ir.ui.view">
|
||||||
|
<field name="name">employee_form</field>
|
||||||
|
<field name="model">hr.employee</field>
|
||||||
|
<field name="inherit_id" ref="hr.view_employee_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//group//field[@name='work_email']" position="attributes">
|
||||||
|
<attribute name="required">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
@@ -163,6 +163,7 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
# 停机时间:关机时间 - 运行时间
|
# 停机时间:关机时间 - 运行时间
|
||||||
# 停机时长:关机时间 - 初次上线时间
|
# 停机时长:关机时间 - 初次上线时间
|
||||||
'img': f'data:image/png;base64,{machine_data.machine_tool_picture.decode("utf-8")}',
|
'img': f'data:image/png;base64,{machine_data.machine_tool_picture.decode("utf-8")}',
|
||||||
|
'equipment_type': machine_data.category_id.name,
|
||||||
})
|
})
|
||||||
|
|
||||||
return json.dumps(res)
|
return json.dumps(res)
|
||||||
@@ -172,49 +173,6 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
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="*")
|
@http.route('/api/logs/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
def logs_list(self, **kw):
|
def logs_list(self, **kw):
|
||||||
"""
|
"""
|
||||||
@@ -226,9 +184,9 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
logging.info('前端请求日志数据的参数为:%s' % kw)
|
logging.info('前端请求日志数据的参数为:%s' % kw)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 获取请求的日志数据
|
# 连接数据库
|
||||||
logs_obj = request.env['maintenance.equipment.oee.log.detail'].sudo()
|
conn = psycopg2.connect(**db_config)
|
||||||
# 获取请求的机床数据
|
cur = conn.cursor()
|
||||||
machine_list = ast.literal_eval(kw['machine_list'])
|
machine_list = ast.literal_eval(kw['machine_list'])
|
||||||
begin_time_str = kw['begin_time'].strip('"')
|
begin_time_str = kw['begin_time'].strip('"')
|
||||||
end_time_str = kw['end_time'].strip('"')
|
end_time_str = kw['end_time'].strip('"')
|
||||||
@@ -239,19 +197,25 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
print('begin_time: %s' % begin_time)
|
print('begin_time: %s' % begin_time)
|
||||||
|
|
||||||
for item in machine_list:
|
for item in machine_list:
|
||||||
log_datas = logs_obj.search(
|
sql = '''
|
||||||
[('equipment_code', '=', item), ('time', '>=', begin_time), ('time', '<=', end_time)])
|
SELECT time, device_state, program_name
|
||||||
print('log_datas: %s' % log_datas)
|
FROM device_data
|
||||||
|
WHERE device_name = %s AND time >= %s AND time <= %s
|
||||||
|
ORDER BY time ASC;
|
||||||
|
'''
|
||||||
|
# 执行SQL命令,使用参数绑定
|
||||||
|
cur.execute(sql, (item, begin_time, end_time))
|
||||||
|
results = cur.fetchall()
|
||||||
|
|
||||||
# 将数据按照 equipment_code 进行分组
|
# 将数据按照 equipment_code 进行分组
|
||||||
if item not in res['data']:
|
if item not in res['data']:
|
||||||
res['data'][item] = []
|
res['data'][item] = []
|
||||||
|
|
||||||
for log_data in log_datas:
|
for result in results:
|
||||||
res['data'][item].append({
|
res['data'][item].append({
|
||||||
'time': log_data.time.strftime('%Y-%m-%d %H:%M:%S'),
|
'time': result[0].strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
'state': log_data.state,
|
'state': result[1],
|
||||||
'production_name': log_data.production_name,
|
'production_name': result[2],
|
||||||
})
|
})
|
||||||
|
|
||||||
return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode()
|
return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode()
|
||||||
@@ -623,7 +587,7 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
|
|
||||||
# 查询pg库来获得待机次数
|
# 查询pg库来获得待机次数
|
||||||
@http.route('/api/IdleAlarmCount', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
@http.route('/api/IdleAlarmCount', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
def idle_count(self, **kw):
|
def idle_alarm_count(self, **kw):
|
||||||
"""
|
"""
|
||||||
查询设备的待机次数
|
查询设备的待机次数
|
||||||
"""
|
"""
|
||||||
@@ -636,69 +600,50 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
try:
|
try:
|
||||||
# 获取请求的机床数据
|
# 获取请求的机床数据
|
||||||
machine_list = ast.literal_eval(kw['machine_list'])
|
machine_list = ast.literal_eval(kw['machine_list'])
|
||||||
idle_times = []
|
total_alarm_time = 0
|
||||||
idle_dict = {}
|
alarm_count_num = 0
|
||||||
|
|
||||||
for item in machine_list:
|
for item in machine_list:
|
||||||
sql = '''
|
sql = '''
|
||||||
SELECT idle_start_time,alarm_time,alarm_repair_time FROM device_data WHERE device_name = %s;
|
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
|
||||||
|
ORDER BY idle_start_time, time
|
||||||
|
) subquery;
|
||||||
|
'''
|
||||||
|
|
||||||
|
sql2 = '''
|
||||||
|
SELECT DISTINCT ON (alarm_time) alarm_time, alarm_repair_time
|
||||||
|
FROM device_data
|
||||||
|
WHERE device_name = %s AND alarm_time IS NOT NULL
|
||||||
|
ORDER BY alarm_time, time;
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# 执行SQL命令
|
# 执行SQL命令
|
||||||
cur.execute(sql, (item,))
|
cur.execute(sql, (item,))
|
||||||
result = cur.fetchall()
|
result = cur.fetchall()
|
||||||
# # print('result', result)
|
print('result========', result)
|
||||||
#
|
|
||||||
# # 将查询结果添加到idle_times列表中
|
|
||||||
# idle_times = [row[0] for row in result if row[0] is not None]
|
|
||||||
#
|
|
||||||
# # 对结果去重
|
|
||||||
# unique_idle_times = set(idle_times)
|
|
||||||
# # print('unique_idle_times', unique_idle_times)
|
|
||||||
#
|
|
||||||
# # 统计去重后的数量
|
|
||||||
# idle_count = len(unique_idle_times)
|
|
||||||
# # idle_dict[item] = idle_count
|
|
||||||
#
|
|
||||||
# res['data'][item] = idle_count
|
|
||||||
|
|
||||||
total_alarm_time = 0
|
|
||||||
alarm_count = 0
|
|
||||||
alarm_time_list = []
|
|
||||||
idle_times = []
|
|
||||||
alarm_times = []
|
|
||||||
|
|
||||||
|
cur.execute(sql2, (item,))
|
||||||
|
result2 = cur.fetchall()
|
||||||
|
print('result2========', result2)
|
||||||
|
#
|
||||||
for row in result:
|
for row in result:
|
||||||
idle_start_time = row[0]
|
res['data'][item] = {'idle_count': row[0]}
|
||||||
alarm_time = row[1]
|
alarm_count = []
|
||||||
alarm_repair_time = row[2]
|
for row in result2:
|
||||||
|
alarm_count.append(row[0])
|
||||||
alarm_time_list.append(alarm_time) # 将时长累加,以秒为单位
|
total_alarm_time += abs(float(row[0]))
|
||||||
idle_times.append(idle_start_time)
|
if len(list(set(alarm_count))) == 1:
|
||||||
# if alarm_repair_time is not None:
|
if list(set(alarm_count))[0] is None:
|
||||||
# alarm_times.append(alarm_repair_time)
|
alarm_count_num = 0
|
||||||
alarm_times.append(alarm_repair_time)
|
else:
|
||||||
|
alarm_count_num = 1
|
||||||
# 对结果去重
|
else:
|
||||||
unique_total_alarm_time = set(alarm_time_list)
|
alarm_count_num = len(list(set(alarm_count)))
|
||||||
unique_idle_times = set(idle_times)
|
res['data'][item]['total_alarm_time'] = total_alarm_time / 3600
|
||||||
unique_alarm_times = set(alarm_times)
|
res['data'][item]['alarm_count_num'] = alarm_count_num
|
||||||
|
|
||||||
# 统计去重后的数量
|
|
||||||
idle_count = len(unique_idle_times)
|
|
||||||
|
|
||||||
for alarm_time in unique_total_alarm_time:
|
|
||||||
if alarm_time is not None:
|
|
||||||
total_alarm_time += abs(float(alarm_time))
|
|
||||||
|
|
||||||
alarm_count = len(unique_alarm_times) if unique_alarm_times else 0
|
|
||||||
alarm_count = alarm_count if total_alarm_time else 0
|
|
||||||
|
|
||||||
# 存储待机次数和总待机时长(单位:秒)
|
|
||||||
res['data'][item] = {
|
|
||||||
'idle_count': idle_count,
|
|
||||||
'total_alarm_time': total_alarm_time / 3600, # 以秒为单位
|
|
||||||
'alarm_count': alarm_count
|
|
||||||
}
|
|
||||||
|
|
||||||
# 返回统计结果
|
# 返回统计结果
|
||||||
return json.dumps(res)
|
return json.dumps(res)
|
||||||
@@ -711,7 +656,7 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
|
|
||||||
# 查询pg库来获得异常情况
|
# 查询pg库来获得异常情况
|
||||||
@http.route('/api/alarm/logs', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
@http.route('/api/alarm/logs', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
def idle_count(self, **kw):
|
def alarm_logs(self, **kw):
|
||||||
"""
|
"""
|
||||||
查询设备的异常情况
|
查询设备的异常情况
|
||||||
"""
|
"""
|
||||||
@@ -763,3 +708,110 @@ class Sf_Dashboard_Connect(http.Controller):
|
|||||||
finally:
|
finally:
|
||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
# 设备oee
|
||||||
|
@http.route('/api/OEE', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
|
def OEE(self, **kw):
|
||||||
|
"""
|
||||||
|
获取产线等oee
|
||||||
|
"""
|
||||||
|
res = {'status': 1, 'message': '成功', 'data': {}}
|
||||||
|
logging.info('前端请求oee数据的参数为:%s' % kw)
|
||||||
|
|
||||||
|
try:
|
||||||
|
count_oee = 1
|
||||||
|
workcenter_obj = request.env['mrp.workcenter'].sudo()
|
||||||
|
workcenter_list = ast.literal_eval(kw['workcenter_list'])
|
||||||
|
print('workcenter_list: %s' % workcenter_list)
|
||||||
|
for line in workcenter_list:
|
||||||
|
res['data'][line] = workcenter_obj.search([('name', '=', line)]).oee
|
||||||
|
count_oee *= workcenter_obj.search([('name', '=', line)]).oee
|
||||||
|
res['data']['综合oee'] = count_oee / 1000000
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred: {e}")
|
||||||
|
|
||||||
|
return json.dumps(res)
|
||||||
|
|
||||||
|
# # 查询某段时间的设备oee
|
||||||
|
# @http.route('/api/OEEByTime', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
|
# def OEEByTime(self, **kw):
|
||||||
|
# """
|
||||||
|
# 获取某段时间的oee
|
||||||
|
# """
|
||||||
|
# res = {'status': 1, 'message': '成功', 'data': {}}
|
||||||
|
# logging.info('前端请求获取某段时间的oee的参数为:%s' % kw)
|
||||||
|
# workcenter_list = ast.literal_eval(kw['workcenter_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('workcenter_list: %s' % workcenter_list)
|
||||||
|
# # 连接数据库
|
||||||
|
# conn = psycopg2.connect(**db_config)
|
||||||
|
# cur = conn.cursor()
|
||||||
|
# # 查询并计算OEE平均值
|
||||||
|
# oee_data = {}
|
||||||
|
# for workcenter in workcenter_list:
|
||||||
|
# cur.execute("""
|
||||||
|
# SELECT AVG(oee) as avg_oee
|
||||||
|
# FROM oee_data
|
||||||
|
# WHERE workcenter_name = %s
|
||||||
|
# AND time BETWEEN %s AND %s
|
||||||
|
# """, (workcenter, begin_time, end_time))
|
||||||
|
#
|
||||||
|
# result = cur.fetchone()
|
||||||
|
# avg_oee = result[0] if result else 0.0
|
||||||
|
# oee_data[workcenter] = avg_oee
|
||||||
|
#
|
||||||
|
# # 返回数据
|
||||||
|
# res['data'] = oee_data
|
||||||
|
# return json.dumps(res)
|
||||||
|
|
||||||
|
@http.route('/api/OEEByTime', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||||
|
def OEEByTime(self, **kw):
|
||||||
|
"""
|
||||||
|
获取某段时间的oee,根据用户指定的时间单位(day或hour)返回对应的平均值
|
||||||
|
"""
|
||||||
|
res = {'status': 1, 'message': '成功', 'data': {}}
|
||||||
|
logging.info('前端请求获取某段时间的oee的参数为:%s' % kw)
|
||||||
|
|
||||||
|
# 获取并解析参数
|
||||||
|
workcenter_list = ast.literal_eval(kw['workcenter_list'])
|
||||||
|
begin_time_str = kw['begin_time'].strip('"')
|
||||||
|
end_time_str = kw['end_time'].strip('"')
|
||||||
|
time_unit = kw.get('time_unit', 'day') # 默认单位为天
|
||||||
|
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')
|
||||||
|
|
||||||
|
# 连接数据库
|
||||||
|
conn = psycopg2.connect(**db_config)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# 根据时间单位选择不同的时间格式
|
||||||
|
if time_unit == 'hour':
|
||||||
|
time_format = 'YYYY-MM-DD HH24:00:00'
|
||||||
|
else: # 默认为'day'
|
||||||
|
time_format = 'YYYY-MM-DD'
|
||||||
|
|
||||||
|
# 查询并计算OEE平均值
|
||||||
|
oee_data = {}
|
||||||
|
for workcenter in workcenter_list:
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT to_char(time, '{time_format}') as time_unit, AVG(oee) as avg_oee
|
||||||
|
FROM oee_data
|
||||||
|
WHERE workcenter_name = %s
|
||||||
|
AND time BETWEEN %s AND %s
|
||||||
|
GROUP BY time_unit
|
||||||
|
ORDER BY time_unit
|
||||||
|
""", (workcenter, begin_time, end_time))
|
||||||
|
|
||||||
|
results = cur.fetchall()
|
||||||
|
oee_data[workcenter] = {row[0]: row[1] for row in results}
|
||||||
|
|
||||||
|
# 关闭数据库连接
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# 返回数据
|
||||||
|
res['data'] = oee_data
|
||||||
|
return json.dumps(res)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
'views/model_type_view.xml',
|
'views/model_type_view.xml',
|
||||||
'views/agv_setting_views.xml',
|
'views/agv_setting_views.xml',
|
||||||
'views/sf_maintenance_equipment.xml',
|
'views/sf_maintenance_equipment.xml',
|
||||||
|
'views/res_config_settings_views.xml',
|
||||||
],
|
],
|
||||||
'assets': {
|
'assets': {
|
||||||
|
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ from . import res_user
|
|||||||
from . import production_line_base
|
from . import production_line_base
|
||||||
from . import agv_setting
|
from . import agv_setting
|
||||||
from . import agv_scheduling
|
from . import agv_scheduling
|
||||||
|
from . import res_config_setting
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ class AgvScheduling(models.Model):
|
|||||||
rec.site_state = '空闲'
|
rec.site_state = '空闲'
|
||||||
rec.end_site_id = agv_task_route.end_site_id.id
|
rec.end_site_id = agv_task_route.end_site_id.id
|
||||||
rec.agv_route_id = agv_task_route.id
|
rec.agv_route_id = agv_task_route.id
|
||||||
# rec._delivery_avg()
|
is_agv_task_dispatch = self.env['ir.config_parameter'].sudo().get_param('is_agv_task_dispatch')
|
||||||
|
if is_agv_task_dispatch:
|
||||||
|
rec._delivery_avg()
|
||||||
# 更新接驳站状态
|
# 更新接驳站状态
|
||||||
rec.env['sf.agv.site'].update_site_state({rec.end_site_id.name: '占用'}, False)
|
rec.env['sf.agv.site'].update_site_state({rec.end_site_id.name: '占用'}, False)
|
||||||
|
|
||||||
|
|||||||
@@ -123,9 +123,39 @@ class MrpProduction(models.Model):
|
|||||||
# 上传零件图纸
|
# 上传零件图纸
|
||||||
part_drawing = fields.Binary('零件图纸')
|
part_drawing = fields.Binary('零件图纸')
|
||||||
|
|
||||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
@api.depends('product_id.manual_quotation')
|
||||||
|
def _compute_manual_quotation(self):
|
||||||
|
for item in self:
|
||||||
|
item.manual_quotation = item.product_id.manual_quotation
|
||||||
|
|
||||||
|
manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True)
|
||||||
is_scrap = fields.Boolean('是否报废', default=False)
|
is_scrap = fields.Boolean('是否报废', default=False)
|
||||||
is_remanufacture = fields.Boolean('是否重新制造', default=False)
|
is_remanufacture = fields.Boolean('是否重新制造', default=False)
|
||||||
|
remanufacture_count = fields.Integer("重新制造订单数量", compute='_compute_remanufacture_production_ids')
|
||||||
|
remanufacture_production_id = fields.Many2one('mrp.production', string='')
|
||||||
|
|
||||||
|
@api.depends('remanufacture_production_id')
|
||||||
|
def _compute_remanufacture_production_ids(self):
|
||||||
|
for production in self:
|
||||||
|
if production.remanufacture_production_id:
|
||||||
|
remanufacture_production = self.env['mrp.production'].search(
|
||||||
|
[('id', '=', production.remanufacture_production_id.id)])
|
||||||
|
if remanufacture_production:
|
||||||
|
production.remanufacture_count = len(remanufacture_production)
|
||||||
|
else:
|
||||||
|
production.remanufacture_count = 0
|
||||||
|
|
||||||
|
def action_view_remanufacture_productions(self):
|
||||||
|
self.ensure_one()
|
||||||
|
mrp_production = self.env['mrp.production'].search(
|
||||||
|
[('id', '=', self.remanufacture_production_id.id)])
|
||||||
|
action = {
|
||||||
|
'res_model': 'mrp.production',
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_id': mrp_production.id,
|
||||||
|
}
|
||||||
|
return action
|
||||||
|
|
||||||
@api.depends(
|
@api.depends(
|
||||||
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'tool_state',
|
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'tool_state',
|
||||||
@@ -446,28 +476,29 @@ class MrpProduction(models.Model):
|
|||||||
# self.env['mrp.workorder'].json_workorder_str(k, production, route))
|
# self.env['mrp.workorder'].json_workorder_str(k, production, route))
|
||||||
# 表面工艺工序
|
# 表面工艺工序
|
||||||
# 获取表面工艺id
|
# 获取表面工艺id
|
||||||
if production.product_id.model_process_parameters_ids:
|
|
||||||
logging.info('model_process_parameters_ids:%s' % production.product_id.model_process_parameters_ids)
|
|
||||||
surface_technics_arr = []
|
|
||||||
# 工序id
|
# 工序id
|
||||||
|
surface_technics_arr = []
|
||||||
route_workcenter_arr = []
|
route_workcenter_arr = []
|
||||||
for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
|
for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
|
||||||
|
if item.route_workcenter_id.surface_technics_id.id:
|
||||||
|
for process_param in production.product_id.model_process_parameters_ids:
|
||||||
|
logging.info('process_param:%s%s' % (process_param.id, process_param.name))
|
||||||
|
if item.route_workcenter_id.surface_technics_id == process_param.process_id:
|
||||||
|
logging.info(
|
||||||
|
'surface_technics_id:%s%s' % (item.route_workcenter_id.surface_technics_id.id,
|
||||||
|
item.route_workcenter_id.surface_technics_id.name))
|
||||||
surface_technics_arr.append(item.route_workcenter_id.surface_technics_id.id)
|
surface_technics_arr.append(item.route_workcenter_id.surface_technics_id.id)
|
||||||
route_workcenter_arr.append(item.route_workcenter_id.id)
|
route_workcenter_arr.append(item.route_workcenter_id.id)
|
||||||
if surface_technics_arr:
|
if surface_technics_arr:
|
||||||
production_process_category = self.env['sf.production.process.category'].search(
|
production_process = self.env['sf.production.process'].search(
|
||||||
[('production_process_ids.id', 'in', surface_technics_arr)],
|
[('id', 'in', surface_technics_arr)],
|
||||||
order='sequence asc'
|
order='sequence asc'
|
||||||
)
|
)
|
||||||
# 用filter刷选表面工艺id'是否存在工艺类别对象里
|
for p in production_process:
|
||||||
if production_process_category:
|
logging.info('production_process:%s' % p.name)
|
||||||
for p in production_process_category:
|
# if production_process:
|
||||||
logging.info('production_process_category:%s' % p.name)
|
|
||||||
production_process = p.production_process_ids.filtered(
|
|
||||||
lambda pp: pp.id in surface_technics_arr)
|
|
||||||
if production_process:
|
|
||||||
process_parameter = production.product_id.model_process_parameters_ids.filtered(
|
process_parameter = production.product_id.model_process_parameters_ids.filtered(
|
||||||
lambda pm: pm.process_id.id == production_process.id)
|
lambda pm: pm.process_id.id == p.id)
|
||||||
if process_parameter:
|
if process_parameter:
|
||||||
# 产品为表面工艺服务的供应商
|
# 产品为表面工艺服务的供应商
|
||||||
product_production_process = self.env['product.template'].search(
|
product_production_process = self.env['product.template'].search(
|
||||||
@@ -475,7 +506,7 @@ class MrpProduction(models.Model):
|
|||||||
if product_production_process:
|
if product_production_process:
|
||||||
route_production_process = self.env[
|
route_production_process = self.env[
|
||||||
'mrp.routing.workcenter'].search(
|
'mrp.routing.workcenter'].search(
|
||||||
[('surface_technics_id', '=', production_process.id),
|
[('surface_technics_id', '=', p.id),
|
||||||
('id', 'in', route_workcenter_arr)])
|
('id', 'in', route_workcenter_arr)])
|
||||||
if route_production_process:
|
if route_production_process:
|
||||||
workorders_values.append(
|
workorders_values.append(
|
||||||
@@ -850,8 +881,8 @@ class MrpProduction(models.Model):
|
|||||||
'target': 'new',
|
'target': 'new',
|
||||||
'context': {
|
'context': {
|
||||||
'default_production_id': self.id,
|
'default_production_id': self.id,
|
||||||
'default_programming_state': '编程中' if cloud_programming[
|
'default_reprogramming_num': cloud_programming['reprogramming_num'],
|
||||||
'programming_state'] != '已下发' else '已下发',
|
'default_programming_states': cloud_programming['programming_state'],
|
||||||
'default_is_reprogramming': True if cloud_programming['programming_state'] in ['已下发'] else False
|
'default_is_reprogramming': True if cloud_programming['programming_state'] in ['已下发'] else False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -998,32 +1029,19 @@ class MrpProduction(models.Model):
|
|||||||
move_values = {'product_description_variants': '',
|
move_values = {'product_description_variants': '',
|
||||||
'date_planned': datetime.now(),
|
'date_planned': datetime.now(),
|
||||||
'date_deadline': datetime.now(),
|
'date_deadline': datetime.now(),
|
||||||
# 'move_dest_ids': self.env['stock.move'].search([('id', '=', move.id)]),
|
|
||||||
'move_dest_ids': move,
|
'move_dest_ids': move,
|
||||||
'group_id': False,
|
'group_id': move.group_id,
|
||||||
'route_ids': [],
|
'route_ids': [],
|
||||||
'warehouse_id': self.warehouse_id,
|
'warehouse_id': self.warehouse_id,
|
||||||
'priority': 0,
|
'priority': 0,
|
||||||
'orderpoint_id': False,
|
'orderpoint_id': False,
|
||||||
'product_packaging_id': False}
|
'product_packaging_id': False}
|
||||||
rule = self.env['stock.rule'].search(
|
|
||||||
[('action', '=', 'pull'), ('procure_method', '=', 'mts_else_mto'), (
|
|
||||||
'location_dest_id', '=', self.env['stock.location'].search([('parent_path', '=', '2/5/')]).id),
|
|
||||||
('location_src_id', '=', self.env['stock.location'].search(
|
|
||||||
[('barcode', '=', 'CP')]).id)])
|
|
||||||
# origin = move._prepare_procurement_origin()
|
|
||||||
procurement_requests.append(self.env['procurement.group'].Procurement(
|
procurement_requests.append(self.env['procurement.group'].Procurement(
|
||||||
move.product_id, 1.0, move.product_uom,
|
move.product_id, 1.0, move.product_uom,
|
||||||
self.env['stock.location'].search([('barcode', '=', 'CP')]),
|
move.location_id, move.rule_id and move.rule_id.name or "/",
|
||||||
rule and rule.name or "/",
|
|
||||||
sale_order.name, move.company_id, move_values))
|
sale_order.name, move.company_id, move_values))
|
||||||
self.env['procurement.group'].run(procurement_requests,
|
self.env['procurement.group'].run(procurement_requests,
|
||||||
raise_user_error=not self.env.context.get('from_orderpoint'))
|
raise_user_error=not self.env.context.get('from_orderpoint'))
|
||||||
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
|
||||||
# productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
|
||||||
# (
|
|
||||||
# p.move_dest_ids.procure_method != 'make_to_order' and
|
|
||||||
# not p.move_raw_ids and not p.workorder_ids)).action_confirm()
|
|
||||||
productions = self.env['mrp.production'].sudo().search(
|
productions = self.env['mrp.production'].sudo().search(
|
||||||
[('origin', '=', self.origin)], order='id desc', limit=1)
|
[('origin', '=', self.origin)], order='id desc', limit=1)
|
||||||
move = self.env['stock.move'].search([('origin', '=', productions.name)], order='id desc')
|
move = self.env['stock.move'].search([('origin', '=', productions.name)], order='id desc')
|
||||||
@@ -1051,8 +1069,29 @@ class MrpProduction(models.Model):
|
|||||||
'picking_id': sfp_move.picking_id.id, 'picking_type_id': sfp_move.picking_type_id.id,
|
'picking_id': sfp_move.picking_id.id, 'picking_type_id': sfp_move.picking_type_id.id,
|
||||||
'production_id': False})
|
'production_id': False})
|
||||||
productions.write({'programming_no': self.programming_no, 'is_remanufacture': True})
|
productions.write({'programming_no': self.programming_no, 'is_remanufacture': True})
|
||||||
productions.procurement_group_id.mrp_production_ids.move_dest_ids.write(
|
# productions.procurement_group_id.mrp_production_ids.move_dest_ids.write(
|
||||||
{'group_id': self.env['procurement.group'].search([('name', '=', sale_order.name)])})
|
# {'group_id': self.env['procurement.group'].search([('name', '=', sale_order.name)])})
|
||||||
|
stock_picking = None
|
||||||
|
pc_picking = self.env['stock.picking'].search(
|
||||||
|
[('origin', '=', productions.name), ('name', 'ilike', 'WH/PC/')])
|
||||||
|
stock_picking = pc_picking
|
||||||
|
int_picking = self.env['stock.picking'].search(
|
||||||
|
[('origin', '=', productions.name), ('name', 'ilike', 'WH/INT/')])
|
||||||
|
stock_picking |= int_picking
|
||||||
|
for pick in stock_picking:
|
||||||
|
if pick.move_ids:
|
||||||
|
product_type_id = pick.move_ids[0].product_id.categ_id
|
||||||
|
if product_type_id.name == '坯料':
|
||||||
|
location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')])
|
||||||
|
if not location_id:
|
||||||
|
logging.info(f'没有搜索到【坯料存货区】: {location_id}')
|
||||||
|
break
|
||||||
|
if pick.picking_type_id.name == '内部调拨':
|
||||||
|
if pick.location_dest_id.product_type != product_type_id:
|
||||||
|
pick.location_dest_id = location_id.id
|
||||||
|
elif pick.picking_type_id.name == '生产发料':
|
||||||
|
if pick.location_id.product_type != product_type_id:
|
||||||
|
pick.location_id = location_id.id
|
||||||
scarp_process_parameter_workorder = self.env['mrp.workorder'].search(
|
scarp_process_parameter_workorder = self.env['mrp.workorder'].search(
|
||||||
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', self.id),
|
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', self.id),
|
||||||
('is_subcontract', '=', True)])
|
('is_subcontract', '=', True)])
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class ResWorkcenter(models.Model):
|
|||||||
|
|
||||||
oee_target = fields.Float(
|
oee_target = fields.Float(
|
||||||
string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True)
|
string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True)
|
||||||
|
oee = fields.Float(compute='_compute_oee', help='Overall Equipment Effectiveness, based on the last month', store=True)
|
||||||
|
|
||||||
time_start = fields.Float('Setup Time', tracking=True)
|
time_start = fields.Float('Setup Time', tracking=True)
|
||||||
time_stop = fields.Float('Cleanup Time', tracking=True)
|
time_stop = fields.Float('Cleanup Time', tracking=True)
|
||||||
|
|||||||
@@ -60,7 +60,12 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True)
|
default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True)
|
||||||
# state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True)
|
# state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True)
|
||||||
|
|
||||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
@api.depends('production_id.manual_quotation')
|
||||||
|
def _compute_manual_quotation(self):
|
||||||
|
for item in self:
|
||||||
|
item.manual_quotation = item.production_id.manual_quotation
|
||||||
|
|
||||||
|
manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True)
|
||||||
|
|
||||||
def _compute_working_users(self):
|
def _compute_working_users(self):
|
||||||
super()._compute_working_users()
|
super()._compute_working_users()
|
||||||
@@ -1162,10 +1167,10 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
def button_finish(self):
|
def button_finish(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.routing_type == '装夹预调':
|
if record.routing_type == '装夹预调':
|
||||||
if not record.material_center_point and record.X_deviation_angle > 0:
|
|
||||||
raise UserError("请对前置三元检测定位参数进行计算定位")
|
|
||||||
if not record.rfid_code and record.is_rework is False:
|
if not record.rfid_code and record.is_rework is False:
|
||||||
raise UserError("请扫RFID码进行绑定")
|
raise UserError("请扫RFID码进行绑定")
|
||||||
|
if not record.material_center_point or record.X_deviation_angle <= 0:
|
||||||
|
raise UserError("请对前置三元检测定位参数进行计算定位")
|
||||||
record.process_state = '待加工'
|
record.process_state = '待加工'
|
||||||
# record.write({'process_state': '待加工'})
|
# record.write({'process_state': '待加工'})
|
||||||
record.production_id.process_state = '待加工'
|
record.production_id.process_state = '待加工'
|
||||||
@@ -1265,15 +1270,14 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
|
|
||||||
# 解绑托盘
|
# 解绑托盘
|
||||||
def unbind_tray(self):
|
def unbind_tray(self):
|
||||||
self.write({
|
self.production_id.workorder_ids.write({
|
||||||
'rfid_code': False,
|
'rfid_code': False,
|
||||||
'tray_serial_number': False,
|
'tray_serial_number': False,
|
||||||
'tray_product_id': False,
|
'tray_product_id': False,
|
||||||
'tray_brand_id': False,
|
'tray_brand_id': False,
|
||||||
'tray_type_id': False,
|
'tray_type_id': False,
|
||||||
'tray_model_id': False,
|
'tray_model_id': False,
|
||||||
'is_trayed': False
|
'is_trayed': False})
|
||||||
})
|
|
||||||
|
|
||||||
# 将FTP的检测报告文件下载到临时目录
|
# 将FTP的检测报告文件下载到临时目录
|
||||||
def download_reportfile_tmp(self, workorder, reportpath):
|
def download_reportfile_tmp(self, workorder, reportpath):
|
||||||
|
|||||||
22
sf_manufacturing/models/res_config_setting.py
Normal file
22
sf_manufacturing/models/res_config_setting.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from odoo import models, fields, api
|
||||||
|
|
||||||
|
|
||||||
|
class ResConfigSettings(models.TransientModel):
|
||||||
|
_inherit = 'res.config.settings'
|
||||||
|
|
||||||
|
is_agv_task_dispatch = fields.Boolean('是否下发AGV任务', default=False)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def get_values(self):
|
||||||
|
values = super(ResConfigSettings, self).get_values()
|
||||||
|
config = self.env['ir.config_parameter'].sudo()
|
||||||
|
is_agv_task_dispatch = config.get_param('is_agv_task_dispatch')
|
||||||
|
values.update(
|
||||||
|
is_agv_task_dispatch=is_agv_task_dispatch,
|
||||||
|
)
|
||||||
|
return values
|
||||||
|
|
||||||
|
def set_values(self):
|
||||||
|
super(ResConfigSettings, self).set_values()
|
||||||
|
config = self.env['ir.config_parameter'].sudo()
|
||||||
|
config.set_param("is_agv_task_dispatch", self.is_agv_task_dispatch or False)
|
||||||
@@ -169,7 +169,6 @@ class StockRule(models.Model):
|
|||||||
else:
|
else:
|
||||||
forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
|
forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
|
||||||
procure_method = 'make_to_stock'
|
procure_method = 'make_to_stock'
|
||||||
|
|
||||||
move_values = rule._get_stock_move_values(*procurement)
|
move_values = rule._get_stock_move_values(*procurement)
|
||||||
move_values['procure_method'] = procure_method
|
move_values['procure_method'] = procure_method
|
||||||
moves_values_by_company[procurement.company_id.id].append(move_values)
|
moves_values_by_company[procurement.company_id.id].append(move_values)
|
||||||
@@ -177,13 +176,10 @@ class StockRule(models.Model):
|
|||||||
for company_id, moves_values in moves_values_by_company.items():
|
for company_id, moves_values in moves_values_by_company.items():
|
||||||
# create the move as SUPERUSER because the current user may not have the rights to do it (mto product
|
# create the move as SUPERUSER because the current user may not have the rights to do it (mto product
|
||||||
# launched by a sale for example)
|
# launched by a sale for example)
|
||||||
logging.info(moves_values)
|
|
||||||
moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
|
moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
|
||||||
moves_values)
|
moves_values)
|
||||||
logging.info(moves)
|
|
||||||
# Since action_confirm launch following procurement_group we should activate it.
|
# Since action_confirm launch following procurement_group we should activate it.
|
||||||
moves._action_confirm()
|
moves._action_confirm()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|||||||
@@ -3,13 +3,34 @@ $(document).off('keydown')
|
|||||||
$(document).on('keydown', 'body.o_web_client', function (e) {
|
$(document).on('keydown', 'body.o_web_client', function (e) {
|
||||||
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){
|
||||||
|
|
||||||
|
let fieldValue1 = $('[name="routing_type"]');
|
||||||
|
console.log('字段值:', fieldValue1.text());
|
||||||
console.log(RFID)
|
console.log(RFID)
|
||||||
if(!RFID || RFID.length <= 3) return;
|
let fieldValue2 = $('[name="rfid_code"]');
|
||||||
$('[name="button_start"]').trigger('click')
|
console.log('字段值2:', fieldValue2.text());
|
||||||
RFID = ''
|
// if(!RFID || RFID.length <= 3) return;
|
||||||
|
// $('[name="button_start"]').trigger('click')
|
||||||
|
// setTimeout(() => {
|
||||||
|
// $('.o_dialog .modal-footer .btn-primary').trigger('click')
|
||||||
|
// }, 50)
|
||||||
|
// RFID = ''
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// fieldValue2.val() === '')
|
||||||
|
// 检查字段值是否等于“装夹预调”
|
||||||
|
if (fieldValue1.text() === '装夹预调') {
|
||||||
|
if (!RFID || RFID.length <= 3) return;
|
||||||
|
$('[name="button_start"]').trigger('click');
|
||||||
|
setTimeout(() => {
|
||||||
|
$('.o_dialog .modal-footer .btn-primary').trigger('click');
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
RFID = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RFID += e.key
|
RFID += e.key
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
confirm="是否确认更新程序"
|
confirm="是否确认更新程序"
|
||||||
attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/>
|
attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/>
|
||||||
<button name="button_rework" string="返工" type="object" groups="sf_base.group_sf_mrp_user"
|
<button name="button_rework" string="返工" type="object" groups="sf_base.group_sf_mrp_user"
|
||||||
attrs="{'invisible': ['|',('state', '!=', 'rework') ,('programming_state', '!=', '已编程')]}"/>
|
attrs="{'invisible': ['|','|',('state', '!=', 'rework') ,('programming_state', '!=', '已编程'),('is_rework', '=', True)]}"/>
|
||||||
<button name="button_scrap_new" string="报废" type="object"
|
<button name="button_scrap_new" string="报废" type="object"
|
||||||
groups="sf_base.group_sf_mrp_user"
|
groups="sf_base.group_sf_mrp_user"
|
||||||
attrs="{'invisible': ['|',('is_scrap', '=', False),('state','=','cancel')]}"/>
|
attrs="{'invisible': ['|',('is_scrap', '=', False),('state','=','cancel')]}"/>
|
||||||
@@ -201,6 +201,19 @@
|
|||||||
data-hotkey="l"/>
|
data-hotkey="l"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//button[@name='action_view_mo_delivery']" position="before">
|
||||||
|
<button class="oe_stat_button" name="action_view_remanufacture_productions" type="object"
|
||||||
|
icon="fa-wrench" attrs="{'invisible': [('remanufacture_count', '=', 0)]}"
|
||||||
|
groups="mrp.group_mrp_user">
|
||||||
|
<div class="o_field_widget o_stat_info">
|
||||||
|
<span class="o_stat_value">
|
||||||
|
<field name="remanufacture_count"/>
|
||||||
|
</span>
|
||||||
|
<span class="o_stat_text">新的制造</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//header//button[@name='action_toggle_is_locked']" position="replace">
|
<xpath expr="//header//button[@name='action_toggle_is_locked']" position="replace">
|
||||||
<button name="action_toggle_is_locked"
|
<button name="action_toggle_is_locked"
|
||||||
attrs="{'invisible': ['|', ('show_lock', '=', False), ('is_locked', '=', True)]}"
|
attrs="{'invisible': ['|', ('show_lock', '=', False), ('is_locked', '=', True)]}"
|
||||||
|
|||||||
@@ -198,7 +198,7 @@
|
|||||||
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="解绑托盘"
|
<button name="unbind_tray" type="object" string="解绑托盘"
|
||||||
class="btn-primary"
|
class="btn-primary"
|
||||||
attrs="{'invisible': ['|', '|', ('routing_type','!=','装夹预调'),('state','!=','progress'), ('is_trayed', '=', False)]}"/>
|
attrs="{'invisible': ['|', '|', '|', ('routing_type','!=','装夹预调'),('state','!=','progress'), ('is_trayed', '=', False), ('state', 'in', ('done'))]}"/>
|
||||||
<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>
|
||||||
|
|||||||
24
sf_manufacturing/views/res_config_settings_views.xml
Normal file
24
sf_manufacturing/views/res_config_settings_views.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record id="res_config_settings_view_form_sf_sync" model="ir.ui.view">
|
||||||
|
<field name="name">res.config.settings.view.form.inherit.sf_sync</field>
|
||||||
|
<field name="model">res.config.settings</field>
|
||||||
|
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//div[@id='agv_config']/div" position="after">
|
||||||
|
<div class="col-12 col-lg-6 o_setting_box">
|
||||||
|
<div class="o_setting_left_pane">
|
||||||
|
<field name="is_agv_task_dispatch"/>
|
||||||
|
</div>
|
||||||
|
<div class="o_setting_right_pane">
|
||||||
|
<div class="text-muted">
|
||||||
|
<label for="is_agv_task_dispatch"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
@@ -13,9 +13,10 @@ class ProductionWizard(models.TransientModel):
|
|||||||
_description = '制造订单向导'
|
_description = '制造订单向导'
|
||||||
|
|
||||||
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
||||||
|
reprogramming_num = fields.Integer('重新编程次数', default=0)
|
||||||
is_reprogramming = fields.Boolean(string='申请重新编程', default=False)
|
is_reprogramming = fields.Boolean(string='申请重新编程', default=False)
|
||||||
is_remanufacture = fields.Boolean(string='重新生成制造订单', default=True)
|
is_remanufacture = fields.Boolean(string='重新生成制造订单', default=True)
|
||||||
programming_state = fields.Selection(
|
programming_states = fields.Selection(
|
||||||
[('待编程', '待编程'), ('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'),
|
[('待编程', '待编程'), ('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'),
|
||||||
('已下发', '已下发')],
|
('已下发', '已下发')],
|
||||||
string='编程状态')
|
string='编程状态')
|
||||||
@@ -26,18 +27,21 @@ class ProductionWizard(models.TransientModel):
|
|||||||
self.is_reprogramming = False
|
self.is_reprogramming = False
|
||||||
|
|
||||||
def confirm(self):
|
def confirm(self):
|
||||||
self.production_id.action_cancel()
|
|
||||||
self.production_id.detection_result_ids.write({'handle_result': '已处理'})
|
self.production_id.detection_result_ids.write({'handle_result': '已处理'})
|
||||||
self.production_id.write({'state': 'cancel', 'scrap_ids': [(0, 0, {
|
self.production_id.write({'state': 'cancel', 'scrap_ids': [(0, 0, {
|
||||||
'name': self.env['ir.sequence'].next_by_code('stock.scrap') or _('New'),
|
'name': self.env['ir.sequence'].next_by_code('stock.scrap') or _('New'),
|
||||||
'product_id': self.production_id.product_id.id,
|
'product_id': self.production_id.product_id.id,
|
||||||
'scrap_qty': 1,
|
'scrap_qty': 1,
|
||||||
'lot_id': self.production_id.move_line_raw_ids.lot_id.id,
|
'origin': self.production_id.origin,
|
||||||
|
'date_done': fields.datetime.now(),
|
||||||
|
'lot_id': self.env['stock.move.line'].search(
|
||||||
|
[('move_id', '=', self.production_id.move_raw_ids[0].id)]).lot_id.id,
|
||||||
'location_id': self.production_id.move_raw_ids.filtered(lambda x: x.state not in (
|
'location_id': self.production_id.move_raw_ids.filtered(lambda x: x.state not in (
|
||||||
'done',
|
'done',
|
||||||
'cancel')) and self.production_id.location_src_id.id or self.production_id.location_dest_id.id,
|
'cancel')) and self.production_id.location_src_id.id or self.production_id.location_dest_id.id,
|
||||||
'scrap_location_id': self.env['stock.scrap']._get_default_scrap_location_id(),
|
'scrap_location_id': self.env['stock.scrap']._get_default_scrap_location_id(),
|
||||||
'state': 'done'})]})
|
'state': 'done'})]})
|
||||||
|
self.production_id.action_cancel()
|
||||||
if self.is_remanufacture is True:
|
if self.is_remanufacture is True:
|
||||||
ret = {'programming_list': [], 'is_reprogramming': self.is_reprogramming}
|
ret = {'programming_list': [], 'is_reprogramming': self.is_reprogramming}
|
||||||
if self.is_reprogramming is True:
|
if self.is_reprogramming is True:
|
||||||
@@ -78,6 +82,7 @@ class ProductionWizard(models.TransientModel):
|
|||||||
ret['programming_list'].append(vals)
|
ret['programming_list'].append(vals)
|
||||||
|
|
||||||
new_production = self.production_id.recreateManufacturing(ret)
|
new_production = self.production_id.recreateManufacturing(ret)
|
||||||
|
self.production_id.write({'remanufacture_production_id': new_production.id})
|
||||||
if self.is_reprogramming is False:
|
if self.is_reprogramming is False:
|
||||||
for panel in new_production.product_id.model_processing_panel.split(','):
|
for panel in new_production.product_id.model_processing_panel.split(','):
|
||||||
scrap_cnc_workorder = max(
|
scrap_cnc_workorder = max(
|
||||||
|
|||||||
@@ -7,15 +7,26 @@
|
|||||||
<form>
|
<form>
|
||||||
<sheet>
|
<sheet>
|
||||||
<field name="production_id" invisible="1"/>
|
<field name="production_id" invisible="1"/>
|
||||||
<field name="programming_state" invisible="1"/>
|
<field name="programming_states" invisible="1"/>
|
||||||
<div>
|
<div>
|
||||||
重新生成制造订单
|
重新生成制造订单
|
||||||
<field name="is_remanufacture" force_save="1"/>
|
<field name="is_remanufacture" force_save="1"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div attrs='{"invisible": [("reprogramming_num","=",0)]}'>
|
||||||
|
注意: 该制造订单产品已申请重新编程次数为<field
|
||||||
|
name="reprogramming_num" string=""
|
||||||
|
readonly="1"
|
||||||
|
style='color:red;'/>,且当前编程状态为
|
||||||
|
<field name="programming_states" string=""
|
||||||
|
decoration-info="programming_states == '待编程'"
|
||||||
|
decoration-success="programming_states == '已下发'"
|
||||||
|
decoration-warning="programming_states =='编程中'"
|
||||||
|
decoration-danger="programming_states =='已编程'" readonly="1"/>
|
||||||
|
</div>
|
||||||
<div attrs='{"invisible": [("is_remanufacture","=",False)]}'>
|
<div attrs='{"invisible": [("is_remanufacture","=",False)]}'>
|
||||||
<span style='font-weight:bold;'>申请重新编程
|
<span style='font-weight:bold;'>申请重新编程
|
||||||
<field name="is_reprogramming" force_save="1"
|
<field name="is_reprogramming" force_save="1"
|
||||||
attrs='{"readonly": [("programming_state","not in",["已下发"])]}'/>
|
attrs='{"readonly": [("programming_states","not in",["已下发"])]}'/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
|
|||||||
@@ -109,11 +109,19 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
|||||||
)
|
)
|
||||||
# 如果关联了工件配送单,则修改状态为已下发
|
# 如果关联了工件配送单,则修改状态为已下发
|
||||||
if self.delivery_ids:
|
if self.delivery_ids:
|
||||||
self.delivery_ids.write({
|
val = {
|
||||||
'status': '已下发',
|
'status': '已下发',
|
||||||
'agv_scheduling_id': scheduling.id,
|
'agv_scheduling_id': scheduling.id,
|
||||||
'feeder_station_start_id': scheduling.start_site_id.id,
|
'feeder_station_start_id': scheduling.start_site_id.id,
|
||||||
|
}
|
||||||
|
# 如果agv任务已经下发,则修改工件配送单信息
|
||||||
|
if scheduling.state == '配送中':
|
||||||
|
val.update({
|
||||||
|
'feeder_station_destination_id': scheduling.end_site_id.id,
|
||||||
|
'route_id': scheduling.agv_route_id.id,
|
||||||
|
'task_delivery_time': fields.Datetime.now()
|
||||||
})
|
})
|
||||||
|
self.delivery_ids.write(val)
|
||||||
|
|
||||||
# 如果是解除装夹工单,则需要处理工单逻辑
|
# 如果是解除装夹工单,则需要处理工单逻辑
|
||||||
for item in self.workorder_ids:
|
for item in self.workorder_ids:
|
||||||
|
|||||||
@@ -24,11 +24,13 @@ class Sf_Mrs_Connect(http.Controller):
|
|||||||
ret = json.loads(datas)
|
ret = json.loads(datas)
|
||||||
ret = json.loads(ret['result'])
|
ret = json.loads(ret['result'])
|
||||||
logging.info('下发编程单:%s' % ret)
|
logging.info('下发编程单:%s' % ret)
|
||||||
|
domain = [('programming_no', '=', ret['programming_no'])]
|
||||||
|
if ret['manufacturing_type'] == 'scrap':
|
||||||
|
domain += [('state', 'not in', ['done', 'scrap'])]
|
||||||
productions = request.env['mrp.production'].with_user(
|
productions = request.env['mrp.production'].with_user(
|
||||||
request.env.ref("base.user_admin")).search(
|
request.env.ref("base.user_admin")).search(domain)
|
||||||
[('programming_no', '=', ret['programming_no'])])
|
|
||||||
if productions:
|
if productions:
|
||||||
# # 拉取所有加工面的程序文件
|
# 拉取所有加工面的程序文件
|
||||||
for r in ret['processing_panel'].split(','):
|
for r in ret['processing_panel'].split(','):
|
||||||
program_path_tmp_r = os.path.join('/tmp', ret['folder_name'], 'return', r)
|
program_path_tmp_r = os.path.join('/tmp', ret['folder_name'], 'return', r)
|
||||||
if os.path.exists(program_path_tmp_r):
|
if os.path.exists(program_path_tmp_r):
|
||||||
@@ -89,8 +91,8 @@ class Sf_Mrs_Connect(http.Controller):
|
|||||||
lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done',
|
lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done',
|
||||||
'cancel'] and ac.processing_panel == panel)
|
'cancel'] and ac.processing_panel == panel)
|
||||||
if cnc_workorder:
|
if cnc_workorder:
|
||||||
program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
||||||
panel)
|
# panel)
|
||||||
program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel)
|
program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel)
|
||||||
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
|
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
|
||||||
files_panel = os.listdir(program_path_tmp_panel)
|
files_panel = os.listdir(program_path_tmp_panel)
|
||||||
@@ -109,12 +111,6 @@ class Sf_Mrs_Connect(http.Controller):
|
|||||||
pre_workorder.write(
|
pre_workorder.write(
|
||||||
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||||
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
|
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||||
cnc_program_ids = [item.id for item in productions]
|
|
||||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
|
||||||
[('production_id', 'in', cnc_program_ids)])
|
|
||||||
if workpiece_delivery:
|
|
||||||
workpiece_delivery.write(
|
|
||||||
{'is_cnc_program_down': True, 'production_line_id': productions.production_line_id.id})
|
|
||||||
return json.JSONEncoder().encode(res)
|
return json.JSONEncoder().encode(res)
|
||||||
else:
|
else:
|
||||||
res = {'status': 0, 'message': '该制造订单暂未开始'}
|
res = {'status': 0, 'message': '该制造订单暂未开始'}
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ class sfProductionProcess(models.Model):
|
|||||||
production_process.processing_day = item['processing_day']
|
production_process.processing_day = item['processing_day']
|
||||||
production_process.travel_day = item['travel_day']
|
production_process.travel_day = item['travel_day']
|
||||||
production_process.active = item['active']
|
production_process.active = item['active']
|
||||||
|
production_process.sequence = item['sequence']
|
||||||
else:
|
else:
|
||||||
self.create({
|
self.create({
|
||||||
"name": item['name'],
|
"name": item['name'],
|
||||||
@@ -338,6 +339,7 @@ class sfProductionProcess(models.Model):
|
|||||||
"processing_day": item['processing_day'],
|
"processing_day": item['processing_day'],
|
||||||
"travel_day": item['travel_day'],
|
"travel_day": item['travel_day'],
|
||||||
"active": item['active'],
|
"active": item['active'],
|
||||||
|
"sequence": item['sequence']
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
raise ValidationError("表面工艺认证未通过")
|
raise ValidationError("表面工艺认证未通过")
|
||||||
@@ -365,6 +367,7 @@ class sfProductionProcess(models.Model):
|
|||||||
"processing_day": item['processing_day'],
|
"processing_day": item['processing_day'],
|
||||||
"travel_day": item['travel_day'],
|
"travel_day": item['travel_day'],
|
||||||
"active": item['active'],
|
"active": item['active'],
|
||||||
|
"sequence": item['sequence']
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
production_process.name = item['name']
|
production_process.name = item['name']
|
||||||
@@ -373,6 +376,7 @@ class sfProductionProcess(models.Model):
|
|||||||
production_process.processing_day = item['processing_day']
|
production_process.processing_day = item['processing_day']
|
||||||
production_process.travel_day = item['travel_day']
|
production_process.travel_day = item['travel_day']
|
||||||
production_process.active = item['active']
|
production_process.active = item['active']
|
||||||
|
production_process.sequence = item['sequence']
|
||||||
else:
|
else:
|
||||||
raise ValidationError("表面工艺认证未通过")
|
raise ValidationError("表面工艺认证未通过")
|
||||||
|
|
||||||
@@ -1088,6 +1092,7 @@ class sfProductionProcessParameter(models.Model):
|
|||||||
production_process_parameter.process_id = process.id
|
production_process_parameter.process_id = process.id
|
||||||
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
|
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
|
||||||
[('materials_no', 'in', item['materials_model_ids_codes'])])
|
[('materials_no', 'in', item['materials_model_ids_codes'])])
|
||||||
|
production_process_parameter.processing_mm = item['processing_mm']
|
||||||
else:
|
else:
|
||||||
self.create({
|
self.create({
|
||||||
"name": item['name'],
|
"name": item['name'],
|
||||||
@@ -1099,6 +1104,7 @@ class sfProductionProcessParameter(models.Model):
|
|||||||
"process_id": process.id,
|
"process_id": process.id,
|
||||||
"materials_model_ids": self.env['sf.materials.model'].search(
|
"materials_model_ids": self.env['sf.materials.model'].search(
|
||||||
[('materials_no', 'in', item['materials_model_ids_codes'])]),
|
[('materials_no', 'in', item['materials_model_ids_codes'])]),
|
||||||
|
"processing_mm": item['processing_mm']
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
raise ValidationError("表面工艺可选参数认证未通过") # 定时同步表面工艺
|
raise ValidationError("表面工艺可选参数认证未通过") # 定时同步表面工艺
|
||||||
@@ -1129,6 +1135,7 @@ class sfProductionProcessParameter(models.Model):
|
|||||||
"process_id": process.id,
|
"process_id": process.id,
|
||||||
'materials_model_ids': self.env['sf.materials.model'].search(
|
'materials_model_ids': self.env['sf.materials.model'].search(
|
||||||
[('materials_no', 'in', item['materials_model_ids_codes'])]),
|
[('materials_no', 'in', item['materials_model_ids_codes'])]),
|
||||||
|
'processing_mm': item['processing_mm']
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
production_process_parameter.name = item['name']
|
production_process_parameter.name = item['name']
|
||||||
@@ -1139,6 +1146,7 @@ class sfProductionProcessParameter(models.Model):
|
|||||||
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
|
production_process_parameter.materials_model_ids = self.env['sf.materials.model'].search(
|
||||||
[('materials_no', 'in', item['materials_model_ids_codes'])])
|
[('materials_no', 'in', item['materials_model_ids_codes'])])
|
||||||
production_process_parameter.active = item['active']
|
production_process_parameter.active = item['active']
|
||||||
|
production_process_parameter.processing_mm = item['processing_mm']
|
||||||
else:
|
else:
|
||||||
raise ValidationError("表面工艺可选参数认证未通过")
|
raise ValidationError("表面工艺可选参数认证未通过")
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>AGV参数配置</h2>
|
<h2>AGV参数配置</h2>
|
||||||
<div class="row mt16 o_settings_container">
|
<div class="row mt16 o_settings_container" id="agv_config">
|
||||||
<div class="col-12 col-lg-6 o_setting_box">
|
<div class="col-12 col-lg-6 o_setting_box">
|
||||||
<div class="o_setting_left_pane"/>
|
<div class="o_setting_left_pane"/>
|
||||||
<div class="o_setting_right_pane">
|
<div class="o_setting_right_pane">
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class ReSaleOrder(models.Model):
|
|||||||
deadline_of_delivery, payments_way, pay_way):
|
deadline_of_delivery, payments_way, pay_way):
|
||||||
now_time = datetime.datetime.now()
|
now_time = datetime.datetime.now()
|
||||||
partner = self.get_customer()
|
partner = self.get_customer()
|
||||||
data ={
|
data = {
|
||||||
'company_id': company_id.id,
|
'company_id': company_id.id,
|
||||||
'date_order': now_time,
|
'date_order': now_time,
|
||||||
'name': self.env['ir.sequence'].next_by_code('sale.order', sequence_date=now_time),
|
'name': self.env['ir.sequence'].next_by_code('sale.order', sequence_date=now_time),
|
||||||
@@ -79,7 +79,7 @@ class ReSaleOrder(models.Model):
|
|||||||
if not isinstance(deadline_of_delivery, str):
|
if not isinstance(deadline_of_delivery, str):
|
||||||
data.update({'deadline_of_delivery': deadline_of_delivery})
|
data.update({'deadline_of_delivery': deadline_of_delivery})
|
||||||
else:
|
else:
|
||||||
if deadline_of_delivery!="False":
|
if deadline_of_delivery != "False":
|
||||||
data.update({'deadline_of_delivery': deadline_of_delivery})
|
data.update({'deadline_of_delivery': deadline_of_delivery})
|
||||||
|
|
||||||
order_id = self.env['sale.order'].sudo().create(data)
|
order_id = self.env['sale.order'].sudo().create(data)
|
||||||
@@ -258,7 +258,7 @@ class RePurchaseOrder(models.Model):
|
|||||||
if is_exist is False:
|
if is_exist is False:
|
||||||
purchase_order = self.env['purchase.order'].search(
|
purchase_order = self.env['purchase.order'].search(
|
||||||
[('state', '=', 'draft'), ('origin', '=', ','.join(production_process))])
|
[('state', '=', 'draft'), ('origin', '=', ','.join(production_process))])
|
||||||
if not purchase_order:
|
if not purchase_order or len(purchase_order) >= 1:
|
||||||
self.env['purchase.order'].sudo().create({
|
self.env['purchase.order'].sudo().create({
|
||||||
'partner_id': server_product.seller_ids.partner_id.id,
|
'partner_id': server_product.seller_ids.partner_id.id,
|
||||||
'origin': ','.join(production_process),
|
'origin': ','.join(production_process),
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel']),'&','&',('check_status',
|
('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel']),'&','&',('check_status',
|
||||||
'=', 'approved'),('state', 'in', ['sale','cancel']),('delivery_status', '!=', False)]}
|
'=', 'approved'),('state', 'in', ['sale','cancel']),('delivery_status', '!=', False)]}
|
||||||
</attribute>
|
</attribute>
|
||||||
|
<attribute name="string">拒绝接单</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//form/header/button[@name='action_draft']" position="attributes">
|
<xpath expr="//form/header/button[@name='action_draft']" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="invisible">1</attribute>
|
||||||
@@ -129,6 +130,9 @@
|
|||||||
<field name="signature" position="attributes">
|
<field name="signature" position="attributes">
|
||||||
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
|
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
|
||||||
</field>
|
</field>
|
||||||
|
<xpath expr="//button[@name='action_cancel']" position="attributes">
|
||||||
|
<attribute name="string">拒绝接单</attribute>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -842,21 +842,21 @@
|
|||||||
<group string="刀柄" attrs="{'invisible': [('handle_product_id', '=', False)]}"
|
<group string="刀柄" attrs="{'invisible': [('handle_product_id', '=', False)]}"
|
||||||
col="1">
|
col="1">
|
||||||
<group attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}">
|
<group attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}">
|
||||||
<group col="3">
|
<!-- <group col="3">-->
|
||||||
<group>
|
<group>
|
||||||
<field name="scrap_boolean" string="是否报废"/>
|
<field name="scrap_boolean" string="是否报废" readonly="0"/>
|
||||||
</group>
|
|
||||||
<group></group>
|
|
||||||
<group>
|
|
||||||
<button string="报废" name="tool_scrap" type="object"
|
|
||||||
class="btn-primary" confirm="是否确认报废刀柄"
|
|
||||||
attrs="{'invisible': [('scrap_boolean', '=', True)]}"/>
|
|
||||||
<button string="取消" name="tool_no_scrap" type="object"
|
|
||||||
class="btn-primary" confirm="是否取消报废刀柄"
|
|
||||||
attrs="{'invisible': [('scrap_boolean', '=', False)]}"/>
|
|
||||||
<group></group>
|
|
||||||
</group>
|
|
||||||
</group>
|
</group>
|
||||||
|
<!-- <group></group>-->
|
||||||
|
<!-- <group>-->
|
||||||
|
<!-- <button string="报废" name="tool_scrap" type="object"-->
|
||||||
|
<!-- class="btn-primary" confirm="是否确认报废刀柄"-->
|
||||||
|
<!-- attrs="{'invisible': [('scrap_boolean', '=', True)]}"/>-->
|
||||||
|
<!-- <button string="取消" name="tool_no_scrap" type="object"-->
|
||||||
|
<!-- class="btn-primary" confirm="是否取消报废刀柄"-->
|
||||||
|
<!-- attrs="{'invisible': [('scrap_boolean', '=', False)]}"/>-->
|
||||||
|
<!-- <group></group>-->
|
||||||
|
<!-- </group>-->
|
||||||
|
<!-- </group>-->
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="handle_rfid" string="Rfid"/>
|
<field name="handle_rfid" string="Rfid"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user