解决冲突

This commit is contained in:
胡尧
2024-11-11 16:32:54 +08:00
33 changed files with 392 additions and 250 deletions

View File

@@ -203,7 +203,7 @@
<record id="quality_alert_action_check" model="ir.actions.act_window"> <record id="quality_alert_action_check" model="ir.actions.act_window">
<field name="name">Quality Alerts</field> <field name="name">Quality Alerts</field>
<field name="res_model">quality.alert</field> <field name="res_model">quality.alert</field>
<field name="view_mode">kanban,tree,form,pivot,graph,calendar</field> <field name="view_mode">tree,kanban,form,pivot,graph,calendar</field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
Create a new quality alert Create a new quality alert

View File

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

View File

@@ -14,6 +14,7 @@
.img-fluid { .img-fluid {
max-width: unset !important; max-width: unset !important;
width: 40px;
} }
.o_inner_group .img-fluid { .o_inner_group .img-fluid {

View File

@@ -2,6 +2,7 @@
<odoo> <odoo>
<data> <data>
<record id="mrp.product_template_action" model="ir.actions.act_window"> <record id="mrp.product_template_action" model="ir.actions.act_window">
<field name="view_mode">tree,kanban,form,activity</field>
<field name="context"> <field name="context">
{"search_default_categ_id":1,"search_default_consumable": 1, 'default_detailed_type': 'product'} {"search_default_categ_id":1,"search_default_consumable": 1, 'default_detailed_type': 'product'}
</field> </field>
@@ -15,6 +16,7 @@
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/> <field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name='is_bfm' invisible="1"/> <field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/> <field name='categ_type' invisible="1"/>
<field name='part_name' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/> <field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/> <field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name="upload_model_file" <field name="upload_model_file"

View File

@@ -689,6 +689,8 @@ class SfMaintenanceEquipment(models.Model):
if next_date < date_now: if next_date < date_now:
next_date = date_now next_date = date_now
else: else:
if not equipment.initial_action_date:
raise ValidationError('重置保养日期不能为空!!!')
next_date = equipment.initial_action_date + timedelta(days=equipment.period) next_date = equipment.initial_action_date + timedelta(days=equipment.period)
equipment.next_action_date = next_date equipment.next_action_date = next_date
else: else:
@@ -735,6 +737,8 @@ class SfMaintenanceEquipment(models.Model):
if next_date < date_now: if next_date < date_now:
next_date = date_now next_date = date_now
else: else:
if not equipment.initial_overhaul_date:
raise ValidationError('重置维修日期不能为空')
next_date = equipment.initial_overhaul_date + timedelta(days=equipment.overhaul_period) next_date = equipment.initial_overhaul_date + timedelta(days=equipment.overhaul_period)
equipment.overhaul_date = next_date equipment.overhaul_date = next_date
else: else:

View File

@@ -21,6 +21,7 @@
'wizard/workpiece_delivery_views.xml', 'wizard/workpiece_delivery_views.xml',
'wizard/rework_wizard_views.xml', 'wizard/rework_wizard_views.xml',
'wizard/production_wizard_views.xml', 'wizard/production_wizard_views.xml',
'wizard/production_technology_wizard_views.xml',
'views/mrp_views_menus.xml', 'views/mrp_views_menus.xml',
'views/agv_scheduling_views.xml', 'views/agv_scheduling_views.xml',
'views/stock_lot_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_setting
from . import agv_scheduling from . import agv_scheduling
from . import res_config_setting 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', route_workcenter_id = fields.Many2one('mrp.routing.workcenter',
domain=[('routing_type', 'in', ['装夹预调', 'CNC加工', '解除装夹'])]) domain=[('routing_type', 'in', ['装夹预调', 'CNC加工', '解除装夹'])])
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat') 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') 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') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
product_model_type_id = fields.Many2one('sf.model.type') product_model_type_id = fields.Many2one('sf.model.type')
@@ -57,24 +40,7 @@ class EmbryoModelTypeRoutingSort(models.Model):
sequence = fields.Integer('Sequence') sequence = fields.Integer('Sequence')
route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['切割'])]) route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['切割'])])
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat') 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') 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') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
embryo_model_type_id = fields.Many2one('sf.model.type') embryo_model_type_id = fields.Many2one('sf.model.type')
@@ -90,24 +56,7 @@ class SurfaceTechnicsModelTypeRoutingSort(models.Model):
sequence = fields.Integer('Sequence') sequence = fields.Integer('Sequence')
route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['表面工艺'])]) route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['表面工艺'])])
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat') 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') 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') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
surface_technics_model_type_id = fields.Many2one('sf.model.type') surface_technics_model_type_id = fields.Many2one('sf.model.type')

View File

@@ -98,6 +98,7 @@ class MrpProduction(models.Model):
# ]) # ])
state = fields.Selection([ state = fields.Selection([
('draft', '草稿'), ('draft', '草稿'),
('technology_to_confirmed', '待工艺确认'),
('confirmed', '待排程'), ('confirmed', '待排程'),
('pending_cam', '待加工'), ('pending_cam', '待加工'),
('progress', '加工中'), ('progress', '加工中'),
@@ -148,6 +149,8 @@ class MrpProduction(models.Model):
quality_standard = fields.Binary('质检标准', related='product_id.quality_standard', readonly=True) quality_standard = fields.Binary('质检标准', related='product_id.quality_standard', readonly=True)
part_name = fields.Char(string='零件名称', related='product_id.part_name', readonly=True)
@api.depends('product_id.manual_quotation') @api.depends('product_id.manual_quotation')
def _compute_manual_quotation(self): def _compute_manual_quotation(self):
for item in self: for item in self:
@@ -158,6 +161,7 @@ class MrpProduction(models.Model):
is_remanufacture = fields.Boolean('是否重新制造', default=False) is_remanufacture = fields.Boolean('是否重新制造', default=False)
remanufacture_count = fields.Integer("重新制造订单数量", compute='_compute_remanufacture_production_ids') remanufacture_count = fields.Integer("重新制造订单数量", compute='_compute_remanufacture_production_ids')
remanufacture_production_id = fields.Many2one('mrp.production', string='') remanufacture_production_id = fields.Many2one('mrp.production', string='')
technology_design_ids = fields.One2many('sf.technology.design', 'production_id', string='工艺设计')
@api.depends('remanufacture_production_id') @api.depends('remanufacture_production_id')
def _compute_remanufacture_production_ids(self): def _compute_remanufacture_production_ids(self):
@@ -214,8 +218,9 @@ class MrpProduction(models.Model):
precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding) precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding)
for move in production.move_raw_ids if move.product_id): for move in production.move_raw_ids if move.product_id):
production.state = 'progress' production.state = 'progress'
elif not production.technology_design_ids:
# # 新添加的状态逻辑 production.state = 'technology_to_confirmed'
# 新添加的状态逻辑
if ( if (
production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排': production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排':
production.state = 'confirmed' production.state = 'confirmed'
@@ -252,6 +257,59 @@ class MrpProduction(models.Model):
if production.tool_state == '2': if production.tool_state == '2':
production.state = 'rework' 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): def action_check(self):
""" """
审核启用 审核启用
@@ -490,73 +548,33 @@ class MrpProduction(models.Model):
'state': 'pending', 'state': 'pending',
}] }]
if production.product_id.categ_id.type == '成品': if production.product_id.categ_id.type == '成品':
# # 根据加工面板的面数及对应的工序模板生成工单 # # 根据工序设计生成工单
i = 0 for route in item.technology_design_ids:
processing_panel_len = len(production.product_id.model_processing_panel.split(',')) if route.route_id.routing_type not in ['表面工艺']:
for k in (production.product_id.model_processing_panel.split(',')): workorders_values.append(
product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search( self.env['mrp.workorder'].json_workorder_str(production, route))
[('product_model_type_id', '=', production.product_id.product_model_type_id.id)], else:
order='sequence asc' product_production_process = self.env['product.template'].search(
) [('server_product_process_parameters_id', '=', route.process_parameters_id.id)])
i += 1 # if product_production_process:
for route in product_routing_workcenter: # route_production_process = self.env[
if route.is_repeat is True: # 'mrp.routing.workcenter'].search(
workorders_values.append( # [('surface_technics_id', '=', p.id),
self.env['mrp.workorder'].json_workorder_str(k, production, route, item)) # ('id', 'in', route_workcenter_arr)])
# if i == processing_panel_len and route.routing_type == '解除装夹': # if route_production_process:
# workorders_values.append( workorders_values.append(
# self.env['mrp.workorder'].json_workorder_str(k, production, route)) self.env[
# 表面工艺工序 'mrp.workorder']._json_workorder_surface_process_str(
# 获取表面工艺id production, route, product_production_process.seller_ids[0].partner_id.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))
elif production.product_id.categ_id.type == '坯料': elif production.product_id.categ_id.type == '坯料':
embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
[('embryo_model_type_id', '=', production.product_id.embryo_model_type_id.id)], [('embryo_model_type_id', '=', production.product_id.embryo_model_type_id.id)],
order='sequence asc' order='sequence asc'
) )
for route in embryo_routing_workcenter: for route_embryo in embryo_routing_workcenter:
workorders_values.append( 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 production.workorder_ids = workorders_values
# for production_item in productions:
process_parameter_workorder = self.env['mrp.workorder'].search( process_parameter_workorder = self.env['mrp.workorder'].search(
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id), [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
('is_subcontract', '=', True)]) ('is_subcontract', '=', True)])
@@ -838,6 +856,7 @@ class MrpProduction(models.Model):
backorders = backorders - productions_to_backorder backorders = backorders - productions_to_backorder
productions_not_to_backorder._post_inventory(cancel_backorder=True) productions_not_to_backorder._post_inventory(cancel_backorder=True)
# 查出最后一张工单完成入库操作
# if self.workorder_ids.filtered(lambda w: w.routing_type in ['表面工艺']): # if self.workorder_ids.filtered(lambda w: w.routing_type in ['表面工艺']):
# move_finish = self.env['stock.move'].search([('created_production_id', '=', self.id)]) # move_finish = self.env['stock.move'].search([('created_production_id', '=', self.id)])
# if move_finish: # if move_finish:
@@ -1229,10 +1248,6 @@ class sf_detection_result(models.Model):
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'res_id': self.id, 'res_id': self.id,
'views': [(self.env.ref('sf_manufacturing.sf_test_report_form').id, 'form')], 'views': [(self.env.ref('sf_manufacturing.sf_test_report_form').id, 'form')],
# 'view_mode': 'form',
# 'context': {
# 'default_id': self.id
# },
'target': 'new' 'target': 'new'
} }

View File

@@ -7,21 +7,23 @@ class ResMrpRoutingWorkcenter(models.Model):
_inherit = 'mrp.routing.workcenter' _inherit = 'mrp.routing.workcenter'
routing_type = fields.Selection([ routing_type = fields.Selection([
# ('获取CNC加工程序', '获取CNC加工程序'),
('装夹预调', '装夹预调'), ('装夹预调', '装夹预调'),
# ('前置三元定位检测', '前置三元定位检测'),
('CNC加工', 'CNC加工'), ('CNC加工', 'CNC加工'),
# ('后置三元质量检测', '后置三元质量检测'),
('解除装夹', '解除装夹'), ('解除装夹', '解除装夹'),
('切割', '切割'), ('切割', '切割'),
('表面工艺', '表面工艺') ('表面工艺', '表面工艺')
], string="工序类型") ], string="工序类型")
routing_tag = fields.Selection([
('standard', '标准'),
('special', '特殊')
], string="标签")
is_repeat = fields.Boolean('重复', default=False) is_repeat = fields.Boolean('重复', default=False)
workcenter_id = fields.Many2one('mrp.workcenter', required=False) workcenter_id = fields.Many2one('mrp.workcenter', required=False)
workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True) workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True)
bom_id = fields.Many2one('mrp.bom', required=False) bom_id = fields.Many2one('mrp.bom', required=False)
surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺") surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺")
reserved_duration = fields.Float('预留时长', default=30, tracking=True) reserved_duration = fields.Float('预留时长', default=30, tracking=True)
def get_no(self): def get_no(self):
international_standards = self.search( international_standards = self.search(
[('code', '!=', ''), ('active', 'in', [True, False])], [('code', '!=', ''), ('active', 'in', [True, False])],
@@ -78,3 +80,13 @@ class ResMrpRoutingWorkcenter(models.Model):
else: else:
workcenter_id = workcenter_ids[0] workcenter_id = workcenter_ids[0]
return workcenter_id 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

@@ -228,6 +228,7 @@ class ResMrpWorkOrder(models.Model):
part_number = fields.Char(related='production_id.part_number', string='零件图号') part_number = fields.Char(related='production_id.part_number', string='零件图号')
machining_drawings = fields.Binary('2D加工图纸', related='production_id.part_drawing', readonly=True) machining_drawings = fields.Binary('2D加工图纸', related='production_id.part_drawing', readonly=True)
quality_standard = fields.Binary('质检标准', related='production_id.quality_standard', readonly=True) quality_standard = fields.Binary('质检标准', related='production_id.quality_standard', readonly=True)
part_name = fields.Char(related='production_id.part_name', string='零件名称')
# 工序状态 # 工序状态
process_state = fields.Selection([ process_state = fields.Selection([
@@ -669,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 # 计算预计时长duration_expected
routing_types = ['切割', '装夹预调', 'CNC加工', '解除装夹'] 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( 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 duration_expected = routing_workcenter.time_cycle
reserved_duration = routing_workcenter.reserved_duration 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: else:
duration_expected = 60 duration_expected = 60
reserved_duration = 30 reserved_duration = 30
@@ -705,26 +685,19 @@ class ResMrpWorkOrder(models.Model):
'product_uom_id': production.product_uom_id.id, 'product_uom_id': production.product_uom_id.id,
'qty_producing': 0, 'qty_producing': 0,
'operation_id': False, 'operation_id': False,
'name': route.route_workcenter_id.name, 'name': route.route_id.name,
'processing_panel': k, 'processing_panel': route.panel,
'quality_point_ids': route.route_workcenter_id.quality_point_ids, 'quality_point_ids': route.route_id.quality_point_ids,
'routing_type': route.routing_type, 'routing_type': route.route_id.routing_type,
# 'work_state': '待发起', 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.route_id.workcenter_ids.ids,
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids, route.route_id.routing_type,
route.routing_type,
production.product_id), production.product_id),
# 设定初始化值避免出现变成bool问题 # 设定初始化值避免出现变成bool问题
'date_planned_start': datetime.now(), 'date_planned_start': datetime.now(),
'date_planned_finished': datetime.now() + timedelta(days=1), 'date_planned_finished': datetime.now() + timedelta(days=1),
'duration_expected': duration_expected, 'duration_expected': duration_expected,
'duration': 0, 'duration': 0,
'tag_type': '重新加工' if item is False else False, # '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)
'reserved_duration': reserved_duration, 'reserved_duration': reserved_duration,
}] }]
return workorders_values_str return workorders_values_str
@@ -755,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, '', { workorders_values_str = [0, '', {
'product_uom_id': production.product_uom_id.id, 'product_uom_id': production.product_uom_id.id,
'qty_producing': 0, 'qty_producing': 0,
'operation_id': False, 'operation_id': False,
'name': '%s-%s' % (route.name, process_parameter.name), 'name': route.process_parameters_id.display_name,
'processing_panel': '', 'processing_panel': '',
'routing_type': '表面工艺', 'routing_type': '表面工艺',
'surface_technics_parameters_id': process_parameter.id, 'surface_technics_parameters_id': route.process_parameters_id.id,
'work_state': '', 'work_state': '',
'supplier_id': supplier_id, '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[ 'workcenter_id': self.env[
'mrp.workcenter'].get_process_outsourcing_workcenter() if process_parameter.gain_way == '外协' else 'mrp.workcenter'].get_process_outsourcing_workcenter() if route.process_parameters_id.gain_way == '外协' else
self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids, self.env['mrp.routing.workcenter'].get_workcenter(route.route_id.workcenter_ids.ids,
route.routing_type, route.route_id.routing_type,
production.product_id), production.product_id),
'date_planned_start': datetime.now(), 'date_planned_start': datetime.now(),
'date_planned_finished': datetime.now() + timedelta(days=1), 'date_planned_finished': datetime.now() + timedelta(days=1),
@@ -1068,37 +1041,6 @@ class ResMrpWorkOrder(models.Model):
workorder.state = 'waiting' workorder.state = 'waiting'
continue 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): def button_start(self):
if self.routing_type == 'CNC加工': if self.routing_type == 'CNC加工':

View File

@@ -777,6 +777,7 @@ class ResProductMo(models.Model):
part_number = fields.Char(string='零件图号', readonly=True) part_number = fields.Char(string='零件图号', readonly=True)
machining_drawings = fields.Binary('2D加工图纸', readonly=True) machining_drawings = fields.Binary('2D加工图纸', readonly=True)
quality_standard = fields.Binary('质检标准', readonly=True) quality_standard = fields.Binary('质检标准', readonly=True)
part_name = fields.Char(string='零件名称', readonly=True)
@api.constrains('tool_length') @api.constrains('tool_length')
def _check_tool_length_size(self): def _check_tool_length_size(self):
@@ -884,6 +885,7 @@ class ResProductMo(models.Model):
'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode( 'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode(
item['machining_drawings']), item['machining_drawings']),
'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']), 'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']),
'part_name': item['part_name'],
} }
tax_id = self.env['account.tax'].sudo().search( tax_id = self.env['account.tax'].sudo().search(
[('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')]) [('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')])

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, 'product_id': production.product_id.id,
'state': 'draft', 'state': 'draft',
}) })
technology_design_values = []
all_production = productions all_production = productions
grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)} grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表 # 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -293,33 +294,31 @@ class StockRule(models.Model):
# 为同一个product_id创建一个生产订单名称列表 # 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in all_production] product_id_to_production_names[product_id] = [production.name for production in all_production]
for production_item in productions: for production_item in productions:
production_programming = self.env['mrp.production'].search( production_programming = self.env['mrp.production'].search(
[('product_id.id', '=', production_item.product_id.id), [('product_id.id', '=', production_item.product_id.id),
('origin', '=', production_item.origin)], ('origin', '=', production_item.origin)],
limit=1, order='id asc') limit=1, order='id asc')
if production_item.product_id.id in product_id_to_production_names: 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:
if production_item.product_id.model_process_parameters_ids: is_purchase = False
is_purchase = False sorted_process_parameters = sorted(production_item.product_id.model_process_parameters_ids,
sorted_process_parameters = sorted(production_item.product_id.model_process_parameters_ids, key=lambda w: w.id)
key=lambda w: w.id)
consecutive_process_parameters = [] consecutive_process_parameters = []
m = 0 m = 0
for i in range(len(sorted_process_parameters) - 1): for i in range(len(sorted_process_parameters) - 1):
if m == 0: if m == 0:
is_purchase = False is_purchase = False
if self.env['product.template']._get_process_parameters_product( if self.env['product.template']._get_process_parameters_product(
sorted_process_parameters[i]).partner_id == self.env[ sorted_process_parameters[i]).partner_id == self.env[
'product.template']._get_process_parameters_product(sorted_process_parameters[ 'product.template']._get_process_parameters_product(sorted_process_parameters[
i + 1]).partner_id and \ i + 1]).partner_id and \
sorted_process_parameters[i].gain_way == '外协': sorted_process_parameters[i].gain_way == '外协':
if sorted_process_parameters[i] not in consecutive_process_parameters: 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])
consecutive_process_parameters.append(sorted_process_parameters[i + 1]) consecutive_process_parameters.append(sorted_process_parameters[i + 1])
m += 1 m += 1
continue continue
else: else:
if m == len(consecutive_process_parameters) - 1 and m != 0: if m == len(consecutive_process_parameters) - 1 and m != 0:
self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
@@ -329,7 +328,7 @@ class StockRule(models.Model):
is_purchase = True is_purchase = True
consecutive_process_parameters = [] consecutive_process_parameters = []
m = 0 m = 0
# 当前面的连续外协采购单生成再生成当前外协采购单 # 当前面的连续外协采购单生成再生成当前外协采购单
if is_purchase is False: if is_purchase is False:
self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, self.env['purchase.order'].get_purchase_order(consecutive_process_parameters,
production_item, production_item,
@@ -355,16 +354,70 @@ class StockRule(models.Model):
self.env['purchase.order'].get_purchase_order(sorted_process_parameters[i], self.env['purchase.order'].get_purchase_order(sorted_process_parameters[i],
production_item, production_item,
product_id_to_production_names) product_id_to_production_names)
# # 同一个产品多个制造订单对应一个编程单和模型库 if not technology_design_values:
# # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递 if production.product_id.categ_id.type == '成品':
if not production_item.programming_no: production.product_id.model_processing_panel = 'ZM,FM'
if not production_programming.programming_no: # 根据加工面板的面数及成品工序模板生成工序设计
production_item.fetchCNC( i = 0
', '.join(product_id_to_production_names[production_item.product_id.id])) for k in (production.product_id.model_processing_panel.split(',')):
else: product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
production_item.write({'programming_no': production_programming.programming_no, [('product_model_type_id', '=', production.product_id.product_model_type_id.id)],
'programming_state': '编程中'}) order='sequence asc'
return True )
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): class ProductionLot(models.Model):
@@ -554,7 +607,9 @@ class StockPicking(models.Model):
retrospect_ref = fields.Char('追溯参考', compute='_compute_move_ids', store=True) 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): def _compute_move_ids(self):
for item in self: for item in self:
if item.move_ids: if item.move_ids:
@@ -574,13 +629,14 @@ class StockPicking(models.Model):
default_codes = '' default_codes = ''
if boms: if boms:
for bom in boms: for bom in boms:
code = bom.product_tmpl_id.default_code.split('-')[-1] if bom.product_tmpl_id.default_code:
default_code = bom.product_tmpl_id.default_code.split(f'-{code}')[0] code = bom.product_tmpl_id.default_code.split('-')[-1]
if default_code not in default_codes: default_code = bom.product_tmpl_id.default_code.split(f'-{code}')[0]
if default_codes == '': if default_code not in default_codes:
default_codes = default_code if default_codes == '':
else: default_codes = default_code
default_codes = default_codes + ',' + default_code else:
default_codes = default_codes + ',' + default_code
item.retrospect_ref = default_codes item.retrospect_ref = default_codes
elif item.picking_type_id.sequence_code in ['INT', 'PC']: elif item.picking_type_id.sequence_code in ['INT', 'PC']:
pass pass

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_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_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 name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done -->
<!-- </attribute> --> <!-- </attribute> -->
<attribute name="statusbar_visible"> <attribute name="statusbar_visible">
confirmed,pending_cam,progress,rework,scrap,done technology_to_confirmed,confirmed,pending_cam,progress,rework,scrap,done
</attribute> </attribute>
</xpath> </xpath>
<xpath expr="//sheet//group//group[2]//label" position="before"> <xpath expr="//sheet//group//group[2]//label" position="before">
@@ -115,12 +115,18 @@
string="验证" type="object" class="oe_highlight" string="验证" type="object" class="oe_highlight"
confirm="There are no components to consume. Are you still sure you want to continue?" 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"/> 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>
<xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace"> <xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace">
<button name="button_mark_done" <button name="button_mark_done"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}" attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}"
string="验证" type="object" data-hotkey="g" string="验证" type="object" data-hotkey="g"
groups="sf_base.group_sf_mrp_user"/> 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>
<xpath expr="(//header//button[@name='button_scrap'])" position="replace"> <xpath expr="(//header//button[@name='button_scrap'])" position="replace">
<button name="button_scrap" invisible="1"/> <button name="button_scrap" invisible="1"/>
@@ -338,6 +344,27 @@
<page string="质检标准"> <page string="质检标准">
<field name="quality_standard" widget="adaptive_viewer"/> <field name="quality_standard" widget="adaptive_viewer"/>
</page> </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> </xpath>
</field> </field>
</record> </record>

View File

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

View File

@@ -281,6 +281,7 @@
<label for="material_height" string="高"/> <label for="material_height" string="高"/>
<field name="material_height" class="o_address_zip"/> <field name="material_height" class="o_address_zip"/>
</div> </div>
<field name="part_name"/>
<field name="part_number" string="成品的零件图号"/> <field name="part_number" string="成品的零件图号"/>
</xpath> </xpath>
<xpath expr="//label[1]" position="attributes"> <xpath expr="//label[1]" position="attributes">

View File

@@ -18,10 +18,13 @@
<field name="inherit_id" ref="stock.view_picking_form"/> <field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='user_id']" position="after"> <xpath expr="//field[@name='user_id']" position="after">
<field name="retrospect_ref"/> <field name="picking_type_sequence_code" invisible="1"/>
<field name="person_of_delivery"/> <field name="retrospect_ref"
<field name="telephone_of_delivery"/> attrs="{'invisible':[('picking_type_sequence_code','not in',['DL', 'INT', 'PC'])]}"/>
<field name="address_of_delivery"/> <field name="person_of_delivery" attrs="{'invisible':[('picking_type_sequence_code','!=','DL')]}"/>
<field name="telephone_of_delivery"
attrs="{'invisible':[('picking_type_sequence_code','!=','DL')]}"/>
<field name="address_of_delivery" attrs="{'invisible':[('picking_type_sequence_code','!=','DL')]}"/>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -1,3 +1,4 @@
from . import workpiece_delivery_wizard from . import workpiece_delivery_wizard
from . import rework_wizard from . import rework_wizard
from . import production_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

@@ -90,7 +90,7 @@
<group string="加工信息"> <group string="加工信息">
<field name="date_planned_start" placeholder="如果不选择计划开始时间,会取当前时间来做排程" required="1"/> <field name="date_planned_start" placeholder="如果不选择计划开始时间,会取当前时间来做排程" required="1"/>
<field name="date_planned_finished" required="1"/> <field name="date_planned_finished" required="0" invisible="1"/>
<field name="actual_process_time"/> <field name="actual_process_time"/>
<field name="actual_start_time"/> <field name="actual_start_time"/>
<field name="actual_end_time"/> <field name="actual_end_time"/>

View File

@@ -33,6 +33,7 @@ class SfQualityCncTest(models.Model):
machining_drawings = fields.Binary('2D加工图纸', related='workorder_id.machining_drawings', readonly=True) machining_drawings = fields.Binary('2D加工图纸', related='workorder_id.machining_drawings', readonly=True)
quality_standard = fields.Binary('质检标准', related='workorder_id.quality_standard', readonly=True) quality_standard = fields.Binary('质检标准', related='workorder_id.quality_standard', readonly=True)
part_name = fields.Char(related='workorder_id.part_name', string='零件名称')
def submit_pass(self): def submit_pass(self):
if self.test_results in ['返工', '报废']: if self.test_results in ['返工', '报废']:

View File

@@ -89,6 +89,7 @@
<field name="model_file" widget="Viewer3D"/> <field name="model_file" widget="Viewer3D"/>
</group> </group>
<group> <group>
<field name="part_name"/>
<field name="part_number"/> <field name="part_number"/>
<field name="processing_panel"/> <field name="processing_panel"/>
</group> </group>
@@ -174,8 +175,8 @@
<field name="name">驾驶舱</field> <field name="name">驾驶舱</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">quality.cnc.test</field> <field name="res_model">quality.cnc.test</field>
<field name="view_mode">kanban,tree,form</field> <field name="view_mode">tree,kanban,form</field>
<field name="view_id" ref="quality_cnc_test_view_kanban"/> <field name="view_id" ref="quality_cnc_test_view_tree"/>
<field name="search_view_id" ref="quality_cnc_test_search"/> <field name="search_view_id" ref="quality_cnc_test_search"/>
<field name="domain">[]</field> <field name="domain">[]</field>
<field name="context">{ 'search_default_filter_waiting':1}</field> <field name="context">{ 'search_default_filter_waiting':1}</field>

View File

@@ -26,7 +26,7 @@
<record id="quality_control.quality_alert_action_check" model="ir.actions.act_window"> <record id="quality_control.quality_alert_action_check" model="ir.actions.act_window">
<field name="name">质量缺陷单</field> <field name="name">质量缺陷单</field>
<field name="res_model">quality.alert</field> <field name="res_model">quality.alert</field>
<field name="view_mode">kanban,tree,form,pivot,graph,calendar</field> <field name="view_mode">tree,kanban,form,pivot,graph,calendar</field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
Create a new quality alert Create a new quality alert

View File

@@ -228,6 +228,7 @@ class QuickEasyOrder(models.Model):
'quality_standard_mimetype': '', 'quality_standard_mimetype': '',
'machining_drawings': item.machining_drawings, 'machining_drawings': item.machining_drawings,
'quality_standard': '', 'quality_standard': '',
'part_name': '',
}) })
# res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list']) # res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list'])
product_id = self.env.ref('sf_dlm.product_template_sf').sudo() product_id = self.env.ref('sf_dlm.product_template_sf').sudo()

View File

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

View File

@@ -218,6 +218,7 @@
<field name="context"> <field name="context">
{"search_default_categ_id":1,"search_default_filter_to_purchase":1, "purchase_product_template": 1} {"search_default_categ_id":1,"search_default_filter_to_purchase":1, "purchase_product_template": 1}
</field> </field>
<field name="view_mode">tree,kanban,form,activity</field>
</record> </record>
</data> </data>
</odoo> </odoo>

View File

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

View File

@@ -95,7 +95,7 @@
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute> <attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
</field> </field>
<field name="payment_term_id" position="after"> <field name="payment_term_id" position="after">
<field name="deadline_of_delivery" readonly="0"/> <field name="deadline_of_delivery" readonly="0"/>
<field name="payments_way" invisible="1"/> <field name="payments_way" invisible="1"/>
<field name="pay_way" invisible="1"/> <field name="pay_way" invisible="1"/>
<!-- <field name="schedule_status" readonly="1"/> --> <!-- <field name="schedule_status" readonly="1"/> -->
@@ -283,6 +283,8 @@
</field> </field>
</record> </record>
<record id="sale.product_template_action" model="ir.actions.act_window"> <record id="sale.product_template_action" model="ir.actions.act_window">
<field name="view_mode">tree,kanban,form,activity</field>
<field name="view_id" ref="product.product_template_tree_view"/>
<field name="context">{"search_default_categ_id":1, <field name="context">{"search_default_categ_id":1,
"search_default_filter_to_sell":1,"sale_multi_pricelist_product_template": 1} "search_default_filter_to_sell":1,"sale_multi_pricelist_product_template": 1}
</field> </field>

View File

@@ -2,6 +2,7 @@
<odoo> <odoo>
<data> <data>
<record id="stock.product_template_action_product" model="ir.actions.act_window"> <record id="stock.product_template_action_product" model="ir.actions.act_window">
<field name="view_mode">tree,kanban,form,activity</field>
<field name="context"> <field name="context">
{"search_default_categ_id":1,"search_default_consumable": 1, 'default_detailed_type': 'product'} {"search_default_categ_id":1,"search_default_consumable": 1, 'default_detailed_type': 'product'}
</field> </field>