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:
jinling.yang
2024-08-02 14:41:42 +08:00
28 changed files with 8676 additions and 77369 deletions

View File

@@ -532,9 +532,3 @@ div:has(.o_required_modifier) > label::before {
position: unset; position: unset;
} }
// 修改表格下拉框会被表格下面数据框覆盖的bug
.tab-pane .o_field_widget {
position: relative;
z-index: 1;
}

View File

@@ -13,7 +13,7 @@ class BasicParametersFixture(models.Model):
diameter = fields.Float('直径(mm)', digits=(16, 2)) 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)) orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
clamping_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='装夹单元数') clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')

View File

@@ -149,7 +149,7 @@ class JdEclp(models.Model):
}, },
} }
_logger.info('准备调接口1') _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) requests.post(url1, json=json1, data=None)
_logger.info('调用成功1') _logger.info('调用成功1')
_logger.info('准备调接口2') _logger.info('准备调接口2')
@@ -158,7 +158,7 @@ class JdEclp(models.Model):
'orderNo': self.origin, '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) response = requests.post(url2, json=json2, data=None)
# _logger.info('调用成功2', response.json()['result']['wbNo']) # _logger.info('调用成功2', response.json()['result']['wbNo'])
tem_ret = response.json().get('result') tem_ret = response.json().get('result')
@@ -196,7 +196,7 @@ class JdEclp(models.Model):
'no': self.origin, '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) response = requests.post(url1, json=json1, data=None)
# _logger.info('调用成功2', response.json()) # _logger.info('调用成功2', response.json())

View File

@@ -42,7 +42,7 @@ class StatusChange(models.Model):
'process_start_time': process_start_time, '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) requests.post(url1, json=json1, data=None)
logging.info('接口已经执行=============') logging.info('接口已经执行=============')
@@ -66,7 +66,7 @@ class StatusChange(models.Model):
'state': '待派单', '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) requests.post(url1, json=json1, data=None)
return res return res

View File

@@ -1,2 +1,3 @@
from . import models from . import models
from . import wizard from . import wizard
from . import controllers

View File

@@ -0,0 +1 @@
from . import controllers

View 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)

View File

@@ -208,24 +208,22 @@ class Machine_ftp(models.Model):
# 机床采集项目 # 机床采集项目
timestamp = fields.Datetime('时间戳', readonly=True) timestamp = fields.Datetime('时间戳', readonly=True)
status = fields.Boolean('机床在线状态', readonly=True) status = fields.Boolean('机床在线状态', readonly=True)
run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='机床运行状态', # run_status = fields.Selection([('0', '空闲中'), ('1', '加工中'), ('2', '加工中'), ('3', '加工中')], string='机床运行状态',
readonly=True, default='0') # readonly=True, default='0')
run_status = fields.Char('机床运行状态', readonly=True)
run_time = fields.Char('机床累计运行时长', readonly=True) run_time = fields.Char('机床累计运行时长', readonly=True)
# 机床系统日期 # 机床系统日期
system_date = fields.Char('机床系统日期', readonly=True) system_date = fields.Char('机床系统日期', readonly=True)
# 机床系统时间 # 机床系统时间
system_time = fields.Char('机床系统时间', readonly=True) system_time = fields.Char('机床系统时间', readonly=True)
cut_time = fields.Char('机床累计切削时间', readonly=True) cut_time = fields.Char('机床累计切削时间', readonly=True)
cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='机床当前切削状态', # cut_status = fields.Selection([('0', '未切削'), ('1', '切削中'), ('2', '切削中'), ('3', '切削中')], string='机床当前切削状态',
readonly=True, default='0') # readonly=True, default='0')
cut_status = fields.Char('机床当前切削状态', readonly=True)
# 当前程序名 # 当前程序名
program = fields.Char('机床当前程序', readonly=True) program = fields.Char('机床当前程序', readonly=True)
# 当前刀具号 # 当前刀具号
tool_num = fields.Integer('机床当前刀具号', readonly=True) tool_num = fields.Integer('机床当前刀具号', readonly=True)
# 机床通电开机时间, 机床加工件数, 机床当前操作模式, 开始加工时间, 结束加工时间, 加工程序开始时间, 加工程序结束时间, 待机开始时间, # 机床通电开机时间, 机床加工件数, 机床当前操作模式, 开始加工时间, 结束加工时间, 加工程序开始时间, 加工程序结束时间, 待机开始时间,
# 待机结束时间, 机床离线开始时间, 机床离线结束时间, 机床急停状态, 机床主程序名称, 程序运行的状态, 机床当前执行指令, 机床当前执行语句号 # 待机结束时间, 机床离线开始时间, 机床离线结束时间, 机床急停状态, 机床主程序名称, 程序运行的状态, 机床当前执行指令, 机床当前执行语句号
# 机床X轴当前位置, 机床Y轴当前位置, 机床Z轴当前位置 # 机床X轴当前位置, 机床Y轴当前位置, 机床Z轴当前位置

View File

@@ -8,11 +8,14 @@ _logger = logging.getLogger(__name__)
class ResBFMConfigSettings(models.TransientModel): class ResBFMConfigSettings(models.TransientModel):
_inherit = 'res.config.settings' _inherit = 'res.config.settings'
bfm_url = fields.Selection( # bfm_url = fields.Selection(
[("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"), # [("https://bfm.cs.jikimo.com", "开发环境(https://bfm.cs.jikimo.com)"),
("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"), # ("https://bfm.t.jikimo.com", "测试环境(https://bfm.t.jikimo.com)"),
# ("正式环境", "https://bfm.jikimo.com")], string='bfm环境', store=True) # ("https://bfm.r.jikimo.com", "预发布环境(https://bfm.r.jikimo.com)"),
("https://bfm.jikimo.com", "正式环境(https://bfm.jikimo.com)")], string='bfm环境', store=True) # # ("正式环境", "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 @api.model
def get_values(self): def get_values(self):
@@ -22,14 +25,14 @@ class ResBFMConfigSettings(models.TransientModel):
""" """
values = super(ResBFMConfigSettings, self).get_values() values = super(ResBFMConfigSettings, self).get_values()
config = self.env['ir.config_parameter'].sudo() 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( values.update(
bfm_url=bfm_url, bfm_url_new=bfm_url_new,
) )
return values return values
def set_values(self): def set_values(self):
super(ResBFMConfigSettings, self).set_values() super(ResBFMConfigSettings, self).set_values()
ir_config = self.env['ir.config_parameter'].sudo() 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 "")

View File

@@ -14,8 +14,8 @@
<div class="o_setting_left_pane"/> <div class="o_setting_left_pane"/>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<div class="text-muted"> <div class="text-muted">
<label for="bfm_url" /> <label for="bfm_url_new" />
<field name="bfm_url" string="访问地址"/> <field name="bfm_url_new" string="业务平台访问地址"/>
</div> </div>
</div> </div>
<!-- </div> --> <!-- </div> -->

View File

@@ -42,7 +42,8 @@ class SfMaintenanceEquipmentOEELog(models.Model):
_description = '设备运行日志' _description = '设备运行日志'
equipment_id = fields.Many2one('maintenance.equipment', '机台号') equipment_id = fields.Many2one('maintenance.equipment', '机台号')
name = fields.Char('设备名称') equipment_code = fields.Char('设备编码')
name = fields.Char('设备名称', readonly='True')
machine_tool_picture = fields.Binary('设备图片') machine_tool_picture = fields.Binary('设备图片')
type_id = fields.Many2one('sf.machine_tool.type', '品牌型号') type_id = fields.Many2one('sf.machine_tool.type', '品牌型号')
state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"), state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"),
@@ -70,6 +71,11 @@ class SfMaintenanceEquipmentOEELog(models.Model):
# work_nums = fields.Integer('加工件数') # work_nums = fields.Integer('加工件数')
equipment_oee_id = fields.Many2one('maintenance.equipment.oee', '设备OEE') 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): class SfMaintenanceEquipmentOEELogDetail(models.Model):

View File

@@ -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_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_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_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,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,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
68
69
70
71
72

View File

@@ -156,6 +156,7 @@
<group> <group>
<group> <group>
<group> <group>
<field name="equipment_id" domain="[('name','ilike','加工中心')]"/>
<field name="type_id"/> <field name="type_id"/>
<field name="state"/> <field name="state"/>
</group> </group>
@@ -195,8 +196,27 @@
</group> </group>
</group> </group>
<notebook> <notebook>
<page string="日志详情"> <page string="24H日志详情">
<!-- 筛选出24小时内的日志 -->
<!-- <field name="detail_ids" domain="[('time','&lt;',(datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))]"> -->
<field name="detail_ids" domain="[('state','ilike','加工')]">
<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"> <field name="detail_ids">
<tree> <tree>
<field name="sequence"/> <field name="sequence"/>
@@ -256,22 +276,15 @@
<field name="model">maintenance.equipment.oee.log.detail</field> <field name="model">maintenance.equipment.oee.log.detail</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="设备运行日志详情"> <form string="设备运行日志详情">
<header>
<field name="sequence" readonly="1"/>
</header>
<sheet> <sheet>
<div class="oe_title">
<h1>
<field name="time" readonly="1"/>
</h1>
</div>
<group> <group>
<group> <group>
<field name="state" readonly="1"/> <field name="state"/>
<field name="production_id" readonly="1"/> <field name="production_id"/>
</group> </group>
<group> <group>
<field name="log_id"/> <field name="sequence"/>
<field name="time"/>
</group> </group>
</group> </group>
</sheet> </sheet>

View File

@@ -8,7 +8,7 @@ from odoo.http import request
class Manufacturing_Connect(http.Controller): 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="*") cors="*")
def get_Work_Info(self, **kw): def get_Work_Info(self, **kw):
""" """
@@ -103,7 +103,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('get_ShiftPlan error:%s' % e) logging.info('get_ShiftPlan error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def get_qcCheck(self, **kw): def get_qcCheck(self, **kw):
""" """
@@ -145,7 +145,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('get_qcCheck error:%s' % e) logging.info('get_qcCheck error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def button_Work_START(self, **kw): def button_Work_START(self, **kw):
""" """
@@ -193,7 +193,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('button_Work_START error:%s' % e) logging.info('button_Work_START error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def button_Work_End(self, **kw): def button_Work_End(self, **kw):
""" """
@@ -244,7 +244,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('button_Work_End error:%s' % e) logging.info('button_Work_End error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def PartQualityInspect(self, **kw): def PartQualityInspect(self, **kw):
""" """
@@ -260,40 +260,27 @@ class Manufacturing_Connect(http.Controller):
request.env['center_control.interface.log'].sudo().create( request.env['center_control.interface.log'].sudo().create(
{'content': ret, 'name': 'AutoDeviceApi/PartQualityInspect'}) {'content': ret, 'name': 'AutoDeviceApi/PartQualityInspect'})
production_id = ret['BillId'] production_id = ret['BillId']
routing_type = ret['CraftId'] # routing_type = ret['CraftId']
workorder = request.env['mrp.workorder'].sudo().search( 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) limit=1)
if workorder: if workorder:
# workorder.test_results = ret['Quality'] # workorder.test_results = ret['Quality']
logging.info('制造订单:%s' % workorder.production_id.name) logging.info('制造订单:%s' % workorder.production_id.name)
if 'ReportPaht' in ret: if 'ReportPaht' in ret:
download_state = request.env['mrp.workorder'].with_user( if ret['ReportPaht'].find('.pdf') != -1:
request.env.ref("base.user_admin")).download_reportfile_tmp(workorder, download_state = request.env['mrp.workorder'].with_user(
ret['ReportPaht']) request.env.ref("base.user_admin")).download_reportfile_tmp(workorder,
if download_state == 1: ret['ReportPaht'])
detection_ret = request.env['mrp.workorder'].with_user( if download_state is True:
request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht']) detection_ret = request.env['mrp.workorder'].with_user(
if detection_ret is True: request.env.ref("base.user_admin")).get_detection_file(workorder, ret['ReportPaht'])
stock_picking_type = request.env['stock.picking.type'].sudo().search( logging.info('detection_ret:%s' % detection_ret)
[('sequence_code', '=', 'SFP')]) if detection_ret is False:
if stock_picking_type: res = {'Succeed': False, 'ErrorCode': 205, 'Error': '检测报告文件读取失败'}
stock_picking = request.env['stock.picking'].sudo().search( else:
[('product_id', '=', workorder.product_id.id), res = {'Succeed': False, 'ErrorCode': 204, 'Error': '检测报告文件从FTP拉取失败'}
('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拉取失败'}
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传ReportPaht字段'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '未传ReportPaht字段'}
else: else:
@@ -303,7 +290,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('PartQualityInspect error:%s' % e) logging.info('PartQualityInspect error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def CMMProgDolod(self, **kw): def CMMProgDolod(self, **kw):
""" """
@@ -343,7 +330,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('CMMProgDolod error:%s' % e) logging.info('CMMProgDolod error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def NCProgDolod(self, **kw): def NCProgDolod(self, **kw):
""" """
@@ -384,7 +371,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('NCProgDolod error:%s' % e) logging.info('NCProgDolod error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def LocationChange(self, **kw): def LocationChange(self, **kw):
""" """
@@ -442,7 +429,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('LocationChange error:%s' % e) logging.info('LocationChange error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def AGVToProduct(self, **kw): def AGVToProduct(self, **kw):
""" """
@@ -503,7 +490,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('AGVToProduct error:%s' % e) logging.info('AGVToProduct error:%s' % e)
return json.JSONEncoder().encode(res) 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="*") cors="*")
def AGVDownProduct(self, **kw): def AGVDownProduct(self, **kw):
""" """

View File

@@ -29,41 +29,42 @@ class MrpProduction(models.Model):
detection_result_ids = fields.One2many('sf.detection.result', 'production_id', '检测报告') detection_result_ids = fields.One2many('sf.detection.result', 'production_id', '检测报告')
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0', tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
store=True, compute='_compute_tool_state') 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) 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') @api.depends('workorder_ids.tool_state')
def _compute_tool_state(self): def _compute_tool_state(self):
# if self.workorder_ids:
for item in self: for item in self:
if item.workorder_ids: 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'): if workorder_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state = '2' item.tool_state = '2'
elif workorder_ids.filtered(lambda a: a.tool_state == '1'): 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 = '1'
item.tool_state_remark = tool_state_remark
item.tool_state_remark2 = ''
else: else:
item.tool_state = '0' item.tool_state = '0'
item.tool_state_remark = '' if tool_state == '2' and item.tool_state != '2':
item.tool_state_remark2 = '' item.detection_result_ids.filtered(
lambda a: a.detailed_reason == '无效功能刀具' and a.handle_result == '待处理').write(
{'handle_result': '已处理'})
# state = fields.Selection(selection_add=[ # state = fields.Selection(selection_add=[
# ('pending_scheduling', '待排程'), # ('pending_scheduling', '待排程'),
@@ -237,7 +238,6 @@ class MrpProduction(models.Model):
ret = requests.post(config_url, json=res, data=None, headers=config_header) ret = requests.post(config_url, json=res, data=None, headers=config_header)
ret = ret.json() ret = ret.json()
result = json.loads(ret['result']) result = json.loads(ret['result'])
logging.info('cron_get_programming_state-ret:%s' % result)
if result['status'] == 1: if result['status'] == 1:
for item in result['programming_list']: for item in result['programming_list']:
if not self: if not self:
@@ -245,7 +245,6 @@ class MrpProduction(models.Model):
if rp.programming_no == item['programming_no']: if rp.programming_no == item['programming_no']:
rp.write({'programming_state': '已编程未下发' if item[ rp.write({'programming_state': '已编程未下发' if item[
'programming_state'] == '已编程' else '编程中'}) 'programming_state'] == '已编程' else '编程中'})
logging.info('rp:%s' % rp.name)
else: else:
return item return item
@@ -794,8 +793,6 @@ class MrpProduction(models.Model):
cloud_programming = None cloud_programming = None
if self.programming_state in ['已编程']: if self.programming_state in ['已编程']:
cloud_programming = self._cron_get_programming_state() 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 { return {
'name': _('返工'), 'name': _('返工'),
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
@@ -814,17 +811,17 @@ class MrpProduction(models.Model):
def do_update_program(self): def do_update_program(self):
program_production = self program_production = self
if len(program_production) >= 1: if len(program_production) >= 1:
same_product_id = None # same_product_id = None
is_not_same_product = 0 # is_not_same_product = 0
for item in program_production: for item in program_production:
if same_product_id is None: # if same_product_id is None:
same_product_id = item.product_id # same_product_id = item.product_id
if item.product_id != same_product_id: # if item.product_id != same_product_id:
is_not_same_product += 1 # is_not_same_product += 1
if item.state != "rework" and item.programming_state != "已编程未下发": if item.state != "rework" and item.programming_state != "已编程未下发":
raise UserError("请选择状态为返工且已编程未下发的制造订单") raise UserError("请选择状态为返工且已编程未下发的制造订单")
if is_not_same_product >= 1: # if is_not_same_product >= 1:
raise UserError("您选择的记录中含有其他产品的制造订单,请选择同一产品的制造订单") # raise UserError("您选择的记录中含有其他产品的制造订单,请选择同一产品的制造订单")
grouped_program_ids = {k: list(g) for k, g in groupby(program_production, key=lambda x: x.programming_no)} grouped_program_ids = {k: list(g) for k, g in groupby(program_production, key=lambda x: x.programming_no)}
program_to_production_names = {} program_to_production_names = {}
for programming_no, program_production in grouped_program_ids.items(): for programming_no, program_production in grouped_program_ids.items():
@@ -904,8 +901,10 @@ class MrpProduction(models.Model):
if pre_workorder: if pre_workorder:
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())})
# if production.state == 'rework' and production.programming_state == '已编程未下发':
logging.info('更新程序完成:%s' % production.name) # production.write(
# {'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
# logging.info('返工含有已编程未下发的程序更新完成:%s' % production.name)
else: else:
raise UserError(result['message']) raise UserError(result['message'])
@@ -1084,18 +1083,3 @@ class sf_processing_panel(models.Model):
name = fields.Char('加工面') name = fields.Char('加工面')
active = fields.Boolean('有效', default=True) 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)

View File

@@ -180,11 +180,28 @@ class ResMrpWorkOrder(models.Model):
# 功能刀具状态 # 功能刀具状态
tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0', tool_state = fields.Selection([('0', '正常'), ('1', '缺刀'), ('2', '无效刀')], string='功能刀具状态', default='0',
store=True, compute='_compute_tool_state') 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') @api.depends('cnc_ids.tool_state')
def _compute_tool_state(self): def _compute_tool_state(self):
for item in self: for item in self:
if item: if item.cnc_ids:
if item.cnc_ids.filtered(lambda a: a.tool_state == '2'): if item.cnc_ids.filtered(lambda a: a.tool_state == '2'):
item.tool_state = '2' item.tool_state = '2'
elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'): elif item.cnc_ids.filtered(lambda a: a.tool_state == '1'):
@@ -240,7 +257,66 @@ class ResMrpWorkOrder(models.Model):
detailed_reason = fields.Text('详细原因') detailed_reason = fields.Text('详细原因')
is_rework = fields.Boolean(string='是否返工', default=False) 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') @api.onchange('rfid_code')
def _onchange(self): def _onchange(self):
@@ -745,7 +821,8 @@ class ResMrpWorkOrder(models.Model):
}] }]
return workorders_values_str 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): def _compute_state(self):
super()._compute_state() super()._compute_state()
for workorder in self: for workorder in self:
@@ -761,18 +838,12 @@ class ResMrpWorkOrder(models.Model):
[('production_id', '=', workorder.production_id.id), [('production_id', '=', workorder.production_id.id),
('processing_panel', '=', workorder.processing_panel), ('processing_panel', '=', workorder.processing_panel),
('routing_type', '=', 'CNC加工'), ('state', 'in', ['pending'])]) ('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.state not in ['cancel', 'progress', 'rework']:
if workorder.production_id.state == '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', if workorder.routing_type == '装夹预调' and workorder.state not in ['done', 'rework',
'cancel']: 'cancel']:
# # 有返工工单 # # 有返工工单
@@ -786,8 +857,6 @@ class ResMrpWorkOrder(models.Model):
if workorder.production_id.is_rework is True: if workorder.production_id.is_rework is True:
if re_work or cnc_workorder: if re_work or cnc_workorder:
workorder.state = 'waiting' 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']: elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'rework', 'cancel']:
pre_workorder = self.env['mrp.workorder'].search( pre_workorder = self.env['mrp.workorder'].search(
@@ -805,27 +874,16 @@ class ResMrpWorkOrder(models.Model):
# if workorder.production_id.is_rework is True: # if workorder.production_id.is_rework is True:
# workorder.state = 'waiting' # workorder.state = 'waiting'
elif workorder.production_id.state == 'progress': 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 \ if workorder.routing_type == '装夹预调' and workorder.production_id.programming_state == '已编程' and \
workorder.is_rework is False and workorder.state not in [ workorder.is_rework is False and workorder.state not in [
'done', 'rework', 'done', 'rework',
'cancel']: 'cancel']:
if (re_work or cnc_workorder) and workorder.production_id.is_rework is False: if workorder.production_id.is_rework is False:
workorder.state = 'ready' 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']: 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 unclamp_workorder:
if workorder.is_subcontract is False: if workorder.is_subcontract is False:
workorder.state = 'ready' workorder.state = 'ready'
@@ -835,13 +893,54 @@ class ResMrpWorkOrder(models.Model):
# else: # else:
# if workorder.state not in ['cancel', 'rework']: # if workorder.state not in ['cancel', 'rework']:
# workorder.state = 'rework' # workorder.state = 'rework'
# if workorder.production_id.state == 'pending_cam': if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']:
# if workorder.routing_type == '装夹预调' and workorder.state in ['ready', 'waiting']: workorder_ids = workorder.production_id.workorder_ids
# if workorder.production_id.tool_state in ['1', '2']: work_bo = True
# workorder.state = 'waiting' for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'):
if not workorder_ids.filtered(
logging.info('工序:%s' % workorder.sequence) lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel']
logging.info('工单最终状态:%s' % workorder.state) 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', # elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress',
# 'rework']: # 'rework']:
@@ -1076,38 +1175,27 @@ class ResMrpWorkOrder(models.Model):
# 将FTP的检测报告文件下载到临时目录 # 将FTP的检测报告文件下载到临时目录
def download_reportfile_tmp(self, workorder, reportpath): def download_reportfile_tmp(self, workorder, reportpath):
logging.info('reportpath:%s' % reportpath) logging.info('reportpath/ftp地址:%s' % reportpath)
production_no_ftp = reportpath.split('/') logging.info('processing_panel:%s' % workorder.processing_panel)
production_no = workorder.production_id.name.replace('/', '_') serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection',
# ftp地址 workorder.processing_panel)
remotepath = os.path.join('/NC', production_no_ftp[1], 'detection') ftp_resconfig = self.env['res.config.settings'].get_values()
logging.info('ftp地址:%s' % remotepath) ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']),
if reportpath.find(production_no) != -1: ftp_resconfig['ftp_user'],
# 服务器内临时地址 ftp_resconfig['ftp_password'])
serverdir = os.path.join('/tmp', production_no_ftp[1], 'detection') if not ftp.file_exists_1(reportpath):
ftp_resconfig = self.env['res.config.settings'].get_values() logging.info('文件不存在:%s' % reportpath)
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), download_state = ftp.download_program_file(reportpath, serverdir)
ftp_resconfig['ftp_user'], logging.info('download_state:%s' % download_state)
ftp_resconfig['ftp_password'])
download_state = ftp.download_reportfile_tree(remotepath, serverdir, reportpath)
logging.info('download_state:%s' % download_state)
else:
download_state = 2
return download_state return download_state
# 根据中控系统提供的检测文件地址去ftp里对应的制造订单里获取 # 根据中控系统提供的检测文件地址去ftp里对应的制造订单里获取
def get_detection_file(self, workorder, reportPath): def get_detection_file(self, workorder, reportPath):
# if reportPath.startswith('/'): serverdir = os.path.join('/tmp', workorder.production_id.name.replace('/', '_'), 'detection',
# reportPath = reportPath[4:] workorder.processing_panel)
# serverdir = os.path.join('/tmp', reportPath)
serverdir = '/tmp' + reportPath
logging.info('get_detection_file-serverdir:%s' % serverdir) logging.info('get_detection_file-serverdir:%s' % serverdir)
serverdir_prefix = os.path.dirname(serverdir) for root, dirs, files in os.walk(serverdir):
logging.info('serverdir_prefix-serverdir:%s' % serverdir_prefix)
for root, dirs, files in os.walk(serverdir_prefix):
for filename in files: for filename in files:
logging.info('filename:%s' % filename)
logging.info('reportPath:%s' % os.path.basename(reportPath))
if filename == os.path.basename(reportPath): if filename == os.path.basename(reportPath):
report_file_path = os.path.join(root, filename) report_file_path = os.path.join(root, filename)
logging.info('get_detection_file-report_file_path:%s' % report_file_path) logging.info('get_detection_file-report_file_path:%s' % report_file_path)

View File

@@ -811,7 +811,7 @@ class ResProductFixture(models.Model):
diameter = fields.Float('直径(mm)', digits=(16, 2)) 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)) orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
clamping_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='装夹单元数') clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')

View File

@@ -7,10 +7,10 @@
<field name="model">mrp.production</field> <field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_tree_view"/> <field name="inherit_id" ref="mrp.mrp_production_tree_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//button[@name='do_unreserve']" position="after"> <!-- <xpath expr="//button[@name='do_unreserve']" position="after">-->
<button name="do_update_program" type="object" string="更新程序" <!-- <button name="do_update_program" type="object" string="更新程序"-->
groups="sf_base.group_sf_mrp_user"/> <!-- groups="sf_base.group_sf_mrp_user"/>-->
</xpath> <!-- </xpath>-->
<xpath expr="//field[@name='product_id']" position="replace"/> <xpath expr="//field[@name='product_id']" position="replace"/>
<xpath expr="//field[@name='product_qty']" position="replace"/> <xpath expr="//field[@name='product_qty']" position="replace"/>
<xpath expr="//field[@name='product_uom_id']" position="replace"/> <xpath expr="//field[@name='product_uom_id']" position="replace"/>
@@ -128,9 +128,9 @@
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', '!=', '已编程')]}"/>
<button name="%(sf_manufacturing.action_sf_production_wizard)d" string="报废" type="action" <!-- <button name="%(sf_manufacturing.action_sf_production_wizard)d" string="报废" type="action"-->
groups="sf_base.group_sf_mrp_user" <!-- groups="sf_base.group_sf_mrp_user"-->
attrs="{'invisible': [('is_scrap', '=', False)]}"/> <!-- attrs="{'invisible': [('is_scrap', '=', False)]}"/>-->
</xpath> </xpath>
<xpath expr="(//header//button[@name='button_mark_done'])[3]" position="replace"> <xpath expr="(//header//button[@name='button_mark_done'])[3]" position="replace">
<button name="button_mark_done" attrs="{'invisible': [ <button name="button_mark_done" attrs="{'invisible': [
@@ -465,6 +465,8 @@
<separator/> <separator/>
<filter string="返工且已编程" name="filter_rework_programmed" <filter string="返工且已编程" name="filter_rework_programmed"
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程')]"/> domain="[('state', '=', 'rework'),('programming_state', '=', '已编程')]"/>
<filter string="返工且已编程未下发" name="filter_rework_programmed_not_delivered"
domain="[('state', '=', 'rework'),('programming_state', '=', '已编程未下发')]"/>
<separator/> <separator/>
<filter name="filter_programming" string="编程中" <filter name="filter_programming" string="编程中"
domain="[('programming_state', '=', '编程中')]"/> domain="[('programming_state', '=', '编程中')]"/>

View File

@@ -31,6 +31,8 @@ class ReworkWizard(models.TransientModel):
('已下发', '已下发')], ('已下发', '已下发')],
string='编程状态') string='编程状态')
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
def confirm(self): def confirm(self):
if self.routing_type in ['装夹预调', 'CNC加工']: if self.routing_type in ['装夹预调', 'CNC加工']:
self.workorder_id.is_rework = True self.workorder_id.is_rework = True
@@ -97,9 +99,12 @@ class ReworkWizard(models.TransientModel):
self.production_id.get_new_program(panel.name) self.production_id.get_new_program(panel.name)
if self.reprogramming_num >= 0 and self.programming_state == '已下发': if self.reprogramming_num >= 0 and self.programming_state == '已下发':
ret = {'programming_list': []} ret = {'programming_list': []}
cnc_rework = self.production_id.workorder_ids.filtered( cnc_rework = max(
lambda crw: crw.processing_panel == panel.name and crw.state in ( self.production_id.workorder_ids.filtered(
'rework') and crw.routing_type == 'CNC加工') 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: if cnc_rework.cnc_ids:
for item_line in cnc_rework.cnc_ids: for item_line in cnc_rework.cnc_ids:
vals = { vals = {
@@ -127,7 +132,7 @@ class ReworkWizard(models.TransientModel):
'sequence_number': cmm_line.sequence_number, 'sequence_number': cmm_line.sequence_number,
'program_name': cmm_line.program_name, 'program_name': cmm_line.program_name,
'program_path': cmm_line.program_path, 'program_path': cmm_line.program_path,
'ftp_path': item_line.program_path, 'ftp_path': cmm_line.program_path,
'processing_panel': panel.name, 'processing_panel': panel.name,
'program_create_date': datetime.strftime( 'program_create_date': datetime.strftime(
cmm_line.program_create_date, 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 ( p: p.routing_type == '装夹预调' and p.processing_panel == panel.name and p.state not in (
'rework', 'done')) 'rework', 'done'))
if new_pre_workorder: 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 ( 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( new_pre_workorder.write(
{'processing_drawing': pre_rework.processing_drawing}) {'processing_drawing': pre_rework.processing_drawing})
self.production_id.write({'state': 'progress', 'is_rework': False}) self.production_id.write({'state': 'progress', 'is_rework': False})
@@ -163,6 +169,14 @@ class ReworkWizard(models.TransientModel):
{'programming_state': '编程中', 'work_state': '编程中'}) {'programming_state': '编程中', 'work_state': '编程中'})
if self.production_id.state == 'progress': if self.production_id.state == 'progress':
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'}) 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') @api.onchange('production_id')
def onchange_processing_panel_id(self): def onchange_processing_panel_id(self):

View File

@@ -9,6 +9,7 @@
<field name="production_id" invisible="True"/> <field name="production_id" invisible="True"/>
<field name="workorder_id" invisible="True"/> <field name="workorder_id" invisible="True"/>
<field name="product_id" invisible="True"/> <field name="product_id" invisible="True"/>
<field name="tool_state" invisible="True"/>
<field name="routing_type" invisible="True"/> <field name="routing_type" invisible="True"/>
<group> <group>
<field name="processing_panel_id" options="{'no_create': True}" <field name="processing_panel_id" options="{'no_create': True}"
@@ -25,15 +26,16 @@
decoration-warning="programming_state =='编程中'" decoration-warning="programming_state =='编程中'"
decoration-danger="programming_state =='已编程'" readonly="1"/> decoration-danger="programming_state =='已编程'" readonly="1"/>
</div> </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;'>申请重新编程 <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> </span>
</div> </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;'>申请重新编程 <span style='font-weight:bold;'>申请重新编程
<field name="is_reprogramming_readonly" <field name="is_reprogramming_readonly"
attrs='{"readonly": [("is_reprogramming_readonly","=",False)]}'/> attrs='{"readonly": ["|",("is_reprogramming_readonly","=",False),("tool_state", "=", "2")]}'/>
</span> </span>
</div> </div>
<group> <group>

View File

@@ -49,7 +49,7 @@ class FtpController():
logging.error(f"Error checking file: {e}") logging.error(f"Error checking file: {e}")
return False return False
# 下载目录下的pdf文件(程序单) # 下载目录下的pdf文件(程序单/检测文件)
def download_program_file(self, target_dir, serverdir): def download_program_file(self, target_dir, serverdir):
if not os.path.exists(serverdir): if not os.path.exists(serverdir):
os.makedirs(serverdir) os.makedirs(serverdir)
@@ -62,7 +62,7 @@ class FtpController():
server = os.path.join(serverdir, file) server = os.path.join(serverdir, file)
if file.find(".pdf") != -1: if file.find(".pdf") != -1:
self.download_file(server, file) self.download_file(server, file)
return True return True
except: except:
return False return False
finally: finally:

File diff suppressed because it is too large Load Diff

View File

@@ -158,7 +158,7 @@ class QuickEasyOrder(models.Model):
payload = { payload = {
'file_path': new_file_path, 'file_path': new_file_path,
'dest_path': new_folder_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) response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200: if response.status_code == 200:

View File

@@ -1103,7 +1103,7 @@ class StockMove(models.Model):
move_line_ids = picking_id.move_line_ids move_line_ids = picking_id.move_line_ids
for move_line_id in move_line_ids: for move_line_id in move_line_ids:
for res in data: 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({ move_line_id.write({
'destination_location_id': res.get('destination').id, 'destination_location_id': res.get('destination').id,
'lot_id': res.get('lot_id').id 'lot_id': res.get('lot_id').id

View File

@@ -53,7 +53,8 @@ class FunctionalCuttingToolEntity(models.Model):
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools', safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
string='功能刀具安全库存', readonly=True) 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): def _compute_current_location_id(self):
for record in self: for record in self:
if record.functional_tool_status == '已拆除': if record.functional_tool_status == '已拆除':
@@ -262,8 +263,17 @@ class FunctionalCuttingToolEntity(models.Model):
if self.tool_name_id.name: if self.tool_name_id.name:
cnc_processing_ids = self.env['sf.cnc.processing'].search( cnc_processing_ids = self.env['sf.cnc.processing'].search(
[('tool_state', '=', '1'), ('cutting_tool_name', '=', self.tool_name_id.name)]) [('tool_state', '=', '1'), ('cutting_tool_name', '=', self.tool_name_id.name)])
production_ids = []
if cnc_processing_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): def tool_inventory_displacement_out(self):
""" """

View File

@@ -105,6 +105,10 @@ class CNCprocessing(models.Model):
'test_results': '返工', 'test_results': '返工',
'handle_result': '待处理' '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: for key in data2:
if data2.get(key): if data2.get(key):

View File

@@ -1,6 +1,6 @@
import logging import logging
from datetime import timedelta, datetime from datetime import timedelta, datetime, date
from odoo import fields, models, api from odoo import fields, models, api
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
@@ -603,6 +603,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
功能刀具组装 功能刀具组装
:return: :return:
""" """
logging.info('功能刀具开始组装!')
# 获取组装单对象 # 获取组装单对象
functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([ functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([
('assembly_order_code', '=', self.assembly_order_code), ('assembly_order_code', '=', self.assembly_order_code),
@@ -649,6 +650,8 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
]) ])
cam_plan.write({'plan_execute_status': '2'}) cam_plan.write({'plan_execute_status': '2'})
logging.info('功能刀具组装完成!')
# 关闭弹出窗口 # 关闭弹出窗口
return {'type': 'ir.actions.act_window_close'} return {'type': 'ir.actions.act_window_close'}
@@ -865,9 +868,10 @@ class StockPicking(models.Model):
# 设置数量,并验证完成 # 设置数量,并验证完成
picking_id.action_set_quantities_to_reservation() picking_id.action_set_quantities_to_reservation()
picking_id.button_validate() picking_id.button_validate()
logging.info(f'刀具物料调拨单状态:{picking_id.state}')
def _get_name_stock1(self, picking_type_id): 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( stock_id = self.env['stock.picking'].sudo().search(
[('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)], [('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)],
limit=1, limit=1,
@@ -876,7 +880,7 @@ class StockPicking(models.Model):
if not stock_id: if not stock_id:
num = "%05d" % 1 num = "%05d" % 1
else: else:
m = int(stock_id.name[-3:]) + 1 m = int(stock_id.name[-5:]) + 1
num = "%05d" % m num = "%05d" % m
return name + str(num) return name + str(num)

View File

@@ -2,6 +2,9 @@
<odoo> <odoo>
<data> <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"> <record id="view_location_form_sf_inherit" model="ir.ui.view">
<field name="name">stock.location.form.sf.inherit</field> <field name="name">stock.location.form.sf.inherit</field>