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

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

View File

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

View File

@@ -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='装夹单元数')