From 9f67dbe9aac41467f74d5eec893b10de7a994009 Mon Sep 17 00:00:00 2001 From: liaodanlong Date: Thu, 12 Dec 2024 16:06:55 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=B7=A5=E5=BA=8F=E5=A4=96=E5=8D=8F?= =?UTF-8?q?=E5=B7=A5=E5=8D=95=E6=B2=A1=E6=9C=89=E8=87=AA=E5=8A=A8=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E5=B7=A5=E5=8D=95=E5=BC=80=E5=A7=8B=E3=80=81=E7=BB=93?= =?UTF-8?q?=E6=9D=9F=E7=9A=84=E4=BC=98=E5=8C=96=E9=9C=80=E6=B1=82=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/__init__.py | 1 + sf_manufacturing/models/purchase_order.py | 31 +++++++++++++++++++ sf_manufacturing/models/stock.py | 37 +++++++++++++++-------- 3 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 sf_manufacturing/models/purchase_order.py diff --git a/sf_manufacturing/models/__init__.py b/sf_manufacturing/models/__init__.py index 9f77d841..c4d8ad94 100644 --- a/sf_manufacturing/models/__init__.py +++ b/sf_manufacturing/models/__init__.py @@ -15,3 +15,4 @@ from . import sf_technology_design from . import sf_production_common from . import sale_order from . import quick_easy_order +from . import purchase_order \ No newline at end of file diff --git a/sf_manufacturing/models/purchase_order.py b/sf_manufacturing/models/purchase_order.py new file mode 100644 index 00000000..e54e96bf --- /dev/null +++ b/sf_manufacturing/models/purchase_order.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from collections import defaultdict + +from odoo import api, fields, models, _ +from odoo.tools import OrderedSet + + +# _get_surface_technics_purchase_ids +class PurchaseOrder(models.Model): + _inherit = 'purchase.order' + + def button_confirm(self): + super().button_confirm() + workorders = self.env['mrp.workorder'].search([('purchase_id', '=', self.id)]) + for workorder in workorders: + if workorder.routing_type == '表面工艺' and workorder.is_subcontract is True: + move_out = workorder.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(workorder.production_id, workorder)) + return True diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index fbe3be8c..6506cc1a 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -644,12 +644,19 @@ class StockPicking(models.Model): 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]: + 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, + 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 ) - + workorder.button_finish() + picking_type_out = self.env.ref('sf_manufacturing.outcontract_picking_out').id + if res and self.picking_type_id.id == picking_type_out: + move_out = self.move_ids + if move_out: + workorder = move_out.subcontract_workorder_id + workorder.button_start() return res # 创建 外协出库入单 @@ -671,14 +678,16 @@ class StockPicking(models.Model): 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 + 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)) + 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) @@ -686,7 +695,8 @@ class StockPicking(models.Model): {'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)) + 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/')) @@ -694,8 +704,7 @@ class StockPicking(models.Model): 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() @@ -706,7 +715,9 @@ class StockPicking(models.Model): 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']: + if workorder.state in ['pending', + 'waiting'] or workorder._get_surface_technics_purchase_ids().state in [ + 'draft', 'sent']: picking.state = 'waiting' @@ -719,7 +730,8 @@ class ReStockMove(models.Model): 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)]) + 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, @@ -997,8 +1009,9 @@ class ReStockMove(models.Model): 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') + + subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True, + index='btree_not_null') class ReStockQuant(models.Model): From bdac1e7460e13f915ed5b065f754e378c8b985f0 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 20 Dec 2024 11:06:41 +0800 Subject: [PATCH 2/5] =?UTF-8?q?1=E3=80=81=E5=A4=84=E7=90=86=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E8=BF=94=E5=B7=A5=E6=97=B6=E5=B0=B1=E8=A7=A3=E9=99=A4?= =?UTF-8?q?rfid=E7=BB=91=E5=AE=9A=E9=97=AE=E9=A2=98=EF=BC=9B2=E3=80=81?= =?UTF-8?q?=E5=90=8C=E6=AD=A5bfm=E7=9A=84=E8=AE=A2=E5=8D=95=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=88=B0=E9=94=80=E5=94=AE=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_bf_connect/models/jd_eclp.py | 6 +++++ sf_manufacturing/models/mrp_workorder.py | 3 +-- sf_manufacturing/wizard/rework_wizard.py | 32 +++++++++++++----------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/sf_bf_connect/models/jd_eclp.py b/sf_bf_connect/models/jd_eclp.py index 58691ca0..aa27736c 100644 --- a/sf_bf_connect/models/jd_eclp.py +++ b/sf_bf_connect/models/jd_eclp.py @@ -151,6 +151,12 @@ class JdEclp(models.Model): _logger.info('准备调接口1') url1 = config['bfm_url_new'] + '/api/create/jd/order' requests.post(url1, json=json1, data=None) + # ===============修改销售订单状态为【物流中】=================== + item = self.env['sale.order'].sudo().search([('name', '=', self.origin)]) + if not item: + raise ValidationError('没有查询到订单号为【%s】的销售订单!' % self.origin) + else: + item.write({'state': 'physical_distribution'}) _logger.info('调用成功1') _logger.info('准备调接口2') json2 = { diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index e9a5c5d9..52fa30c8 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1423,8 +1423,7 @@ class ResMrpWorkOrder(models.Model): len(done_workorder) == len(record.production_id.workorder_ids)): is_production_id = True if record.routing_type in ['解除装夹'] or ( - record.is_rework is True and record.routing_type in ['装夹预调']) or ( - record.test_results in ['返工', '报废'] and record.routing_type in ['CNC加工']): + record.is_rework is True and record.routing_type in ['装夹预调']): for workorder in record.production_id.workorder_ids: if workorder.processing_panel == record.processing_panel: rfid_code = workorder.rfid_code diff --git a/sf_manufacturing/wizard/rework_wizard.py b/sf_manufacturing/wizard/rework_wizard.py index 1352e84d..fcafd490 100644 --- a/sf_manufacturing/wizard/rework_wizard.py +++ b/sf_manufacturing/wizard/rework_wizard.py @@ -85,7 +85,8 @@ class ReworkWizard(models.TransientModel): # 2、当FM工单在CNC工单进行选择返工,并将已全部完成的ZM面工序全部勾选上时,FM工单上所有的已完成的工单(装夹预调工单)也必须进行勾选 if not wk_ids.filtered(lambda wk: wk.name == '装夹预调' and wk.processing_panel == panel): if wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel): - sequence_max = wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel).sequence + sequence_max = wk_ids.filtered( + lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel).sequence for wk_id in wk_ids.filtered(lambda wk: wk.sequence < sequence_max): if len(wk_ids.filtered(lambda wk: wk.processing_panel == wk_id.processing_panel)) == 3: raise ValidationError( @@ -114,19 +115,17 @@ class ReworkWizard(models.TransientModel): else: raise ValidationError('请选择返工工单!!!') if rework_workorder_ids: - clamp_workorder_ids = None - if rework_workorder_ids: - # 限制 - # 1、单独返工CNC工单则不解绑托盘RFID,如单独返工装夹预调工单,则自动解绑托盘RFID; - # 2、返工CNC工单和装夹预调工单则自动解绑RFID - clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调') - if clamp_workorder_ids: - for clamp_workorder_id in clamp_workorder_ids: - self.production_id.workorder_ids.filtered( - lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write( - {'rfid_code': None}) - # 返工工单状态设置为【返工】 - rework_workorder_ids.write({'state': 'rework'}) + # 限制 + # 1、单独返工CNC工单则不解绑托盘RFID,如单独返工装夹预调工单,则自动解绑托盘RFID; + # 2、返工CNC工单和装夹预调工单则自动解绑RFID + clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调') + if clamp_workorder_ids: + for clamp_workorder_id in clamp_workorder_ids: + self.production_id.workorder_ids.filtered( + lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write( + {'rfid_code': None}) + # 返工工单状态设置为【返工】 + rework_workorder_ids.write({'state': 'rework'}) # 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单 workorders_values = [] for work in rework_workorder_ids: @@ -147,6 +146,11 @@ class ReworkWizard(models.TransientModel): new_pre_workorder_ids = self.production_id.workorder_ids.filtered( lambda kw: kw.routing_type == '装夹预调' and kw.sequence == 0) self.production_id._reset_work_order_sequence() + # ====新工单绑定rfid=== + for new_work_id in new_work_ids: + if new_work_id.routing_type in ['CNC加工', '解除装夹']: + new_work_id.write({'rfid_code': self.production_id.workorder_ids.filtered( + lambda wk: wk.sequence == new_work_id.sequence - 1).rfid_code}) self.production_id.detection_result_ids.filtered( lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'}) panels = [] # 返工的加工面 From f2e8d0175bc17af5ddd4c3cb267ffc110ae66bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Dec 2024 12:51:42 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=B7=A5=E5=BA=8F?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E6=8E=92=E9=99=A4=E5=B7=B2=E7=BB=8F=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E7=9A=84=E5=B7=A5=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/model_type.py | 2 +- sf_manufacturing/models/mrp_routing_workcenter.py | 6 ++++++ sf_manufacturing/views/model_type_view.xml | 8 ++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/sf_manufacturing/models/model_type.py b/sf_manufacturing/models/model_type.py index 1fe36b90..601c34e8 100644 --- a/sf_manufacturing/models/model_type.py +++ b/sf_manufacturing/models/model_type.py @@ -75,7 +75,7 @@ class ManualProductModelTypeRoutingSort(models.Model): _description = '成品工序排序(人工线下加工)' sequence = fields.Integer('Sequence') - route_workcenter_id = fields.Many2one('mrp.routing.workcenter') + route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['人工线下加工'])]) is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat') routing_type = fields.Selection(string="工序类型", related='route_workcenter_id.routing_type') workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids') diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index e28bd091..e09b0aa5 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -94,4 +94,10 @@ class ResMrpRoutingWorkcenter(models.Model): 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) + if self._context.get('is_duplicate') and self._context.get('model_type'): + # 查询出已经选择的工序 + model_type = self.env[self._context.get('model_type')].search_read([],['route_workcenter_id']) + route_workcenter_ids = [item['route_workcenter_id'][0] if item['route_workcenter_id'] else False for item in model_type] + domain = args + [('id', 'not in', route_workcenter_ids)] + 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/views/model_type_view.xml b/sf_manufacturing/views/model_type_view.xml index 0f8b3085..d3f90fd7 100644 --- a/sf_manufacturing/views/model_type_view.xml +++ b/sf_manufacturing/views/model_type_view.xml @@ -37,7 +37,7 @@ - + @@ -48,7 +48,7 @@ - + @@ -59,7 +59,7 @@ - + @@ -70,7 +70,7 @@ - + From 2a20d54530dd36a2fc488f90efa65c7c6d343627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Dec 2024 13:02:10 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=B7=A5=E5=BA=8F?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E6=8E=92=E9=99=A4=E5=B7=B2=E7=BB=8F=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E7=9A=84=E5=B7=A5=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/mrp_routing_workcenter.py | 4 ++-- sf_manufacturing/views/model_type_view.xml | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sf_manufacturing/models/mrp_routing_workcenter.py b/sf_manufacturing/models/mrp_routing_workcenter.py index e09b0aa5..27c8e9d2 100644 --- a/sf_manufacturing/models/mrp_routing_workcenter.py +++ b/sf_manufacturing/models/mrp_routing_workcenter.py @@ -94,9 +94,9 @@ class ResMrpRoutingWorkcenter(models.Model): 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) - if self._context.get('is_duplicate') and self._context.get('model_type'): + if self._context.get('is_duplicate') and self._context.get('model_name'): # 查询出已经选择的工序 - model_type = self.env[self._context.get('model_type')].search_read([],['route_workcenter_id']) + model_type = self.env[self._context.get('model_name')].search_read([],['route_workcenter_id']) route_workcenter_ids = [item['route_workcenter_id'][0] if item['route_workcenter_id'] else False for item in model_type] domain = args + [('id', 'not in', route_workcenter_ids)] return self._search(domain, limit=limit, access_rights_uid=name_get_uid) diff --git a/sf_manufacturing/views/model_type_view.xml b/sf_manufacturing/views/model_type_view.xml index d3f90fd7..f4c1f994 100644 --- a/sf_manufacturing/views/model_type_view.xml +++ b/sf_manufacturing/views/model_type_view.xml @@ -3,7 +3,7 @@ #------------------模型类型------------------ - + search.sf.model.type sf.model.type @@ -14,7 +14,7 @@ - + tree.sf.model.type sf.model.type @@ -24,7 +24,7 @@ - + form.sf.model.type sf.model.type @@ -37,7 +37,7 @@ - + @@ -48,7 +48,7 @@ - + @@ -59,7 +59,7 @@ - + @@ -70,7 +70,7 @@ - + @@ -81,7 +81,7 @@ - + 模型类型 ir.actions.act_window sf.model.type @@ -96,11 +96,11 @@ \ No newline at end of file From c8df5ed1794653af65108c57b88c4fbc31cb678c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Fri, 20 Dec 2024 14:16:25 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E5=B7=A5=E8=89=BA?= =?UTF-8?q?=E5=A4=96=E5=8D=8F=E5=B7=A5=E5=BA=8F=E9=87=87=E8=B4=AD=E5=8D=95?= =?UTF-8?q?=E5=B7=B2=E5=88=9B=E5=BB=BA=E8=B4=A6=E5=8D=95=E5=B9=B6=E4=B8=94?= =?UTF-8?q?=E8=BF=87=E8=B4=A6=EF=BC=8C=E9=80=80=E5=9B=9E=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=90=8E=E6=8A=A5=E9=94=99=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 7bfc0abb..4d8f11df 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -440,6 +440,18 @@ class MrpProduction(models.Model): process_parameters = [] account_moves = [] parameters_not = [] + # 获取原有的工单对应的工序 + origin_designs = self.workorder_ids.technology_design_id + # 获取已删除的工序 + deleted_designs = origin_designs - self.technology_design_ids + if deleted_designs: + for deleted_design in deleted_designs: + workorder = self.env['mrp.workorder'].search([('technology_design_id', '=', deleted_design.id)]) + purchase = workorder._get_surface_technics_purchase_ids() + account = self.env['account.move'].search([('id', 'in', purchase.invoice_ids.ids)]) + if account.state not in ['cancel', False]: + if purchase.name not in account_moves: + account_moves.append(purchase.name) special_design = self.technology_design_ids.filtered( lambda a: a.routing_tag == 'special' and a.is_auto is False) for special in special_design: @@ -451,11 +463,7 @@ class MrpProduction(models.Model): if not product_production_process: if special.process_parameters_id not in process_parameters: process_parameters.append(special.process_parameters_id.display_name) - purchase = self.env['purchase.order'].search([('origin', '=', special.production_id.name)]) - account = self.env['account.move'].search([('id', 'in', purchase.invoice_ids)]) - if account.state not in ['cancel', False]: - if purchase.name not in account_moves: - account_moves.append(purchase.name) + if account_moves: raise UserError(_("请联系工厂生产经理对采购订单为%s生成的账单进行取消", ", ".join(account_moves))) if parameters_not: