diff --git a/jikimo_sale_multiple_supply_methods/__init__.py b/jikimo_sale_multiple_supply_methods/__init__.py index 62b89387..74eea1d2 100644 --- a/jikimo_sale_multiple_supply_methods/__init__.py +++ b/jikimo_sale_multiple_supply_methods/__init__.py @@ -10,7 +10,7 @@ def _data_install(cr, registry): env.ref('jikimo_sale_multiple_supply_methods.product_template_purchase').product_variant_id.write({'active': False, 'is_bfm': True}) env.ref('jikimo_sale_multiple_supply_methods.product_template_manual_processing').product_variant_id.write({'active': False, 'single_manufacturing': True, 'is_bfm': True}) env.ref('jikimo_sale_multiple_supply_methods.product_template_default').product_variant_id.write({'active': False, 'is_bfm': True}) - env.ref('jikimo_sale_multiple_supply_methods.product_template_raw_material_customer_provided').product_variant_id.write({'active': False}) + env.ref('jikimo_sale_multiple_supply_methods.product_template_embryo_customer_provided').product_variant_id.write({'active': False}) env.ref('jikimo_sale_multiple_supply_methods.product_template_outsourcing').product_variant_id.write({'active': False, 'is_bfm': True}) env.ref('sf_dlm.product_embryo_sf_self_machining').product_tmpl_id.write({'categ_type': '坯料'}) env.ref('sf_dlm.product_template_sf').product_tmpl_id.write({'categ_type': '成品'}) diff --git a/jikimo_sale_multiple_supply_methods/controllers/main.py b/jikimo_sale_multiple_supply_methods/controllers/main.py index 9127f80e..b5a25749 100644 --- a/jikimo_sale_multiple_supply_methods/controllers/main.py +++ b/jikimo_sale_multiple_supply_methods/controllers/main.py @@ -34,6 +34,9 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect): if kw.get('logistics_way'): order_id.logistics_way = kw['logistics_way'] for item in bfm_process_order_list: + if item.get('embryo_redundancy_id'): + item['embryo_redundancy'] = request.env['sf.embryo.redundancy'].sudo().search([('code', '=', item['embryo_redundancy_id'])], limit=1) + item['embryo_redundancy_id'] = item['embryo_redundancy'].id product = request.env['product.template'].sudo().product_create(product_id, item, order_id, kw['order_number'], i) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) diff --git a/jikimo_sale_multiple_supply_methods/data/product_data.xml b/jikimo_sale_multiple_supply_methods/data/product_data.xml index dc9b70a7..b63da7ea 100644 --- a/jikimo_sale_multiple_supply_methods/data/product_data.xml +++ b/jikimo_sale_multiple_supply_methods/data/product_data.xml @@ -65,7 +65,7 @@ - + 坯料客供料模板 diff --git a/jikimo_sale_multiple_supply_methods/models/product_template.py b/jikimo_sale_multiple_supply_methods/models/product_template.py index fd9de9f9..c7dfa1ab 100644 --- a/jikimo_sale_multiple_supply_methods/models/product_template.py +++ b/jikimo_sale_multiple_supply_methods/models/product_template.py @@ -8,7 +8,7 @@ class ProductTemplate(models.Model): def product_create(self, product_id, item, order_id, order_number, i): product_id = super(ProductTemplate, self).product_create(product_id, item, order_id, order_number, i) - product_id.product_tmpl_id.is_customer_provided = item['is_incoming_material'] + product_id.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False return product_id diff --git a/jikimo_sale_multiple_supply_methods/models/sale_order.py b/jikimo_sale_multiple_supply_methods/models/sale_order.py index 27cecac6..a1920a50 100644 --- a/jikimo_sale_multiple_supply_methods/models/sale_order.py +++ b/jikimo_sale_multiple_supply_methods/models/sale_order.py @@ -54,7 +54,10 @@ class SaleOrder(models.Model): 'model_width': product.width, 'model_height': product.height, 'price': product.list_price, + 'embryo_redundancy_id': line.embryo_redundancy_id, } + # 获取成品名结尾-n的n + product_seria = int(product.name.split('-')[-1]) # 成品供货方式为采购则不生成bom if line.supply_method != 'purchase': bom_data = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).get_bom(product) @@ -64,14 +67,14 @@ class SaleOrder(models.Model): bom.with_user(self.env.ref("base.user_admin")).bom_create_line_has(bom_data) else: # 当成品上带有客供料选项时,生成坯料时选择“客供料”路线 - if line.is_incoming_material: + if line.embryo_redundancy_id: # 将成品模板的内容复制到成品上 - customer_provided_embryo = self.env.ref('jikimo_sale_multiple_supply_methods.product_tempalte_raw_material_customer_provided').sudo() + customer_provided_embryo = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_embryo_customer_provided').sudo() # 创建坯料,客供料的批量不需要创建bom material_customer_provided_embryo = self.env['product.template'].sudo().no_bom_product_create( customer_provided_embryo.with_context(active_test=False).product_variant_id, item, - order_id, 'material_customer_provided', 0, product) + order_id, 'material_customer_provided', product_seria, product) # 成品配置bom product_bom_material_customer_provided = self.env['mrp.bom'].with_user( self.env.ref("base.user_admin")).bom_create( @@ -84,7 +87,7 @@ class SaleOrder(models.Model): self_machining_embryo = self.env['product.template'].sudo().no_bom_product_create( self_machining_id, item, - order_id, 'self_machining', 0, product) + order_id, 'self_machining', product_seria, product) # 创建坯料的bom self_machining_bom = self.env['mrp.bom'].with_user( self.env.ref("base.user_admin")).bom_create( @@ -108,7 +111,7 @@ class SaleOrder(models.Model): item, order_id, 'subcontract', - 0, product) + product_seria, product) if outsource_embryo == -3: raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配') # 创建坯料的bom @@ -130,7 +133,7 @@ class SaleOrder(models.Model): purchase_embryo = self.env['product.template'].sudo().no_bom_product_create(purchase_id, item, order_id, - 'purchase', 0, + 'purchase', product_seria, product) if purchase_embryo == -3: raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配') diff --git a/jikimo_sale_multiple_supply_methods/views/sale_order_views.xml b/jikimo_sale_multiple_supply_methods/views/sale_order_views.xml index 2ea9a835..8b1a85d0 100644 --- a/jikimo_sale_multiple_supply_methods/views/sale_order_views.xml +++ b/jikimo_sale_multiple_supply_methods/views/sale_order_views.xml @@ -22,7 +22,7 @@ confirm_to_supply_method - + draft,sent,supply method,sale @@ -59,6 +59,7 @@ + {'search_default_draft': 1} diff --git a/sf_base/models/base.py b/sf_base/models/base.py index 2c4bf22a..15d4f9cc 100644 --- a/sf_base/models/base.py +++ b/sf_base/models/base.py @@ -410,3 +410,14 @@ class ReSaleOrder(models.Model): person_of_delivery = fields.Char('收货人') telephone_of_delivery = fields.Char('电话号码') address_of_delivery = fields.Char('联系地址') + + +class EmbryoRedundancy(models.Model): + _name = "sf.embryo.redundancy" + + name = fields.Char('名称', required=True) + long = fields.Float('长度(mm)', required=True) + width = fields.Float('宽度(mm)', required=True) + height = fields.Float('高度(mm)', required=True) + code = fields.Char('编码', required=True) + active = fields.Boolean('有效', default=True) diff --git a/sf_base/models/common.py b/sf_base/models/common.py index 9061ffe0..4152c119 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -158,6 +158,8 @@ class MrsProductionProcessParameter(models.Model): for parameter in self: if parameter.process_id: name = parameter.process_id.name + '-' + parameter.name + else: + name = parameter.name result.append((parameter.id, name)) return result diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index 34605cca..8dd4a023 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -251,3 +251,6 @@ access_sf_cutting_tool_type_group_plan_dispatch,sf_cutting_tool_type_group_plan_ access_sf_machining_accuracy,sf_machining_accuracy,model_sf_machining_accuracy,base.group_user,1,0,0,0 access_sf_machining_accuracy_admin,sf_machining_accuracy_admin,model_sf_machining_accuracy,base.group_system,1,0,0,0 + +access_sf_embryo_redundancy,sf_embryo_redundancy,model_sf_embryo_redundancy,base.group_user,1,0,0,0 +access_sf_embryo_redundancy_admin,sf_embryo_redundancy_admin,model_sf_embryo_redundancy,base.group_system,1,0,0,0 diff --git a/sf_base/views/base_view.xml b/sf_base/views/base_view.xml index eb2c1571..bd6f103b 100644 --- a/sf_base/views/base_view.xml +++ b/sf_base/views/base_view.xml @@ -633,4 +633,26 @@ sf.machining.accuracy tree + + #------------------坯料冗余量------------------ + + tree.sf.embryo.redundancy + sf.embryo.redundancy + + + + + + + + + + + + + 坯料冗余量 + ir.actions.act_window + sf.embryo.redundancy + tree + \ No newline at end of file diff --git a/sf_base/views/menu_view.xml b/sf_base/views/menu_view.xml index 4c662976..cf7c7aaf 100644 --- a/sf_base/views/menu_view.xml +++ b/sf_base/views/menu_view.xml @@ -141,18 +141,25 @@ sequence="1" action="action_sf_machine_brand"/> + + diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 8e4417b9..2bde02d9 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -10,7 +10,7 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse', 'jikimo_attachment_viewer'], + 'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse','jikimo_attachment_viewer', 'jikimo_sale_multiple_supply_methods'], 'data': [ 'data/cron_data.xml', 'data/stock_data.xml', @@ -23,6 +23,7 @@ 'wizard/rework_wizard_views.xml', 'wizard/production_wizard_views.xml', 'wizard/production_technology_wizard_views.xml', + 'wizard/production_technology_re_adjust_wizard_views.xml', 'views/mrp_views_menus.xml', 'views/agv_scheduling_views.xml', 'views/stock_lot_views.xml', diff --git a/sf_manufacturing/models/model_type.py b/sf_manufacturing/models/model_type.py index d08b024b..0dd272bd 100644 --- a/sf_manufacturing/models/model_type.py +++ b/sf_manufacturing/models/model_type.py @@ -6,7 +6,8 @@ class ModelType(models.Model): _description = '模型类型' name = fields.Char('名称') - embryo_tolerance = fields.Integer('坯料容余') + # embryo_tolerance = fields.Char('坯料容余') + embryo_tolerance_id = fields.Many2one('sf.embryo.redundancy', string='坯料容余') product_routing_tmpl_ids = fields.One2many('sf.product.model.type.routing.sort', 'product_model_type_id', '成品工序模板(自动化产线加工') embryo_routing_tmpl_ids = fields.One2many('sf.embryo.model.type.routing.sort', 'embryo_model_type_id', diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 69e6afb1..644e08e5 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -306,16 +306,17 @@ 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' - # 新添加的状态逻辑 if ( production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排': - production.state = 'confirmed' + if not production.workorder_ids: + production.state = 'technology_to_confirmed' + else: + production.state = 'confirmed' elif production.state == 'pending_cam' and production.schedule_state == '未排': production.state = 'confirmed' elif production.state == 'to_close' and production.schedule_state == '已排': production.state = 'pending_cam' - if production.state == 'progress': if all(wo_state not in ('progress', 'done', 'rework', 'scrap') for wo_state in production.workorder_ids.mapped('state')): @@ -344,11 +345,44 @@ class MrpProduction(models.Model): if production.tool_state == '2': production.state = 'rework' + # 退回调整 + def technology_back_adjust(self): + process_parameters = [] + domain = [('state', '=', 'confirmed'), ('origin', '=', self.origin)] + if self.production_type == '自动化产线加工': + cloud_programming = self._cron_get_programming_state() + if cloud_programming['send_state'] == 'sending': + raise UserError(_("编程文件正在下发中,请稍后重试")) + domain += [('programming_no', '=', self.programming_no)] + # 带排程的制造订单 + production_confirmed = self.env['mrp.production'].search(domain) + for special in production_confirmed.technology_design_ids: + 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))) + if production_confirmed: + return { + 'name': _('退回调整'), + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'sf.production.technology.re_adjust.wizard', + 'target': 'new', + 'context': { + 'default_production_id': self.id, + 'default_origin': self.origin, + }} + # 工艺确认 def technology_confirm(self): process_parameters = [] + account_moves = [] special_design = self.technology_design_ids.filtered( - lambda a: a.routing_tag == 'special' and a.process_parameters_id is not False) + lambda a: a.routing_tag == 'special' and a.is_auto is False) for special in special_design: if special.process_parameters_id: product_production_process = self.env['product.template'].search( @@ -356,6 +390,13 @@ class MrpProduction(models.Model): if not product_production_process: if special.process_parameters_id not in process_parameters: process_parameters.append(special.process_parameters_id.display_name) + purchase = self.env['purchase.order'].search([('origin', '=', special.production_id.name)]) + account = self.env['account.move'].search([('id', 'in', purchase.invoice_ids)]) + if account.state not in ['cancel', False]: + if purchase.name not in account_moves: + account_moves.append(purchase.name) + if account_moves: + raise UserError(_("请联系工厂生产经理对采购订单为%s生成的账单进行取消", ", ".join(account_moves))) if process_parameters: raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters))) # 判断同一个加工面的标准工序的顺序是否依次排序 @@ -368,8 +409,8 @@ class MrpProduction(models.Model): 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)) + # 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: @@ -636,19 +677,13 @@ class MrpProduction(models.Model): }] if production.product_id.categ_id.type == '成品': # # 根据工序设计生成工单 - for route in item.technology_design_ids: + for route in production.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( @@ -662,54 +697,60 @@ class MrpProduction(models.Model): workorders_values.append( self.env['mrp.workorder'].json_workorder_str('', production, route_embryo)) production.workorder_ids = workorders_values - process_parameter_workorder = self.env['mrp.workorder'].search( - [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.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) - 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) - if m == len(consecutive_workorders) - 1 and m != 0: - self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, - production) - 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) - if is_pick is False and m == 0: - if len(sorted_workorders) == 1: - self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production) - else: - self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production) for workorder in production.workorder_ids: workorder.duration_expected = workorder._get_duration_expected() + # 外协出入库单处理 + def get_subcontract_pick_purchase(self): + production_all = self.sorted(lambda x: x.id) + product_id_to_production_names = {} + grouped_product_ids = {k: list(g) for k, g in + groupby(production_all, key=lambda x: x.product_id.id)} + for product_id, pd in grouped_product_ids.items(): + product_id_to_production_names[product_id] = [p.name for p in pd] + for production in production_all: + process_parameter_workorder = self.env['mrp.workorder'].search( + [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id), + ('is_subcontract', '=', True)], order='sequence asc') + if process_parameter_workorder: + consecutive_workorders = [] + sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.sequence) + for i, workorder in enumerate(sorted_workorders): + # 检查当前工作订单和下一个工作订单是否连续,并且供应商相同 + if workorder.sequence == 1: + consecutive_workorders.append(workorder) + elif workorder.sequence == sorted_workorders[ + i - 1].sequence + 1 and workorder.supplier_id.id == sorted_workorders[i - 1].supplier_id.id: + consecutive_workorders.append(workorder) + else: + # 处理连续组,如果它不为空 + if consecutive_workorders: + # 创建出库拣货单和采购订单 + self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production) + self.env['purchase.order'].get_purchase_order(consecutive_workorders, production, + product_id_to_production_names) + if i < len(sorted_workorders) - 1: + # 重置连续组,并添加当前工作订单 + consecutive_workorders = [workorder] + else: + # 判断最后一笔: + if workorder.sequence == sorted_workorders[ + i - 1].sequence and workorder.supplier_id.id == sorted_workorders[ + i - 1].supplier_id.id: + consecutive_workorders = [workorder] + else: + # 立即创建出库拣货单和采购订单 + self.env['stock.picking'].create_outcontract_picking(workorder, production) + self.env['purchase.order'].get_purchase_order(workorder, production, + product_id_to_production_names) + consecutive_workorders = [] + + # 处理最后一个组,即使它可能只有一个工作订单 + if consecutive_workorders: + self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production) + self.env['purchase.order'].get_purchase_order(consecutive_workorders, production, + product_id_to_production_names) + # 工单排序 def _reset_work_order_sequence1(self, k): for rec in self: @@ -1305,17 +1346,17 @@ class MrpProduction(models.Model): return production_values_str # 增加制造订单类型 - # production_type = fields.Selection( - # [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')], - # string='制造类型', - # compute='_compute_production_type', - # store=True - # ) + production_type = fields.Selection( + [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')], + string='制造类型', + compute='_compute_production_type', + store=True + ) - # @api.depends('product_id.is_manual_processing') - # def _compute_production_type(self): - # for production in self: - # production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工' + @api.depends('product_id.is_manual_processing') + def _compute_production_type(self): + for production in self: + production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工' class sf_detection_result(models.Model): diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 22a7317a..c8267b41 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -38,13 +38,10 @@ class ResMrpWorkOrder(models.Model): processing_panel = fields.Char('加工面') sequence = fields.Integer(string='工序') routing_type = fields.Selection([ - # ('获取CNC加工程序', '获取CNC加工程序'), ('装夹预调', '装夹预调'), - # ('前置三元定位检测', '前置三元定位检测'), ('CNC加工', 'CNC加工'), - # ('后置三元质量检测', '后置三元质量检测'), ('解除装夹', '解除装夹'), - ('切割', '切割'), ('表面工艺', '表面工艺') + ('切割', '切割'), ('表面工艺', '表面工艺'), ('线切割', '线切割') ], string="工序类型") results = fields.Char('结果') state = fields.Selection([ @@ -233,7 +230,7 @@ class ResMrpWorkOrder(models.Model): def _compute_surface_technics_picking_ids(self): for workorder in self: if workorder.routing_type == '表面工艺': - domain = [('origin', '=', workorder.production_id.name)] + domain = [('origin', '=', workorder.production_id.name), ('state', 'not in', ['cancel'])] previous_workorder = self.env['mrp.workorder'].search( [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), ('production_id', '=', workorder.production_id.id)]) @@ -267,24 +264,47 @@ class ResMrpWorkOrder(models.Model): def _compute_surface_technics_purchase_ids(self): for order in self: if order.routing_type == '表面工艺': - production_programming = self.env['mrp.production'].search( - [('programming_no', '=', order.production_id.programming_no)], order='name asc') - production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False) + if order.production_id.production_type == '自动化产线加工': + domain = [('programming_no', '=', order.production_id.programming_no)] + else: + domain = [('origin', '=', order.production_id.origin)] + production_programming = self.env['mrp.production'].search(domain, order='name asc') production_list = [production.name for production in production_programming] - purchase = self.env['purchase.order'].search([('origin', '=', ','.join(production_list))]) + production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False) + technology_design = self.env['sf.technology.design'].search( + [('process_parameters_id', '=', order.surface_technics_parameters_id.id), + ('production_id', '=', order.production_id.id)]) + if technology_design.is_auto is False: + domain = [('origin', '=', order.production_id.name)] + else: + domain = [('origin', '=', ','.join(production_list))] + purchase = self.env['purchase.order'].search(domain) + if not purchase: + order.surface_technics_purchase_count = 0 for line in purchase.order_line: - if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id and line.product_qty == len( - production_no_remanufacture): - order.surface_technics_purchase_count = len(purchase) + if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id: + if (line.product_qty == len(production_no_remanufacture)) or technology_design.is_auto is False: + order.surface_technics_purchase_count = len(purchase) else: order.surface_technics_purchase_count = 0 def action_view_surface_technics_purchase(self): self.ensure_one() - production_programming = self.env['mrp.production'].search( - [('programming_no', '=', self.production_id.programming_no)], order='name asc') + if self.routing_type == '表面工艺': + if self.production_id.production_type == '自动化产线加工': + domain = [('programming_no', '=', self.production_id.programming_no)] + else: + domain = [('origin', '=', self.production_id.origin)] + production_programming = self.env['mrp.production'].search(domain, order='name asc') production_list = [production.name for production in production_programming] - purchase_orders = self.env['purchase.order'].search([('origin', '=', ','.join(production_list))]) + technology_design = self.env['sf.technology.design'].search( + [('process_parameters_id', '=', self.surface_technics_parameters_id.id), + ('production_id', '=', self.production_id.id)]) + if technology_design.is_auto is False: + domain = [('origin', '=', self.production_id.name)] + else: + domain = [('origin', '=', ','.join(production_list))] + purchase_orders = self.env['purchase.order'].search(domain) result = { "type": "ir.actions.act_window", "res_model": "purchase.order", @@ -410,7 +430,8 @@ class ResMrpWorkOrder(models.Model): @api.constrains('blocked_by_workorder_ids') def _check_no_cyclic_dependencies(self): - if self.production_id.state not in ['rework'] and self.state not in ['rework']: + if self.production_id.state not in ['rework', 'technology_to_confirmed', 'confirmed'] and self.state not in [ + 'rework']: if not self._check_m2m_recursion('blocked_by_workorder_ids'): raise ValidationError(_("您不能创建周期性的依赖关系.")) @@ -421,8 +442,9 @@ class ResMrpWorkOrder(models.Model): for workorder in self.blocked_by_workorder_ids: if workorder.state in ['done', 'cancel', 'rework']: continue - workorder._plan_workorder(replan) - start_date = max(start_date, workorder.date_planned_finished) + if workorder.production_id.state not in ['technology_to_confirmed', 'confirmed']: + workorder._plan_workorder(replan) + start_date = max(start_date, workorder.date_planned_finished) # Plan only suitable workorders if self.state not in ['pending', 'waiting', 'ready']: return @@ -769,6 +791,7 @@ class ResMrpWorkOrder(models.Model): 'operation_id': False, 'name': route.route_id.name, 'processing_panel': route.panel, + 'sequence': route.sequence, '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, @@ -817,6 +840,7 @@ class ResMrpWorkOrder(models.Model): 'operation_id': False, 'name': route.process_parameters_id.display_name, 'processing_panel': '', + 'sequence': route.sequence, 'routing_type': '表面工艺', 'surface_technics_parameters_id': route.process_parameters_id.id, 'work_state': '', @@ -977,10 +1001,47 @@ class ResMrpWorkOrder(models.Model): return workorders_values_str @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state', - 'production_id.tool_state') + 'production_id.tool_state', 'production_id.schedule_state') def _compute_state(self): - super()._compute_state() + # super()._compute_state() for workorder in self: + if workorder.sequence != 1: + previous_workorder = self.env['mrp.workorder'].search( + [('production_id', '=', workorder.production_id.id), + ('sequence', '=', workorder.sequence - 1)]) + if workorder.state == 'pending': + if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]): + if workorder.production_id.reservation_state == 'assigned' and workorder.production_id.schedule_state == '已排': + if (workorder.sequence == 1 and not workorder.blocked_by_workorder_ids) or ( + workorder.blocked_by_workorder_ids.state in ('done', 'cancel')) or ( + previous_workorder.state in ( + 'done', 'cancel') and not workorder.blocked_by_workorder_ids): + workorder.state = 'ready' + continue + if workorder.production_id.schedule_state == '未排' and workorder.state in ('waiting', 'ready'): + if workorder.sequence != 1: + workorder.state = 'pending' + continue + if workorder.state not in ('waiting', 'ready'): + continue + if workorder.state in ( + 'waiting') and workorder.sequence == 1 and workorder.production_id.schedule_state == '已排': + workorder.state = 'ready' + continue + if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]): + workorder.state = 'pending' + if workorder.state in ['waiting']: + if previous_workorder.state == 'waiting': + workorder.state = 'pending' + if workorder.sequence == 1 and workorder.state == 'pending': + workorder.state = 'waiting' + continue + if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'): + continue + if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting' and workorder.production_id.schedule_state == '已排': + workorder.state = 'ready' + elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready': + workorder.state = 'waiting' re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id), ('processing_panel', '=', workorder.processing_panel), ('is_rework', '=', True), ('state', 'in', ['done', 'rework'])]) @@ -1044,7 +1105,7 @@ class ResMrpWorkOrder(models.Model): workorder.state = 'ready' else: production_programming = self.env['mrp.production'].search( - [('programming_no', '=', self.production_id.programming_no)], order='name asc') + [('origin', '=', self.production_id.origin)], order='name asc') production_no_remanufacture = production_programming.filtered( lambda a: a.is_remanufacture is False) production_list = [production.name for production in production_programming] @@ -1060,68 +1121,68 @@ class ResMrpWorkOrder(models.Model): elif workorder.production_id.state == 'scrap': if workorder.routing_type == '解除装夹' and unclamp_workorder.test_results == '报废': workorder.state = 'waiting' - if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']: - workorder_ids = workorder.production_id.workorder_ids - work_bo = True - for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'): - if not workorder_ids.filtered( - lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel'] - and a.processing_panel == wo.processing_panel)): - work_bo = False - break - if (workorder.production_id.programming_state == '已编程' and work_bo - and not workorder_ids.filtered(lambda a: a.sequence == 0)): - # 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】 - if workorder.production_id.tool_state in ['1', '2']: - if workorder.state in ['ready']: - workorder.state = 'waiting' - continue - elif workorder.state in ['waiting']: - continue - elif workorder.state == 'pending' and workorder == self.search( - [('production_id', '=', workorder.production_id.id), - ('routing_type', '=', '装夹预调'), - ('state', 'not in', ['rework', 'done', 'cancel'])], - limit=1, - order="sequence"): - workorder.state = 'waiting' - continue - elif workorder.production_id.tool_state in ['0']: - if workorder_ids.filtered(lambda a: a.state == 'rework'): - if not workorder_ids.filtered( - lambda a: (a.routing_type not in ['装夹预调'] and - a.state not in ['pending', 'done', 'rework', 'cancel'])): - # 查询工序最小的非完工、非返工的装夹预调工单 - work_id = self.search( - [('production_id', '=', workorder.production_id.id), - ('state', 'not in', ['rework', 'done', 'cancel'])], - limit=1, - order="sequence") - if work_id.routing_type == '装夹预调': - if workorder == work_id: - if workorder.production_id.reservation_state == 'assigned': - workorder.state = 'ready' - elif workorder.production_id.reservation_state != 'assigned': - workorder.state = 'waiting' - continue - elif (workorder.name == '装夹预调' and - workorder.state not in ['rework', 'done', 'cancel']): - if workorder.state != 'pending': - workorder.state = 'pending' - if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready': - workorder.state = 'waiting' - continue - if (workorder.production_id.tool_state in ['1', '2'] - and not workorder.production_id.workorder_ids.filtered(lambda a: a.sequence == 0) - and workorder.production_id.programming_state == '编程中' and workorder.name == '装夹预调'): - if workorder.state == 'pending' and workorder == self.search( - [('production_id', '=', workorder.production_id.id), - ('routing_type', '=', '装夹预调'), - ('state', 'not in', ['rework', 'done', 'cancel'])], - limit=1, - order="sequence"): - workorder.state = 'waiting' - continue + # if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']: + # workorder_ids = workorder.production_id.workorder_ids + # work_bo = True + # for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'): + # if not workorder_ids.filtered( + # lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel'] + # and a.processing_panel == wo.processing_panel)): + # work_bo = False + # break + # if (workorder.production_id.programming_state == '已编程' and work_bo + # and not workorder_ids.filtered(lambda a: a.sequence == 0)): + # # 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】 + # if workorder.production_id.tool_state in ['1', '2']: + # if workorder.state in ['ready']: + # workorder.state = 'waiting' + # continue + # elif workorder.state in ['waiting']: + # continue + # elif workorder.state == 'pending' and workorder == self.search( + # [('production_id', '=', workorder.production_id.id), + # ('routing_type', '=', '装夹预调'), + # ('state', 'not in', ['rework', 'done', 'cancel'])], + # limit=1, + # order="sequence"): + # workorder.state = 'waiting' + # continue + # elif workorder.production_id.tool_state in ['0']: + # if workorder_ids.filtered(lambda a: a.state == 'rework'): + # if not workorder_ids.filtered( + # lambda a: (a.routing_type not in ['装夹预调'] and + # a.state not in ['pending', 'done', 'rework', 'cancel'])): + # # 查询工序最小的非完工、非返工的装夹预调工单 + # work_id = self.search( + # [('production_id', '=', workorder.production_id.id), + # ('state', 'not in', ['rework', 'done', 'cancel'])], + # limit=1, + # order="sequence") + # if work_id.routing_type == '装夹预调': + # if workorder == work_id: + # if workorder.production_id.reservation_state == 'assigned': + # workorder.state = 'ready' + # elif workorder.production_id.reservation_state != 'assigned': + # workorder.state = 'waiting' + # continue + # elif (workorder.name == '装夹预调' and + # workorder.state not in ['rework', 'done', 'cancel']): + # if workorder.state != 'pending': + # workorder.state = 'pending' + # if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready': + # workorder.state = 'waiting' + # continue + # if (workorder.production_id.tool_state in ['1', '2'] + # and not workorder.production_id.workorder_ids.filtered(lambda a: a.sequence == 0) + # and workorder.production_id.programming_state == '编程中' and workorder.name == '装夹预调'): + # if workorder.state == 'pending' and workorder == self.search( + # [('production_id', '=', workorder.production_id.id), + # ('routing_type', '=', '装夹预调'), + # ('state', 'not in', ['rework', 'done', 'cancel'])], + # limit=1, + # order="sequence"): + # workorder.state = 'waiting' + # continue # 重写工单开始按钮方法 def button_start(self): @@ -1131,7 +1192,7 @@ class ResMrpWorkOrder(models.Model): 'actual_start_time': datetime.now() }) - if self.routing_type == '装夹预调': + if self.sequence == 1: # 判断是否有坯料的序列号信息 boolean = False if self.production_id.move_raw_ids: @@ -1242,8 +1303,8 @@ class ResMrpWorkOrder(models.Model): if record.is_rework is False: if not record.material_center_point: raise UserError("坯料中心点为空,请检查") - # if record.X_deviation_angle <= 0: - # raise UserError("X偏差角度小于等于0,请检查!本次计算的X偏差角度为:%s" % record.X_deviation_angle) + # if record.X_deviation_angle <= 0: + # raise UserError("X偏差角度小于等于0,请检查!本次计算的X偏差角度为:%s" % record.X_deviation_angle) record.process_state = '待加工' # record.write({'process_state': '待加工'}) record.production_id.process_state = '待加工' @@ -1273,23 +1334,10 @@ class ResMrpWorkOrder(models.Model): ''' record.date_finished = datetime.now() if record.routing_type == '表面工艺': - logging.info('record.picking_ids:%s' % record.picking_ids) - logging.info('record.picking_out:%s' % record.picking_ids[0]) if record.picking_ids: - for pick_item in record.picking_ids: - if pick_item.state not in ['done']: - raise UserError( - '请先完成该工单的工艺外协再进行操作') - picking_out = record.env['stock.move.line'].search( - [('picking_id', '=', record.picking_ids[0].id)]) - logging.info('picking_out:%s' % picking_out.picking_id.name) - # if picking_out: - # order_line_ids = [] - # logging.info('surface_technics_parameters_id:%s' % record.surface_technics_parameters_id.name) - # - # else: - # raise UserError( - # '请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name) + picks = record.picking_ids.filtered(lambda p: p.state not in ('done')) + if picks: + raise UserError('请先完成该工单的工艺外协再进行操作') tem_date_planned_finished = record.date_planned_finished tem_date_finished = record.date_finished logging.info('routing_type:%s' % record.routing_type) diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index baf0c1b5..b01cc465 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -850,14 +850,21 @@ class ResProductMo(models.Model): copy_product_id.product_tmpl_id.active = True model_type = self.env['sf.model.type'].search([], limit=1) attachment = self.attachment_create(item['model_name'], item['model_data']) + # 获取坯料冗余配置 + if not item.get('embryo_redundancy'): + embryo_redundancy_id = model_type.embryo_tolerance_id + else: + embryo_redundancy_id = item.get('embryo_redundancy') + if not embryo_redundancy_id: + raise UserError('请先配置模型类型内的坯料冗余') vals = { 'name': '%s-%s-%s' % ('P', order_id.name, i), - 'model_long': item['model_long'] + model_type.embryo_tolerance, - 'model_width': item['model_width'] + model_type.embryo_tolerance, - 'model_height': item['model_height'] + model_type.embryo_tolerance, - 'model_volume': (item['model_long'] + model_type.embryo_tolerance) * ( - item['model_width'] + model_type.embryo_tolerance) * ( - item['model_height'] + model_type.embryo_tolerance), + 'model_long': item['model_long'] + embryo_redundancy_id.long, + 'model_width': item['model_width'] + embryo_redundancy_id.width, + 'model_height': item['model_height'] + embryo_redundancy_id.height, + 'model_volume': (item['model_long'] + embryo_redundancy_id.long) * ( + item['model_width'] + embryo_redundancy_id.width) * ( + item['model_height'] + embryo_redundancy_id.height), 'product_model_type_id': model_type.id, 'model_processing_panel': item['processing_panel_detail'], 'model_machining_precision': item['model_machining_precision'], @@ -941,19 +948,26 @@ class ResProductMo(models.Model): [('materials_no', '=', item['texture_type_code'])]) model_type = self.env['sf.model.type'].search([], limit=1) supplier = self.env['mrp.bom'].get_supplier(materials_type_id) + # 获取坯料冗余配置 + if not item.get('embryo_redundancy_id'): + embryo_redundancy_id = model_type.embryo_tolerance_id + else: + embryo_redundancy_id = item.get('embryo_redundancy_id') + if not embryo_redundancy_id: + raise UserError('请先配置模型类型内的坯料冗余') logging.info('no_bom_copy_product_supplier-vals:%s' % supplier) vals = { 'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R', order_id.name, i, materials_id.name, materials_type_id.name, - item['model_long'] + model_type.embryo_tolerance, - item['model_width'] + model_type.embryo_tolerance, - item['model_height'] + model_type.embryo_tolerance), - 'length': item['model_long'] + model_type.embryo_tolerance, - 'width': item['model_width'] + model_type.embryo_tolerance, - 'height': item['model_height'] + model_type.embryo_tolerance, - 'volume': (item['model_long'] + model_type.embryo_tolerance) * ( - item['model_width'] + model_type.embryo_tolerance) * ( - item['model_height'] + model_type.embryo_tolerance), + item['model_long'] + embryo_redundancy_id.long, + item['model_width'] + embryo_redundancy_id.width, + item['model_height'] + embryo_redundancy_id.height), + 'length': item['model_long'] + embryo_redundancy_id.long, + 'width': item['model_width'] + embryo_redundancy_id.width, + 'height': item['model_height'] + embryo_redundancy_id.height, + 'volume': (item['model_long'] + embryo_redundancy_id.long) * ( + item['model_width'] + embryo_redundancy_id.width) * ( + item['model_height'] + embryo_redundancy_id.height), 'embryo_model_type_id': model_type.id, 'list_price': item['price'], 'materials_id': materials_id.id, diff --git a/sf_manufacturing/models/sf_technology_design.py b/sf_manufacturing/models/sf_technology_design.py index da9c88ee..b1bd229d 100644 --- a/sf_manufacturing/models/sf_technology_design.py +++ b/sf_manufacturing/models/sf_technology_design.py @@ -16,13 +16,13 @@ class sf_technology_design(models.Model): is_auto = fields.Boolean('是否自动生成', default=False) active = fields.Boolean('有效', default=True) - def json_technology_design_str(self, k, route, i): + def json_technology_design_str(self, k, route, i, process_parameter): workorders_values_str = [0, '', { 'route_id': route.id, 'panel': k, 'process_parameters_id': False if route.routing_type != '表面工艺' else self.env[ 'sf.production.process.parameter'].search( - [('process_id', '=', route.surface_technics_id.id)]).id, + [('id', '=', process_parameter.id)]).id, 'sequence': i, 'is_auto': True}] return workorders_values_str diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index b3d80e47..9642cb51 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -66,358 +66,311 @@ class stockWarehouse(models.Model): class StockRule(models.Model): _inherit = 'stock.rule' - # @api.model - # def _run_pull(self, procurements): - # logging.info(procurements) - # moves_values_by_company = defaultdict(list) - # mtso_products_by_locations = defaultdict(list) + @api.model + def _run_pull(self, procurements): + logging.info(procurements) + moves_values_by_company = defaultdict(list) + mtso_products_by_locations = defaultdict(list) - # # To handle the `mts_else_mto` procure method, we do a preliminary loop to - # # isolate the products we would need to read the forecasted quantity, - # # in order to to batch the read. We also make a sanitary check on the - # # `location_src_id` field. + # To handle the `mts_else_mto` procure method, we do a preliminary loop to + # isolate the products we would need to read the forecasted quantity, + # in order to to batch the read. We also make a sanitary check on the + # `location_src_id` field. - # # list1 = [] - # # for item in procurements: - # # num = int(item[0].product_qty) - # # if num > 1: - # # for no in range(1, num+1): - # # - # # Procurement = namedtuple('Procurement', ['product_id', 'product_qty', - # # 'product_uom', 'location_id', 'name', 'origin', - # # 'company_id', - # # 'values']) - # # s = Procurement(product_id=item[0].product_id,product_qty=1.0,product_uom=item[0].product_uom, - # # location_id=item[0].location_id, - # # name=item[0].name, - # # origin=item[0].origin, - # # company_id=item[0].company_id, - # # values=item[0].values, - # # ) - # # item1 = list(item) - # # item1[0]=s - # # - # # list1.append(tuple(item1)) - # # else: - # # list1.append(item) + # list1 = [] + # for item in procurements: + # num = int(item[0].product_qty) + # if num > 1: + # for no in range(1, num+1): + # + # Procurement = namedtuple('Procurement', ['product_id', 'product_qty', + # 'product_uom', 'location_id', 'name', 'origin', + # 'company_id', + # 'values']) + # s = Procurement(product_id=item[0].product_id,product_qty=1.0,product_uom=item[0].product_uom, + # location_id=item[0].location_id, + # name=item[0].name, + # origin=item[0].origin, + # company_id=item[0].company_id, + # values=item[0].values, + # ) + # item1 = list(item) + # item1[0]=s + # + # list1.append(tuple(item1)) + # else: + # list1.append(item) - # for procurement, rule in procurements: - # if not rule.location_src_id: - # msg = _('No source location defined on stock rule: %s!') % (rule.name,) - # raise ProcurementException([(procurement, msg)]) + for procurement, rule in procurements: + if not rule.location_src_id: + msg = _('No source location defined on stock rule: %s!') % (rule.name,) + raise ProcurementException([(procurement, msg)]) - # if rule.procure_method == 'mts_else_mto': - # mtso_products_by_locations[rule.location_src_id].append(procurement.product_id.id) + if rule.procure_method == 'mts_else_mto': + mtso_products_by_locations[rule.location_src_id].append(procurement.product_id.id) - # # Get the forecasted quantity for the `mts_else_mto` procurement. - # forecasted_qties_by_loc = {} - # for location, product_ids in mtso_products_by_locations.items(): - # products = self.env['product.product'].browse(product_ids).with_context(location=location.id) - # forecasted_qties_by_loc[location] = {product.id: product.free_qty for product in products} + # Get the forecasted quantity for the `mts_else_mto` procurement. + forecasted_qties_by_loc = {} + for location, product_ids in mtso_products_by_locations.items(): + products = self.env['product.product'].browse(product_ids).with_context(location=location.id) + forecasted_qties_by_loc[location] = {product.id: product.free_qty for product in products} - # # Prepare the move values, adapt the `procure_method` if needed. - # procurements = sorted(procurements, key=lambda proc: float_compare(proc[0].product_qty, 0.0, - # precision_rounding=proc[ - # 0].product_uom.rounding) > 0) - # list2 = [] - # for item in procurements: - # num = int(item[0].product_qty) + # Prepare the move values, adapt the `procure_method` if needed. + procurements = sorted(procurements, key=lambda proc: float_compare(proc[0].product_qty, 0.0, + precision_rounding=proc[ + 0].product_uom.rounding) > 0) + list2 = [] + for item in procurements: + num = int(item[0].product_qty) - # product = self.env['product.product'].search( - # [("id", '=', item[0].product_id.id)]) - # product_tmpl = self.env['product.template'].search( - # ["&", ("id", '=', product.product_tmpl_id.id), ('single_manufacturing', "!=", False)]) - # if product_tmpl: - # if num > 1: - # for no in range(1, num + 1): - # Procurement = namedtuple('Procurement', ['product_id', 'product_qty', - # 'product_uom', 'location_id', 'name', 'origin', - # 'company_id', - # 'values']) - # s = Procurement(product_id=item[0].product_id, product_qty=1.0, product_uom=item[0].product_uom, - # location_id=item[0].location_id, - # name=item[0].name, - # origin=item[0].origin, - # company_id=item[0].company_id, - # values=item[0].values, - # ) - # item1 = list(item) - # item1[0] = s + product = self.env['product.product'].search( + [("id", '=', item[0].product_id.id)]) + product_tmpl = self.env['product.template'].search( + ["&", ("id", '=', product.product_tmpl_id.id), ('single_manufacturing', "!=", False)]) + if product_tmpl: + if num > 1: + for no in range(1, num + 1): + Procurement = namedtuple('Procurement', ['product_id', 'product_qty', + 'product_uom', 'location_id', 'name', 'origin', + 'company_id', + 'values']) + s = Procurement(product_id=item[0].product_id, product_qty=1.0, product_uom=item[0].product_uom, + location_id=item[0].location_id, + name=item[0].name, + origin=item[0].origin, + company_id=item[0].company_id, + values=item[0].values, + ) + item1 = list(item) + item1[0] = s - # list2.append(tuple(item1)) - # else: - # list2.append(item) - # else: - # list2.append(item) + list2.append(tuple(item1)) + else: + list2.append(item) + else: + list2.append(item) - # for procurement, rule in list2: - # procure_method = rule.procure_method - # if rule.procure_method == 'mts_else_mto': - # qty_needed = procurement.product_uom._compute_quantity(procurement.product_qty, - # procurement.product_id.uom_id) - # if float_compare(qty_needed, 0, precision_rounding=procurement.product_id.uom_id.rounding) <= 0: - # procure_method = 'make_to_order' - # for move in procurement.values.get('group_id', self.env['procurement.group']).stock_move_ids: - # if move.rule_id == rule and float_compare(move.product_uom_qty, 0, - # precision_rounding=move.product_uom.rounding) > 0: - # procure_method = move.procure_method - # break - # forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed - # elif float_compare(qty_needed, forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id], - # precision_rounding=procurement.product_id.uom_id.rounding) > 0: - # procure_method = 'make_to_order' - # else: - # forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed - # procure_method = 'make_to_stock' - # move_values = rule._get_stock_move_values(*procurement) - # move_values['procure_method'] = procure_method - # moves_values_by_company[procurement.company_id.id].append(move_values) + for procurement, rule in list2: + procure_method = rule.procure_method + if rule.procure_method == 'mts_else_mto': + qty_needed = procurement.product_uom._compute_quantity(procurement.product_qty, + procurement.product_id.uom_id) + if float_compare(qty_needed, 0, precision_rounding=procurement.product_id.uom_id.rounding) <= 0: + procure_method = 'make_to_order' + for move in procurement.values.get('group_id', self.env['procurement.group']).stock_move_ids: + if move.rule_id == rule and float_compare(move.product_uom_qty, 0, + precision_rounding=move.product_uom.rounding) > 0: + procure_method = move.procure_method + break + forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed + elif float_compare(qty_needed, forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id], + precision_rounding=procurement.product_id.uom_id.rounding) > 0: + procure_method = 'make_to_order' + else: + forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed + procure_method = 'make_to_stock' + move_values = rule._get_stock_move_values(*procurement) + move_values['procure_method'] = procure_method + moves_values_by_company[procurement.company_id.id].append(move_values) - # for company_id, moves_values in moves_values_by_company.items(): - # # create the move as SUPERUSER because the current user may not have the rights to do it (mto product - # # launched by a sale for example) - # moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( - # moves_values) - # # Since action_confirm launch following procurement_group we should activate it. - # moves._action_confirm() - # return True + for company_id, moves_values in moves_values_by_company.items(): + # create the move as SUPERUSER because the current user may not have the rights to do it (mto product + # launched by a sale for example) + moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( + moves_values) + # Since action_confirm launch following procurement_group we should activate it. + moves._action_confirm() + return True def attachment_update(self, name, res_id, res_field): attachment_info = self.env['ir.attachment'].sudo().search( [('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1) attachment_info.write({'name': name}) - # @api.model - # def _run_manufacture(self, procurements): - # productions_values_by_company = defaultdict(list) - # errors = [] - # for procurement, rule in procurements: - # if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0: - # # If procurement contains negative quantity, don't create a MO that would be for a negative value. - # continue - # bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values) + @api.model + def _run_manufacture(self, procurements): + productions_values_by_company = defaultdict(list) + errors = [] + for procurement, rule in procurements: + if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0: + # If procurement contains negative quantity, don't create a MO that would be for a negative value. + continue + bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values) - # productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom)) + productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom)) - # if errors: - # raise ProcurementException(errors) + if errors: + raise ProcurementException(errors) - # for company_id, productions_values in productions_values_by_company.items(): - # # create the MO as SUPERUSER because the current user may not have the rights to do it - # # (mto product launched by a sale for example) - # '''创建制造订单''' - # productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( - # productions_values) + for company_id, productions_values in productions_values_by_company.items(): + # create the MO as SUPERUSER because the current user may not have the rights to do it + # (mto product launched by a sale for example) + '''创建制造订单''' + productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( + productions_values) - # # self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) - # # self.env['stock.move'].sudo().create(productions._get_moves_finished_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() - # # - # self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) - # 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 in productions: - # if production.picking_ids: - # product_type_id = production.picking_ids[0].move_ids[0].product_id.categ_id - # if product_type_id.name == '坯料': - # location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')]) - # if not location_id: - # logging.info(f'没有搜索到【坯料存货区】: {location_id}') - # break - # for picking_id in production.picking_ids: - # if picking_id.picking_type_id.name == '内部调拨': - # if picking_id.location_dest_id.product_type != product_type_id: - # picking_id.location_dest_id = location_id.id - # elif picking_id.picking_type_id.name == '生产发料': - # if picking_id.location_id.product_type != product_type_id: - # picking_id.location_id = location_id.id + ''' + 创建工单 + ''' + # productions._create_workorder() + # + self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) + 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 in productions: + if production.picking_ids: + product_type_id = production.picking_ids[0].move_ids[0].product_id.categ_id + if product_type_id.name == '坯料': + location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')]) + if not location_id: + logging.info(f'没有搜索到【坯料存货区】: {location_id}') + break + for picking_id in production.picking_ids: + if picking_id.picking_type_id.name == '内部调拨': + if picking_id.location_dest_id.product_type != product_type_id: + picking_id.location_dest_id = location_id.id + elif picking_id.picking_type_id.name == '生产发料': + if picking_id.location_id.product_type != product_type_id: + picking_id.location_id = location_id.id - # for production in productions: - # ''' - # 创建制造订单时生成序列号 - # ''' - # production.action_generate_serial() - # 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) + for production in productions: + ''' + 创建制造订单时生成序列号 + ''' + production.action_generate_serial() + 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 production.workorder_ids: - # workorder_duration += workorder.duration_expected + ''' + 创建生产计划 + ''' + # 工单耗时 + workorder_duration = 0 + for workorder in production.workorder_ids: + workorder_duration += workorder.duration_expected - # sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) - # if sale_order: - # # sale_order.write({'schedule_status': 'to schedule'}) - # self.env['sf.production.plan'].sudo().with_company(company_id).create({ - # 'name': production.name, - # 'order_deadline': sale_order.deadline_of_delivery, - # 'production_id': production.id, - # 'date_planned_start': production.date_planned_start, - # 'origin': production.origin, - # 'product_qty': production.product_qty, - # '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对应的生产订单名称列表 - # product_id_to_production_names = {} - # # 对于每个product_id,获取其所有生产订单的名称 - # for product_id, all_production in grouped_product_ids.items(): - # # 为同一个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 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) + sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) + if sale_order: + # sale_order.write({'schedule_status': 'to schedule'}) + self.env['sf.production.plan'].sudo().with_company(company_id).create({ + 'name': production.name, + 'order_deadline': sale_order.deadline_of_delivery, + 'production_id': production.id, + 'date_planned_start': production.date_planned_start, + 'origin': production.origin, + 'product_qty': production.product_qty, + '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对应的生产订单名称列表 + product_id_to_production_names = {} + # 对于每个product_id,获取其所有生产订单的名称 + for product_id, all_production in grouped_product_ids.items(): + # 为同一个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: + # 同一个产品多个制造订单对应一个编程单和模型库 + # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递 + if not production_item.programming_no and production.production_type == '自动化产线加工': + 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': '编程中'}) + if not technology_design_values: + i = 0 + if production_item.product_id.categ_id.type == '成品': + # 根据加工面板的面数及成品工序模板生成工序设计 + + for k in (production_item.product_id.model_processing_panel.split(',')): + if production_item.production_type == '自动化产线加工': + product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search( + [('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)], + order='sequence asc' + ) + else: + product_routing_workcenter = self.env['sf.manual.product.model.type.routing.sort'].search( + [('manual_product_model_type_id', '=', production_item.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, False)) + elif production.product_id.categ_id.type == '坯料': + embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( + [('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)], + order='sequence asc' + ) + for route_embryo in embryo_routing_workcenter: + i += 1 + technology_design_values.append( + self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i, + False)) + surface_technics_arr = [] + route_workcenter_arr = [] + for item in production_item.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_item.product_id.model_process_parameters_ids: + if item.route_workcenter_id.surface_technics_id == process_param.process_id: + 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_item.product_id.model_process_parameters_ids.filtered( + lambda pm: pm.process_id.id == p.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(False, + route_production_process, + i, + process_parameter)) + productions.technology_design_ids = technology_design_values - # 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, - # production_item, - # product_id_to_production_names) - # if sorted_process_parameters[i] in consecutive_process_parameters: - # 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, - # product_id_to_production_names) - # if m == len(consecutive_process_parameters) - 1 and m != 0: - # self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, - # production_item, - # product_id_to_production_names) - # if sorted_process_parameters[i] in consecutive_process_parameters: - # is_purchase = True - # consecutive_process_parameters = [] - # m = 0 - # if m == len(consecutive_process_parameters) - 1 and m != 0: - # self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, - # production_item, - # product_id_to_production_names) - # if is_purchase is False and m == 0: - # if len(sorted_process_parameters) == 1: - # self.env['purchase.order'].get_purchase_order(sorted_process_parameters, - # production_item, - # product_id_to_production_names) - # else: - # self.env['purchase.order'].get_purchase_order(sorted_process_parameters[i], - # production_item, - # product_id_to_production_names) - # 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 + return True class ProductionLot(models.Model): @@ -659,31 +612,27 @@ class StockPicking(models.Model): return '%s%s' % (rescode, num) def button_validate(self): - move_out = self.env['stock.move'].search( - [('location_id', '=', self.env['stock.location'].search( - [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), - ('location_dest_id', '=', self.env['stock.location'].search( - [('barcode', 'ilike', 'VL-SPOC')]).id), - ('origin', '=', self.origin)]) - # if self.id == move_out.picking_id.id: - # if move_out.move_line_ids.workorder_id.state not in ['progress']: - # raise UserError( - # _('该出库单里源单据内的单号为%s的工单还未开始,不能进行验证操作!' % move_out.move_line_ids.workorder_id.name)) - # 入库单验证 - move_in = self.env['stock.move'].search( - [('location_dest_id', '=', self.env['stock.location'].search( - [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), - ('location_id', '=', self.env['stock.location'].search( - [('barcode', 'ilike', 'VL-SPOC')]).id), - ('origin', '=', self.origin), ('picking_id', '=', self.id)]) - if self.location_id == move_in.location_id and self.location_dest_id == move_in.location_dest_id: - if move_out.origin == move_in.origin: - move_in.write({'production_id': False}) - if move_out.picking_id.state != 'done': - raise UserError( - _('该入库单对应的单号为%s的出库单还未完成,不能进行验证操作!' % move_out.picking_id.name)) + if self.picking_type_id.barcode == 'OCOUT': + move_out = self.env['stock.move'].search( + [('location_id', '=', self.env['stock.location'].search( + [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), + ('location_dest_id', '=', self.env['stock.location'].search( + [('barcode', 'ilike', 'VL-SPOC')]).id), + ('origin', '=', self.origin)]) + move_in = self.env['stock.move'].search( + [('location_dest_id', '=', self.env['stock.location'].search( + [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), + ('location_id', '=', self.env['stock.location'].search( + [('barcode', 'ilike', 'VL-SPOC')]).id), + ('origin', '=', self.origin), ('picking_id', '=', self.id)]) + if self.location_id == move_in.location_id and self.location_dest_id == move_in.location_dest_id: + if move_out.origin == move_in.origin: + move_in.write({'production_id': False}) + if move_out.picking_id.state != 'done': + raise UserError( + _('该入库单对应的单号为%s的出库单还未完成,不能进行验证操作!' % move_out.picking_id.name)) res = super().button_validate() - if res is True: + if res is True and self.picking_type_id.barcode == 'OCIN': if self.id == move_out.picking_id.id: # if move_out.move_line_ids.workorder_id.state == 'progress': move_in = self.env['stock.move'].search( @@ -701,42 +650,43 @@ class StockPicking(models.Model): # 创建 外协出库入单 def create_outcontract_picking(self, sorted_workorders_arr, item): - m = 0 - for sorted_workorders in sorted_workorders_arr: - # pick_ids = [] - if m == 0: - outcontract_stock_move = self.env['stock.move'].search( - [('workorder_id', '=', sorted_workorders.id), ('production_id', '=', item.id)]) - if not outcontract_stock_move: - new_picking = True - location_id = self.env['stock.location'].search( - [('barcode', 'ilike', 'VL-SPOC')]).id, - location_dest_id = self.env['stock.location'].search( - [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id, - outcontract_picking_type_in = self.env.ref( - 'sf_manufacturing.outcontract_picking_in').id, - outcontract_picking_type_out = self.env.ref( - 'sf_manufacturing.outcontract_picking_out').id, - moves_out = self.env['stock.move'].sudo().create( - self.env['stock.move']._get_stock_move_values_Res(item, location_dest_id, location_id, - outcontract_picking_type_out)) - picking_out = self.create( - moves_out._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCOUT/')) - # pick_ids.append(picking_out.id) - moves_out.write( - {'picking_id': picking_out.id, 'state': 'waiting', 'workorder_id': sorted_workorders.id}) - moves_out._assign_picking_post_process(new=new_picking) - moves_in = self.env['stock.move'].sudo().create( - self.env['stock.move']._get_stock_move_values_Res(item, location_id, location_dest_id, - outcontract_picking_type_in)) - picking_in = self.create( - moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/')) - # pick_ids.append(picking_in.id) - moves_in.write( - {'picking_id': picking_in.id, 'state': 'waiting', 'workorder_id': sorted_workorders.id}) - moves_in._assign_picking_post_process(new=new_picking) - m += 1 - # sorted_workorders.write({'picking_ids': [(6, 0, pick_ids)]}) + if len(sorted_workorders_arr) > 1: + sorted_workorders_arr = sorted_workorders_arr[0] + stock_picking = self.env['stock.picking'].search( + [('origin', '=', sorted_workorders_arr.production_id.name), ('name', 'ilike', 'OCOUT')]) + if not stock_picking: + for sorted_workorders in sorted_workorders_arr: + # pick_ids = [] + if not sorted_workorders.picking_ids: + outcontract_stock_move = self.env['stock.move'].search([('production_id', '=', item.id)]) + if not outcontract_stock_move: + new_picking = True + location_id = self.env['stock.location'].search( + [('barcode', 'ilike', 'VL-SPOC')]).id, + location_dest_id = self.env['stock.location'].search( + [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id, + outcontract_picking_type_in = self.env.ref( + 'sf_manufacturing.outcontract_picking_in').id, + outcontract_picking_type_out = self.env.ref( + 'sf_manufacturing.outcontract_picking_out').id, + moves_out = self.env['stock.move'].sudo().create( + self.env['stock.move']._get_stock_move_values_Res(item, location_dest_id, location_id, + outcontract_picking_type_out)) + picking_out = self.create( + moves_out._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCOUT/')) + # pick_ids.append(picking_out.id) + moves_out.write( + {'picking_id': picking_out.id, 'state': 'waiting'}) + moves_out._assign_picking_post_process(new=new_picking) + moves_in = self.env['stock.move'].sudo().create( + self.env['stock.move']._get_stock_move_values_Res(item, location_id, location_dest_id, + outcontract_picking_type_in)) + picking_in = self.create( + moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/')) + # pick_ids.append(picking_in.id) + moves_in.write( + {'picking_id': picking_in.id, 'state': 'waiting'}) + moves_in._assign_picking_post_process(new=new_picking) class ReStockMove(models.Model): @@ -772,7 +722,7 @@ class ReStockMove(models.Model): return { 'name': self.env['stock.picking']._get_name_Res(rescode), 'origin': item.name, - 'surface_technics_parameters_id': sorted_workorders.surface_technics_parameters_id.id, + # 'surface_technics_parameters_id': sorted_workorders.surface_technics_parameters_id.id, 'company_id': self.mapped('company_id').id, 'user_id': False, 'move_type': self.mapped('group_id').move_type or 'direct', @@ -793,7 +743,7 @@ class ReStockMove(models.Model): 'picking_id': self.picking_id.id, 'reserved_uom_qty': 1.0, 'lot_id': production_id.move_line_raw_ids.lot_id.id, - 'company_id': self.company_id.id, + 'company_id': self.env.company.id, # 'workorder_id': '' if not sorted_workorders else sorted_workorders.id, # 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id, 'state': 'assigned', @@ -842,7 +792,6 @@ class ReStockMove(models.Model): elif self.product_id.tracking == "lot": self._put_tool_lot(self.company_id, self.product_id, self.origin) - return { 'name': _('Detailed Operations'), 'type': 'ir.actions.act_window', @@ -991,6 +940,11 @@ class ReStockMove(models.Model): move_lines_commands.append((0, 0, move_line_cmd)) qty_by_location[loc.id] += 1 return move_lines_commands + + # def _prepare_procurement_origin(self): + # """修改采购来源""" + # self.ensure_one() + # return self.group_id and self.group_id.name or (self.origin or self.picking_id.name or "/") class ReStockQuant(models.Model): diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index 693a39a2..b9d0710f 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -171,6 +171,9 @@ access_sf_technology_design_group_production_engineer,sf_technology_design_group 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 +access_sf_production_technology_re_adjust_wizard_group_plan_dispatch,sf_production_technology_re_adjust_wizard_group_plan_dispatch,model_sf_production_technology_re_adjust_wizard,sf_base.group_plan_dispatch,1,1,1,0 +access_sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,model_sf_production_technology_re_adjust_wizard,sf_base.group_sf_mrp_manager,1,1,1,0 +access_sf_production_technology_re_adjust_wizard_group_production_engineer,sf_production_technology_re_adjust_wizard_group_production_engineer,model_sf_production_technology_re_adjust_wizard,sf_base.group_production_engineer,1,1,1,0 access_sf_manual_product_model_type_routing_sort_group_sf_mrp_user,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_manual_product_model_type_routing_sort_manager,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0 diff --git a/sf_manufacturing/views/model_type_view.xml b/sf_manufacturing/views/model_type_view.xml index 56d5f94c..f0ffd81a 100644 --- a/sf_manufacturing/views/model_type_view.xml +++ b/sf_manufacturing/views/model_type_view.xml @@ -31,7 +31,7 @@ - + diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index ff492436..f88182cb 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -35,10 +35,10 @@ - + @@ -91,10 +91,13 @@ - - - + + + @@ -127,20 +130,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"/> - - - + + - {'invisible': ['|',('schedule_state', '=', '未排'),('workorder_ids', '=', - [])]} + {'invisible': [('workorder_ids', '=', [])]} @@ -352,23 +352,20 @@ - - - - + - + - + + + + + + + diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index c27f2175..bbda259c 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -250,7 +250,7 @@ - diff --git a/sf_manufacturing/wizard/__init__.py b/sf_manufacturing/wizard/__init__.py index b10ec066..e2206a5f 100644 --- a/sf_manufacturing/wizard/__init__.py +++ b/sf_manufacturing/wizard/__init__.py @@ -2,3 +2,4 @@ from . import workpiece_delivery_wizard from . import rework_wizard from . import production_wizard from . import production_technology_wizard +from . import production_technology_re_adjust_wizard diff --git a/sf_manufacturing/wizard/production_technology_re_adjust_wizard.py b/sf_manufacturing/wizard/production_technology_re_adjust_wizard.py new file mode 100644 index 00000000..93cd9db1 --- /dev/null +++ b/sf_manufacturing/wizard/production_technology_re_adjust_wizard.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +import logging +from itertools import groupby +from odoo import models, api, fields, _ + + +class ProductionTechnologyReAdjustWizard(models.TransientModel): + _name = 'sf.production.technology.re_adjust.wizard' + _description = '制造订单工艺调整' + + production_id = fields.Many2one('mrp.production', string='制造订单号') + origin = fields.Char(string='源单据') + is_technology_re_adjust = fields.Boolean(default=False) + + def confirm(self): + if self.is_technology_re_adjust is True: + domain = [('origin', '=', self.origin), ('state', '=', 'confirmed')] + else: + domain = [('id', '=', self.production_id.id)] + technology_designs = self.env['sf.technology.design'].sudo().search( + [('production_id', '=', self.production_id.id), ('active', 'in', [True, False])]) + productions = self.env['mrp.production'].search(domain) + for production_item in productions: + # 该制造订单的其他同一销售订单的制造订单的工艺设计处理 + if production_item != self.production_id: + for td_other in production_item.technology_design_ids: + if td_other.is_auto is False: + td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id) + if not td_del or td_del.active is False: + td_other.write({'active': False}) + for td_main in technology_designs: + route_other = production_item.technology_design_ids.filtered( + lambda td: td.route_id.id == td_main.route_id.id) + if not route_other and td_main.active is True: + production_item.write({'technology_design_ids': [(0, 0, { + 'route_id': td_main.route_id.id, + 'process_parameters_id': False if td_main.process_parameters_id is False else + self.env[ + 'sf.production.process.parameter'].search( + [('id', '=', td_main.process_parameters_id.id)]).id, + 'sequence': td_main.sequence, + 'is_auto': td_main.is_auto})]}) + else: + for ro in route_other: + domain = [('production_id', '=', self.production_id.id), ('active', 'in', [True, False]), + ('route_id', '=', ro.route_id.id)] + if ro.route_id.routing_type == '表面工艺': + domain += [('process_parameters_id', '=', ro.process_parameters_id.id)] + elif ro.route_id.routing_tag == 'special' and ro.is_auto is False: + display_name = ro.route_id.display_name + domain += [('name', 'ilike', display_name)] + elif ro.panel is not False: + domain += [('panel', '=', ro.panel)] + td_upd = self.env['sf.technology.design'].sudo().search(domain) + if td_upd: + ro.write({'sequence': td_upd.sequence, 'active': td_upd.active}) + special_design = self.env['sf.technology.design'].sudo().search( + [('routing_tag', '=', 'special'), ('production_id', '=', production_item.id), + ('is_auto', '=', False), ('active', 'in', [True, False])]) + for special in special_design: + workorders_values = [] + if special.active is False: + # 工单采购单外协出入库单皆需取消 + domain = [('production_id', '=', special.production_id.id)] + if special.process_parameters_id: + domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id)] + else: + domain += [('name', '=', special.route_id.name)] + workorder = self.env['mrp.workorder'].search(domain) + if workorder.state != 'cancel': + workorder.write({'state': 'cancel'}) + workorder.picking_ids.write({'state': 'cancel'}) + workorder.picking_ids.move_ids.write({'state': 'cancel'}) + purchase_order = self.env['purchase.order'].search( + [('origin', '=', workorder.production_id.origin)]) + for line in purchase_order.order_line: + if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id: + purchase_order.write({'state': 'cancel'}) + else: + if special.route_id.routing_type == '表面工艺': + display_name = special.process_parameters_id.display_name + else: + display_name = special.route_id.display_name + workorder = self.env['mrp.workorder'].search( + [('name', '=', display_name), ('production_id', '=', special.production_id.id)]) + if not workorder: + if special.route_id.routing_type == '表面工艺': + product_production_process = self.env['product.template'].search( + [('server_product_process_parameters_id', '=', special.process_parameters_id.id)]) + workorders_values.append( + self.env[ + 'mrp.workorder']._json_workorder_surface_process_str(special.production_id, special, + product_production_process.seller_ids[ + 0].partner_id.id)) + else: + workorders_values.append( + self.env['mrp.workorder'].json_workorder_str(special.production_id, special)) + special.production_id.write({'workorder_ids': workorders_values}) + else: + if len(workorder.blocked_by_workorder_ids) > 1: + if workorder.sequence == 1: + workorder.blocked_by_workorder_ids = None + else: + workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0] + productions._reset_work_order_sequence() + productions.get_subcontract_pick_purchase() + for item in productions: + workorders = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted( + key=lambda a: a.sequence) + workorders[0].state = 'waiting' diff --git a/sf_manufacturing/wizard/production_technology_re_adjust_wizard_views.xml b/sf_manufacturing/wizard/production_technology_re_adjust_wizard_views.xml new file mode 100644 index 00000000..48346cb2 --- /dev/null +++ b/sf_manufacturing/wizard/production_technology_re_adjust_wizard_views.xml @@ -0,0 +1,34 @@ + + + + sf.production.technology.re_adjust.wizard.form.view + sf.production.technology.re_adjust.wizard + + + + + + + + 当前制造订单,同一销售订单相同产品所生成的制造订单是否统一进行退回调整操作 + + + + + + + + + 工艺退回调整 + sf.production.technology.re_adjust.wizard + form + + + + new + + + \ No newline at end of file diff --git a/sf_manufacturing/wizard/production_technology_wizard.py b/sf_manufacturing/wizard/production_technology_wizard.py index 648ea24b..2293dc73 100644 --- a/sf_manufacturing/wizard/production_technology_wizard.py +++ b/sf_manufacturing/wizard/production_technology_wizard.py @@ -1,10 +1,7 @@ # -*- 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 itertools import groupby from odoo import models, api, fields, _ @@ -21,5 +18,47 @@ class ProductionTechnologyWizard(models.TransientModel): domain = [('origin', '=', self.origin)] else: domain = [('id', '=', self.production_id.id)] + technology_designs = self.production_id.technology_design_ids productions = self.env['mrp.production'].search(domain) - productions._create_workorder(self.production_id) + for production in productions: + if production != self.production_id: + for td_other in production.technology_design_ids: + if td_other.is_auto is False: + td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id) + if not td_del or td_del.active is False: + td_other.write({'active': False}) + for td_main in technology_designs: + route_other = production.technology_design_ids.filtered( + lambda td: td.route_id.id == td_main.route_id.id) + if not route_other and td_main.active is True: + production.write({'technology_design_ids': [(0, 0, { + 'route_id': td_main.route_id.id, + 'process_parameters_id': False if td_main.process_parameters_id is False else self.env[ + 'sf.production.process.parameter'].search( + [('id', '=', td_main.process_parameters_id.id)]).id, + 'sequence': td_main.sequence})]}) + else: + for ro in route_other: + domain = [('production_id', '=', self.production_id.id), + ('active', 'in', [True, False]), + ('route_id', '=', ro.route_id.id)] + if ro.route_id.routing_type == '表面工艺': + domain += [('process_parameters_id', '=', ro.process_parameters_id.id)] + elif ro.route_id.routing_tag == 'special' and ro.is_auto is False: + display_name = ro.route_id.display_name + domain += [('name', 'ilike', display_name)] + elif ro.panel is not False: + domain += [('panel', '=', ro.panel)] + td_upd = self.env['sf.technology.design'].sudo().search(domain) + if td_upd: + ro.write({'sequence': td_upd.sequence, 'active': td_upd.active}) + # special = production.technology_design_ids.filtered( + # lambda td: td.is_auto is False and td.process_parameters_id is not False) + # # if special: + productions._create_workorder(False) + productions.get_subcontract_pick_purchase() + for item in productions: + workorder = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted( + key=lambda a: a.sequence) + if workorder[0].state in ['pending']: + workorder[0].state = 'waiting' diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py index 39b4ad8a..5f5aee06 100644 --- a/sf_mrs_connect/controllers/controllers.py +++ b/sf_mrs_connect/controllers/controllers.py @@ -28,6 +28,8 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController): domain = [('programming_no', '=', ret['programming_no'])] if ret['manufacturing_type'] in ('scrap', 'invalid_tool_rework'): domain += [('state', 'not in', ['done', 'scrap', 'cancel'])] + else: + domain += [('state', '=', 'confirmed')] productions = request.env['mrp.production'].with_user( request.env.ref("base.user_admin")).search(domain) if productions: @@ -48,26 +50,21 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController): res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no']) return json.JSONEncoder().encode(res) for production in productions: - if not production.workorder_ids: - production.product_id.model_processing_panel = ret['processing_panel'] - production._create_workorder(ret) - productions.process_range_time() - else: - for panel in ret['processing_panel'].split(','): - # 查询状态为进行中且工序类型为CNC加工的工单 - cnc_workorder_has = production.workorder_ids.filtered( - lambda ach: ach.routing_type == 'CNC加工' and ach.state not in ['progress', 'done', - 'rework', - 'cancel'] and ach.processing_panel == panel) - if cnc_workorder_has: - if cnc_workorder_has.cnc_ids: - cnc_workorder_has.cmm_ids.sudo().unlink() - cnc_workorder_has.cnc_ids.sudo().unlink() - # request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan( - # production) - cnc_workorder_has.write( - {'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret), - 'cmm_ids': cnc_workorder_has.cmm_ids.sudo()._json_cmm_program(panel, ret)}) + for panel in ret['processing_panel'].split(','): + # 查询状态为进行中且工序类型为CNC加工的工单 + cnc_workorder_has = production.workorder_ids.filtered( + lambda ach: ach.routing_type == 'CNC加工' and ach.state not in ['progress', 'done', + 'rework', + 'cancel'] and ach.processing_panel == panel) + if cnc_workorder_has: + if cnc_workorder_has.cnc_ids: + cnc_workorder_has.cmm_ids.sudo().unlink() + cnc_workorder_has.cnc_ids.sudo().unlink() + # request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan( + # production) + cnc_workorder_has.write( + {'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret), + 'cmm_ids': cnc_workorder_has.cmm_ids.sudo()._json_cmm_program(panel, ret)}) for panel in ret['processing_panel'].split(','): # 查询状态为进行中且工序类型为CNC加工的工单 cnc_workorder = productions.workorder_ids.filtered( @@ -77,7 +74,6 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController): # program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test', # panel) program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel) - logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel) files_panel = os.listdir(program_path_tmp_panel) if files_panel: for file in files_panel: @@ -85,17 +81,13 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController): if file_extension.lower() == '.pdf': panel_file_path = os.path.join(program_path_tmp_panel, file) logging.info('panel_file_path:%s' % panel_file_path) - logging.info('更新工作指令:%s' % cnc_workorder) cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())}) - logging.info('更新工作指令完成:%s' % cnc_workorder) pre_workorder = productions.workorder_ids.filtered( lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done', 'rework' 'cancel'] and ap.processing_panel == panel) if pre_workorder: - logging.info('更新加工图纸:%s' % pre_workorder) pre_workorder.write( {'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())}) - logging.info('更新加工图纸完成:%s' % pre_workorder) productions.write({'programming_state': '已编程', 'work_state': '已编程'}) logging.info('已更新制造订单编程状态:%s' % productions.ids) res.update({ diff --git a/sf_mrs_connect/models/res_config_setting.py b/sf_mrs_connect/models/res_config_setting.py index 5243ccb2..eb853186 100644 --- a/sf_mrs_connect/models/res_config_setting.py +++ b/sf_mrs_connect/models/res_config_setting.py @@ -86,6 +86,8 @@ class ResConfigSettings(models.TransientModel): _logger.info("同步刀具物料每齿走刀量完成") self.env['sf.machining.accuracy'].sync_machining_accuracy_all() _logger.info("同步加工精度完成") + self.env['sf.embryo.redundancy'].sync_embryo_redundancy_all() + _logger.info("同步坯料冗余完成") except Exception as e: _logger.info("sf_all_sync error: %s" % e) diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py index 29d32e5f..835183b3 100644 --- a/sf_mrs_connect/models/sync_common.py +++ b/sf_mrs_connect/models/sync_common.py @@ -76,6 +76,8 @@ class MrStaticResourceDataSync(models.Model): _logger.info("同步刀具物料每齿走刀量完成") self.env['sf.machining.accuracy'].sync_machining_accuracy_all() _logger.info("同步加工精度完成") + self.env['sf.embryo.redundancy'].sync_embryo_redundancy_all() + _logger.info("同步坯料冗余完成") except Exception as e: traceback_error = traceback.format_exc() logging.error("同步静态资源库失败:%s" % traceback_error) @@ -3149,7 +3151,7 @@ class MachiningAccuracySync(models.Model): r = requests.post(strUrl, json={}, data=None, headers=headers) r = r.json() result = json.loads(r['result']) - _logger.info('加工精度:%s' % result) + # _logger.info('加工精度:%s' % result) if result['status'] == 1: machining_accuracy_all_list = result['machining_accuracy_all_list'] # 获取同步的id集合 @@ -3168,3 +3170,42 @@ class MachiningAccuracySync(models.Model): "name": time['name'], "standard_tolerance": time['standard_tolerance'], }) + +class EmbryoRedundancySync(models.Model): + _inherit = 'sf.embryo.redundancy' + _description = '坯料冗余' + url = '/api/embryo_redundancy/list' + + def sync_embryo_redundancy_all(self): + config = self.env['res.config.settings'].get_values() + headers = Common.get_headers(self, config['token'], config['sf_secret_key']) + strUrl = config['sf_url'] + self.url + r = requests.post(strUrl, json={}, data=None, headers=headers) + r = r.json() + result = json.loads(r['result']) + # _logger.info('加工精度:%s' % result) + if result['status'] == 1: + embryo_redundancy_all_list = result['embryo_redundancy_all_list'] + # 获取同步的id集合 + codes = [obj['code'] for obj in embryo_redundancy_all_list] + self.env['sf.embryo.redundancy'].sudo().search( + [('code', 'not in', codes)]).unlink() + for item in embryo_redundancy_all_list: + embryo_redundancy = self.env['sf.embryo.redundancy'].sudo().search( + [('code', '=', item['code'])]) + if embryo_redundancy: + embryo_redundancy.name = item['name'] + embryo_redundancy.code = item['code'] + embryo_redundancy.long = item['long'] + embryo_redundancy.width = item['width'] + embryo_redundancy.height = item['height'] + embryo_redundancy.active = item['active'] + else: + self.env['sf.embryo.redundancy'].sudo().create({ + "name": item['name'], + "code": item['code'], + "long": item['long'], + "width": item['width'], + "height": item['height'], + "active": item['active'], + }) \ No newline at end of file diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py index d8cbe1fd..e357f93e 100644 --- a/sf_plan/models/custom_plan.py +++ b/sf_plan/models/custom_plan.py @@ -93,7 +93,11 @@ class sf_production_plan(models.Model): @api.model def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None): - + """ + 修改搜索方法,只有制造订单状态为待排程时才显示 + """ + domain = domain or [] + domain.append(('production_id.state', 'not in', ['draft', 'technology_to_confirmed'])) info = super(sf_production_plan, self).search_read(domain, fields, offset, limit, order) return info @@ -417,12 +421,12 @@ class sf_production_plan(models.Model): raise UserError(e) # 增加制造订单类型 - # production_type = fields.Selection( - # [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')], - # string='制造类型', - # related='production_id.production_type', - # store=True - # ) + production_type = fields.Selection( + [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')], + string='制造类型', + related='production_id.production_type', + store=True + ) # 机台作业计划 @@ -446,8 +450,12 @@ class MrpProductionInheritForPlan(models.Model): def toggle_active(self): # 调用父类方法切换 active 状态 res = super(MrpProductionInheritForPlan, self).toggle_active() + stage_active = self.filtered('active') + stage_inactive = self - stage_active self.env['sf.production.plan'].search( - [('production_id', '=', self.id), '|', ('active', '=', False), ('active', '=', True)]).write( - {'active': self.active}) - + [('production_id', 'in', stage_active.ids)]).write( + {'active': True}) + self.env['sf.production.plan'].search( + [('production_id', 'in', stage_inactive.ids)]).write( + {'active': False}) return res diff --git a/sf_plan/views/view.xml b/sf_plan/views/view.xml index 58e7cea0..fad3d779 100644 --- a/sf_plan/views/view.xml +++ b/sf_plan/views/view.xml @@ -22,7 +22,7 @@ - + diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index ee22696b..5cc826eb 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -133,7 +133,7 @@ class ReSaleOrder(models.Model): 'product_uom_qty': item['number'], 'model_glb_file': base64.b64decode(item['model_file']), 'remark': item.get('remark'), - 'is_incoming_material': item.get('is_incoming_material'), + 'embryo_redundancy_id': item.get('embryo_redundancy_id'), 'manual_quotation': item.get('manual_quotation') } return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals) @@ -175,7 +175,8 @@ class ResaleOrderLine(models.Model): check_status = fields.Selection(related='order_id.check_status') remark = fields.Char('备注') - is_incoming_material = fields.Boolean('客供料', default=False) + # is_incoming_material = fields.Boolean('客供料', default=False) + embryo_redundancy_id = fields.Many2one('sf.embryo.redundancy', '坯料冗余') manual_quotation = fields.Boolean('人工编程', default=False) @api.depends('product_template_id') @@ -244,39 +245,39 @@ class RePurchaseOrder(models.Model): production_process = product_id_to_production_names.get( production.product_id.id) for pp in consecutive_process_parameters: - if pp.gain_way == '外协': - server_template = self.env['product.template'].search( - [('server_product_process_parameters_id', '=', pp.id), - ('detailed_type', '=', 'service')]) - purchase_order_line = self.env['purchase.order.line'].search( - [('product_id', '=', server_template.product_variant_id.id), - ('product_qty', '=', len(production_process))], limit=1, order='id desc') - if not purchase_order_line: - server_product_process.append((0, 0, { - 'product_id': server_template.product_variant_id.id, - 'product_qty': len(production_process), - 'product_uom': server_template.uom_id.id - })) - else: - for item in purchase_order_line: - if production.name in production_process: - purchase_order = self.env['purchase.order'].search( - [('state', '=', 'draft'), ('origin', '=', ','.join(production_process)), - ('id', '=', item.order_id.id)]) - if not purchase_order: - server_product_process.append((0, 0, { - 'product_id': server_template.product_variant_id.id, - 'product_qty': len(production_process), - 'product_uom': server_template.uom_id.id - })) + server_template = self.env['product.template'].search( + [('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id), + ('detailed_type', '=', 'service')]) + purchase_order_line = self.env['purchase.order.line'].search( + [('product_id', '=', server_template.product_variant_id.id), + ('product_qty', '=', len(production_process))], limit=1, order='id desc') + if not purchase_order_line: + server_product_process.append((0, 0, { + 'product_id': server_template.product_variant_id.id, + 'product_qty': len(production_process), + 'product_uom': server_template.uom_id.id + })) + else: + for item in purchase_order_line: + if production.name in production_process: + purchase_order = self.env['purchase.order'].search( + [('state', '=', 'draft'), ('origin', '=', ','.join(production_process)), + ('id', '=', item.order_id.id)]) + if not purchase_order: + server_product_process.append((0, 0, { + 'product_id': server_template.product_variant_id.id, + 'product_qty': len(production_process), + 'product_uom': server_template.uom_id.id + })) + if server_product_process: self.env['purchase.order'].sudo().create({ - 'partner_id': server_template.seller_ids.partner_id.id, + 'partner_id': server_template.seller_ids[0].partner_id.id, 'origin': ','.join(production_process), 'state': 'draft', 'purchase_type': 'consignment', 'order_line': server_product_process}) - # self.env.cr.commit() + # self.env.cr.commit() @api.onchange('order_line') def _onchange_order_line(self): diff --git a/sf_sale/views/sale_order_view.xml b/sf_sale/views/sale_order_view.xml index a5adfcfa..5da88398 100644 --- a/sf_sale/views/sale_order_view.xml +++ b/sf_sale/views/sale_order_view.xml @@ -119,7 +119,7 @@ - + {'readonly': [('state', 'in', ['cancel','sale'])]} @@ -167,7 +167,7 @@ - +