diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 985b87a4..39da4482 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -19,6 +19,7 @@ 'security/ir.model.access.csv', 'wizard/workpiece_delivery_views.xml', 'wizard/rework_wizard_views.xml', + 'wizard/production_wizard_views.xml', 'views/mrp_views_menus.xml', 'views/stock_lot_views.xml', 'views/mrp_production_addional_change.xml', diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 8eca7387..a39b58eb 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -83,7 +83,7 @@ class MrpProduction(models.Model): part_drawing = fields.Binary('零件图纸') manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) - rework_production = fields.Many2one('mrp.production', string='返工的制造订单') + is_scrap = fields.Boolean('是否报废', default=False) @api.depends( 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', @@ -136,7 +136,8 @@ class MrpProduction(models.Model): # production.state = 'done' if any( ( - wo.test_results == '返工' and wo.state == 'done' and production.programming_state == '已编程') or ( + wo.test_results == '返工' and wo.state == 'done' and production.programming_state in [ + '已编程', '已下发']) or ( wo.state == 'rework' and production.programming_state == '编程中') or ( wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中', '已编程']) @@ -203,7 +204,7 @@ class MrpProduction(models.Model): production.write({'programming_state': '已编程未下发' if item[ 'programming_state'] == '已编程' else '编程中'}) else: - return item['programming_state'] + return item else: raise UserError(ret['message']) @@ -213,7 +214,8 @@ class MrpProduction(models.Model): # 编程单更新 def update_programming_state(self): try: - res = {'programming_no': self.programming_no, 'manufacturing_type': 'rework'} + res = {'programming_no': self.programming_no, + 'manufacturing_type': 'rework' if self.is_scrap is False else 'scrap'} logging.info('res=%s:' % res) configsettings = self.env['res.config.settings'].get_values() config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key']) @@ -488,28 +490,6 @@ class MrpProduction(models.Model): for workorder in production.workorder_ids: workorder.duration_expected = workorder._get_duration_expected() - # 在之前的销售单上重新生成制造订单 - def create_production1_values(self, production): - production_values_str = {'origin': production.origin, - 'product_id': production.product_id.id, - 'product_description_variants': production.product_description_variants, - 'product_qty': production.product_qty, - 'product_uom_id': production.product_uom_id.id, - 'location_src_id': production.location_src_id.id, - 'location_dest_id': production.location_dest_id.id, - 'bom_id': production.bom_id.id, - 'date_deadline': production.date_deadline, - 'date_planned_start': production.date_planned_start, - 'date_planned_finished': production.date_planned_finished, - 'procurement_group_id': False, - 'propagate_cancel': production.propagate_cancel, - 'orderpoint_id': production.orderpoint_id.id, - 'picking_type_id': production.picking_type_id.id, - 'company_id': production.company_id.id, - 'move_dest_ids': production.move_dest_ids.ids, - 'user_id': production.user_id.id} - return production_values_str - # 工单排序 def _reset_work_order_sequence1(self, k): for rec in self: @@ -765,10 +745,13 @@ class MrpProduction(models.Model): # 返工 def button_rework(self): - cloud_programming_state = None - if self.programming_state != '已编程' and self.reprogramming_num >= 1: - cloud_programming_state = self._cron_get_programming_state() - logging.info('cloud_programming_state:%s' % cloud_programming_state) + + cloud_programming = None + if self.programming_state == '已编程' and self.reprogramming_num >= 0: + cloud_programming = self._cron_get_programming_state() + if self.reprogramming_num == 0: + self.reprogramming_num = cloud_programming['reprogramming_num'] + logging.info('cloud_programming_state:%s' % cloud_programming['programming_state']) logging.info('programming_state:%s' % self.programming_state) return { 'name': _('返工'), @@ -778,20 +761,18 @@ class MrpProduction(models.Model): 'target': 'new', 'context': { 'default_production_id': self.id, - 'default_product_id': self.product_id.id, - 'default_programming_state': self.programming_state if cloud_programming_state is not None else cloud_programming_state, - 'default_is_reprogramming': False if (cloud_programming_state in ['编程中', - '待编程'] and self.programming_state in [ + 'default_reprogramming_num': self.reprogramming_num, + 'default_programming_state': self.programming_state if cloud_programming[ + 'programming_state'] is None else + cloud_programming['programming_state'], + 'default_is_reprogramming': False if (cloud_programming['programming_state'] in ['编程中', + '待编程'] and self.programming_state in [ '编程中']) - or (cloud_programming_state in [ + or (cloud_programming['programming_state'] in [ '已编程'] and self.programming_state in ['已编程未下发']) else True } } - # 报废 - def button_scrap_new(self): - return True - # 更新程序 def do_update_program(self): program_production = self @@ -815,11 +796,13 @@ class MrpProduction(models.Model): if production.programming_no in program_to_production_names: rework_workorder = production.workorder_ids.filtered(lambda m: m.state == 'rework') if rework_workorder: - new_pancel_workorder = production.workorder_ids.filtered( - lambda m1: m1.state != 'rework' and m1.processing_panel == rework_workorder[0].processing_panel) - if not new_pancel_workorder.cnc_ids: - production.get_new_program(rework_workorder[0].processing_panel) - production.write({'state': 'progress', 'programming_state': '已下发'}) + for rework_item in rework_workorder: + pending_workorder = production.workorder_ids.filtered( + lambda m1: m1.state in [ + 'pending'] and m1.processing_panel == rework_item.processing_panel and m1.routing_type == 'CNC加工') + if not pending_workorder.cnc_ids: + production.get_new_program(rework_item.processing_panel) + production.write({'state': 'progress', 'programming_state': '已编程'}) # 从cloud获取重新编程过的最新程序 def get_new_program(self, processing_panel): @@ -881,6 +864,134 @@ class MrpProduction(models.Model): logging.info('get_new_program error:%s' % e) raise UserError("从云平台获取最新程序失败,请联系管理员") + def recreateManufacturing(self): + """ + 重新生成制造订单 + """ + if self.is_scrap is True: + sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)]) + values = self.env['mrp.production'].create_production1_values(self.production_id) + productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company( + self.production_id.company_id).create( + values) + # self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) + self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) + productions._create_workorder() + productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ + ( + p.move_dest_ids.procure_method != 'make_to_order' and + not p.move_raw_ids and not p.workorder_ids)).action_confirm() + for production_item in productions: + process_parameter_workorder = self.env['mrp.workorder'].search( + [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_item.id), + ('is_subcontract', '=', True)]) + if process_parameter_workorder: + is_pick = False + consecutive_workorders = [] + m = 0 + sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id) + for i in range(len(sorted_workorders) - 1): + if m == 0: + is_pick = False + if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \ + sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \ + sorted_workorders[i].id == sorted_workorders[i + 1].id - 1: + if sorted_workorders[i] not in consecutive_workorders: + consecutive_workorders.append(sorted_workorders[i]) + consecutive_workorders.append(sorted_workorders[i + 1]) + m += 1 + continue + else: + if m == len(consecutive_workorders) - 1 and m != 0: + self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, + production_item) + if sorted_workorders[i] in consecutive_workorders: + is_pick = True + consecutive_workorders = [] + m = 0 + # 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单 + if is_pick is False: + self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], + production_item) + if m == len(consecutive_workorders) - 1 and m != 0: + self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, + production_item) + if sorted_workorders[i] in consecutive_workorders: + is_pick = True + consecutive_workorders = [] + m = 0 + if m == len(consecutive_workorders) - 1 and m != 0: + self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item) + if is_pick is False and m == 0: + if len(sorted_workorders) == 1: + self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item) + else: + self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item) + + for production in productions: + origin_production = production.move_dest_ids and production.move_dest_ids[ + 0].raw_material_production_id or False + orderpoint = production.orderpoint_id + if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual': + production.message_post( + body=_('This production order has been created from Replenishment Report.'), + message_type='comment', + subtype_xmlid='mail.mt_note') + elif orderpoint: + production.message_post_with_view( + 'mail.message_origin_link', + values={'self': production, 'origin': orderpoint}, + subtype_id=self.env.ref('mail.mt_note').id) + elif origin_production: + production.message_post_with_view( + 'mail.message_origin_link', + values={'self': production, 'origin': origin_production}, + subtype_id=self.env.ref('mail.mt_note').id) + + ''' + 创建生产计划 + ''' + # 工单耗时 + workorder_duration = 0 + for workorder in productions.workorder_ids: + workorder_duration += workorder.duration_expected + + if sale_order: + sale_order.mrp_production_ids |= productions + # sale_order.write({'schedule_status': 'to schedule'}) + self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({ + 'name': productions.name, + 'order_deadline': sale_order.deadline_of_delivery, + 'production_id': productions.id, + 'date_planned_start': productions.date_planned_start, + 'origin': productions.origin, + 'product_qty': productions.product_qty, + 'product_id': productions.product_id.id, + 'state': 'draft', + }) + + # 在之前的销售单上重新生成制造订单 + def create_production1_values(self, production, sale_order): + production_values_str = {'origin': production.origin, + 'product_id': production.product_id.id, + 'product_description_variants': production.product_description_variants, + 'product_qty': production.product_qty, + 'product_uom_id': production.product_uom_id.id, + 'location_src_id': production.location_src_id.id, + 'location_dest_id': production.location_dest_id.id, + 'bom_id': production.bom_id.id, + 'date_deadline': production.date_deadline, + 'date_planned_start': production.date_planned_start, + 'date_planned_finished': production.date_planned_finished, + 'procurement_group_id': sale_order.id, + 'propagate_cancel': production.propagate_cancel, + 'orderpoint_id': production.orderpoint_id.id, + 'picking_type_id': production.picking_type_id.id, + 'company_id': production.company_id.id, + 'move_dest_ids': production.move_dest_ids.ids, + 'user_id': production.user_id.id} + return production_values_str + class sf_detection_result(models.Model): _name = 'sf.detection.result' diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 692dde1a..599b729c 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -19,7 +19,7 @@ from odoo.addons.sf_mrs_connect.models.ftp_operate import FtpController class ResMrpWorkOrder(models.Model): _inherit = 'mrp.workorder' - _order = 'id' + _order = 'sequence asc' product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name') @@ -47,7 +47,18 @@ class ResMrpWorkOrder(models.Model): ('切割', '切割'), ('表面工艺', '表面工艺') ], string="工序类型") results = fields.Char('结果') - state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True) + state = fields.Selection([ + ('pending', '等待其他工单'), + ('waiting', '等待组件'), + ('ready', '就绪'), + ('progress', '进行中'), + ('to be detected', "待检测"), + ('done', '已完工'), + ('rework', '返工'), + ('cancel', '取消')], string='Status', + compute='_compute_state', store=True, + default='pending', copy=False, readonly=True, recursive=True, index=True, tracking=True) + # state = fields.Selection(selection_add=[('to be detected', "待检测"), ('rework', '返工')], tracking=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) @@ -474,6 +485,7 @@ class ResMrpWorkOrder(models.Model): 'context': { 'default_workorder_id': self.id, 'default_production_id': self.production_id.id, + # 'default_programming_state': self.production_id.programming_state, 'default_routing_type': self.routing_type }} @@ -684,119 +696,6 @@ class ResMrpWorkOrder(models.Model): # 'target':'new' # } - def recreateManufacturingOrWorkerOrder(self): - """ - 重新生成制造订单或者重新生成工单 - """ - if self.test_results in ['返工', '报废']: - values = self.env['mrp.production'].create_production1_values(self.production_id) - productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company( - self.production_id.company_id).create( - values) - # self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) - self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) - productions._create_workorder() - productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ - ( - p.move_dest_ids.procure_method != 'make_to_order' and - not p.move_raw_ids and not p.workorder_ids)).action_confirm() - for production_item in productions: - process_parameter_workorder = self.env['mrp.workorder'].search( - [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_item.id), - ('is_subcontract', '=', True)]) - if process_parameter_workorder: - is_pick = False - consecutive_workorders = [] - m = 0 - sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id) - for i in range(len(sorted_workorders) - 1): - if m == 0: - is_pick = False - if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \ - sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \ - sorted_workorders[i].id == sorted_workorders[i + 1].id - 1: - if sorted_workorders[i] not in consecutive_workorders: - consecutive_workorders.append(sorted_workorders[i]) - consecutive_workorders.append(sorted_workorders[i + 1]) - m += 1 - continue - else: - if m == len(consecutive_workorders) - 1 and m != 0: - self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, - production_item) - if sorted_workorders[i] in consecutive_workorders: - is_pick = True - consecutive_workorders = [] - m = 0 - # 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单 - if is_pick is False: - self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], - production_item) - if m == len(consecutive_workorders) - 1 and m != 0: - self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, - production_item) - if sorted_workorders[i] in consecutive_workorders: - is_pick = True - consecutive_workorders = [] - m = 0 - if m == len(consecutive_workorders) - 1 and m != 0: - self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item) - if is_pick is False and m == 0: - if len(sorted_workorders) == 1: - self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item) - else: - self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item) - - for production in productions: - origin_production = production.move_dest_ids and production.move_dest_ids[ - 0].raw_material_production_id or False - orderpoint = production.orderpoint_id - if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual': - production.message_post( - body=_('This production order has been created from Replenishment Report.'), - message_type='comment', - subtype_xmlid='mail.mt_note') - elif orderpoint: - production.message_post_with_view( - 'mail.message_origin_link', - values={'self': production, 'origin': orderpoint}, - subtype_id=self.env.ref('mail.mt_note').id) - elif origin_production: - production.message_post_with_view( - 'mail.message_origin_link', - values={'self': production, 'origin': origin_production}, - subtype_id=self.env.ref('mail.mt_note').id) - - ''' - 创建生产计划 - ''' - # 工单耗时 - workorder_duration = 0 - for workorder in productions.workorder_ids: - workorder_duration += workorder.duration_expected - - sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)]) - if sale_order: - sale_order.mrp_production_ids |= productions - # sale_order.write({'schedule_status': 'to schedule'}) - self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({ - 'name': productions.name, - 'order_deadline': sale_order.deadline_of_delivery, - 'production_id': productions.id, - 'date_planned_start': productions.date_planned_start, - 'origin': productions.origin, - 'product_qty': productions.product_qty, - 'product_id': productions.product_id.id, - 'state': 'draft', - }) - # if self.test_results == '返工': - # productions = self.production_id - # # self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) - # # self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) - # productions._create_workorder2(self.processing_panel) - # else: - # self.results = '合格' - def json_workorder_str1(self, k, production, route): workorders_values_str = [0, '', { 'product_uom_id': production.product_uom_id.id, @@ -847,15 +746,26 @@ class ResMrpWorkOrder(models.Model): ('routing_type', '=', '装夹预调'), ('state', '=', 'done')]) if pre_workorder: workorder.state = 'waiting' + if workorder.routing_type == '解除装夹' and workorder.state not in ['done', 'rework', 'cancel']: + cnc_workorder = self.env['mrp.workorder'].search( + [('production_id', '=', workorder.production_id.id), + ('processing_panel', '=', workorder.processing_panel), + ('routing_type', '=', 'CNC加工'), ('state', '=', 'done')]) + if cnc_workorder: + workorder.state = 'waiting' elif workorder.production_id.state == 'progress': logging.info('len(re_work):%s' % len(re_work)) logging.info('工序:%s' % workorder.routing_type) logging.info('状态:%s' % workorder.state) logging.info('is_rework:%s' % workorder.is_rework) logging.info('面:%s' % workorder.processing_panel) + logging.info('reprogramming_num:%s' % workorder.production_id.reprogramming_num) logging.info('编程状态:%s' % workorder.production_id.programming_state) logging.info('制造状态:%s' % workorder.production_id.state) - if workorder.routing_type == '装夹预调' and workorder.production_id.programming_state == '已下发': + if workorder.routing_type == '装夹预调' and workorder.production_id.programming_state == '已编程' and \ + workorder.is_rework is False and workorder.state not in [ + 'done', 'rework', + 'cancel']: if re_work: workorder.state = 'ready' # else: @@ -1006,7 +916,7 @@ class ResMrpWorkOrder(models.Model): record.process_state = '待解除装夹' # record.write({'process_state': '待加工'}) record.production_id.process_state = '待解除装夹' - if record.test_results in ['返工']: + if record.test_results in ['返工', '报废']: record.production_id.write({'detection_result_ids': [(0, 0, { 'rework_reason': record.reason, 'detailed_reason': record.detailed_reason, @@ -1014,7 +924,8 @@ class ResMrpWorkOrder(models.Model): 'routing_type': record.routing_type, 'handle_result': '待处理' if record.test_results == '返工' or record.is_rework is True else '', 'test_results': record.test_results, - 'test_report': record.detection_report})]}) + 'test_report': record.detection_report})], + 'is_scrap': True if record.test_results == '报废' else False}) if record.routing_type == '解除装夹': ''' 记录结束时间 diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index 358e2879..8325d703 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -147,6 +147,8 @@ access_sf_detection_result_group_sf_order_user,sf_detection_result_group_sf_orde access_sf_detection_result_group_plan_dispatch,sf_detection_result_group_plan_dispatch,model_sf_detection_result,sf_base.group_plan_dispatch,1,1,1,0 access_sf_detection_result_group_sf_equipment_user,sf_detection_result_group_sf_equipment_user,model_sf_detection_result,sf_base.group_sf_equipment_user,1,1,1,0 access_sf_processing_panel_group_sf_order_user,sf_processing_panel_group_sf_order_user,model_sf_processing_panel,sf_base.group_sf_order_user,1,1,1,0 +access_sf_production_wizard_group_sf_order_user,sf_production_wizard_group_sf_order_user,model_sf_production_wizard,sf_base.group_sf_order_user,1,1,1,0 access_sf_processing_panel_group_plan_dispatch,sf_processing_panel_group_plan_dispatch,model_sf_processing_panel,sf_base.group_plan_dispatch,1,1,1,0 + diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index 11d746da..28da8c14 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -75,19 +75,21 @@ - + - + + @@ -122,9 +124,10 @@ confirm="是否确认更新程序" attrs="{'invisible': ['|',('state', '!=', 'rework'),('programming_state', '!=', '已编程未下发')]}"/>