Accept Merge Request #1495: (feature/修复表面工艺工单完成入库操作 -> develop)

Merge Request: 制造订单根据工艺设计生成工单

Created By: @杨金灵
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1495
This commit is contained in:
杨金灵
2024-11-11 15:41:36 +08:00
committed by Coding
18 changed files with 348 additions and 232 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

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

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

@@ -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'
}

View File

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

View File

@@ -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加工':

View File

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

View File

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

View File

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

View File

@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
165
166
167
168
169
170
171
172
173
174
175
176

View File

@@ -70,7 +70,7 @@
<!-- <attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done -->
<!-- </attribute> -->
<attribute name="statusbar_visible">
confirmed,pending_cam,progress,rework,scrap,done
technology_to_confirmed,confirmed,pending_cam,progress,rework,scrap,done
</attribute>
</xpath>
<xpath expr="//sheet//group//group[2]//label" position="before">
@@ -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"/>
<button name="technology_confirm" string="工艺确认" type="object" class="oe_highlight"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '!=', [])]}"></button>
</xpath>
<xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace">
<button name="button_mark_done"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}"
string="验证" type="object" data-hotkey="g"
groups="sf_base.group_sf_mrp_user"/>
<button name="technology_confirm" string="工艺确认" type="object" class="oe_highlight"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}"
></button>
</xpath>
<xpath expr="(//header//button[@name='button_scrap'])" position="replace">
<button name="button_scrap" invisible="1"/>
@@ -338,6 +344,27 @@
<page string="质检标准">
<field name="quality_standard" widget="adaptive_viewer"/>
</page>
<page string="工艺设计">
<field name="technology_design_ids" widget="one2many">
<tree editable="bottom">
<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'"
decoration-warning="routing_tag == 'special'"/>
<field name="time_cycle_manual" attrs="{'readonly': [('is_auto', '=', True)]}"/>
<field name="is_auto" invisible="1"/>
<field name="production_id" invisible="1"/>
<button name="unlink_technology_design" confirm="是否确认删除?" class="oe_highlight"
attrs="{'invisible': [('is_auto', '=', True)]}" type="object"
string="删除"></button>
</tree>
</field>
</page>
</xpath>
</field>
</record>

View File

@@ -16,6 +16,7 @@
</field>
<field name="bom_product_template_attribute_value_ids" position="after">
<field name="routing_type" required="1"/>
<field name="routing_tag" required="1" string="工序标签"/>
<field name="is_repeat"/>
<field name="reserved_duration"/>
</field>

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>

View File

@@ -208,7 +208,8 @@ class RePurchaseOrder(models.Model):
compute='_compute_user_id',
store=True)
purchase_type = fields.Selection([('standard', '标准采购'), ('consignment', '委外加工')], string='采购类型', default='standard')
purchase_type = fields.Selection([('standard', '标准采购'), ('consignment', '委外加工')], string='采购类型',
default='standard')
@api.depends('partner_id')
def _compute_user_id(self):
@@ -273,6 +274,7 @@ class RePurchaseOrder(models.Model):
'partner_id': server_template.seller_ids.partner_id.id,
'origin': ','.join(production_process),
'state': 'draft',
'purchase_type': 'consignment',
'order_line': server_product_process})
# self.env.cr.commit()

View File

@@ -74,7 +74,7 @@
<!-- <field name="process_id"/>-->
<field name="parameter_ids" widget="many2many_tags" string="表面工艺参数"
options="{'no_create': True}"/>
<field name="machining_precision" required="1"/>
<!-- <field name="machining_precision" required="1"/>-->
<field name="processing_time"/>
<field name="quantity" options="{'format': false}"/>
<field name="unit_price"/>