根据工序生成工单

This commit is contained in:
jinling.yang
2024-11-08 18:01:23 +08:00
parent e981d68805
commit 38c4aba45c
13 changed files with 167 additions and 194 deletions

View File

@@ -100,6 +100,7 @@ class MrsProductionProcess(models.Model):
travel_day = fields.Float('路途天数/d')
sequence = fields.Integer('排序')
# class MrsProcessingTechnology(models.Model):
# _name = 'sf.processing.technology'
# _description = '加工工艺'
@@ -157,7 +158,7 @@ class MrsProductionProcessParameter(models.Model):
for parameter in self:
if parameter.process_id:
name = parameter.process_id.name + '-' + parameter.name
result.append((parameter.id, name))
result.append((parameter.id, name))
return result
# 获取表面工艺的获取方式

View File

@@ -21,6 +21,7 @@
'wizard/workpiece_delivery_views.xml',
'wizard/rework_wizard_views.xml',
'wizard/production_wizard_views.xml',
'wizard/production_technology_wizard_views.xml',
'views/mrp_views_menus.xml',
'views/agv_scheduling_views.xml',
'views/stock_lot_views.xml',

View File

@@ -12,3 +12,4 @@ from . import agv_setting
from . import agv_scheduling
from . import res_config_setting
from . import sf_technology_design
from . import sf_production_common

View File

@@ -24,24 +24,7 @@ class ProductModelTypeRoutingSort(models.Model):
route_workcenter_id = fields.Many2one('mrp.routing.workcenter',
domain=[('routing_type', 'in', ['装夹预调', 'CNC加工', '解除装夹'])])
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat')
# routing_type = fields.Selection([
# ('获取CNC加工程序', '获取CNC加工程序'),
# ('装夹', '装夹'),
# ('前置三元定位检测', '前置三元定位检测'),
# ('CNC加工', 'CNC加工'),
# ('后置三元质量检测', '后置三元质量检测'),
# ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺')
# ], string="工序类型", compute='_compute_route_workcenter_id')
#
# @api.depends('route_workcenter_id')
# def _compute_route_workcenter_id(self):
# for record in self:
# if record:
# record.routing_type = record.route_workcenter_id.routing_type
routing_type = fields.Selection(string="工序类型", related='route_workcenter_id.routing_type')
workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
product_model_type_id = fields.Many2one('sf.model.type')
@@ -57,24 +40,7 @@ class EmbryoModelTypeRoutingSort(models.Model):
sequence = fields.Integer('Sequence')
route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['切割'])])
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat')
# routing_type = fields.Selection([
# ('获取CNC加工程序', '获取CNC加工程序'),
# ('装夹', '装夹'),
# ('前置三元定位检测', '前置三元定位检测'),
# ('CNC加工', 'CNC加工'),
# ('后置三元质量检测', '后置三元质量检测'),
# ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺')
# ], string="工序类型", compute='_compute_route_workcenter_id')
#
# @api.depends('route_workcenter_id')
# def _compute_route_workcenter_id(self):
# for record in self:
# if record:
# record.routing_type = record.route_workcenter_id.routing_type
routing_type = fields.Selection(string="工序类型", related='route_workcenter_id.routing_type')
workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
embryo_model_type_id = fields.Many2one('sf.model.type')
@@ -90,24 +56,7 @@ class SurfaceTechnicsModelTypeRoutingSort(models.Model):
sequence = fields.Integer('Sequence')
route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['表面工艺'])])
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat')
# routing_type = fields.Selection([
# ('获取CNC加工程序', '获取CNC加工程序'),
# ('装夹', '装夹'),
# ('前置三元定位检测', '前置三元定位检测'),
# ('CNC加工', 'CNC加工'),
# ('后置三元质量检测', '后置三元质量检测'),
# ('解除装夹', '解除装夹'), ('切割', '切割'), ('表面工艺', '表面工艺')
# ], string="工序类型", compute='_compute_route_workcenter_id')
#
# @api.depends('route_workcenter_id')
# def _compute_route_workcenter_id(self):
# for record in self:
# if record:
# record.routing_type = record.route_workcenter_id.routing_type
routing_type = fields.Selection(string="工序类型", related='route_workcenter_id.routing_type')
workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
surface_technics_model_type_id = fields.Many2one('sf.model.type')

View File

@@ -216,8 +216,9 @@ class MrpProduction(models.Model):
precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding)
for move in production.move_raw_ids if move.product_id):
production.state = 'progress'
# # 新添加的状态逻辑
elif not production.technology_design_ids:
production.state = 'technology_to_confirmed'
# 新添加的状态逻辑
if (
production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排':
production.state = 'confirmed'
@@ -254,42 +255,45 @@ class MrpProduction(models.Model):
if production.tool_state == '2':
production.state = 'rework'
# 工艺确认
def technology_confirm(self):
# 判断同一个加工面的标准工序的顺序是否依次排序
technology_design = self.technology_design_ids.sorted(key=lambda m: m.sequence)
current_design_index = None
for index, design in enumerate(technology_design.filtered(lambda a: a.routing_tag == 'standard')):
if design == current_design:
current_design_index = index
break # 找到了 current_design跳出循环
# 现在我们有了 current_design 的索引,我们可以找到下一条设计
if current_design_index is not None and current_design_index + 1 < len(technology_design):
next_design = technology_design[current_design_index + 1]
# 下一条设计是 next_design
else:
# 如果 current_design_index 为 None 或者没有下一条设计,则 next_design 为 None
next_design = None
for design in technology_design.filtered(lambda a: a.routing_tag == 'standard'):
technology_design = self.technology_design_ids.filtered(lambda a: a.routing_tag == 'standard').sorted(
key=lambda m: m.sequence)
error_panel = []
for index, design in enumerate(technology_design):
routing_type = design.route_id.routing_type
if routing_type in ['装夹预调', 'CNC加工', '解除装夹']:
# standard_designs = [d for d in technology_design_ids if d.routing_tag == 'standard']
# last_design = technology_design[technology_design.index(design) - 1]
next_design = technology_design[2]
for next_design in technology_design:
next_design_routing_type = next_design.route_id.routing_type
logging.info('next_design:%s' % next_design.route_id.name)
logging.info('next_design面:%s' % next_design.panel)
logging.info('design:%s' % design.route_id.name)
logging.info('design面:%s' % design.panel)
if next_design == design:
break
if design.panel != next_design.panel and routing_type not in ['解除装夹']:
if index < len(technology_design) - 1:
next_index = index + 1
next_design = technology_design[next_index]
next_design_routing_type = next_design.route_id.routing_type
logging.info('当前工序和加工面: %s-%s' % (design.route_id.name, design.panel))
logging.info('下一个工序和加工面: %s-%s' % (next_design.route_id.name, next_design.panel))
if design.panel != next_design.panel:
if index == 0:
raise UserError('【加工面】为%s的标准工序里含有其他加工面的工序,请调整后重试' % design.panel)
if design.panel == next_design.panel:
if (routing_type == '装夹预调' and next_design_routing_type == '解除装夹') or (
routing_type == 'CNC加工' and next_design_routing_type == '装夹预调'):
raise UserError('【加工面】为%s的标准工序顺序有误,请调整后重试' % design.panel)
if routing_type not in ['解除装夹']:
raise UserError('【加工面】为%s的标准工序顺序有误,请调整后重试' % design.panel)
if design.panel == next_design.panel:
if (routing_type == '装夹预调' and next_design_routing_type == '解除装夹') or (
routing_type == 'CNC加工' and next_design_routing_type == '装夹预调'):
if design.panel not in error_panel:
error_panel.append(design.panel)
else:
if not error_panel:
return {
'name': _('工艺确认'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'sf.production.technology.wizard',
'target': 'new',
'context': {
'default_production_id': self.id,
'default_origin': self.origin,
}}
if error_panel:
raise UserError(_("【加工面】为%s的标准工序顺序有误,请调整后重试", ", ".join(error_panel)))
return True
def action_check(self):
@@ -530,73 +534,33 @@ class MrpProduction(models.Model):
'state': 'pending',
}]
if production.product_id.categ_id.type == '成品':
# # 根据加工面板的面数及对应的工序模板生成工单
i = 0
processing_panel_len = len(production.product_id.model_processing_panel.split(','))
for k in (production.product_id.model_processing_panel.split(',')):
product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
[('product_model_type_id', '=', production.product_id.product_model_type_id.id)],
order='sequence asc'
)
i += 1
for route in product_routing_workcenter:
if route.is_repeat is True:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(k, production, route, item))
# if i == processing_panel_len and route.routing_type == '解除装夹':
# workorders_values.append(
# self.env['mrp.workorder'].json_workorder_str(k, production, route))
# 表面工艺工序
# 获取表面工艺id
# 工序id
surface_technics_arr = []
route_workcenter_arr = []
for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
if item.route_workcenter_id.surface_technics_id.id:
for process_param in production.product_id.model_process_parameters_ids:
logging.info('process_param:%s%s' % (process_param.id, process_param.name))
if item.route_workcenter_id.surface_technics_id == process_param.process_id:
logging.info(
'surface_technics_id:%s%s' % (item.route_workcenter_id.surface_technics_id.id,
item.route_workcenter_id.surface_technics_id.name))
surface_technics_arr.append(item.route_workcenter_id.surface_technics_id.id)
route_workcenter_arr.append(item.route_workcenter_id.id)
if surface_technics_arr:
production_process = self.env['sf.production.process'].search(
[('id', 'in', surface_technics_arr)],
order='sequence asc'
)
for p in production_process:
logging.info('production_process:%s' % p.name)
# if production_process:
process_parameter = production.product_id.model_process_parameters_ids.filtered(
lambda pm: pm.process_id.id == p.id)
if process_parameter:
# 产品为表面工艺服务的供应商
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', process_parameter.id)])
if product_production_process:
route_production_process = self.env[
'mrp.routing.workcenter'].search(
[('surface_technics_id', '=', p.id),
('id', 'in', route_workcenter_arr)])
if route_production_process:
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(
production, route_production_process,
process_parameter,
product_production_process.seller_ids[0].partner_id.id))
# # 根据工序设计生成工单
for route in item.technology_design_ids:
if route.route_id.routing_type not in ['表面工艺']:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(production, route))
else:
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', route.process_parameters_id.id)])
# if product_production_process:
# route_production_process = self.env[
# 'mrp.routing.workcenter'].search(
# [('surface_technics_id', '=', p.id),
# ('id', 'in', route_workcenter_arr)])
# if route_production_process:
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(
production, route, product_production_process.seller_ids[0].partner_id.id))
elif production.product_id.categ_id.type == '坯料':
embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
[('embryo_model_type_id', '=', production.product_id.embryo_model_type_id.id)],
order='sequence asc'
)
for route in embryo_routing_workcenter:
for route_embryo in embryo_routing_workcenter:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str('', production, route))
self.env['mrp.workorder'].json_workorder_str('', production, route_embryo))
production.workorder_ids = workorders_values
# for production_item in productions:
process_parameter_workorder = self.env['mrp.workorder'].search(
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
('is_subcontract', '=', True)])

View File

@@ -669,35 +669,14 @@ class ResMrpWorkOrder(models.Model):
}}
# 拼接工单对象属性值
def json_workorder_str(self, k, production, route, item):
def json_workorder_str(self, production, route):
# 计算预计时长duration_expected
routing_types = ['切割', '装夹预调', 'CNC加工', '解除装夹']
if route.routing_type in routing_types:
if route.route_id.routing_type in routing_types:
routing_workcenter = self.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', route.routing_type)])
[('name', '=', route.route_id.routing_type)])
duration_expected = routing_workcenter.time_cycle
reserved_duration = routing_workcenter.reserved_duration
# if route.routing_type == '切割':
# duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
# [('name', '=', '切割')]).time_cycle
# # elif route.routing_type == '获取CNC加工程序':
# # duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
# # [('name', '=', '获取CNC加工程序')]).time_cycle
# elif route.routing_type == '装夹预调':
# duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
# [('name', '=', '装夹预调')]).time_cycle
# # elif route.routing_type == '前置三元定位检测':
# # duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
# # [('name', '=', '前置三元定位检测')]).time_cycle
# elif route.routing_type == 'CNC加工':
# duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
# [('name', '=', 'CNC加工')]).time_cycle
# # elif route.routing_type == '后置三元质量检测':
# # duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
# # [('name', '=', '后置三元质量检测')]).time_cycle
# elif route.routing_type == '解除装夹':
# duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
# [('name', '=', '解除装夹')]).time_cycle
else:
duration_expected = 60
reserved_duration = 30
@@ -705,26 +684,19 @@ class ResMrpWorkOrder(models.Model):
'product_uom_id': production.product_uom_id.id,
'qty_producing': 0,
'operation_id': False,
'name': route.route_workcenter_id.name,
'processing_panel': k,
'quality_point_ids': route.route_workcenter_id.quality_point_ids,
'routing_type': route.routing_type,
# 'work_state': '待发起',
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
route.routing_type,
'name': route.route_id.name,
'processing_panel': route.panel,
'quality_point_ids': route.route_id.quality_point_ids,
'routing_type': route.route_id.routing_type,
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.route_id.workcenter_ids.ids,
route.route_id.routing_type,
production.product_id),
# 设定初始化值避免出现变成bool问题
'date_planned_start': datetime.now(),
'date_planned_finished': datetime.now() + timedelta(days=1),
'duration_expected': duration_expected,
'duration': 0,
'tag_type': '重新加工' if item is False else False,
'cnc_ids': False if route.routing_type != 'CNC加工' else self.env['sf.cnc.processing']._json_cnc_processing(
k, item),
'cmm_ids': False if route.routing_type != 'CNC加工' else self.env['sf.cmm.program']._json_cmm_program(k,
item),
# 'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self._json_workpiece_delivery_list(
# production)
# 'tag_type': '重新加工' if item is False else False,
'reserved_duration': reserved_duration,
}]
return workorders_values_str
@@ -755,22 +727,22 @@ class ResMrpWorkOrder(models.Model):
]
# 拼接工单对象属性值(表面工艺)
def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id):
def _json_workorder_surface_process_str(self, production, route, supplier_id):
workorders_values_str = [0, '', {
'product_uom_id': production.product_uom_id.id,
'qty_producing': 0,
'operation_id': False,
'name': '%s-%s' % (route.name, process_parameter.name),
'name': route.process_parameters_id.display_name,
'processing_panel': '',
'routing_type': '表面工艺',
'surface_technics_parameters_id': process_parameter.id,
'surface_technics_parameters_id': route.process_parameters_id.id,
'work_state': '',
'supplier_id': supplier_id,
'is_subcontract': True if process_parameter.gain_way == '外协' else False,
'is_subcontract': True if route.process_parameters_id.gain_way == '外协' else False,
'workcenter_id': self.env[
'mrp.workcenter'].get_process_outsourcing_workcenter() if process_parameter.gain_way == '外协' else
self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
route.routing_type,
'mrp.workcenter'].get_process_outsourcing_workcenter() if route.process_parameters_id.gain_way == '外协' else
self.env['mrp.routing.workcenter'].get_workcenter(route.route_id.workcenter_ids.ids,
route.route_id.routing_type,
production.product_id),
'date_planned_start': datetime.now(),
'date_planned_finished': datetime.now() + timedelta(days=1),

View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
import logging
from odoo import fields, models, api
from odoo.exceptions import UserError
class SfProductionProcessParameter(models.Model):
_inherit = 'sf.production.process.parameter'
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if self._context.get('route_id'):
routing = self.env['mrp.routing.workcenter'].search([('id', '=', self._context.get('route_id'))])
domain = [('process_id', '=', routing.surface_technics_id.id)]
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

@@ -6,9 +6,10 @@ class sf_technology_design(models.Model):
_name = 'sf.technology.design'
_description = "工艺设计"
route_id = fields.Many2one('mrp.routing.workcenter', '工序')
panel = fields.Char('加工面')
sequence = fields.Integer('序号')
route_id = fields.Many2one('mrp.routing.workcenter', '工序')
process_parameters_id = fields.Many2one('sf.production.process.parameter', string='表面工艺参数')
panel = fields.Char('加工面')
routing_tag = fields.Selection(related='route_id.routing_tag', string='标签', store=True)
time_cycle_manual = fields.Float(related='route_id.time_cycle_manual', string='预计时长')
production_id = fields.Many2one('mrp.production')
@@ -19,10 +20,12 @@ class sf_technology_design(models.Model):
workorders_values_str = [0, '', {
'route_id': route.id,
'panel': k,
'process_parameters_id': False if route.routing_type.id != '表面工艺' else self.env[
'sf.production.process.parameter'].search(
[('process_id', '=', route.surface_technics_id.id)]).id,
'sequence': i,
'is_auto': True}]
return workorders_values_str
def unlink_technology_design(self):
self.active = False

View File

@@ -168,5 +168,9 @@ access_sf_agv_scheduling_group_sf_equipment_user,sf_agv_scheduling_group_sf_equi
access_sf_technology_design_group_plan_dispatch,sf_technology_design_group_plan_dispatch,model_sf_technology_design,sf_base.group_plan_dispatch,1,1,1,0
access_sf_technology_design_group_sf_mrp_manager,sf_technology_design_group_sf_mrp_manager,model_sf_technology_design,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_technology_design_group_production_engineer,sf_technology_design_group_production_engineer,model_sf_technology_design,sf_base.group_production_engineer,1,1,1,0
access_sf_production_technology_wizard_group_plan_dispatch,sf_production_technology_wizard_group_plan_dispatch,model_sf_production_technology_wizard,sf_base.group_plan_dispatch,1,1,1,0
access_sf_production_technology_wizard_group_sf_mrp_manager,sf_production_technology_wizard_group_sf_mrp_manager,model_sf_production_technology_wizard,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_production_technology_wizard_group_production_engineer,sf_production_technology_wizard_group_production_engineer,model_sf_production_technology_wizard,sf_base.group_production_engineer,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
168
169
170
171
172
173
174
175
176

View File

@@ -349,6 +349,8 @@
<field name="sequence" widget="handle"/>
<field name="route_id" context="{'production_id': production_id}"
attrs="{'readonly': [('is_auto', '=', True)]}" options="{'no_create': True}"/>
<field name="process_parameters_id" attrs="{'readonly': [('is_auto', '=', True)]}"
string="参数" context="{'route_id':route_id}" options="{'no_create': True}"/>
<field name="panel" readonly="1"/>
<field name="routing_tag" readonly="1" widget="badge"
decoration-success="routing_tag == 'standard'"

View File

@@ -1,3 +1,4 @@
from . import workpiece_delivery_wizard
from . import rework_wizard
from . import production_wizard
from . import production_technology_wizard

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.exceptions import UserError, ValidationError
from collections import defaultdict, namedtuple
from odoo.addons.stock.models.stock_rule import ProcurementException
from datetime import datetime
from odoo import models, api, fields, _
class ProductionTechnologyWizard(models.TransientModel):
_name = 'sf.production.technology.wizard'
_description = '制造订单工艺确认向导'
production_id = fields.Many2one('mrp.production', string='制造订单号')
origin = fields.Char(string='源单据')
is_technology_confirm = fields.Boolean(default=False)
def confirm(self):
if self.is_technology_confirm is True:
domain = [('origin', '=', self.origin)]
else:
domain = [('id', '=', self.production_id.id)]
productions = self.env['mrp.production'].search(domain)
productions._create_workorder(self.production_id)

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="sf_production_technology_wizard_form_view">
<field name="name">sf.production.technology.wizard.form.view</field>
<field name="model">sf.production.technology.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<field name="production_id" invisible="1"/>
<field name="origin" invisible="1"/>
<div>
<field name="is_technology_confirm" force_save="1"/>
对当前制造订单,同一销售订单相同产品所生成的制造订单统一进行工艺调整与确认
</div>
<footer>
<button string="确认" name="confirm" type="object" class="oe_highlight" confirm="是否确认工艺调整"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<record id="action_sf_production_technology_wizard" model="ir.actions.act_window">
<field name="name">工艺确认</field>
<field name="res_model">sf.production.technology.wizard</field>
<field name="view_mode">form</field>
<!-- <field name="context">{-->
<!-- 'default_production_id': active_id}-->
<!-- </field>-->
<field name="target">new</field>
</record>
</odoo>