diff --git a/jikimo_sale_multiple_supply_methods/__init__.py b/jikimo_sale_multiple_supply_methods/__init__.py index 74eea1d2..b02eeb6f 100644 --- a/jikimo_sale_multiple_supply_methods/__init__.py +++ b/jikimo_sale_multiple_supply_methods/__init__.py @@ -12,10 +12,6 @@ def _data_install(cr, registry): 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_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': '成品'}) - env.ref('sf_dlm.product_embryo_sf_outsource').product_tmpl_id.write({'categ_type': '坯料'}) - env.ref('sf_dlm.product_embryo_sf_purchase').product_tmpl_id.write({'categ_type': '坯料'}) # 为三步制造增加规则 warehouse = env['stock.warehouse'].search([('company_id', '=', env.company.id)], limit=1) diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 2bde02d9..35620913 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -2,7 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. { 'name': '机企猫智能工厂 制造管理', - 'version': '1.0', + 'version': '1.1', 'summary': '智能工厂制造模块', 'sequence': 1, 'description': """ diff --git a/sf_manufacturing/migrations/1.1/post-migrate.py b/sf_manufacturing/migrations/1.1/post-migrate.py new file mode 100644 index 00000000..0606049e --- /dev/null +++ b/sf_manufacturing/migrations/1.1/post-migrate.py @@ -0,0 +1,12 @@ +# migrations/1.1.0/post-migrate.py +from odoo import api, SUPERUSER_ID + +def migrate(cr, version): + # 获取环境 + env = api.Environment(cr, SUPERUSER_ID, {}) + + # 示例:添加新字段 + 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': '成品'}) + env.ref('sf_dlm.product_embryo_sf_outsource').product_tmpl_id.write({'categ_type': '坯料'}) + env.ref('sf_dlm.product_embryo_sf_purchase').product_tmpl_id.write({'categ_type': '坯料'}) \ No newline at end of file diff --git a/sf_manufacturing/models/model_type.py b/sf_manufacturing/models/model_type.py index 0dd272bd..1fe36b90 100644 --- a/sf_manufacturing/models/model_type.py +++ b/sf_manufacturing/models/model_type.py @@ -7,7 +7,7 @@ class ModelType(models.Model): name = fields.Char('名称') # embryo_tolerance = fields.Char('坯料容余') - embryo_tolerance_id = fields.Many2one('sf.embryo.redundancy', string='坯料容余') + 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 112a41ff..232b4907 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -309,8 +309,7 @@ class MrpProduction(models.Model): 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 == '未排': + if production.state in ['to_close', 'progress', 'technology_to_confirmed'] and production.schedule_state == '未排': if not production.workorder_ids or production.is_adjust is True: production.state = 'technology_to_confirmed' else: @@ -324,6 +323,8 @@ class MrpProduction(models.Model): production.state = 'pending_cam' elif production.state == 'confirmed' and production.is_adjust is True: production.state = 'technology_to_confirmed' + if production.state == 'confirmed' 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')): @@ -650,8 +651,8 @@ class MrpProduction(models.Model): if self.move_finished_ids.filtered(lambda m: m.product_id == self.product_id).move_line_ids: self.move_finished_ids.filtered( lambda m: m.product_id == self.product_id).move_line_ids.lot_id = self.lot_producing_id - if self.product_id.tracking == 'serial': - self._set_qty_producing() + # if self.product_id.tracking == 'serial': + # self._set_qty_producing() # 重载根据工序生成工单的程序:如果产品BOM中没有工序时, # 根据产品对应的模板类型中工序,去生成工单; @@ -691,7 +692,7 @@ class MrpProduction(models.Model): # # 根据工序设计生成工单 for route in production.technology_design_ids: workorder_has = self.env['mrp.workorder'].search( - [('name', '=', route.route_id.name), ('production_id', '=', production.id)]) + [('technology_design_id', '=', route.id), ('production_id', '=', production.id)]) if not workorder_has: if route.route_id.routing_type not in ['表面工艺']: workorders_values.append( @@ -842,7 +843,7 @@ class MrpProduction(models.Model): # workorder.picking_ids.move_ids = False workorder.picking_ids = False purchase_order = self.env['purchase.order'].search( - [('state', '=', 'draft'), ('origin', '=', ','.join(production_process)), + [('state', '=', 'draft'), ('origin', '=', item.name), ('purchase_type', '=', 'consignment')]) for line in purchase_order.order_line: server_template = self.env['product.template'].search( @@ -850,7 +851,7 @@ class MrpProduction(models.Model): ('detailed_type', '=', 'service')]) purchase_order_line = self.env['purchase.order.line'].search( [('product_id', '=', server_template.product_variant_id.id), ('id', '=', line.id), - ('product_qty', '=', len(production_process))], limit=1, order='id desc') + ('product_qty', '=', 1)], limit=1, order='id desc') if purchase_order_line: line.unlink() @@ -886,6 +887,14 @@ class MrpProduction(models.Model): and item.panel == work.processing_panel)) if td_ids: work.sequence = td_ids[0].sequence + cancel_work_ids = workorder_ids.filtered(lambda item: item.state in ('已取消', 'cancel')) + if cancel_work_ids: + sequence = max(workorder_ids.filtered(lambda item: item.state not in ('已取消', 'cancel')), + key=lambda w: w.sequence).sequence + for cw in cancel_work_ids: + cw.sequence = sequence + 1 + + def _reset_work_order_sequence_1(self): """ @@ -1137,13 +1146,13 @@ class MrpProduction(models.Model): if self.programming_state in ['已编程']: cloud_programming = self._cron_get_programming_state() result_ids = self.detection_result_ids.filtered(lambda dr: dr.handle_result == '待处理') - work_ids = [] + work_id_list = [] if result_ids: - for result_id in result_ids: - work_ids.append(self.workorder_ids.filtered( - lambda wk: (wk.name == result_id.routing_type - and wk.processing_panel == result_id.processing_panel - and wk.state == 'done')).id) + work_id_list = [self.workorder_ids.filtered( + lambda wk: (wk.name == result_id.routing_type and wk.processing_panel == result_id.processing_panel + and wk.state == 'done')).id + for result_id in result_ids] + return { 'name': _('返工'), 'type': 'ir.actions.act_window', @@ -1152,7 +1161,8 @@ class MrpProduction(models.Model): 'target': 'new', 'context': { 'default_production_id': self.id, - 'default_workorder_ids': work_ids, + 'default_workorder_ids': self.workorder_ids.ids, + 'default_hidden_workorder_ids': ','.join(map(str, work_id_list)) if work_id_list != [] else '', 'default_reprogramming_num': cloud_programming['reprogramming_num'], 'default_programming_state': cloud_programming['programming_state'], 'default_is_reprogramming': True if cloud_programming['programming_state'] in ['已下发'] else False @@ -1310,11 +1320,10 @@ class MrpProduction(models.Model): move = self.env['stock.move'].search([('origin', '=', productions.name)], order='id desc') for mo in move: domain = [] - if mo.procure_method == 'make_to_order' and mo.name != productions.name: - if mo.name == '/': - domain = [('barcode', '=', 'WH-PC'), ('sequence_code', '=', 'PC')] - elif mo.name == '拉': - domain = [('barcode', '=', 'WH-INTERNAL'), ('sequence_code', '=', 'INT')] + if mo.location_id.barcode == 'WH-POSTPRODUCTION' and mo.rule_id.picking_type_id.barcode == 'PC': + domain = [('barcode', '=', 'WH-PC'), ('sequence_code', '=', 'PC')] + elif mo.location_id.barcode == 'PL' and mo.rule_id.picking_type_id.barcode == 'INT': + domain = [('barcode', '=', 'WH-INTERNAL'), ('sequence_code', '=', 'INT')] if domain: picking_type = self.env['stock.picking.type'].search(domain) mo.write({'picking_type_id': picking_type.id}) @@ -1469,10 +1478,12 @@ class MrpProduction(models.Model): def action_view_purchase_orders(self): self.ensure_one() if self.product_id.product_tmpl_id.single_manufacturing == True: - production = self.env['mrp.production'].search([('origin', '=', self.origin), ('product_id', '=', self.product_id.id)], limit=1, order='id asc') + production = self.env['mrp.production'].search( + [('origin', '=', self.origin), ('product_id', '=', self.product_id.id)], limit=1, order='id asc') else: - production = self - purchase_order_ids = (production.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id | production.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids + production = self + purchase_order_ids = ( + production.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id | production.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id).ids action = { 'res_model': 'purchase.order', 'type': 'ir.actions.act_window', @@ -1490,6 +1501,7 @@ class MrpProduction(models.Model): }) return action + class sf_detection_result(models.Model): _name = 'sf.detection.result' _description = "检测结果" diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index 537c6fd5..e28bd091 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -86,9 +86,12 @@ class ResMrpRoutingWorkcenter(models.Model): @api.model def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): if self._context.get('production_id'): + route_ids = [] technology_design = self.env['sf.technology.design'].search( [('production_id', '=', self._context.get('production_id'))]) - route_ids = [t.route_id.id for t in technology_design] - domain = [('id', 'not in', route_ids)] + for t in technology_design.filtered(lambda a: a.routing_tag == 'special'): + if not t.process_parameters_id: + route_ids.append(t.route_id.surface_technics_id.id) + domain = [('id', 'not in', route_ids), ('routing_tag', '=', 'special')] return self._search(domain, limit=limit, access_rights_uid=name_get_uid) return super()._name_search(name, args, operator, limit, name_get_uid) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index e00aa1d3..ab4166ea 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -141,8 +141,8 @@ class ResMrpWorkOrder(models.Model): # 是否绑定托盘 is_trayed = fields.Boolean(string='是否绑定托盘', default=False) - tag_type = fields.Selection([("重新加工", "重新加工")], string="标签", tracking=True) + tag_type = fields.Selection([("重新加工", "重新加工")], string="标签", tracking=True) technology_design_id = fields.Many2one('sf.technology.design') def _compute_default_construction_period_status(self): @@ -235,15 +235,17 @@ class ResMrpWorkOrder(models.Model): for workorder in self: if workorder.routing_type == '表面工艺': domain = [('origin', '=', workorder.production_id.name), ('state', 'not in', ['cancel']), - ('partner_id', '!=', False)] + ('partner_id', '=', workorder.supplier_id.id)] previous_workorder = self.env['mrp.workorder'].search( [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), ('production_id', '=', workorder.production_id.id)]) if previous_workorder: if previous_workorder.supplier_id != workorder.supplier_id: - process_product = self.env['product.template']._get_process_parameters_product( - previous_workorder.surface_technics_parameters_id) - domain += [('partner_id', '=', process_product.partner_id.id)] + # process_product = self.env['product.template']._get_process_parameters_product( + # previous_workorder.surface_technics_parameters_id) + domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)] + else: + domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)] picking_ids = self.env['stock.picking'].search(domain, order='id asc') workorder.surface_technics_picking_count = len(picking_ids) workorder.picking_ids = picking_ids.ids @@ -267,52 +269,62 @@ class ResMrpWorkOrder(models.Model): @api.depends('state', 'production_id.name') def _compute_surface_technics_purchase_ids(self): for order in self: - if order.routing_type == '表面工艺': - 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] - production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False) + if order.routing_type == '表面工艺' and order.state not in ['cancel']: + # if order.production_id.production_type == '自动化产线加工': + # domain = [('programming_no', '=', order.production_id.programming_no)] + # else:buzhdiao + # 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] + # 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 = [('purchase_type', '=', 'consignment'), ('origin', '=', ','.join(production_list))] + domain = [('purchase_type', '=', 'consignment'), ('origin', '=', order.production_id.name)] purchase = self.env['purchase.order'].search(domain) + purchase_num = 0 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: - if line.product_qty == len(production_no_remanufacture): - order.surface_technics_purchase_count = len(purchase) + for po in purchase: + for line in po.order_line: + if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id: + if line.product_qty == 1: + purchase_num += 1 + order.surface_technics_purchase_count = purchase_num else: order.surface_technics_purchase_count = 0 def action_view_surface_technics_purchase(self): self.ensure_one() - 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] + # 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] + # production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False) # 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_type', '=', 'consignment')] + domain = [('origin', '=', self.production_id.name), ('purchase_type', '=', 'consignment')] purchase_orders = self.env['purchase.order'].search(domain) + purchase_orders_id = None + for po in purchase_orders: + for line in po.order_line: + if line.product_id.server_product_process_parameters_id == self.surface_technics_parameters_id: + if line.product_qty == 1: + purchase_orders_id = line.order_id.id result = { "type": "ir.actions.act_window", "res_model": "purchase.order", - "res_id": purchase_orders.id, + "res_id": purchase_orders_id, # "domain": [['id', 'in', self.purchase_id]], "name": _("Purchase Orders"), 'view_mode': 'form', @@ -1118,7 +1130,7 @@ class ResMrpWorkOrder(models.Model): if ( line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id and line.product_qty == len(production_no_remanufacture)): - if purchase_orders.state == 'purchase': + if all(pur_order.state == 'purchase' for pur_order in purchase_orders): workorder.state = 'ready' else: workorder.state = 'waiting' @@ -1191,13 +1203,19 @@ class ResMrpWorkOrder(models.Model): }) if self.sequence == 1: + # 判断工单状态是否为等待组件 + if self.state == 'waiting': + raise UserError('制造订单【%s】缺少组件信息!' % self.production_id.name) # 判断是否有坯料的序列号信息 boolean = False if self.production_id.move_raw_ids: - if self.production_id.move_raw_ids[0].move_line_ids: + if self.production_id.move_raw_ids[0].product_id.categ_type == '坯料': if self.production_id.move_raw_ids[0].move_line_ids: - if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name: - boolean = True + if self.production_id.move_raw_ids[0].move_line_ids: + if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name: + boolean = True + else: + boolean = True if not boolean: raise UserError('制造订单【%s】缺少组件的序列号信息!' % self.production_id.name) self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name @@ -1206,8 +1224,8 @@ class ResMrpWorkOrder(models.Model): cnc_workorder = self.search( [('production_id', '=', self.production_id.id), ('routing_type', '=', 'CNC加工')], limit=1, order='id asc') - if not cnc_workorder.cnc_ids: - raise UserError(_('该制造订单还未下发CNC程序,请稍后再试')) + # if not cnc_workorder.cnc_ids: + # raise UserError(_('该制造订单还未下发CNC程序,请稍后再试')) else: if self.production_id.tool_state in ['1', '2']: if self.production_id.tool_state == '1': @@ -1355,7 +1373,7 @@ class ResMrpWorkOrder(models.Model): # record.recreateManufacturingOrWorkerOrder() is_production_id = False rework_workorder = record.production_id.workorder_ids.filtered(lambda p: p.state == 'rework') - done_workorder = record.production_id.workorder_ids.filtered(lambda p1: p1.state == 'done') + done_workorder = record.production_id.workorder_ids.filtered(lambda p1: p1.state in ['done']) if (len(rework_workorder) + len(done_workorder) == len(record.production_id.workorder_ids)) or ( len(done_workorder) == len(record.production_id.workorder_ids)): is_production_id = True @@ -1372,7 +1390,8 @@ class ResMrpWorkOrder(models.Model): # workorder.rfid_code_old = rfid_code # workorder.rfid_code = False logging.info('workorder.rfid_code:%s' % workorder.rfid_code) - if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']: + # if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺', '切割']: + if is_production_id is True: logging.info('product_qty:%s' % record.production_id.product_qty) for move_raw_id in record.production_id.move_raw_ids: move_raw_id.quantity_done = move_raw_id.product_uom_qty diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index f5f685aa..6e211f09 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -884,7 +884,7 @@ class ResProductMo(models.Model): 'model_process_parameters_ids': [(6, 0, [])] if not item.get( 'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']), 'model_remark': item['remark'], - 'single_manufacturing': True, + 'single_manufacturing': False, 'default_code': '%s-%s' % (order_number, i), 'manual_quotation': item['manual_quotation'] or False, 'part_number': item.get('part_number') or '', diff --git a/sf_manufacturing/models/sf_production_common.py b/sf_manufacturing/models/sf_production_common.py index dc9ff2a3..113858c1 100644 --- a/sf_manufacturing/models/sf_production_common.py +++ b/sf_manufacturing/models/sf_production_common.py @@ -10,8 +10,14 @@ class SfProductionProcessParameter(models.Model): @api.model def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): if self._context.get('route_id'): + parameter = [] routing = self.env['mrp.routing.workcenter'].search([('id', '=', self._context.get('route_id'))]) - domain = [('process_id', '=', routing.surface_technics_id.id)] + technology_design = self.env['sf.technology.design'].search( + [('production_id', '=', self._context.get('production_id')), ('routing_tag', '=', 'special'), + ('route_id', '=', self._context.get('route_id'))]) + for t in technology_design: + if t.process_parameters_id: + parameter.append(t.process_parameters_id.id) + domain = [('process_id', '=', routing.surface_technics_id.id), ('id', 'not in', parameter)] return self._search(domain, limit=limit, access_rights_uid=name_get_uid) return super()._name_search(name, args, operator, limit, name_get_uid) - diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index fb42da12..853634f7 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -283,23 +283,24 @@ class StockRule(models.Model): sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) # 如果订单为空,则获取来源制造订单的销售单 if not sale_order: - mrp_production = self.env['mrp.production'].sudo().search([('name', '=', production.origin)], limit=1) + mrp_production = self.env['mrp.production'].sudo().search([('name', '=', production.origin)], + limit=1) if mrp_production: sale_order = self.env['sale.order'].sudo().search([('name', '=', mrp_production.origin)]) else: mrp_production = production - if sale_order: + # 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': mrp_production.origin, - 'product_qty': production.product_qty, - 'product_id': production.product_id.id, - 'state': 'draft', - }) + 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': mrp_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)} @@ -388,6 +389,7 @@ class StockRule(models.Model): i, process_parameter)) productions.technology_design_ids = technology_design_values + productions.write({'state': 'technology_to_confirmed'}) return True @@ -670,10 +672,14 @@ class StockPicking(models.Model): # 创建 外协出库入单 def create_outcontract_picking(self, sorted_workorders_arr, item): + domain = [('origin', '=', item.name), ('name', 'ilike', 'OCOUT')] if len(sorted_workorders_arr) > 1: sorted_workorders_arr = sorted_workorders_arr[0] - stock_picking = self.env['stock.picking'].search([('origin', '=', item.name), ('name', 'ilike', 'OCOUT')]) - if not stock_picking or sorted_workorders_arr: + else: + domain += [ + ('surface_technics_parameters_id', '=', sorted_workorders_arr[0].surface_technics_parameters_id.id)] + stock_picking = self.env['stock.picking'].search(domain) + if not stock_picking: for sorted_workorders in sorted_workorders_arr: # pick_ids = [] if not sorted_workorders.picking_ids: @@ -965,7 +971,7 @@ class ReStockMove(models.Model): 合并制造订单的完成move单据 """ res = super(ReStockMove, self)._merge_moves_fields() - if self[0].origin and self.picking_type_id.name in ['生产发料', '内部调拨']: + if self[0].origin and self.picking_type_id.name in ['生产发料', '内部调拨', '生产入库']: production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc') productions = self.env['mrp.production'].search( [('origin', '=', production.origin), ('product_id', '=', production.product_id.id)]) diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index 461c2321..5f9a7ef3 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -368,7 +368,8 @@ attrs="{'readonly': [('id', '!=', False)]}" options="{'no_create': True}"/> + string="参数" context="{'route_id':route_id,'production_id': production_id}" + options="{'no_create': True}"/> + attrs="{'invisible': [('surface_technics_purchase_count', '=', 0)]}">
diff --git a/sf_manufacturing/wizard/production_technology_re_adjust_wizard.py b/sf_manufacturing/wizard/production_technology_re_adjust_wizard.py index 746c953e..89ba95d0 100644 --- a/sf_manufacturing/wizard/production_technology_re_adjust_wizard.py +++ b/sf_manufacturing/wizard/production_technology_re_adjust_wizard.py @@ -49,8 +49,8 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel): 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)] + # display_name = ro.route_id.display_name + domain += [('id', '=', ro.id)] elif ro.panel is not False: domain += [('panel', '=', ro.panel)] td_upd = self.env['sf.technology.design'].sudo().search(domain) @@ -62,14 +62,23 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel): for special in special_design: workorders_values = [] if special.active is False: + is_cancel = 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)] + domain += [('technology_design_id', '=', special.id)] workorder = self.env['mrp.workorder'].search(domain) - if workorder.state != 'cancel': + previous_workorder = self.env['mrp.workorder'].search( + [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), + ('production_id', '=', workorder.production_id.id)]) + if previous_workorder: + if previous_workorder.supplier_id != workorder.supplier_id: + is_cancel = True + else: + is_cancel = True + if workorder.state != 'cancel' and is_cancel is True: workorder.write({'state': 'cancel'}) workorder.picking_ids.write({'state': 'cancel'}) workorder.picking_ids.move_ids.write({'state': 'cancel'}) @@ -79,12 +88,8 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel): 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)]) + [('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id)]) if not workorder: if special.route_id.routing_type == '表面工艺': product_production_process = self.env['product.template'].search( @@ -103,7 +108,8 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel): if workorder.sequence == 1: workorder.blocked_by_workorder_ids = None else: - workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0] + if workorder.blocked_by_workorder_ids: + workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0] productions._reset_work_order_sequence() if self.production_id.product_id.categ_id.type == '成品': productions._reset_subcontract_pick_purchase() @@ -113,5 +119,6 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel): workorders = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted( key=lambda a: a.sequence) if workorders[0].state in ['pending']: - if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': + if workorders[ + 0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': workorders[0].state = 'waiting' diff --git a/sf_manufacturing/wizard/production_technology_wizard.py b/sf_manufacturing/wizard/production_technology_wizard.py index 04f8f12a..d81a89a0 100644 --- a/sf_manufacturing/wizard/production_technology_wizard.py +++ b/sf_manufacturing/wizard/production_technology_wizard.py @@ -46,16 +46,68 @@ class ProductionTechnologyWizard(models.TransientModel): 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)] + # display_name = ro.route_id.display_name + domain += [('id', '=', ro.id)] 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: + special_design = self.env['sf.technology.design'].sudo().search( + [('routing_tag', '=', 'special'), ('production_id', '=', production.id), + ('is_auto', '=', False), ('active', 'in', [True, False])]) + for special in special_design: + workorders_values = [] + if special.active is False: + is_cancel = 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 += [('technology_design_id', '=', special.id)] + workorder = self.env['mrp.workorder'].search(domain) + previous_workorder = self.env['mrp.workorder'].search( + [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), + ('production_id', '=', workorder.production_id.id)]) + if previous_workorder: + if previous_workorder.supplier_id != workorder.supplier_id: + is_cancel = True + else: + is_cancel = True + if workorder.state != 'cancel' and is_cancel is True: + 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.production_id.workorder_ids: + workorder = self.env['mrp.workorder'].search( + [('technology_design_id', '=', special.id), ('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: + if workorder.blocked_by_workorder_ids: + workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0] productions._create_workorder(False) if self.production_id.product_id.categ_id.type == '成品': productions.get_subcontract_pick_purchase() @@ -65,4 +117,4 @@ class ProductionTechnologyWizard(models.TransientModel): key=lambda a: a.sequence) if workorder[0].state in ['pending']: if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': - workorders[0].state = 'waiting' + workorder[0].state = 'waiting' diff --git a/sf_manufacturing/wizard/rework_wizard.py b/sf_manufacturing/wizard/rework_wizard.py index 8a73ec57..bb787c11 100644 --- a/sf_manufacturing/wizard/rework_wizard.py +++ b/sf_manufacturing/wizard/rework_wizard.py @@ -15,8 +15,7 @@ class ReworkWizard(models.TransientModel): production_id = fields.Many2one('mrp.production', string='制造订单号') workorder_ids = fields.Many2many('mrp.workorder', 'rework_wizard_to_work_order', string='所有工单', domain="[('production_id', '=', production_id),('state','=','done')]") - hidden_workorder_ids = fields.Many2many('mrp.workorder', 'rework_wizard_to_work_order_hidden', - string='所有工单(hidden)') + hidden_workorder_ids = fields.Char('') rework_reason = fields.Selection( [("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"), @@ -52,9 +51,26 @@ class ReworkWizard(models.TransientModel): 'test_report': self.workorder_id.detection_report})]}) self.workorder_id.button_finish() else: - if self.workorder_ids: - rework_workorder_ids = self.production_id.workorder_ids.filtered( - lambda ap: ap.id in self.workorder_ids.ids) + if self.hidden_workorder_ids: + hidden_workorder_list = self.hidden_workorder_ids.split(',') + rework_workorder_ids = self.workorder_ids.filtered(lambda w: str(w.id) in hidden_workorder_list) + # 限制判断 + # 1、当制造订单内ZM面的工单都已完成时,返工勾选工序时只能勾选上ZM面的所有工序进行返工 + # 2、当FM工单在CNC工单进行选择返工,并将已全部完成的ZM面工序全部勾选上时,FM工单上所有的已完成的工单(装夹预调工单)也必须进行勾选 + # 获取已完成的标准工单 + done_normative_workorder_ids = self.workorder_ids.filtered( + lambda w: w.state == 'done' and w.processing_panel is not False) + # 获取需要返工的标准工单 + rework_normative_workorder_ids = rework_workorder_ids.filtered( + lambda w: w.processing_panel is not False) + if rework_normative_workorder_ids: + for rw in rework_normative_workorder_ids: + if len(done_normative_workorder_ids.filtered( + lambda w: w.processing_panel == rw.processing_panel)) == 3: + pass + else: + raise ValidationError('请选择返工工单!!!') + if rework_workorder_ids: clamp_workorder_ids = None if rework_workorder_ids: # 限制 diff --git a/sf_manufacturing/wizard/rework_wizard_views.xml b/sf_manufacturing/wizard/rework_wizard_views.xml index 4482fda7..05d1cc04 100644 --- a/sf_manufacturing/wizard/rework_wizard_views.xml +++ b/sf_manufacturing/wizard/rework_wizard_views.xml @@ -12,10 +12,15 @@ - + - + + + diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py index ac79ff8b..87aee0dd 100644 --- a/sf_mrs_connect/controllers/controllers.py +++ b/sf_mrs_connect/controllers/controllers.py @@ -32,6 +32,12 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController): domain += [('state', 'in', ['confirmed', 'pending_cam'])] productions = request.env['mrp.production'].with_user( request.env.ref("base.user_admin")).search(domain) + productions_technology_to_confirmed = request.env['mrp.production'].with_user( + request.env.ref("base.user_admin")).search( + [('programming_no', '=', ret['programming_no']), ('state', 'in', ['technology_to_confirmed'])]) + if productions_technology_to_confirmed: + res = {'status': -2, 'message': '查询到待工艺确认的制造订单'} + return json.JSONEncoder().encode(res) if productions: # 拉取所有加工面的程序文件 for r in ret['processing_panel'].split(','): diff --git a/sf_plan/models/custom_plan.py b/sf_plan/models/custom_plan.py index f0214c9a..e7785ad4 100644 --- a/sf_plan/models/custom_plan.py +++ b/sf_plan/models/custom_plan.py @@ -231,26 +231,42 @@ class sf_production_plan(models.Model): if not record.production_line_id: raise ValidationError("未选择生产线") else: - if record.production_id.workorder_ids: - last_cnc_start = record.date_planned_start if record.date_planned_start else datetime.now() - for item in record.production_id.workorder_ids: - if item.name == 'CNC加工': - # 将同一个面的所有工单筛选出来 - workorder_list = record.production_id.workorder_ids.filtered(lambda x: x.processing_panel == item.processing_panel) - routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( - [('name', '=', 'CNC加工')], limit=1) - # 设置一个小的开始时间 - item.date_planned_start = datetime.now() - timedelta(days=100) - item.date_planned_finished = last_cnc_start + timedelta( - minutes=routing_workcenter.time_cycle) - item.date_planned_start = last_cnc_start - record.sudo().production_id.plan_start_processing_time = item.date_planned_start - item.duration_expected = routing_workcenter.time_cycle - pre_duration , next_duration = record.calculate_plan_time(item, workorder_list) - record.date_planned_finished = item.date_planned_finished - # 计算下一个cnc工单的开始时间 - last_cnc_start = workorder_list[-1].date_planned_finished + timedelta(minutes=pre_duration) - # 没有工单也能排程 + # 自动化产线加工 + if record.production_id.production_type == '自动化产线加工': + if record.production_id.workorder_ids: + last_cnc_start = record.date_planned_start if record.date_planned_start else datetime.now() + for item in record.production_id.workorder_ids: + if item.name == 'CNC加工': + # 将同一个面的所有工单筛选出来 + workorder_list = record.production_id.workorder_ids.filtered(lambda x: x.processing_panel == item.processing_panel) + routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( + [('name', '=', 'CNC加工')], limit=1) + # 设置一个小的开始时间 + item.date_planned_start = datetime.now() - timedelta(days=100) + item.date_planned_finished = last_cnc_start + timedelta( + minutes=routing_workcenter.time_cycle) + item.date_planned_start = last_cnc_start + record.sudo().production_id.plan_start_processing_time = item.date_planned_start + item.duration_expected = routing_workcenter.time_cycle + pre_duration , next_duration = record.calculate_plan_time(item, workorder_list) + record.date_planned_finished = item.date_planned_finished + # 计算下一个cnc工单的开始时间 + last_cnc_start = workorder_list[-1].date_planned_finished + timedelta(minutes=pre_duration) + # 没有工单也能排程 + else: + # 人工线下加工只排第一张工单 + if record.production_id.workorder_ids: + item = record.production_id.workorder_ids[0] + last_wo_start = record.date_planned_start if record.date_planned_start else datetime.now() + routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( + [('name', '=', item.routing_type)], limit=1) + item.date_planned_start = datetime.now() - timedelta(days=100) + item.date_planned_finished = last_wo_start + timedelta( + minutes=routing_workcenter.time_cycle) + item.date_planned_start = last_wo_start + record.sudo().production_id.plan_start_processing_time = item.date_planned_start + item.duration_expected = routing_workcenter.time_cycle + record.calculate_plan_time(item, item) record.state = 'done' # record.production_id.schedule_state = '已排' record.sudo().production_id.schedule_state = '已排' diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index a73b0a35..9c0e0b09 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -250,35 +250,36 @@ class RePurchaseOrder(models.Model): server_product_process = [] production_process = product_id_to_production_names.get( production.product_id.id) + purchase_order = self.env['purchase.order'].search( + [('state', '=', 'draft'), ('origin', '=', production.name), + ('purchase_type', '=', 'consignment')], order='name asc') for pp in consecutive_process_parameters: 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: + if not purchase_order: server_product_process.append((0, 0, { 'product_id': server_template.product_variant_id.id, - 'product_qty': len(production_process), + 'product_qty': 1, 'product_uom': server_template.uom_id.id })) - else: - if production.name in production_process: - purchase_order = self.env['purchase.order'].search( - [('state', '=', 'draft'), ('origin', '=', ','.join(production_process)), - ('purchase_type', '=', 'consignment')]) - 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 - })) - + for purchase in purchase_order: + for po in purchase.order_line: + if server_template.server_product_process_parameters_id == pp.surface_technics_parameters_id: + purchase_order_line = self.env['purchase.order.line'].search( + [('product_id', '=', server_template.product_variant_id.id), + ('product_qty', '=', 1.0), ('id', '=', po.id)], limit=1, + order='id desc') + if not purchase_order_line and purchase not in purchase_order: + server_product_process.append((0, 0, { + 'product_id': server_template.product_variant_id.id, + 'product_qty': 1, + 'product_uom': server_template.uom_id.id + })) if server_product_process: self.env['purchase.order'].sudo().create({ 'partner_id': server_template.seller_ids[0].partner_id.id, - 'origin': ','.join(production_process), + 'origin': production.name, 'state': 'draft', 'purchase_type': 'consignment', 'order_line': server_product_process}) diff --git a/sf_tool_management/models/mrp_workorder.py b/sf_tool_management/models/mrp_workorder.py index 8fe9748e..25ccc460 100644 --- a/sf_tool_management/models/mrp_workorder.py +++ b/sf_tool_management/models/mrp_workorder.py @@ -221,5 +221,6 @@ class MrpProduction(models.Model): logging.info('调用CAM工单程序用刀计划创建方法!!!') self.env['sf.cam.work.order.program.knife.plan'].sudo().create_cam_work_plan(cnc_ids) if not invalid_tool and not missing_tool_1: + self.sudo().write({'tool_state': '0'}) logging.info('校验cnc用刀正常!!!') logging.info('工单cnc程序用刀校验完成!!!')