diff --git a/jikimo_frontend/static/src/scss/custom_style.scss b/jikimo_frontend/static/src/scss/custom_style.scss index 8eb76259..6904dbac 100644 --- a/jikimo_frontend/static/src/scss/custom_style.scss +++ b/jikimo_frontend/static/src/scss/custom_style.scss @@ -536,3 +536,7 @@ div:has(.o_required_modifier) > label::before { position: unset; } +// 修复搜索面板checkbox样式 +.o_search_panel .form-check .form-check-label span { + position: relative; +} \ No newline at end of file diff --git a/jikimo_hide_options/models/models.py b/jikimo_hide_options/models/models.py index 8f30543c..6386192d 100644 --- a/jikimo_hide_options/models/models.py +++ b/jikimo_hide_options/models/models.py @@ -190,7 +190,7 @@ def _create(self, data_list): # 如果该用户组被限制创建或更新操作 if rec['is_create_or_update']: raise UserError( - _("You are restricted from performing this operation. Please contact the administrator.")) + _("您没有执行此操作的权限。请联系管理员")) else: # 如果 'access.right' 模型不存在,可以在这里定义备选逻辑 # 例如,记录日志、发送通知或者简单地跳过这部分逻辑 diff --git a/jikimo_sale_multiple_supply_methods/__manifest__.py b/jikimo_sale_multiple_supply_methods/__manifest__.py index a7d39ac7..cfc56321 100644 --- a/jikimo_sale_multiple_supply_methods/__manifest__.py +++ b/jikimo_sale_multiple_supply_methods/__manifest__.py @@ -6,12 +6,11 @@ 'author': 'fox', 'website': '', 'category': '', - 'depends': ['sf_dlm', 'sale_stock', 'sf_sale'], + 'depends': ['sf_dlm', 'sale_stock', 'sf_sale', 'sale'], "data": [ 'security/ir.model.access.csv', 'data/stock_routes.xml', 'data/product_data.xml', - 'views/sale_order_views.xml', # 'views/product_product_views.xml', ],'assets': { # 'web.assets_backend': [ diff --git a/jikimo_sale_multiple_supply_methods/controllers/__init__.py b/jikimo_sale_multiple_supply_methods/controllers/__init__.py index cd4d6a8b..40a96afc 100644 --- a/jikimo_sale_multiple_supply_methods/controllers/__init__.py +++ b/jikimo_sale_multiple_supply_methods/controllers/__init__.py @@ -1,2 +1 @@ # -*- coding: utf-8 -*- -from . import main \ No newline at end of file diff --git a/jikimo_sale_multiple_supply_methods/models/__init__.py b/jikimo_sale_multiple_supply_methods/models/__init__.py index 6629e86d..0674dbe8 100644 --- a/jikimo_sale_multiple_supply_methods/models/__init__.py +++ b/jikimo_sale_multiple_supply_methods/models/__init__.py @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- from . import product_template -from . import sale_order from . import mrp_bom diff --git a/sf_dlm/models/stock_rule_inherit.py b/sf_dlm/models/stock_rule_inherit.py index b1e5b911..4a40ca2f 100644 --- a/sf_dlm/models/stock_rule_inherit.py +++ b/sf_dlm/models/stock_rule_inherit.py @@ -44,7 +44,7 @@ class StockRuleInherit(models.Model): po = self.env['purchase.order'].sudo().search([ ('partner_id', '=', supplier.partner_id.id), ('company_id', '=', procurement.company_id.id), # 保证公司一致 - ('origin', '=', procurement.origin), # 根据来源匹配 + ('origin', 'like', procurement.origin), # 根据来源匹配 ('state', '=', 'draft') # 状态为草稿 ], limit=1) logging.info("po=: %s", po) diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 35620913..991b26ab 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -37,6 +37,7 @@ 'views/agv_setting_views.xml', 'views/sf_maintenance_equipment.xml', 'views/res_config_settings_views.xml', + 'views/sale_order_views.xml', ], 'assets': { diff --git a/sf_manufacturing/controllers/__init__.py b/sf_manufacturing/controllers/__init__.py index 4d20cb33..4b95e252 100644 --- a/sf_manufacturing/controllers/__init__.py +++ b/sf_manufacturing/controllers/__init__.py @@ -1,2 +1,3 @@ from . import controllers from . import workpiece +from . import main diff --git a/jikimo_sale_multiple_supply_methods/controllers/main.py b/sf_manufacturing/controllers/main.py similarity index 100% rename from jikimo_sale_multiple_supply_methods/controllers/main.py rename to sf_manufacturing/controllers/main.py diff --git a/sf_manufacturing/models/__init__.py b/sf_manufacturing/models/__init__.py index b0c295f5..9f77d841 100644 --- a/sf_manufacturing/models/__init__.py +++ b/sf_manufacturing/models/__init__.py @@ -13,3 +13,5 @@ from . import agv_scheduling from . import res_config_setting from . import sf_technology_design from . import sf_production_common +from . import sale_order +from . import quick_easy_order 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 21d4b8ee..4fc7fde0 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -788,7 +788,7 @@ class MrpProduction(models.Model): # 立即创建外协出入库单和采购订单 # self.env['stock.picking'].create_outcontract_picking(workorder, production) # self.env['purchase.order'].get_purchase_order(workorder, production, - # product_id_to_production_names) + # product_id_to_production_names) consecutive_workorders = [] # 处理最后一个组,即使它可能只有一个工作订单 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 d50b1df2..bab7e282 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -23,12 +23,15 @@ class ResMrpWorkOrder(models.Model): product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name') - product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True, - string="坯料长度(mm)") - product_tmpl_id_width = fields.Float(related='production_id.product_tmpl_id.width', readonly=True, store=True, - string="坯料宽度(mm)") - product_tmpl_id_height = fields.Float(related='production_id.product_tmpl_id.height', readonly=True, store=True, - string="坯料高度(mm)") + product_tmpl_id_length = fields.Float(string='坯料长度(mm)', related='material_length', readonly=True, store=False) + product_tmpl_id_width = fields.Float(string='坯料宽度(mm)', related='material_width', readonly=True, store=False) + product_tmpl_id_height = fields.Float(string='坯料高度(mm)', related='material_height', readonly=True, store=False) + # product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True, + # string="坯料长度(mm)") + # product_tmpl_id_width = fields.Float(related='production_id.product_tmpl_id.width', readonly=True, store=True, + # string="坯料宽度(mm)") + # product_tmpl_id_height = fields.Float(related='production_id.product_tmpl_id.height', readonly=True, store=True, + # string="坯料高度(mm)") product_tmpl_id_materials_id = fields.Many2one(related='production_id.product_tmpl_id.materials_id', readonly=True, store=True, check_company=True, string="材料") product_tmpl_id_materials_type_id = fields.Many2one(related='production_id.product_tmpl_id.materials_type_id', @@ -134,8 +137,10 @@ class ResMrpWorkOrder(models.Model): glb_file = fields.Binary("glb模型文件", related='production_id.model_file') is_subcontract = fields.Boolean(string='是否外协') surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数") - picking_ids = fields.Many2many('stock.picking', string='外协出入库单') - # purchase_id = fields.Many2one('purchase.order', string='外协采购单') + + picking_ids = fields.Many2many('stock.picking', string='外协出入库单', compute='_compute_surface_technics_picking_ids') + + purchase_id = fields.Many2many('purchase.order', string='外协采购单') surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids') surface_technics_purchase_count = fields.Integer("外协采购", compute='_compute_surface_technics_purchase_ids') @@ -239,13 +244,11 @@ class ResMrpWorkOrder(models.Model): 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)] - else: - domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)] + # if previous_workorder: + # if previous_workorder.supplier_id != workorder.supplier_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 @@ -269,65 +272,72 @@ 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), + ('state', '!=', 'cancel')] 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): - purchase_num += 1 - order.surface_technics_purchase_count = purchase_num + 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] - production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False) + # 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')] - purchase_orders = self.env['purchase.order'].search(domain) - purchase_orders_id = None - for line in purchase_orders.order_line: - if line.product_id.server_product_process_parameters_id == self.surface_technics_parameters_id: - if line.product_qty == len(production_no_remanufacture): - purchase_orders_id = line.order_id.id + purchase_orders_id = self._get_surface_technics_purchase_ids() result = { "type": "ir.actions.act_window", "res_model": "purchase.order", - "res_id": purchase_orders_id, + "res_id": purchase_orders_id.id, # "domain": [['id', 'in', self.purchase_id]], "name": _("Purchase Orders"), 'view_mode': 'form', } return result + + def _get_surface_technics_purchase_ids(self): + domain = [('origin', '=', self.production_id.name), ('purchase_type', '=', 'consignment')] + purchase_orders = self.env['purchase.order'].search(domain) + purchase_orders_id = self.env['purchase.order'] + 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 + return purchase_orders_id supplier_id = fields.Many2one('res.partner', string='外协供应商') equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True) @@ -1025,47 +1035,47 @@ class ResMrpWorkOrder(models.Model): 'production_id.programming_state') def _compute_state(self): # 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') - and workorder.blocked_by_workorder_ids.test_results not in ['报废', '返工']) - or (previous_workorder.state in ('done', 'cancel') - and not workorder.blocked_by_workorder_ids - and previous_workorder.test_results not in ['报废', '返工']) - ): - 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' + # 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') + # and workorder.blocked_by_workorder_ids.test_results not in ['报废', '返工']) + # or (previous_workorder.state in ('done', 'cancel') + # and not workorder.blocked_by_workorder_ids + # and previous_workorder.test_results not in ['报废', '返工']) + # ): + # 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' for workorder in self: # 如果工单的工序没有进行排序则跳出循环 @@ -1090,13 +1100,21 @@ class ResMrpWorkOrder(models.Model): and workorder.production_id.schedule_state == '已排' and len(workorder.production_id.picking_ids.filtered( lambda w: w.state not in ['done', 'cancel'])) == 0): - workorder.state = 'ready' + if workorder.is_subcontract is True: + purchase_orders_id = self._get_surface_technics_purchase_ids() + if purchase_orders_id.state == 'purchase': + workorder.state = 'ready' + continue + else: + workorder.state = 'waiting' + continue + else: + workorder.state = 'ready' continue # ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]========================== if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework' or workorder.production_id.schedule_state != '已排' - or len( - workorder.production_id.picking_ids.filtered(lambda w: w.state not in ['done', 'cancel'])) != 0 + or workorder.production_id.reservation_state not in ['assigned'] or workorder.production_id.workorder_ids.filtered( lambda wk: wk.sequence == workorder.sequence - 1).test_results in ['报废', '返工']): if workorder.state != 'waiting': @@ -1117,21 +1135,26 @@ class ResMrpWorkOrder(models.Model): if workorder.is_subcontract is False: workorder.state = 'ready' else: - production_programming = self.env['mrp.production'].search( - [('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] - purchase_orders = self.env['purchase.order'].search( - [('origin', 'ilike', ','.join(production_list))]) - for line in purchase_orders.order_line: - if ( - line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id - and line.product_qty == len(production_no_remanufacture)): - if all(pur_order.state == 'purchase' for pur_order in purchase_orders): - workorder.state = 'ready' - else: - workorder.state = 'waiting' + # production_programming = self.env['mrp.production'].search( + # [('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] + # purchase_orders = self.env['purchase.order'].search( + # [('origin', 'ilike', ','.join(production_list))]) + # for line in purchase_orders.order_line: + # if ( + # line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id + # and line.product_qty == len(production_no_remanufacture)): + # if all(pur_order.state == 'purchase' for pur_order in purchase_orders): + # workorder.state = 'ready' + # else: + # workorder.state = 'waiting' + purchase_orders_id = self._get_surface_technics_purchase_ids() + if purchase_orders_id: + workorder.state = 'ready' if purchase_orders_id.state == 'purchase' else 'waiting' + else: + workorder.state = 'waiting' # re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id), # ('processing_panel', '=', workorder.processing_panel), @@ -1194,6 +1217,10 @@ class ResMrpWorkOrder(models.Model): # 重写工单开始按钮方法 def button_start(self): + # 判断工单状态是否为等待组件 + if self.state in ['waiting', 'pending']: + raise UserError('制造订单【%s】缺少组件信息!' % self.production_id.name) + if self.routing_type == 'CNC加工': self.env['sf.production.plan'].sudo().search([('name', '=', self.production_id.name)]).write({ 'state': 'processing', @@ -1201,9 +1228,6 @@ 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: @@ -1240,15 +1264,33 @@ class ResMrpWorkOrder(models.Model): # 表面工艺外协出库单 if self.routing_type == '表面工艺': if self.is_subcontract is True: - 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.production_id.name)]) - if move_out.state != 'done': - move_out.write({'state': 'assigned', 'production_id': False}) - self.env['stock.move.line'].create(move_out.get_move_line(self.production_id, self)) + move_out = self.move_subcontract_workorder_ids[1] + # 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.production_id.name), ('state', 'not in', ['cancel', 'done'])]) + for mo in move_out: + if mo.state != 'done': + mo.write({'state': 'assigned', 'production_id': False}) + if not mo.move_line_ids: + self.env['stock.move.line'].create(mo.get_move_line(self.production_id, self)) + # product_qty = mo.product_uom._compute_quantity( + # mo.product_uom_qty, mo.product_id.uom_id, rounding_method='HALF-UP') + # available_quantity = self.env['stock.quant']._get_available_quantity( + # mo.product_id, + # mo.location_id, + # lot_id=mo.move_line_ids.lot_id, + # strict=False, + # ) + # mo._update_reserved_quantity( + # product_qty, + # available_quantity, + # mo.location_id, + # lot_id=mo.move_line_ids.lot_id, + # strict=False, + # ) # move_out._action_assign() if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress': @@ -1353,6 +1395,13 @@ class ResMrpWorkOrder(models.Model): picks = record.picking_ids.filtered(lambda p: p.state not in ('done')) if picks: raise UserError('请先完成该工单的工艺外协再进行操作') + # 表面工艺外协,最后一张工单 + workorders = self.production_id.workorder_ids + subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence') + if self == subcontract_workorders[-1]: + # 给下一个库存移动就绪 + self.move_subcontract_workorder_ids[0].move_dest_ids._action_done() + # self.production_id.button_mark_done() tem_date_planned_finished = record.date_planned_finished tem_date_finished = record.date_finished logging.info('routing_type:%s' % record.routing_type) @@ -1371,7 +1420,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 @@ -1388,19 +1437,20 @@ 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 record.process_state = '已完工' record.production_id.process_state = '已完工' - if record.routing_type in ['表面工艺']: - raw_move = self.env['stock.move'].sudo().search( - [('origin', '=', record.production_id.name), - ('procure_method', 'in', ['make_to_order', 'make_to_stock']), - ('state', '!=', 'done')]) - if raw_move: - raw_move.write({'state': 'done'}) + # if record.routing_type in ['表面工艺']: + # raw_move = self.env['stock.move'].sudo().search( + # [('origin', '=', record.production_id.name), + # ('procure_method', 'in', ['make_to_order', 'make_to_stock']), + # ('state', '!=', 'done')]) + # if raw_move: + # raw_move.write({'state': 'done'}) record.production_id.button_mark_done1() # record.production_id.state = 'done' @@ -1520,6 +1570,8 @@ class ResMrpWorkOrder(models.Model): 'default_confirm_button': '确认解除', # 'default_feeder_station_start_id': feeder_station_start_id, }} + + move_subcontract_workorder_ids = fields.One2many('stock.move', 'subcontract_workorder_id', string='组件') class CNCprocessing(models.Model): diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index f5f685aa..460fd994 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -859,12 +859,12 @@ class ResProductMo(models.Model): raise UserError('请先配置模型类型内的坯料冗余') vals = { 'name': '%s-%s-%s' % ('P', order_id.name, i), - '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) * ( + 'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long), + 'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width), + 'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height), + 'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * ( item['model_width'] + embryo_redundancy_id.width) * ( - item['model_height'] + embryo_redundancy_id.height), + 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'], @@ -907,6 +907,20 @@ class ResProductMo(models.Model): self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id, 'quality_standard', item['quality_standard_mimetype']) return copy_product_id + + def format_float(self, value): + # 将浮点数转换为字符串 + value_str = str(value) + # 检查小数点的位置 + if '.' in value_str: + # 获取小数部分 + decimal_part = value_str.split('.')[1] + # 判断小数位数是否超过2位 + if len(decimal_part) > 2: + # 超过2位则保留2位小数 + return "{:.2f}".format(value) + # 否则保持原来的位数 + return float(value_str) def _get_ids(self, param): type_ids = [] diff --git a/jikimo_sale_multiple_supply_methods/models/quick_easy_order.py b/sf_manufacturing/models/quick_easy_order.py similarity index 100% rename from jikimo_sale_multiple_supply_methods/models/quick_easy_order.py rename to sf_manufacturing/models/quick_easy_order.py diff --git a/jikimo_sale_multiple_supply_methods/models/sale_order.py b/sf_manufacturing/models/sale_order.py similarity index 98% rename from jikimo_sale_multiple_supply_methods/models/sale_order.py rename to sf_manufacturing/models/sale_order.py index b7e25835..a56721a2 100644 --- a/jikimo_sale_multiple_supply_methods/models/sale_order.py +++ b/sf_manufacturing/models/sale_order.py @@ -43,6 +43,8 @@ class SaleOrder(models.Model): # 复制成品模板上的属性 line.product_id.product_tmpl_id.copy_template(product_template_id) + # 将模板上的single_manufacturing属性复制到成品上 + line.product_id.single_manufacturing = product_template_id.single_manufacturing order_id = self product = line.product_id 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/sf_technology_design.py b/sf_manufacturing/models/sf_technology_design.py index a38e7897..392aa021 100644 --- a/sf_manufacturing/models/sf_technology_design.py +++ b/sf_manufacturing/models/sf_technology_design.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -from odoo import fields, models +from odoo import fields, models, api, _ +from odoo.exceptions import ValidationError class sf_technology_design(models.Model): @@ -29,3 +30,11 @@ class sf_technology_design(models.Model): def unlink_technology_design(self): self.active = False + + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if not vals.get('route_id'): + raise ValidationError(_("工序不能为空")) + return super(sf_technology_design, self).create(vals_list) diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index ba4908a3..54d58234 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -283,24 +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: - # 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', - }) - technology_design_values = [] + # 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', + }) 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对应的生产订单名称列表 @@ -310,6 +310,7 @@ class StockRule(models.Model): # 为同一个product_id创建一个生产订单名称列表 product_id_to_production_names[product_id] = [production.name for production in all_production] for production_item in productions: + technology_design_values = [] production_programming = self.env['mrp.production'].search( [('product_id.id', '=', production_item.product_id.id), ('origin', '=', production_item.origin)], @@ -317,77 +318,76 @@ class StockRule(models.Model): 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_item.programming_no and production_item.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 == '成品': - # 根据加工面板的面数及成品工序模板生成工序设计 - if production_item.production_type == '自动化产线加工': - model = 'sf.product.model.type.routing.sort' - domain = [ - ('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)] - else: - model = 'sf.manual.product.model.type.routing.sort' - domain = [('manual_product_model_type_id', '=', - production_item.product_id.product_model_type_id.id)] - product_routing_workcenter = self.env[model].search(domain, order='sequence asc') - if production_item.production_type == '自动化产线加工': - for k in (production_item.product_id.model_processing_panel.split(',')): - 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)) - else: + i = 0 + if production_item.product_id.categ_id.type == '成品': + # 根据加工面板的面数及成品工序模板生成工序设计 + if production_item.production_type == '自动化产线加工': + model = 'sf.product.model.type.routing.sort' + domain = [ + ('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)] + else: + model = 'sf.manual.product.model.type.routing.sort' + domain = [('manual_product_model_type_id', '=', + production_item.product_id.product_model_type_id.id)] + product_routing_workcenter = self.env[model].search(domain, order='sequence asc') + if production_item.production_type == '自动化产线加工': + for k in (production_item.product_id.model_processing_panel.split(',')): for route in product_routing_workcenter: i += 1 technology_design_values.append( - self.env['sf.technology.design'].json_technology_design_str(False, route, i, False)) - elif production_item.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: + self.env['sf.technology.design'].json_technology_design_str(k, route, i, False)) + else: + for route in product_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 + self.env['sf.technology.design'].json_technology_design_str(False, route, i, False)) + elif production_item.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)) + production_item.technology_design_ids = technology_design_values productions.write({'state': 'technology_to_confirmed'}) return True @@ -423,6 +423,8 @@ class ProductionLot(models.Model): """Generate `lot_names` from a string.""" if first_lot.__contains__(display_name): first_lot = first_lot[(len(display_name) + 1):] + else: + first_lot = first_lot[-3:] # We look if the first lot contains at least one digit. caught_initial_number = regex_findall(r"\d+", first_lot) @@ -633,80 +635,79 @@ class StockPicking(models.Model): return '%s%s' % (rescode, num) def button_validate(self): - 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 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( - [('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)]) - production = self.env['mrp.production'].search([('name', '=', self.origin)]) - if move_in.state != 'done': - move_in.write({'state': 'assigned'}) - self.env['stock.move.line'].create(move_in.get_move_line(production, None)) - + picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id + if res is True and self.picking_type_id.id == picking_type_in: + # 如果是最后一张外协入库单,则设置库存位置的预留数量 + move_in = self.move_ids + if move_in: + workorder = move_in.subcontract_workorder_id + workorders = workorder.production_id.workorder_ids + subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence') + if workorder == subcontract_workorders[-1]: + self.env['stock.quant']._update_reserved_quantity( + move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty, lot_id=move_in.move_line_ids.lot_id, + package_id=False, owner_id=False, strict=False + ) + return res # 创建 外协出库入单 - def create_outcontract_picking(self, sorted_workorders_arr, item): - 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: - 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) + def create_outcontract_picking(self, workorders, item, sorted_workorders): + for workorder in workorders: + if workorder.move_subcontract_workorder_ids: + workorder.move_subcontract_workorder_ids.write({'state': 'draft'}) + workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'draft'}) + else: + # 创建一个新的补货组 + procurement_group_id = self.env['procurement.group'].create({ + 'name': workorder.name, + 'partner_id': self.partner_id.id, + }) + move_dest_id = False + # 如果当前工单是是制造订单的最后一个工单 + if workorder == item.workorder_ids[-1]: + move_dest_id = item.move_raw_ids[0].id + else: + # 从sorted_workorders中找到上一工单的move + if sorted_workorders.index(workorder) > 0: + move_dest_id = sorted_workorders[sorted_workorders.index(workorder) - 1].move_subcontract_workorder_ids[1].id + new_picking = True + 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_in = self.env['stock.move'].sudo().create( + self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in, procurement_group_id.id, move_dest_id)) + picking_in = self.create( + moves_in._get_new_picking_values_Res(item, workorder, '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) + moves_out = self.env['stock.move'].sudo().create( + self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out, procurement_group_id.id, moves_in.id)) + workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]}) + picking_out = self.create( + moves_out._get_new_picking_values_Res(item, workorder, '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) + + + @api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id') + def _compute_state(self): + super(StockPicking, self)._compute_state() + for picking in self: + # 外协出库单根据工单状态,采购单状态来确定 + picking_type_id = self.env.ref('sf_manufacturing.outcontract_picking_out').id + if picking.picking_type_id.id == picking_type_id: + if picking.move_ids: + workorder = picking.move_ids[0].subcontract_workorder_id + if picking.state == 'assigned': + if workorder.state in ['pending', 'waiting'] or workorder._get_surface_technics_purchase_ids().state in ['draft', 'sent']: + picking.state = 'waiting' class ReStockMove(models.Model): @@ -716,17 +717,20 @@ class ReStockMove(models.Model): materiel_width = fields.Float(string='物料宽度', digits=(16, 4)) materiel_height = fields.Float(string='物料高度', digits=(16, 4)) - def _get_stock_move_values_Res(self, item, location_src_id, location_dest_id, picking_type_id): - route = self.env['stock.route'].sudo().search([('name', '=', '表面工艺外协')]) + def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False): + route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id + stock_rule = self.env['stock.rule'].sudo().search([('route_id', '=', route_id), ('picking_type_id', '=', picking_type_id)]) move_values = { 'name': '推', 'company_id': item.company_id.id, 'product_id': item.bom_id.bom_line_ids.product_id.id, 'product_uom': item.bom_id.bom_line_ids.product_uom_id.id, 'product_uom_qty': 1.0, - 'location_id': location_src_id, - 'location_dest_id': location_dest_id, + 'location_id': stock_rule.location_src_id.id, + 'location_dest_id': stock_rule.location_dest_id.id, 'origin': item.name, + 'group_id': group_id, + 'move_dest_ids': [(6, 0, [move_dest_ids])] if move_dest_ids else False, # 'route_ids': False if not route else [(4, route.id)], 'date_deadline': datetime.now(), 'picking_type_id': picking_type_id, @@ -750,7 +754,7 @@ class ReStockMove(models.Model): 'picking_type_id': picking_type_id, 'location_id': self.mapped('location_id').id, 'location_dest_id': self.mapped('location_dest_id').id, - 'state': 'confirmed', + 'state': 'waiting', } def get_move_line(self, production_id, sorted_workorders): @@ -966,7 +970,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)]) @@ -989,9 +993,12 @@ class ReStockMove(models.Model): 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)]) - res['origin'] = ','.join(productions.mapped('name')) + if productions.mapped('name'): + res['origin'] = ','.join(productions.mapped('name')) res['retrospect_ref'] = production.product_id.name return res + + subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True, index='btree_not_null') class ReStockQuant(models.Model): diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index 24c38570..2880e662 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -52,6 +52,7 @@ access_mrp_routing_workcenter_manager_group_sf_mrp_user,mrp.routing.workcenter.m access_mrp_bom_manager_group_sf_mrp_user,mrp.bom.manager,mrp.model_mrp_bom,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_line_manager_group_sf_mrp_user,mrp.bom.line.manager,mrp.model_mrp_bom_line,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_line_group_plan_director,mrp_bom_line_group_plan_director,mrp.model_mrp_bom_line,sf_base.group_plan_director,1,1,1,0 +access_mrp_bom_line_group_sf_stock_user,mrp_bom_line_group_sf_stock_user,mrp.model_mrp_bom_line,sf_base.group_sf_stock_user,1,1,1,0 access_mrp_bom_line_group_sale_director,mrp_bom_line_group_sale_director,mrp.model_mrp_bom_line,sf_base.group_sale_director,1,1,1,0 access_mrp_bom_line_group_sale_salemanager,mrp_bom_line_group_sale_salemanager,mrp.model_mrp_bom_line,sf_base.group_sale_salemanager,1,0,1,0 access_mrp_bom_line_group_purchase_director,mrp_bom_line_group_purchase_director,mrp.model_mrp_bom_line,sf_base.group_purchase_director,1,1,1,0 @@ -116,7 +117,7 @@ access_mrp_production_group_quality,mrp_production,model_mrp_production,sf_base. access_mrp_production_group_quality_director,mrp_production,model_mrp_production,sf_base.group_quality_director,1,1,0,0 access_mrp_workorder_group_quality,mrp_workorder,model_mrp_workorder,sf_base.group_quality,1,1,0,0 access_mrp_workorder_group_quality_director,mrp_workorder,model_mrp_workorder,sf_base.group_quality_director,1,1,0,0 -access_mrp_workorder,mrp_workorder,model_mrp_workorder,sf_base.group_plan_dispatch,1,1,0,0 +access_mrp_workorder,mrp_workorder,model_mrp_workorder,sf_base.group_plan_dispatch,1,1,1,0 access_sf_production_line_group_plan_dispatch,sf.production.line,model_sf_production_line,sf_base.group_plan_dispatch,1,0,0,0 access_sf_production_line_group_plan_director,sf.production.line,model_sf_production_line,sf_base.group_plan_director,1,1,1,0 access_sf_production_line,sf.production.line,model_sf_production_line,sf_maintenance.sf_group_equipment_user,1,1,1,0 @@ -166,10 +167,12 @@ access_sf_agv_scheduling_group_sf_mrp_manager,sf_agv_scheduling_group_sf_mrp_man access_sf_agv_scheduling_group_sf_equipment_user,sf_agv_scheduling_group_sf_equipment_user,model_sf_agv_scheduling,sf_base.group_sf_equipment_user,1,1,1,0 access_sf_technology_design_group_plan_dispatch,sf_technology_design_group_plan_dispatch,model_sf_technology_design,sf_base.group_plan_dispatch,1,1,1,0 -access_sf_technology_design_group_sf_mrp_manager,sf_technology_design_group_sf_mrp_manager,model_sf_technology_design,sf_base.group_sf_mrp_manager,1,1,1,0 +access_sf_technology_design_group_sf_mrp_manager,sf_technology_design_group_sf_mrp_manager,model_sf_technology_design,sf_base.group_sf_mrp_manager,1,0,0,0 access_sf_technology_design_group_production_engineer,sf_technology_design_group_production_engineer,model_sf_technology_design,sf_base.group_production_engineer,1,1,1,0 +access_sf_technology_design_group_sf_equipment_user,sf_technology_design_group_sf_equipment_user,model_sf_technology_design,sf_base.group_sf_equipment_user,1,0,0,0 +access_sf_technology_design_group_sf_order_user,sf_technology_design_group_sf_order_user,model_sf_technology_design,sf_base.group_sf_order_user,1,0,0,0 access_sf_production_technology_wizard_group_plan_dispatch,sf_production_technology_wizard_group_plan_dispatch,model_sf_production_technology_wizard,sf_base.group_plan_dispatch,1,1,1,0 -access_sf_production_technology_wizard_group_sf_mrp_manager,sf_production_technology_wizard_group_sf_mrp_manager,model_sf_production_technology_wizard,sf_base.group_sf_mrp_manager,1,1,1,0 +access_sf_production_technology_wizard_group_sf_mrp_manager,sf_production_technology_wizard_group_sf_mrp_manager,model_sf_production_technology_wizard,sf_base.group_sf_mrp_manager,1,0,0,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 diff --git a/sf_manufacturing/views/model_type_view.xml b/sf_manufacturing/views/model_type_view.xml index f0ffd81a..0f8b3085 100644 --- a/sf_manufacturing/views/model_type_view.xml +++ b/sf_manufacturing/views/model_type_view.xml @@ -31,7 +31,7 @@