Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化表面工艺
# Conflicts: # sf_manufacturing/models/mrp_production.py # sf_manufacturing/models/mrp_workorder.py
This commit is contained in:
@@ -532,9 +532,3 @@ div:has(.o_required_modifier) > label::before {
|
||||
position: unset;
|
||||
}
|
||||
|
||||
// 修改表格下拉框会被表格下面数据框覆盖的bug
|
||||
.tab-pane .o_field_widget {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class BasicParametersFixture(models.Model):
|
||||
diameter = fields.Float('直径(mm)', digits=(16, 2))
|
||||
|
||||
# '零点卡盘' 字段
|
||||
weight = fields.Float('重量(mm)', digits=(16, 2))
|
||||
weight = fields.Float('重量(kg)', digits=(16, 2))
|
||||
orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
|
||||
clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2))
|
||||
clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')
|
||||
|
||||
@@ -149,7 +149,7 @@ class JdEclp(models.Model):
|
||||
},
|
||||
}
|
||||
_logger.info('准备调接口1')
|
||||
url1 = config['bfm_url'] + '/api/create/jd/order'
|
||||
url1 = config['bfm_url_new'] + '/api/create/jd/order'
|
||||
requests.post(url1, json=json1, data=None)
|
||||
_logger.info('调用成功1')
|
||||
_logger.info('准备调接口2')
|
||||
@@ -158,7 +158,7 @@ class JdEclp(models.Model):
|
||||
'orderNo': self.origin,
|
||||
},
|
||||
}
|
||||
url2 = config['bfm_url'] + '/api/get/jd/no'
|
||||
url2 = config['bfm_url_new'] + '/api/get/jd/no'
|
||||
response = requests.post(url2, json=json2, data=None)
|
||||
# _logger.info('调用成功2', response.json()['result']['wbNo'])
|
||||
tem_ret = response.json().get('result')
|
||||
@@ -196,7 +196,7 @@ class JdEclp(models.Model):
|
||||
'no': self.origin,
|
||||
},
|
||||
}
|
||||
url1 = config['bfm_url'] + '/api/create/jd/bill'
|
||||
url1 = config['bfm_url_new'] + '/api/create/jd/bill'
|
||||
response = requests.post(url1, json=json1, data=None)
|
||||
# _logger.info('调用成功2', response.json())
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class StatusChange(models.Model):
|
||||
'process_start_time': process_start_time,
|
||||
},
|
||||
}
|
||||
url1 = config['bfm_url'] + '/api/get/state/get_order'
|
||||
url1 = config['bfm_url_new'] + '/api/get/state/get_order'
|
||||
requests.post(url1, json=json1, data=None)
|
||||
logging.info('接口已经执行=============')
|
||||
|
||||
@@ -66,7 +66,7 @@ class StatusChange(models.Model):
|
||||
'state': '待派单',
|
||||
},
|
||||
}
|
||||
url1 = config['bfm_url'] + '/api/get/state/cancel_order'
|
||||
url1 = config['bfm_url_new'] + '/api/get/state/cancel_order'
|
||||
requests.post(url1, json=json1, data=None)
|
||||
|
||||
return res
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from . import models
|
||||
from . import wizard
|
||||
from . import controllers
|
||||
|
||||
1
sf_machine_connect/controllers/__init__.py
Normal file
1
sf_machine_connect/controllers/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import controllers
|
||||
98
sf_machine_connect/controllers/controllers.py
Normal file
98
sf_machine_connect/controllers/controllers.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import ast
|
||||
import json
|
||||
import logging
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class Sf_Dashboard_Connect(http.Controller):
|
||||
|
||||
@http.route('/api/get_machine_datas/list', type='http', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def get_machine_datas_list(self, **kw):
|
||||
"""
|
||||
拿到机床数据返回给大屏展示
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
res = {'status': 1, 'message': '成功', 'data': []}
|
||||
logging.info('前端请求机床数据的参数为:%s' % kw)
|
||||
# tem_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"
|
||||
# ]
|
||||
try:
|
||||
equipment_obj = request.env['maintenance.equipment'].sudo()
|
||||
# 获取请求的机床数据
|
||||
machine_list = ast.literal_eval(kw['machine_list'])
|
||||
for item in machine_list:
|
||||
machine_data = equipment_obj.search([('code', '=', item)])
|
||||
if machine_data:
|
||||
res['data'].append({
|
||||
'id': machine_data.id,
|
||||
'name': machine_data.name,
|
||||
'code': machine_data.code,
|
||||
'status': machine_data.status,
|
||||
'run_status': machine_data.run_status,
|
||||
'run_time': machine_data.run_time,
|
||||
'system_date': machine_data.system_date,
|
||||
'system_time': machine_data.system_time,
|
||||
'cut_time': machine_data.cut_time,
|
||||
'cut_status': machine_data.cut_status,
|
||||
'program': machine_data.program,
|
||||
'program_name': machine_data.program_name,
|
||||
'program_status': machine_data.program_status,
|
||||
'tool_num': machine_data.tool_num,
|
||||
'machine_power_on_time': machine_data.machine_power_on_time,
|
||||
'product_counts': machine_data.product_counts,
|
||||
'mode': machine_data.mode,
|
||||
'start_time': machine_data.start_time,
|
||||
'end_time': machine_data.end_time,
|
||||
'program_start_time': machine_data.program_start_time,
|
||||
'program_end_time': machine_data.program_end_time,
|
||||
'standby_start_time': machine_data.standby_start_time,
|
||||
'standby_end_time': machine_data.standby_end_time,
|
||||
'offline_start_time': machine_data.offline_start_time,
|
||||
'offline_end_time': machine_data.offline_end_time,
|
||||
'emg_status': machine_data.emg_status,
|
||||
'current_program': machine_data.current_program,
|
||||
'current_program_seq': machine_data.current_program_seq,
|
||||
'x_abs_pos': machine_data.x_abs_pos,
|
||||
'y_abs_pos': machine_data.y_abs_pos,
|
||||
'z_abs_pos': machine_data.z_abs_pos,
|
||||
'feed_speed_set': machine_data.feed_speed_set,
|
||||
'act_feed_speed': machine_data.act_feed_speed,
|
||||
'spindle_speed_set': machine_data.spindle_speed_set,
|
||||
'act_spindle_speed': machine_data.act_spindle_speed,
|
||||
'spindle_load': machine_data.spindle_load,
|
||||
'x_axis_load': machine_data.x_axis_load,
|
||||
'y_axis_load': machine_data.y_axis_load,
|
||||
'z_axis_load': machine_data.z_axis_load,
|
||||
'rapid_feed': machine_data.rapid_feed,
|
||||
'feed_rate': machine_data.feed_rate,
|
||||
'x_mach_coord': machine_data.x_mach_coord,
|
||||
'y_mach_coord': machine_data.y_mach_coord,
|
||||
'z_mach_coord': machine_data.z_mach_coord,
|
||||
'x_rel_coord': machine_data.x_rel_coord,
|
||||
'y_rel_coord': machine_data.y_rel_coord,
|
||||
'z_rel_coord': machine_data.z_rel_coord,
|
||||
'x_dis_coord': machine_data.x_dis_coord,
|
||||
'y_dis_coord': machine_data.y_dis_coord,
|
||||
'z_dis_coord': machine_data.z_dis_coord,
|
||||
'alarm_time': machine_data.alarm_time,
|
||||
'alarm_msg': machine_data.alarm_msg,
|
||||
'clear_time': machine_data.clear_time,
|
||||
})
|
||||
|
||||
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)
|
||||
@@ -208,24 +208,22 @@ class Machine_ftp(models.Model):
|
||||
# 机床采集项目
|
||||
timestamp = fields.Datetime('时间戳', readonly=True)
|
||||
status = fields.Boolean('机床在线状态', readonly=True)
|
||||
run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='机床运行状态',
|
||||
readonly=True, default='0')
|
||||
# run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='机床运行状态',
|
||||
# readonly=True, default='0')
|
||||
run_status = fields.Char('机床运行状态', readonly=True)
|
||||
run_time = fields.Char('机床累计运行时长', readonly=True)
|
||||
# 机床系统日期
|
||||
system_date = fields.Char('机床系统日期', readonly=True)
|
||||
# 机床系统时间
|
||||
system_time = fields.Char('机床系统时间', readonly=True)
|
||||
|
||||
cut_time = fields.Char('机床累计切削时间', readonly=True)
|
||||
cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='机床当前切削状态',
|
||||
readonly=True, default='0')
|
||||
# cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='机床当前切削状态',
|
||||
# readonly=True, default='0')
|
||||
cut_status = fields.Char('机床当前切削状态', readonly=True)
|
||||
# 当前程序名
|
||||
|
||||
program = fields.Char('机床当前程序', readonly=True)
|
||||
|
||||
# 当前刀具号
|
||||
tool_num = fields.Integer('机床当前刀具号', readonly=True)
|
||||
|
||||
# 机床通电开机时间, 机床加工件数, 机床当前操作模式, 开始加工时间, 结束加工时间, 加工程序开始时间, 加工程序结束时间, 待机开始时间,
|
||||
# 待机结束时间, 机床离线开始时间, 机床离线结束时间, 机床急停状态, 机床主程序名称, 程序运行的状态, 机床当前执行指令, 机床当前执行语句号
|
||||
# 机床X轴当前位置, 机床Y轴当前位置, 机床Z轴当前位置
|
||||
|
||||
@@ -8,11 +8,14 @@ _logger = logging.getLogger(__name__)
|
||||
class ResBFMConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
bfm_url = fields.Selection(
|
||||
[("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"),
|
||||
("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"),
|
||||
# ("正式环境", "https://bfm.jikimo.com")], string='bfm环境', store=True)
|
||||
("https://bfm.jikimo.com", "正式环境(https://bfm.jikimo.com)")], string='bfm环境', store=True)
|
||||
# bfm_url = fields.Selection(
|
||||
# [("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"),
|
||||
# ("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"),
|
||||
# ("https://bfm.r.jikimo.com", "预发布环境(https://bfm.r.jikimo.com)"),
|
||||
# # ("正式环境", "https://bfm.jikimo.com")], string='bfm环境', store=True)
|
||||
# ("https://bfm.jikimo.com", "正式环境(https://bfm.jikimo.com)")], string='bfm环境', store=True)
|
||||
|
||||
bfm_url_new = fields.Char('业务平台环境路径', placeholder='请输入当前对应的业务平台环境路径')
|
||||
|
||||
@api.model
|
||||
def get_values(self):
|
||||
@@ -22,14 +25,14 @@ class ResBFMConfigSettings(models.TransientModel):
|
||||
"""
|
||||
values = super(ResBFMConfigSettings, self).get_values()
|
||||
config = self.env['ir.config_parameter'].sudo()
|
||||
bfm_url = config.get_param('bfm_url', default='')
|
||||
bfm_url_new = config.get_param('bfm_url_new', default='')
|
||||
|
||||
values.update(
|
||||
bfm_url=bfm_url,
|
||||
bfm_url_new=bfm_url_new,
|
||||
)
|
||||
return values
|
||||
|
||||
def set_values(self):
|
||||
super(ResBFMConfigSettings, self).set_values()
|
||||
ir_config = self.env['ir.config_parameter'].sudo()
|
||||
ir_config.set_param("bfm_url", self.bfm_url or "")
|
||||
ir_config.set_param("bfm_url_new", self.bfm_url_new or "")
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<div class="o_setting_left_pane"/>
|
||||
<div class="o_setting_right_pane">
|
||||
<div class="text-muted">
|
||||
<label for="bfm_url" />
|
||||
<field name="bfm_url" string="访问地址"/>
|
||||
<label for="bfm_url_new" />
|
||||
<field name="bfm_url_new" string="业务平台访问地址"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
|
||||
@@ -42,7 +42,8 @@ class SfMaintenanceEquipmentOEELog(models.Model):
|
||||
_description = '设备运行日志'
|
||||
|
||||
equipment_id = fields.Many2one('maintenance.equipment', '机台号')
|
||||
name = fields.Char('设备名称')
|
||||
equipment_code = fields.Char('设备编码')
|
||||
name = fields.Char('设备名称', readonly='True')
|
||||
machine_tool_picture = fields.Binary('设备图片')
|
||||
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号')
|
||||
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
|
||||
@@ -70,6 +71,11 @@ class SfMaintenanceEquipmentOEELog(models.Model):
|
||||
# work_nums = fields.Integer('加工件数')
|
||||
equipment_oee_id = fields.Many2one('maintenance.equipment.oee', '设备OEE')
|
||||
|
||||
@api.onchange('equipment_id')
|
||||
def get_name(self):
|
||||
self.name = self.equipment_id.name
|
||||
self.equipment_code = self.equipment_id.code
|
||||
|
||||
|
||||
# 设备运行日志详情
|
||||
class SfMaintenanceEquipmentOEELogDetail(models.Model):
|
||||
|
||||
@@ -68,5 +68,5 @@ access_sf_cutting_tool_type_group_purchase_director_sf_group_equipment_user,sf_c
|
||||
access_sf_cutting_tool_type_group_sale_director_sf_group_equipment_user,sf_cutting_tool_type_group_sale_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
access_sf_cutting_tool_type_group_plan_director_sf_group_equipment_user,sf_cutting_tool_type_group_plan_director,sf_base.model_sf_cutting_tool_type,sf_maintenance.sf_group_equipment_user,1,0,0,0
|
||||
|
||||
access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_maintenance.sf_group_equipment_manager,1,1,1,0
|
||||
access_maintenance_equipment_oee_log_detail,maintenance_equipment_oee_log_detail,model_maintenance_equipment_oee_log_detail,sf_maintenance.sf_group_equipment_manager,1,1,1,0
|
||||
access_maintenance_equipment_oee_logs,maintenance_equipment_oee_logs,model_maintenance_equipment_oee_logs,sf_maintenance.sf_group_equipment_manager,1,1,1,1
|
||||
access_maintenance_equipment_oee_log_detail,maintenance_equipment_oee_log_detail,model_maintenance_equipment_oee_log_detail,sf_maintenance.sf_group_equipment_manager,1,1,1,1
|
||||
|
@@ -156,6 +156,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
|
||||
<field name="type_id"/>
|
||||
<field name="state"/>
|
||||
</group>
|
||||
@@ -195,8 +196,27 @@
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="日志详情">
|
||||
<notebook>
|
||||
<page string="24H日志详情">
|
||||
<!-- 筛选出24小时内的日志 -->
|
||||
<!-- <field name="detail_ids" domain="[('time','<',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
|
||||
<field name="detail_ids" domain="[('state','ilike','加工')]">
|
||||
<tree>
|
||||
<field name="sequence"/>
|
||||
<field name="time"/>
|
||||
<field name="state"/>
|
||||
<field name="production_id"/>
|
||||
</tree>
|
||||
<!-- <form> -->
|
||||
<!-- <field name="sequence"/> -->
|
||||
<!-- <field name="time"/> -->
|
||||
<!-- <field name="state"/> -->
|
||||
<!-- <field name="production_id"/> -->
|
||||
<!-- </form> -->
|
||||
|
||||
</field>
|
||||
</page>
|
||||
<page string="历史日志详情">
|
||||
<field name="detail_ids">
|
||||
<tree>
|
||||
<field name="sequence"/>
|
||||
@@ -256,22 +276,15 @@
|
||||
<field name="model">maintenance.equipment.oee.log.detail</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="设备运行日志详情">
|
||||
<header>
|
||||
<field name="sequence" readonly="1"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="time" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="state" readonly="1"/>
|
||||
<field name="production_id" readonly="1"/>
|
||||
<field name="state"/>
|
||||
<field name="production_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="log_id"/>
|
||||
<field name="sequence"/>
|
||||
<field name="time"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
@@ -8,7 +8,7 @@ from odoo.http import request
|
||||
|
||||
class Manufacturing_Connect(http.Controller):
|
||||
|
||||
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def get_Work_Info(self, **kw):
|
||||
"""
|
||||
@@ -103,7 +103,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('get_ShiftPlan error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/QcCheck', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/QcCheck', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def get_qcCheck(self, **kw):
|
||||
"""
|
||||
@@ -145,7 +145,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('get_qcCheck error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def button_Work_START(self, **kw):
|
||||
"""
|
||||
@@ -193,7 +193,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('button_Work_START error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/FeedBackEnd', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/FeedBackEnd', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def button_Work_End(self, **kw):
|
||||
"""
|
||||
@@ -244,7 +244,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('button_Work_End error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/PartQualityInspect', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/PartQualityInspect', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def PartQualityInspect(self, **kw):
|
||||
"""
|
||||
@@ -260,40 +260,27 @@ class Manufacturing_Connect(http.Controller):
|
||||
request.env['center_control.interface.log'].sudo().create(
|
||||
{'content': ret, 'name': 'AutoDeviceApi/PartQualityInspect'})
|
||||
production_id = ret['BillId']
|
||||
routing_type = ret['CraftId']
|
||||
# routing_type = ret['CraftId']
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type), ('state', '!=', 'rework')],
|
||||
[('production_id', '=', production_id), ('routing_type', '=', 'CNC加工'),
|
||||
('state', 'not in', ['rework', 'done', 'cancel'])], order='sequence asc',
|
||||
limit=1)
|
||||
if workorder:
|
||||
# workorder.test_results = ret['Quality']
|
||||
logging.info('制造订单:%s' % workorder.production_id.name)
|
||||
if 'ReportPaht' in ret:
|
||||
download_state = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).download_reportfile_tmp(workorder,
|
||||
ret['ReportPaht'])
|
||||
if download_state == 1:
|
||||
detection_ret = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht'])
|
||||
if detection_ret is True:
|
||||
stock_picking_type = request.env['stock.picking.type'].sudo().search(
|
||||
[('sequence_code', '=', 'SFP')])
|
||||
if stock_picking_type:
|
||||
stock_picking = request.env['stock.picking'].sudo().search(
|
||||
[('product_id', '=', workorder.product_id.id),
|
||||
('origin', '=', workorder.production_id.origin),
|
||||
('picking_type_id', '=', stock_picking_type.id)])
|
||||
if stock_picking:
|
||||
quality_check = request.env['quality.check'].sudo().search(
|
||||
[('product_id', '=', workorder.product_id.id),
|
||||
('picking_id', '=', stock_picking.id)])
|
||||
if quality_check:
|
||||
logging.info('质检单:%s' % quality_check.name)
|
||||
quality_check.write({'report_pdf': workorder.detection_report})
|
||||
elif download_state == 2:
|
||||
res = {'Succeed': False, 'ErrorCode': 205,
|
||||
'Error': 'ReportPaht中的工件号与制造订单%s不匹配,请检查ReportPaht是否正确' % workorder.production_id.name}
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 204, 'Error': '检测报告文件从FTP拉取失败'}
|
||||
if ret['ReportPaht'].find('.pdf') != -1:
|
||||
download_state = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).download_reportfile_tmp(workorder,
|
||||
ret['ReportPaht'])
|
||||
if download_state is True:
|
||||
detection_ret = request.env['mrp.workorder'].with_user(
|
||||
request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht'])
|
||||
logging.info('detection_ret:%s' % detection_ret)
|
||||
if detection_ret is False:
|
||||
res = {'Succeed': False, 'ErrorCode': 205, 'Error': '检测报告文件读取失败'}
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 204, 'Error': '检测报告文件从FTP拉取失败'}
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传ReportPaht字段'}
|
||||
else:
|
||||
@@ -303,7 +290,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('PartQualityInspect error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/CMMProgDolod', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/CMMProgDolod', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def CMMProgDolod(self, **kw):
|
||||
"""
|
||||
@@ -343,7 +330,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('CMMProgDolod error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/NCProgDolod', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/NCProgDolod', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def NCProgDolod(self, **kw):
|
||||
"""
|
||||
@@ -384,7 +371,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('NCProgDolod error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/LocationChange', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/LocationChange', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def LocationChange(self, **kw):
|
||||
"""
|
||||
@@ -442,7 +429,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('LocationChange error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/AGVToProduct', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/AGVToProduct', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def AGVToProduct(self, **kw):
|
||||
"""
|
||||
@@ -503,7 +490,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('AGVToProduct error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/AGVDownProduct', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/AGVDownProduct', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def AGVDownProduct(self, **kw):
|
||||
"""
|
||||
|
||||
@@ -29,41 +29,42 @@ class MrpProduction(models.Model):
|
||||
detection_result_ids = fields.One2many('sf.detection.result', 'production_id', '检测报告')
|
||||
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
|
||||
store=True, compute='_compute_tool_state')
|
||||
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', readonly=True)
|
||||
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
|
||||
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
|
||||
|
||||
@api.depends('workorder_ids.tool_state_remark')
|
||||
def _compute_tool_state_remark(self):
|
||||
for item in self:
|
||||
if item.workorder_ids:
|
||||
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ['rework', 'done', 'cancel'])
|
||||
if workorder_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
work_ids = workorder_ids.filtered(lambda a: a.tool_state == '1')
|
||||
tool_state_remark = ''
|
||||
for work_id in work_ids:
|
||||
if tool_state_remark == '':
|
||||
tool_state_remark = f'{work_id.tool_state_remark}'
|
||||
else:
|
||||
tool_state_remark = f"{tool_state_remark}\n{work_id.tool_state_remark}"
|
||||
item.tool_state_remark = tool_state_remark
|
||||
else:
|
||||
item.tool_state_remark = False
|
||||
|
||||
@api.depends('workorder_ids.tool_state')
|
||||
def _compute_tool_state(self):
|
||||
# if self.workorder_ids:
|
||||
for item in self:
|
||||
if item.workorder_ids:
|
||||
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ('rework', '返工'))
|
||||
tool_state = item.tool_state
|
||||
workorder_ids = item.workorder_ids.filtered(lambda a: a.state not in ['rework', 'done', 'cancel'])
|
||||
if workorder_ids.filtered(lambda a: a.tool_state == '2'):
|
||||
item.tool_state = '2'
|
||||
elif workorder_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
tool_state_remark = ''
|
||||
data = {}
|
||||
# 获取所有缺刀工单加工面对应缺的刀
|
||||
for work in workorder_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
if work.processing_panel not in list(data.keys()):
|
||||
data.update({work.processing_panel: []})
|
||||
for cnc in work.cnc_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
if cnc.cutting_tool_name not in data[work.processing_panel]:
|
||||
data[work.processing_panel].append(cnc.cutting_tool_name)
|
||||
# 按格式生成缺刀提示信息
|
||||
for key in data:
|
||||
if data.get(key) and not data.get(key):
|
||||
if tool_state_remark != '':
|
||||
tool_state_remark = f'{tool_state_remark}\n{key}缺刀:{data.get(key)}'
|
||||
else:
|
||||
tool_state_remark = f'{key}缺刀:{data.get(key)}'
|
||||
item.tool_state = '1'
|
||||
item.tool_state_remark = tool_state_remark
|
||||
item.tool_state_remark2 = ''
|
||||
else:
|
||||
item.tool_state = '0'
|
||||
item.tool_state_remark = ''
|
||||
item.tool_state_remark2 = ''
|
||||
if tool_state == '2' and item.tool_state != '2':
|
||||
item.detection_result_ids.filtered(
|
||||
lambda a: a.detailed_reason == '无效功能刀具' and a.handle_result == '待处理').write(
|
||||
{'handle_result': '已处理'})
|
||||
|
||||
# state = fields.Selection(selection_add=[
|
||||
# ('pending_scheduling', '待排程'),
|
||||
@@ -237,7 +238,6 @@ class MrpProduction(models.Model):
|
||||
ret = requests.post(config_url, json=res, data=None, headers=config_header)
|
||||
ret = ret.json()
|
||||
result = json.loads(ret['result'])
|
||||
logging.info('cron_get_programming_state-ret:%s' % result)
|
||||
if result['status'] == 1:
|
||||
for item in result['programming_list']:
|
||||
if not self:
|
||||
@@ -245,7 +245,6 @@ class MrpProduction(models.Model):
|
||||
if rp.programming_no == item['programming_no']:
|
||||
rp.write({'programming_state': '已编程未下发' if item[
|
||||
'programming_state'] == '已编程' else '编程中'})
|
||||
logging.info('rp:%s' % rp.name)
|
||||
|
||||
else:
|
||||
return item
|
||||
@@ -794,8 +793,6 @@ class MrpProduction(models.Model):
|
||||
cloud_programming = None
|
||||
if self.programming_state in ['已编程']:
|
||||
cloud_programming = self._cron_get_programming_state()
|
||||
logging.info('cloud_programming_state:%s' % cloud_programming['programming_state'])
|
||||
logging.info('programming_state:%s' % self.programming_state)
|
||||
return {
|
||||
'name': _('返工'),
|
||||
'type': 'ir.actions.act_window',
|
||||
@@ -814,17 +811,17 @@ class MrpProduction(models.Model):
|
||||
def do_update_program(self):
|
||||
program_production = self
|
||||
if len(program_production) >= 1:
|
||||
same_product_id = None
|
||||
is_not_same_product = 0
|
||||
# same_product_id = None
|
||||
# is_not_same_product = 0
|
||||
for item in program_production:
|
||||
if same_product_id is None:
|
||||
same_product_id = item.product_id
|
||||
if item.product_id != same_product_id:
|
||||
is_not_same_product += 1
|
||||
# if same_product_id is None:
|
||||
# same_product_id = item.product_id
|
||||
# if item.product_id != same_product_id:
|
||||
# is_not_same_product += 1
|
||||
if item.state != "rework" and item.programming_state != "已编程未下发":
|
||||
raise UserError("请选择状态为返工且已编程未下发的制造订单")
|
||||
if is_not_same_product >= 1:
|
||||
raise UserError("您选择的记录中含有其他产品的制造订单,请选择同一产品的制造订单")
|
||||
# if is_not_same_product >= 1:
|
||||
# raise UserError("您选择的记录中含有其他产品的制造订单,请选择同一产品的制造订单")
|
||||
grouped_program_ids = {k: list(g) for k, g in groupby(program_production, key=lambda x: x.programming_no)}
|
||||
program_to_production_names = {}
|
||||
for programming_no, program_production in grouped_program_ids.items():
|
||||
@@ -904,8 +901,10 @@ class MrpProduction(models.Model):
|
||||
if pre_workorder:
|
||||
pre_workorder.write(
|
||||
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||
|
||||
logging.info('更新程序完成:%s' % production.name)
|
||||
# if production.state == 'rework' and production.programming_state == '已编程未下发':
|
||||
# production.write(
|
||||
# {'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
|
||||
# logging.info('返工含有已编程未下发的程序更新完成:%s' % production.name)
|
||||
|
||||
else:
|
||||
raise UserError(result['message'])
|
||||
@@ -1084,18 +1083,3 @@ class sf_processing_panel(models.Model):
|
||||
|
||||
name = fields.Char('加工面')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
|
||||
# @api.model
|
||||
# def name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
|
||||
# if self.env.user.has_group('sf_base.group_sf_order_user'):
|
||||
# if self._context.get('product_id'):
|
||||
# product = self.env['product.product'].search([('id', '=', self._context.get('product_id'))])
|
||||
# if product:
|
||||
# panel = self.env['sf.processing.panel'].search([('name', 'ilike', 'ZM')])
|
||||
# if panel:
|
||||
# ids = [t.id for t in panel]
|
||||
# domain = [('id', 'in', ids)]
|
||||
# else:
|
||||
# domain = [('id', '=', False)]
|
||||
# return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||
# return super()._name_search(name, args, operator, limit, name_get_uid)
|
||||
|
||||
@@ -180,11 +180,28 @@ class ResMrpWorkOrder(models.Model):
|
||||
# 功能刀具状态
|
||||
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
|
||||
store=True, compute='_compute_tool_state')
|
||||
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
|
||||
|
||||
@api.depends('cnc_ids.tool_state')
|
||||
def _compute_tool_state_remark(self):
|
||||
for item in self:
|
||||
if item.cnc_ids:
|
||||
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
|
||||
item.tool_state_remark = None
|
||||
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
tool_state_remark = []
|
||||
cnc_ids = item.cnc_ids.filtered(lambda a: a.tool_state == '1')
|
||||
for cnc_id in cnc_ids:
|
||||
if cnc_id.cutting_tool_name not in tool_state_remark:
|
||||
tool_state_remark.append(cnc_id.cutting_tool_name)
|
||||
item.tool_state_remark = f"{item.processing_panel}缺刀:{tool_state_remark}"
|
||||
else:
|
||||
item.tool_state_remark = None
|
||||
|
||||
@api.depends('cnc_ids.tool_state')
|
||||
def _compute_tool_state(self):
|
||||
for item in self:
|
||||
if item:
|
||||
if item.cnc_ids:
|
||||
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
|
||||
item.tool_state = '2'
|
||||
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
|
||||
@@ -240,7 +257,66 @@ class ResMrpWorkOrder(models.Model):
|
||||
detailed_reason = fields.Text('详细原因')
|
||||
is_rework = fields.Boolean(string='是否返工', default=False)
|
||||
|
||||
# is_send_program_again = fields.Boolean(string='是否重新下发NC程序', default=False)
|
||||
@api.constrains('blocked_by_workorder_ids')
|
||||
def _check_no_cyclic_dependencies(self):
|
||||
if self.production_id.state not in ['rework'] and self.state not in ['rework']:
|
||||
if not self._check_m2m_recursion('blocked_by_workorder_ids'):
|
||||
raise ValidationError(_("您不能创建周期性的依赖关系."))
|
||||
|
||||
def _plan_workorder(self, replan=False):
|
||||
self.ensure_one()
|
||||
# Plan workorder after its predecessors
|
||||
start_date = max(self.production_id.date_planned_start, datetime.now())
|
||||
for workorder in self.blocked_by_workorder_ids:
|
||||
if workorder.state in ['done', 'cancel', 'rework']:
|
||||
continue
|
||||
workorder._plan_workorder(replan)
|
||||
start_date = max(start_date, workorder.date_planned_finished)
|
||||
# Plan only suitable workorders
|
||||
if self.state not in ['pending', 'waiting', 'ready']:
|
||||
return
|
||||
if self.leave_id:
|
||||
if replan:
|
||||
self.leave_id.unlink()
|
||||
else:
|
||||
return
|
||||
# Consider workcenter and alternatives
|
||||
workcenters = self.workcenter_id | self.workcenter_id.alternative_workcenter_ids
|
||||
best_finished_date = datetime.max
|
||||
vals = {}
|
||||
for workcenter in workcenters:
|
||||
# Compute theoretical duration
|
||||
if self.workcenter_id == workcenter:
|
||||
duration_expected = self.duration_expected
|
||||
else:
|
||||
duration_expected = self._get_duration_expected(alternative_workcenter=workcenter)
|
||||
from_date, to_date = workcenter._get_first_available_slot(start_date, duration_expected)
|
||||
# If the workcenter is unavailable, try planning on the next one
|
||||
if not from_date:
|
||||
continue
|
||||
# Check if this workcenter is better than the previous ones
|
||||
if to_date and to_date < best_finished_date:
|
||||
best_start_date = from_date
|
||||
best_finished_date = to_date
|
||||
best_workcenter = workcenter
|
||||
vals = {
|
||||
'workcenter_id': workcenter.id,
|
||||
'duration_expected': duration_expected,
|
||||
}
|
||||
# If none of the workcenter are available, raise
|
||||
if best_finished_date == datetime.max:
|
||||
raise UserError(_('Impossible to plan the workorder. Please check the workcenter availabilities.'))
|
||||
# Create leave on chosen workcenter calendar
|
||||
leave = self.env['resource.calendar.leaves'].create({
|
||||
'name': self.display_name,
|
||||
'calendar_id': best_workcenter.resource_calendar_id.id,
|
||||
'date_from': best_start_date,
|
||||
'date_to': best_finished_date,
|
||||
'resource_id': best_workcenter.resource_id.id,
|
||||
'time_type': 'other'
|
||||
})
|
||||
vals['leave_id'] = leave.id
|
||||
self.write(vals)
|
||||
|
||||
@api.onchange('rfid_code')
|
||||
def _onchange(self):
|
||||
@@ -745,7 +821,8 @@ class ResMrpWorkOrder(models.Model):
|
||||
}]
|
||||
return workorders_values_str
|
||||
|
||||
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state')
|
||||
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state',
|
||||
'production_id.tool_state')
|
||||
def _compute_state(self):
|
||||
super()._compute_state()
|
||||
for workorder in self:
|
||||
@@ -761,18 +838,12 @@ class ResMrpWorkOrder(models.Model):
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('processing_panel', '=', workorder.processing_panel),
|
||||
('routing_type', '=', 'CNC加工'), ('state', 'in', ['pending'])])
|
||||
unclamp_workorder = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('sequence', '=', workorder.sequence - 1),
|
||||
('state', 'in', ['done'])])
|
||||
if workorder.state not in ['cancel', 'progress', 'rework']:
|
||||
if workorder.production_id.state == 'rework':
|
||||
logging.info('len(re_work):%s' % len(re_work))
|
||||
logging.info('len(cnc_workorder):%s' % len(cnc_workorder))
|
||||
logging.info('len(cnc_workorder_pending):%s' % len(cnc_workorder_pending))
|
||||
logging.info('工序:%s' % workorder.routing_type)
|
||||
logging.info('状态:%s' % workorder.state)
|
||||
logging.info('is_rework:%s' % workorder.is_rework)
|
||||
logging.info('production_id.is_rework:%s' % workorder.production_id.is_rework)
|
||||
logging.info('面:%s' % workorder.processing_panel)
|
||||
logging.info('编程状态:%s' % workorder.production_id.programming_state)
|
||||
logging.info('制造状态:%s' % workorder.production_id.state)
|
||||
if workorder.routing_type == '装夹预调' and workorder.state not in ['done', 'rework',
|
||||
'cancel']:
|
||||
# # 有返工工单
|
||||
@@ -786,8 +857,6 @@ class ResMrpWorkOrder(models.Model):
|
||||
if workorder.production_id.is_rework is True:
|
||||
if re_work or cnc_workorder:
|
||||
workorder.state = 'waiting'
|
||||
if workorder.production_id.tool_state in ['1', '2'] and workorder.state != 'pending':
|
||||
workorder.state = 'waiting'
|
||||
|
||||
elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'rework', 'cancel']:
|
||||
pre_workorder = self.env['mrp.workorder'].search(
|
||||
@@ -805,27 +874,16 @@ class ResMrpWorkOrder(models.Model):
|
||||
# if workorder.production_id.is_rework is True:
|
||||
# workorder.state = 'waiting'
|
||||
elif workorder.production_id.state == 'progress':
|
||||
logging.info('len(re_work):%s' % len(re_work))
|
||||
logging.info('len(cnc_workorder):%s' % len(cnc_workorder))
|
||||
logging.info('len(cnc_workorder_pending):%s' % len(cnc_workorder_pending))
|
||||
logging.info('工序:%s' % workorder.routing_type)
|
||||
logging.info('状态:%s' % workorder.state)
|
||||
logging.info('is_rework:%s' % workorder.is_rework)
|
||||
logging.info('production_id.is_rework:%s' % workorder.production_id.is_rework)
|
||||
logging.info('面:%s' % workorder.processing_panel)
|
||||
logging.info('编程状态:%s' % workorder.production_id.programming_state)
|
||||
logging.info('制造状态:%s' % workorder.production_id.state)
|
||||
if workorder.routing_type == '装夹预调' and workorder.production_id.programming_state == '已编程' and \
|
||||
workorder.is_rework is False and workorder.state not in [
|
||||
'done', 'rework',
|
||||
'cancel']:
|
||||
if (re_work or cnc_workorder) and workorder.production_id.is_rework is False:
|
||||
workorder.state = 'ready'
|
||||
if workorder.production_id.is_rework is False:
|
||||
if re_work or cnc_workorder or unclamp_workorder:
|
||||
workorder.state = 'ready'
|
||||
# if (re_work or cnc_workorder) and workorder.production_id.is_rework is False:
|
||||
# workorder.state = 'ready'
|
||||
if workorder.routing_type == '表面工艺' and workorder.state not in ['done', 'progress']:
|
||||
unclamp_workorder = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('sequence', '=', workorder.sequence - 1),
|
||||
('state', 'in', ['done'])])
|
||||
if unclamp_workorder:
|
||||
if workorder.is_subcontract is False:
|
||||
workorder.state = 'ready'
|
||||
@@ -835,13 +893,54 @@ class ResMrpWorkOrder(models.Model):
|
||||
# else:
|
||||
# if workorder.state not in ['cancel', 'rework']:
|
||||
# workorder.state = 'rework'
|
||||
# if workorder.production_id.state == 'pending_cam':
|
||||
# if workorder.routing_type == '装夹预调' and workorder.state in ['ready', 'waiting']:
|
||||
# if workorder.production_id.tool_state in ['1', '2']:
|
||||
# workorder.state = 'waiting'
|
||||
|
||||
logging.info('工序:%s' % workorder.sequence)
|
||||
logging.info('工单最终状态:%s' % workorder.state)
|
||||
if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']:
|
||||
workorder_ids = workorder.production_id.workorder_ids
|
||||
work_bo = True
|
||||
for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'):
|
||||
if not workorder_ids.filtered(
|
||||
lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel']
|
||||
and a.processing_panel == wo.processing_panel)):
|
||||
work_bo = False
|
||||
break
|
||||
if (workorder.production_id.programming_state == '已编程' and work_bo
|
||||
and not workorder_ids.filtered(lambda a: a.sequence == 0)):
|
||||
# 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】
|
||||
if workorder.production_id.tool_state in ['1', '2']:
|
||||
if workorder.state in ['ready']:
|
||||
workorder.state = 'waiting'
|
||||
continue
|
||||
elif workorder.state in ['waiting']:
|
||||
continue
|
||||
elif workorder.state == 'pending' and workorder == self.search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('routing_type', '=', '装夹预调'),
|
||||
('state', 'not in', ['rework', 'done', 'cancel'])],
|
||||
limit=1,
|
||||
order="sequence"):
|
||||
workorder.state = 'waiting'
|
||||
continue
|
||||
elif workorder.production_id.tool_state in ['0']:
|
||||
if workorder_ids.filtered(lambda a: a.state == 'rework'):
|
||||
if not workorder_ids.filtered(
|
||||
lambda a: (a.routing_type not in ['装夹预调'] and
|
||||
a.state not in ['pending', 'done', 'rework', 'cancel'])):
|
||||
# 查询工序最小的非完工、非返工的装夹预调工单
|
||||
work_id = self.search(
|
||||
[('production_id', '=', workorder.production_id.id),
|
||||
('routing_type', '=', '装夹预调'),
|
||||
('state', 'not in', ['rework', 'done', 'cancel'])],
|
||||
limit=1,
|
||||
order="sequence")
|
||||
if workorder == work_id:
|
||||
if workorder.production_id.reservation_state == 'assigned':
|
||||
workorder.state = 'ready'
|
||||
elif workorder.production_id.reservation_state != 'assigned':
|
||||
workorder.state = 'waiting'
|
||||
continue
|
||||
if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready':
|
||||
workorder.state = 'waiting'
|
||||
continue
|
||||
>>>>>>> 3f27ae0f35c7054b2e6583cc60502d6faef3fc92
|
||||
|
||||
# elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress',
|
||||
# 'rework']:
|
||||
@@ -1076,38 +1175,27 @@ class ResMrpWorkOrder(models.Model):
|
||||
|
||||
# 将FTP的检测报告文件下载到临时目录
|
||||
def download_reportfile_tmp(self, workorder, reportpath):
|
||||
logging.info('reportpath:%s' % reportpath)
|
||||
production_no_ftp = reportpath.split('/')
|
||||
production_no = workorder.production_id.name.replace('/', '_')
|
||||
# ftp地址
|
||||
remotepath = os.path.join('/NC', production_no_ftp[1], 'detection')
|
||||
logging.info('ftp地址:%s' % remotepath)
|
||||
if reportpath.find(production_no) != -1:
|
||||
# 服务器内临时地址
|
||||
serverdir = os.path.join('/tmp', production_no_ftp[1], 'detection')
|
||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']),
|
||||
ftp_resconfig['ftp_user'],
|
||||
ftp_resconfig['ftp_password'])
|
||||
download_state = ftp.download_reportfile_tree(remotepath, serverdir, reportpath)
|
||||
logging.info('download_state:%s' % download_state)
|
||||
else:
|
||||
download_state = 2
|
||||
logging.info('reportpath/ftp地址:%s' % reportpath)
|
||||
logging.info('processing_panel:%s' % workorder.processing_panel)
|
||||
serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection',
|
||||
workorder.processing_panel)
|
||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']),
|
||||
ftp_resconfig['ftp_user'],
|
||||
ftp_resconfig['ftp_password'])
|
||||
if not ftp.file_exists_1(reportpath):
|
||||
logging.info('文件不存在:%s' % reportpath)
|
||||
download_state = ftp.download_program_file(reportpath, serverdir)
|
||||
logging.info('download_state:%s' % download_state)
|
||||
return download_state
|
||||
|
||||
# 根据中控系统提供的检测文件地址去ftp里对应的制造订单里获取
|
||||
def get_detection_file(self, workorder, reportPath):
|
||||
# if reportPath.startswith('/'):
|
||||
# reportPath = reportPath[4:]
|
||||
# serverdir = os.path.join('/tmp', reportPath)
|
||||
serverdir = '/tmp' + reportPath
|
||||
serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection',
|
||||
workorder.processing_panel)
|
||||
logging.info('get_detection_file-serverdir:%s' % serverdir)
|
||||
serverdir_prefix = os.path.dirname(serverdir)
|
||||
logging.info('serverdir_prefix-serverdir:%s' % serverdir_prefix)
|
||||
for root, dirs, files in os.walk(serverdir_prefix):
|
||||
for root, dirs, files in os.walk(serverdir):
|
||||
for filename in files:
|
||||
logging.info('filename:%s' % filename)
|
||||
logging.info('reportPath:%s' % os.path.basename(reportPath))
|
||||
if filename == os.path.basename(reportPath):
|
||||
report_file_path = os.path.join(root, filename)
|
||||
logging.info('get_detection_file-report_file_path:%s' % report_file_path)
|
||||
|
||||
@@ -811,7 +811,7 @@ class ResProductFixture(models.Model):
|
||||
diameter = fields.Float('直径(mm)', digits=(16, 2))
|
||||
|
||||
# '零点卡盘' 字段
|
||||
weight = fields.Float('重量(mm)', digits=(16, 2))
|
||||
weight = fields.Float('重量(kg)', digits=(16, 2))
|
||||
orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
|
||||
clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2))
|
||||
clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='do_unreserve']" position="after">
|
||||
<button name="do_update_program" type="object" string="更新程序"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//button[@name='do_unreserve']" position="after">-->
|
||||
<!-- <button name="do_update_program" type="object" string="更新程序"-->
|
||||
<!-- groups="sf_base.group_sf_mrp_user"/>-->
|
||||
<!-- </xpath>-->
|
||||
<xpath expr="//field[@name='product_id']" position="replace"/>
|
||||
<xpath expr="//field[@name='product_qty']" position="replace"/>
|
||||
<xpath expr="//field[@name='product_uom_id']" position="replace"/>
|
||||
@@ -128,9 +128,9 @@
|
||||
attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/>
|
||||
<button name="button_rework" string="返工" type="object" groups="sf_base.group_sf_mrp_user"
|
||||
attrs="{'invisible': ['|',('state', '!=', 'rework') ,('programming_state', '!=', '已编程')]}"/>
|
||||
<button name="%(sf_manufacturing.action_sf_production_wizard)d" string="报废" type="action"
|
||||
groups="sf_base.group_sf_mrp_user"
|
||||
attrs="{'invisible': [('is_scrap', '=', False)]}"/>
|
||||
<!-- <button name="%(sf_manufacturing.action_sf_production_wizard)d" string="报废" type="action"-->
|
||||
<!-- groups="sf_base.group_sf_mrp_user"-->
|
||||
<!-- attrs="{'invisible': [('is_scrap', '=', False)]}"/>-->
|
||||
</xpath>
|
||||
<xpath expr="(//header//button[@name='button_mark_done'])[3]" position="replace">
|
||||
<button name="button_mark_done" attrs="{'invisible': [
|
||||
@@ -465,6 +465,8 @@
|
||||
<separator/>
|
||||
<filter string="返工且已编程" name="filter_rework_programmed"
|
||||
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程')]"/>
|
||||
<filter string="返工且已编程未下发" name="filter_rework_programmed_not_delivered"
|
||||
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程未下发')]"/>
|
||||
<separator/>
|
||||
<filter name="filter_programming" string="编程中"
|
||||
domain="[('programming_state', '=', '编程中')]"/>
|
||||
|
||||
@@ -31,6 +31,8 @@ class ReworkWizard(models.TransientModel):
|
||||
('已下发', '已下发')],
|
||||
string='编程状态')
|
||||
|
||||
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
|
||||
|
||||
def confirm(self):
|
||||
if self.routing_type in ['装夹预调', 'CNC加工']:
|
||||
self.workorder_id.is_rework = True
|
||||
@@ -97,9 +99,12 @@ class ReworkWizard(models.TransientModel):
|
||||
self.production_id.get_new_program(panel.name)
|
||||
if self.reprogramming_num >= 0 and self.programming_state == '已下发':
|
||||
ret = {'programming_list': []}
|
||||
cnc_rework = self.production_id.workorder_ids.filtered(
|
||||
lambda crw: crw.processing_panel == panel.name and crw.state in (
|
||||
'rework') and crw.routing_type == 'CNC加工')
|
||||
cnc_rework = max(
|
||||
self.production_id.workorder_ids.filtered(
|
||||
lambda
|
||||
crw: crw.processing_panel == panel.name and crw.state == 'rework' and crw.routing_type == 'CNC加工'),
|
||||
key=lambda w: w.create_date
|
||||
)
|
||||
if cnc_rework.cnc_ids:
|
||||
for item_line in cnc_rework.cnc_ids:
|
||||
vals = {
|
||||
@@ -127,7 +132,7 @@ class ReworkWizard(models.TransientModel):
|
||||
'sequence_number': cmm_line.sequence_number,
|
||||
'program_name': cmm_line.program_name,
|
||||
'program_path': cmm_line.program_path,
|
||||
'ftp_path': item_line.program_path,
|
||||
'ftp_path': cmm_line.program_path,
|
||||
'processing_panel': panel.name,
|
||||
'program_create_date': datetime.strftime(
|
||||
cmm_line.program_create_date,
|
||||
@@ -148,9 +153,10 @@ class ReworkWizard(models.TransientModel):
|
||||
p: p.routing_type == '装夹预调' and p.processing_panel == panel.name and p.state not in (
|
||||
'rework', 'done'))
|
||||
if new_pre_workorder:
|
||||
pre_rework = self.production_id.workorder_ids.filtered(
|
||||
pre_rework = max(self.production_id.workorder_ids.filtered(
|
||||
lambda pr: pr.processing_panel == panel.name and pr.state in (
|
||||
'rework') and pr.routing_type == '装夹预调')
|
||||
'rework') and pr.routing_type == '装夹预调'),
|
||||
key=lambda w1: w1.create_date)
|
||||
new_pre_workorder.write(
|
||||
{'processing_drawing': pre_rework.processing_drawing})
|
||||
self.production_id.write({'state': 'progress', 'is_rework': False})
|
||||
@@ -163,6 +169,14 @@ class ReworkWizard(models.TransientModel):
|
||||
{'programming_state': '编程中', 'work_state': '编程中'})
|
||||
if self.production_id.state == 'progress':
|
||||
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
|
||||
productions_not_delivered = self.env['mrp.production'].search(
|
||||
[('programming_no', '=', self.production_id.programming_no),
|
||||
('programming_state', '=', '已编程未下发')])
|
||||
if productions_not_delivered:
|
||||
productions_not_delivered.write(
|
||||
{'state': 'progress', 'programming_state': '已编程', 'work_state': '已编程',
|
||||
'is_rework': False})
|
||||
|
||||
@api.onchange('production_id')
|
||||
def onchange_processing_panel_id(self):
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<field name="production_id" invisible="True"/>
|
||||
<field name="workorder_id" invisible="True"/>
|
||||
<field name="product_id" invisible="True"/>
|
||||
<field name="tool_state" invisible="True"/>
|
||||
<field name="routing_type" invisible="True"/>
|
||||
<group>
|
||||
<field name="processing_panel_id" options="{'no_create': True}"
|
||||
@@ -25,15 +26,16 @@
|
||||
decoration-warning="programming_state =='编程中'"
|
||||
decoration-danger="programming_state =='已编程'" readonly="1"/>
|
||||
</div>
|
||||
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])]}'>
|
||||
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","not in",["已下发"])],"readonly": [("tool_state", "=", "2")]}'>
|
||||
<span style='font-weight:bold;'>申请重新编程
|
||||
<field name="is_reprogramming" force_save="1"/>
|
||||
<field name="is_reprogramming" force_save="1"
|
||||
attrs='{"readonly": [("tool_state", "=", "2")]}'/>
|
||||
</span>
|
||||
</div>
|
||||
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": [("is_reprogramming_readonly","=",False)]}'>
|
||||
<div attrs='{"invisible": ["|",("routing_type","in",["装夹预调","CNC加工"]),("programming_state","in",["已下发"])],"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'>
|
||||
<span style='font-weight:bold;'>申请重新编程
|
||||
<field name="is_reprogramming_readonly"
|
||||
attrs='{"readonly": [("is_reprogramming_readonly","=",False)]}'/>
|
||||
attrs='{"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'/>
|
||||
</span>
|
||||
</div>
|
||||
<group>
|
||||
|
||||
@@ -49,7 +49,7 @@ class FtpController():
|
||||
logging.error(f"Error checking file: {e}")
|
||||
return False
|
||||
|
||||
# 下载目录下的pdf文件(程序单)
|
||||
# 下载目录下的pdf文件(程序单/检测文件)
|
||||
def download_program_file(self, target_dir, serverdir):
|
||||
if not os.path.exists(serverdir):
|
||||
os.makedirs(serverdir)
|
||||
@@ -62,7 +62,7 @@ class FtpController():
|
||||
server = os.path.join(serverdir, file)
|
||||
if file.find(".pdf") != -1:
|
||||
self.download_file(server, file)
|
||||
return True
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
finally:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -158,7 +158,7 @@ class QuickEasyOrder(models.Model):
|
||||
payload = {
|
||||
'file_path': new_file_path,
|
||||
'dest_path': new_folder_path,
|
||||
'back_url': config['bfm_url']
|
||||
'back_url': config['bfm_url_new']
|
||||
}
|
||||
response = requests.post(url, json=payload, headers=headers)
|
||||
if response.status_code == 200:
|
||||
|
||||
@@ -1103,7 +1103,7 @@ class StockMove(models.Model):
|
||||
move_line_ids = picking_id.move_line_ids
|
||||
for move_line_id in move_line_ids:
|
||||
for res in data:
|
||||
if move_line_id.lot_id.product_id == res['lot_id'].product_id:
|
||||
if move_line_id.product_id == res['lot_id'].product_id:
|
||||
move_line_id.write({
|
||||
'destination_location_id': res.get('destination').id,
|
||||
'lot_id': res.get('lot_id').id
|
||||
|
||||
@@ -53,7 +53,8 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
|
||||
string='功能刀具安全库存', readonly=True)
|
||||
|
||||
@api.depends('barcode_id.quant_ids', 'functional_tool_status', 'current_shelf_location_id')
|
||||
@api.depends('barcode_id.quant_ids', 'barcode_id.quant_ids.location_id', 'functional_tool_status',
|
||||
'current_shelf_location_id')
|
||||
def _compute_current_location_id(self):
|
||||
for record in self:
|
||||
if record.functional_tool_status == '已拆除':
|
||||
@@ -262,8 +263,17 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
if self.tool_name_id.name:
|
||||
cnc_processing_ids = self.env['sf.cnc.processing'].search(
|
||||
[('tool_state', '=', '1'), ('cutting_tool_name', '=', self.tool_name_id.name)])
|
||||
production_ids = []
|
||||
if cnc_processing_ids:
|
||||
cnc_processing_ids.sudo().write({'tool_state': '0'})
|
||||
for item in cnc_processing_ids:
|
||||
if item.workorder_id and item.workorder_id.production_id not in production_ids:
|
||||
production_ids.append(item.workorder_id.production_id)
|
||||
if production_ids:
|
||||
# 对同一制造订单的工单的cnc编程单的功能刀具状态进行变更,并调用工单的功能刀具状态计算方法
|
||||
for production_id in production_ids:
|
||||
cnc_ids = cnc_processing_ids.filtered(lambda a: a.workorder_id.production_id == production_id)
|
||||
cnc_ids.sudo().write({'tool_state': '0'})
|
||||
cnc_ids.workorder_id._compute_tool_state()
|
||||
|
||||
def tool_inventory_displacement_out(self):
|
||||
"""
|
||||
|
||||
@@ -105,6 +105,10 @@ class CNCprocessing(models.Model):
|
||||
'test_results': '返工',
|
||||
'handle_result': '待处理'
|
||||
})
|
||||
# 修改当前面装夹预调工单的 is_rework 为 True
|
||||
# work_ids = production_id.workorder_ids.filtered(
|
||||
# lambda a: a.routing_type == '装夹预调' and a.processing_panel == key and not a.is_rework)
|
||||
# work_ids.write({'is_rework': True})
|
||||
# 对缺刀信息进行处理
|
||||
for key in data2:
|
||||
if data2.get(key):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
from datetime import timedelta, datetime, date
|
||||
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import ValidationError
|
||||
@@ -603,6 +603,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
功能刀具组装
|
||||
:return:
|
||||
"""
|
||||
logging.info('功能刀具开始组装!')
|
||||
# 获取组装单对象
|
||||
functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([
|
||||
('assembly_order_code', '=', self.assembly_order_code),
|
||||
@@ -649,6 +650,8 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
])
|
||||
cam_plan.write({'plan_execute_status': '2'})
|
||||
|
||||
logging.info('功能刀具组装完成!')
|
||||
|
||||
# 关闭弹出窗口
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -865,9 +868,10 @@ class StockPicking(models.Model):
|
||||
# 设置数量,并验证完成
|
||||
picking_id.action_set_quantities_to_reservation()
|
||||
picking_id.button_validate()
|
||||
logging.info(f'刀具物料调拨单状态:{picking_id.state}')
|
||||
|
||||
def _get_name_stock1(self, picking_type_id):
|
||||
name = picking_type_id.sequence_id.prefix
|
||||
name = f'{picking_type_id.sequence_id.prefix}DJ/{date.today().strftime("%y")}'
|
||||
stock_id = self.env['stock.picking'].sudo().search(
|
||||
[('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)],
|
||||
limit=1,
|
||||
@@ -876,7 +880,7 @@ class StockPicking(models.Model):
|
||||
if not stock_id:
|
||||
num = "%05d" % 1
|
||||
else:
|
||||
m = int(stock_id.name[-3:]) + 1
|
||||
m = int(stock_id.name[-5:]) + 1
|
||||
num = "%05d" % m
|
||||
return name + str(num)
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record model="ir.actions.act_window" id="stock.stock_picking_type_action">
|
||||
<field name="context">{'search_default_groupby_code':1}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_location_form_sf_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.location.form.sf.inherit</field>
|
||||
|
||||
Reference in New Issue
Block a user