Create a new quality alert
diff --git a/sf_base/models/common.py b/sf_base/models/common.py
index 95572631..257eb2d4 100644
--- a/sf_base/models/common.py
+++ b/sf_base/models/common.py
@@ -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
# 获取表面工艺的获取方式
diff --git a/sf_base/static/src/scss/format_img.scss b/sf_base/static/src/scss/format_img.scss
index 982d3c50..fc6f02dc 100644
--- a/sf_base/static/src/scss/format_img.scss
+++ b/sf_base/static/src/scss/format_img.scss
@@ -14,6 +14,7 @@
.img-fluid {
max-width: unset !important;
+ width: 40px;
}
.o_inner_group .img-fluid {
diff --git a/sf_dlm_management/views/product_template_management_view.xml b/sf_dlm_management/views/product_template_management_view.xml
index f335c1b5..cae895e3 100644
--- a/sf_dlm_management/views/product_template_management_view.xml
+++ b/sf_dlm_management/views/product_template_management_view.xml
@@ -2,6 +2,7 @@
+ tree,kanban,form,activity
{"search_default_categ_id":1,"search_default_consumable": 1, 'default_detailed_type': 'product'}
diff --git a/sf_maintenance/models/sf_maintenance.py b/sf_maintenance/models/sf_maintenance.py
index 3d68bb9a..de6be8da 100644
--- a/sf_maintenance/models/sf_maintenance.py
+++ b/sf_maintenance/models/sf_maintenance.py
@@ -689,6 +689,8 @@ class SfMaintenanceEquipment(models.Model):
if next_date < date_now:
next_date = date_now
else:
+ if not equipment.initial_action_date:
+ raise ValidationError('重置保养日期不能为空!!!')
next_date = equipment.initial_action_date + timedelta(days=equipment.period)
equipment.next_action_date = next_date
else:
@@ -735,6 +737,8 @@ class SfMaintenanceEquipment(models.Model):
if next_date < date_now:
next_date = date_now
else:
+ if not equipment.initial_overhaul_date:
+ raise ValidationError('重置维修日期不能为空')
next_date = equipment.initial_overhaul_date + timedelta(days=equipment.overhaul_period)
equipment.overhaul_date = next_date
else:
diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py
index 5106dcb1..3320f943 100644
--- a/sf_manufacturing/__manifest__.py
+++ b/sf_manufacturing/__manifest__.py
@@ -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',
diff --git a/sf_manufacturing/models/__init__.py b/sf_manufacturing/models/__init__.py
index 7d6aa8ae..b0c295f5 100644
--- a/sf_manufacturing/models/__init__.py
+++ b/sf_manufacturing/models/__init__.py
@@ -11,3 +11,5 @@ from . import production_line_base
from . import agv_setting
from . import agv_scheduling
from . import res_config_setting
+from . import sf_technology_design
+from . import sf_production_common
diff --git a/sf_manufacturing/models/model_type.py b/sf_manufacturing/models/model_type.py
index 10157f63..27ebfb03 100644
--- a/sf_manufacturing/models/model_type.py
+++ b/sf_manufacturing/models/model_type.py
@@ -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')
diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py
index c1936e6d..fa81837f 100644
--- a/sf_manufacturing/models/mrp_production.py
+++ b/sf_manufacturing/models/mrp_production.py
@@ -98,6 +98,7 @@ class MrpProduction(models.Model):
# ])
state = fields.Selection([
('draft', '草稿'),
+ ('technology_to_confirmed', '待工艺确认'),
('confirmed', '待排程'),
('pending_cam', '待加工'),
('progress', '加工中'),
@@ -160,6 +161,7 @@ class MrpProduction(models.Model):
is_remanufacture = fields.Boolean('是否重新制造', default=False)
remanufacture_count = fields.Integer("重新制造订单数量", compute='_compute_remanufacture_production_ids')
remanufacture_production_id = fields.Many2one('mrp.production', string='')
+ technology_design_ids = fields.One2many('sf.technology.design', 'production_id', string='工艺设计')
@api.depends('remanufacture_production_id')
def _compute_remanufacture_production_ids(self):
@@ -216,8 +218,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,6 +257,59 @@ class MrpProduction(models.Model):
if production.tool_state == '2':
production.state = 'rework'
+ # 工艺确认
+ def technology_confirm(self):
+ process_parameters = []
+ special_design = self.technology_design_ids.filtered(
+ lambda a: a.routing_tag == 'special' and a.process_parameters_id is not False)
+ for special in special_design:
+ if special.process_parameters_id:
+ product_production_process = self.env['product.template'].search(
+ [('server_product_process_parameters_id', '=', special.process_parameters_id.id)])
+ if not product_production_process:
+ if special.process_parameters_id not in process_parameters:
+ process_parameters.append(special.process_parameters_id.display_name)
+ if process_parameters:
+ raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters)))
+ # 判断同一个加工面的标准工序的顺序是否依次排序
+ error_panel = []
+ technology_design = self.technology_design_ids.filtered(lambda a: a.routing_tag == 'standard').sorted(
+ key=lambda m: m.sequence)
+ for index, design in enumerate(technology_design):
+ routing_type = design.route_id.routing_type
+ 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 is not False:
+ if design.panel != next_design.panel:
+ if index == 0:
+ 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 and not process_parameters:
+ 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):
"""
审核启用
@@ -492,73 +548,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)])
@@ -840,6 +856,7 @@ class MrpProduction(models.Model):
backorders = backorders - productions_to_backorder
productions_not_to_backorder._post_inventory(cancel_backorder=True)
+ # 查出最后一张工单完成入库操作
# if self.workorder_ids.filtered(lambda w: w.routing_type in ['表面工艺']):
# move_finish = self.env['stock.move'].search([('created_production_id', '=', self.id)])
# if move_finish:
@@ -1218,10 +1235,6 @@ class sf_detection_result(models.Model):
'type': 'ir.actions.act_window',
'res_id': self.id,
'views': [(self.env.ref('sf_manufacturing.sf_test_report_form').id, 'form')],
- # 'view_mode': 'form',
- # 'context': {
- # 'default_id': self.id
- # },
'target': 'new'
}
diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py
index a584379f..2916bdce 100644
--- a/sf_manufacturing/models/mrp_routing_workcenter.py
+++ b/sf_manufacturing/models/mrp_routing_workcenter.py
@@ -7,21 +7,23 @@ class ResMrpRoutingWorkcenter(models.Model):
_inherit = 'mrp.routing.workcenter'
routing_type = fields.Selection([
- # ('获取CNC加工程序', '获取CNC加工程序'),
('装夹预调', '装夹预调'),
- # ('前置三元定位检测', '前置三元定位检测'),
('CNC加工', 'CNC加工'),
- # ('后置三元质量检测', '后置三元质量检测'),
('解除装夹', '解除装夹'),
('切割', '切割'),
('表面工艺', '表面工艺')
], string="工序类型")
+ routing_tag = fields.Selection([
+ ('standard', '标准'),
+ ('special', '特殊')
+ ], string="标签")
is_repeat = fields.Boolean('重复', default=False)
workcenter_id = fields.Many2one('mrp.workcenter', required=False)
workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True)
bom_id = fields.Many2one('mrp.bom', required=False)
surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺")
reserved_duration = fields.Float('预留时长', default=30, tracking=True)
+
def get_no(self):
international_standards = self.search(
[('code', '!=', ''), ('active', 'in', [True, False])],
@@ -78,3 +80,13 @@ class ResMrpRoutingWorkcenter(models.Model):
else:
workcenter_id = workcenter_ids[0]
return workcenter_id
+
+ @api.model
+ def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
+ if self._context.get('production_id'):
+ technology_design = self.env['sf.technology.design'].search(
+ [('production_id', '=', self._context.get('production_id'))])
+ route_ids = [t.route_id.id for t in technology_design]
+ domain = [('id', 'not in', route_ids)]
+ return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
+ return super()._name_search(name, args, operator, limit, name_get_uid)
diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py
index 3125cb4b..9bfc82e1 100644
--- a/sf_manufacturing/models/mrp_workorder.py
+++ b/sf_manufacturing/models/mrp_workorder.py
@@ -670,35 +670,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
@@ -706,26 +685,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
@@ -756,22 +728,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),
@@ -1069,37 +1041,6 @@ class ResMrpWorkOrder(models.Model):
workorder.state = 'waiting'
continue
- # elif workorder.routing_type == 'CNC加工' and workorder.state not in ['done', 'cancel', 'progress',
- # 'rework']:
- # per_work = self.env['mrp.workorder'].search(
- # [('routing_type', '=', '装夹预调'), ('production_id', '=', workorder.production_id.id),
- # ('processing_panel', '=', workorder.processing_panel), ('is_rework', '=', True)])
- # if per_work:
- # workorder.state = 'waiting'
- # if workorder.routing_type == 'CNC加工' and workorder.state == 'progress':
- # workorder.state = 'to be detected'
-
- # for workorder in self:
- # if workorder.is_rework is True and workorder.state == 'done':
- # cnc_work = self.env['mrp.workorder'].search([('routing_type','=','CNC加工'),('production_id','=',workorder.production_id.id)])
- # if cnc_work:
- # cnc_work.state = 'waiting'
- # if workorder.state == 'pending':
- # if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
- # workorder.state = 'ready' if workorder.production_id.reservation_state == 'assigned' else 'waiting'
- # continue
- # if workorder.state not in ('waiting', 'ready'):
- # continue
- # if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
- # workorder.state = 'pending'
- # continue
- # if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
- # continue
- # if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting':
- # workorder.state = 'ready'
- # elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
- # workorder.state = 'waiting'
-
# 重写工单开始按钮方法
def button_start(self):
if self.routing_type == 'CNC加工':
diff --git a/sf_manufacturing/models/sf_production_common.py b/sf_manufacturing/models/sf_production_common.py
new file mode 100644
index 00000000..dc9ff2a3
--- /dev/null
+++ b/sf_manufacturing/models/sf_production_common.py
@@ -0,0 +1,17 @@
+# -*- 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)
+
diff --git a/sf_manufacturing/models/sf_technology_design.py b/sf_manufacturing/models/sf_technology_design.py
new file mode 100644
index 00000000..6aa49f5a
--- /dev/null
+++ b/sf_manufacturing/models/sf_technology_design.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+from odoo import fields, models
+
+
+class sf_technology_design(models.Model):
+ _name = 'sf.technology.design'
+ _description = "工艺设计"
+
+ 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')
+ is_auto = fields.Boolean('是否自动生成', default=False)
+ active = fields.Boolean('有效', default=True)
+
+ def json_technology_design_str(self, k, route, i):
+ 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
diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py
index 55667d41..a0787477 100644
--- a/sf_manufacturing/models/stock.py
+++ b/sf_manufacturing/models/stock.py
@@ -284,6 +284,7 @@ class StockRule(models.Model):
'product_id': production.product_id.id,
'state': 'draft',
})
+ technology_design_values = []
all_production = productions
grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -293,33 +294,31 @@ class StockRule(models.Model):
# 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in all_production]
for production_item in productions:
-
production_programming = self.env['mrp.production'].search(
[('product_id.id', '=', production_item.product_id.id),
('origin', '=', production_item.origin)],
limit=1, order='id asc')
if production_item.product_id.id in product_id_to_production_names:
- if not production_programming.programming_no:
- if production_item.product_id.model_process_parameters_ids:
- is_purchase = False
- sorted_process_parameters = sorted(production_item.product_id.model_process_parameters_ids,
- key=lambda w: w.id)
+ if production_item.product_id.model_process_parameters_ids:
+ is_purchase = False
+ sorted_process_parameters = sorted(production_item.product_id.model_process_parameters_ids,
+ key=lambda w: w.id)
- consecutive_process_parameters = []
- m = 0
- for i in range(len(sorted_process_parameters) - 1):
- if m == 0:
- is_purchase = False
- if self.env['product.template']._get_process_parameters_product(
- sorted_process_parameters[i]).partner_id == self.env[
- 'product.template']._get_process_parameters_product(sorted_process_parameters[
- i + 1]).partner_id and \
- sorted_process_parameters[i].gain_way == '外协':
- if sorted_process_parameters[i] not in consecutive_process_parameters:
- consecutive_process_parameters.append(sorted_process_parameters[i])
- consecutive_process_parameters.append(sorted_process_parameters[i + 1])
- m += 1
- continue
+ consecutive_process_parameters = []
+ m = 0
+ for i in range(len(sorted_process_parameters) - 1):
+ if m == 0:
+ is_purchase = False
+ if self.env['product.template']._get_process_parameters_product(
+ sorted_process_parameters[i]).partner_id == self.env[
+ 'product.template']._get_process_parameters_product(sorted_process_parameters[
+ i + 1]).partner_id and \
+ sorted_process_parameters[i].gain_way == '外协':
+ if sorted_process_parameters[i] not in consecutive_process_parameters:
+ consecutive_process_parameters.append(sorted_process_parameters[i])
+ consecutive_process_parameters.append(sorted_process_parameters[i + 1])
+ m += 1
+ continue
else:
if m == len(consecutive_process_parameters) - 1 and m != 0:
self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
@@ -329,7 +328,7 @@ class StockRule(models.Model):
is_purchase = True
consecutive_process_parameters = []
m = 0
- # 当前面的连续外协采购单生成再生成当前外协采购单
+ # 当前面的连续外协采购单生成再生成当前外协采购单
if is_purchase is False:
self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
production_item,
@@ -355,16 +354,70 @@ class StockRule(models.Model):
self.env['purchase.order'].get_purchase_order(sorted_process_parameters[i],
production_item,
product_id_to_production_names)
- # # 同一个产品多个制造订单对应一个编程单和模型库
- # # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
- if not production_item.programming_no:
- if not production_programming.programming_no:
- production_item.fetchCNC(
- ', '.join(product_id_to_production_names[production_item.product_id.id]))
- else:
- production_item.write({'programming_no': production_programming.programming_no,
- 'programming_state': '编程中'})
- return True
+ if not technology_design_values:
+ if production.product_id.categ_id.type == '成品':
+ production.product_id.model_processing_panel = 'ZM,FM'
+ # 根据加工面板的面数及成品工序模板生成工序设计
+ i = 0
+ 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'
+ )
+ for route in product_routing_workcenter:
+ i += 1
+ technology_design_values.append(
+ self.env['sf.technology.design'].json_technology_design_str(k, route, i))
+ surface_technics_arr = []
+ route_workcenter_arr = []
+ for process_param in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids.filtered(
+ lambda st: st.id in production.product_id.model_process_parameters_ids.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)
+ process_parameter = production.product_id.model_process_parameters_ids.filtered(
+ lambda pm: pm.process_id.id == p.id)
+ product_production_process = self.env['product.template'].search(
+ [('server_product_process_parameters_id', '=',
+ process_parameter.id)])
+ if process_parameter:
+ i += 1
+ route_production_process = self.env[
+ 'mrp.routing.workcenter'].search(
+ [('surface_technics_id', '=', p.id),
+ ('id', 'in', route_workcenter_arr)])
+ technology_design_values.append(
+ self.env['sf.technology.design'].json_technology_design_str(k,
+ route_production_process,
+ product_production_process,
+ i))
+ productions.technology_design_ids = technology_design_values
+
+ # # 同一个产品多个制造订单对应一个编程单和模型库
+ # # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
+ # if not production_item.programming_no:
+ # if not production_programming.programming_no:
+ # production_item.fetchCNC(
+ # ', '.join(product_id_to_production_names[production_item.product_id.id]))
+ # else:
+ # production_item.write({'programming_no': production_programming.programming_no,
+ # 'programming_state': '编程中'})
+ return True
class ProductionLot(models.Model):
@@ -554,7 +607,9 @@ class StockPicking(models.Model):
retrospect_ref = fields.Char('追溯参考', compute='_compute_move_ids', store=True)
- @api.depends('move_ids')
+ picking_type_sequence_code = fields.Char(related='picking_type_id.sequence_code')
+
+ @api.depends('move_ids', 'move_ids.product_id')
def _compute_move_ids(self):
for item in self:
if item.move_ids:
@@ -574,13 +629,14 @@ class StockPicking(models.Model):
default_codes = ''
if boms:
for bom in boms:
- code = bom.product_tmpl_id.default_code.split('-')[-1]
- default_code = bom.product_tmpl_id.default_code.split(f'-{code}')[0]
- if default_code not in default_codes:
- if default_codes == '':
- default_codes = default_code
- else:
- default_codes = default_codes + ',' + default_code
+ if bom.product_tmpl_id.default_code:
+ code = bom.product_tmpl_id.default_code.split('-')[-1]
+ default_code = bom.product_tmpl_id.default_code.split(f'-{code}')[0]
+ if default_code not in default_codes:
+ if default_codes == '':
+ default_codes = default_code
+ else:
+ default_codes = default_codes + ',' + default_code
item.retrospect_ref = default_codes
elif item.picking_type_id.sequence_code in ['INT', 'PC']:
pass
diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv
index a8511245..21386995 100644
--- a/sf_manufacturing/security/ir.model.access.csv
+++ b/sf_manufacturing/security/ir.model.access.csv
@@ -165,6 +165,12 @@ access_sf_agv_scheduling_group_sf_order_user,sf_agv_scheduling_group_sf_order_us
access_sf_agv_scheduling_group_sf_mrp_manager,sf_agv_scheduling_group_sf_mrp_manager,model_sf_agv_scheduling,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_agv_scheduling_group_sf_equipment_user,sf_agv_scheduling_group_sf_equipment_user,model_sf_agv_scheduling,sf_base.group_sf_equipment_user,1,1,1,0
+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
diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml
index a271b622..b0bbb924 100644
--- a/sf_manufacturing/views/mrp_production_addional_change.xml
+++ b/sf_manufacturing/views/mrp_production_addional_change.xml
@@ -70,7 +70,7 @@
- confirmed,pending_cam,progress,rework,scrap,done
+ technology_to_confirmed,confirmed,pending_cam,progress,rework,scrap,done
@@ -115,12 +115,18 @@
string="验证" type="object" class="oe_highlight"
confirm="There are no components to consume. Are you still sure you want to continue?"
data-hotkey="g" groups="sf_base.group_sf_mrp_user"/>
+
+
+
@@ -338,6 +344,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+