From 5be5e8b3ec3fd69fe0200eabca40c5547f906e1b Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Mon, 1 Jul 2024 17:11:44 +0800 Subject: [PATCH 01/20] =?UTF-8?q?1=E3=80=81=E5=8A=9F=E8=83=BD=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=BB=84=E8=A3=85=E5=AE=8C=E6=88=90=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=86=85=E9=83=A8=E8=B0=83?= =?UTF-8?q?=E6=8B=A8=E5=8D=95=E4=BB=A5=E5=8F=8A=E6=89=80=E6=9C=89=E7=9A=84?= =?UTF-8?q?=E5=88=80=E5=85=B7=E7=89=A9=E6=96=99=E7=9A=84=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E5=92=8C=E7=A7=BB=E5=8A=A8=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=EF=BC=8C=E5=B9=B6=E8=87=AA=E5=8A=A8=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E8=AF=A5=E8=B0=83=E6=8B=A8=E5=8D=95=EF=BC=9B=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7=E7=9A=84=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=BB=84=E8=A3=85=E5=85=A5=E5=BA=93=E5=8D=95=E7=9A=84?= =?UTF-8?q?=E7=94=9F=E6=88=90=EF=BC=8C=E7=AE=80=E5=8C=96=E5=85=A5=E5=BA=93?= =?UTF-8?q?=E6=AD=A5=E9=AA=A4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/functional_tool_views.xml | 2 +- sf_tool_management/wizard/wizard.py | 153 +++++++++++------- 2 files changed, 95 insertions(+), 60 deletions(-) diff --git a/sf_tool_management/views/functional_tool_views.xml b/sf_tool_management/views/functional_tool_views.xml index 6fde82a0..7211548c 100644 --- a/sf_tool_management/views/functional_tool_views.xml +++ b/sf_tool_management/views/functional_tool_views.xml @@ -174,7 +174,7 @@ - + diff --git a/sf_tool_management/wizard/wizard.py b/sf_tool_management/wizard/wizard.py index af772016..005d8f84 100644 --- a/sf_tool_management/wizard/wizard.py +++ b/sf_tool_management/wizard/wizard.py @@ -621,26 +621,10 @@ class FunctionalToolAssemblyOrder(models.TransientModel): desc_1 = self.get_desc_1(stock_lot) # 封装功能刀具数据,用于创建功能刀具记录 desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly) - # 创建刀具组装入库单 + # 创建功能刀具组装入库单 self.env['stock.picking'].create_stocking_picking(stock_lot, functional_tool_assembly, self) - # 刀具物料出库 - if self.handle_code_id: - product_id.tool_material_stock_moves(self.handle_code_id, self.assembly_order_code) - if self.integral_product_id: - self.integral_product_id.material_stock_moves(self.integral_freight_barcode_id, - self.integral_freight_lot_id, self.assembly_order_code) - if self.blade_product_id: - self.blade_product_id.material_stock_moves(self.blade_freight_barcode_id, - self.blade_freight_lot_id, self.assembly_order_code) - if self.bar_product_id: - self.bar_product_id.material_stock_moves(self.bar_freight_barcode_id, - self.bar_freight_lot_id, self.assembly_order_code) - if self.pad_product_id: - self.pad_product_id.material_stock_moves(self.pad_freight_barcode_id, - self.pad_freight_lot_id, self.assembly_order_code) - if self.chuck_product_id: - self.chuck_product_id.material_stock_moves(self.chuck_freight_barcode_id, - self.chuck_freight_lot_id, self.assembly_order_code) + # 创建刀具物料出库单 + self.env['stock.picking'].create_stocking_picking1(self) # ============================创建功能刀具列表、安全库存记录=============================== # 创建功能刀具列表记录 @@ -788,7 +772,7 @@ class StockPicking(models.Model): def create_stocking_picking(self, stock_lot, functional_tool_assembly, obj): """ - 创建刀具组装入库单 + 创建功能刀具组装入库单 """ # 获取名称为刀具组装入库的作业类型 picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '刀具组装入库')]) @@ -807,6 +791,7 @@ class StockPicking(models.Model): 'location_id': picking_id.location_id.id, 'location_dest_id': picking_id.location_dest_id.id, 'lot_id': stock_lot.id, + 'install_tool_time': fields.Datetime.now(), 'qty_done': 1, 'functional_tool_name_id': functional_tool_assembly.id, 'functional_tool_type_id': obj.functional_tool_type_id.id, @@ -836,6 +821,65 @@ class StockPicking(models.Model): num = "%03d" % m return name + str(num) + def create_stocking_picking1(self, obj): + """ + 创建刀具物料出库单 + """ + # 获取名称为内部调拨的作业类型 + picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')]) + # 创建刀具物料出库单 + picking_id = self.env['stock.picking'].create({ + 'name': self._get_name_stock1(picking_type_id), + 'picking_type_id': picking_type_id.id, + 'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id, + 'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id, + 'origin': obj.assembly_order_code + }) + # =============刀具物料出库=================== + product_id = self.env['product.product'] + datas = {'data': [], 'picking_id': picking_id} + if obj.handle_code_id: + datas['data'].append( + {'current_location_id': self.env['sf.shelf.location'], 'lot_id': obj.handle_code_id}) + if obj.integral_product_id: + datas['data'].append( + {'current_location_id': obj.integral_freight_barcode_id, 'lot_id': obj.integral_freight_lot_id.lot_id}) + if obj.blade_product_id: + datas['data'].append( + {'current_location_id': obj.blade_freight_barcode_id, 'lot_id': obj.blade_freight_lot_id.lot_id}) + if obj.bar_product_id: + datas['data'].append( + {'current_location_id': obj.bar_freight_barcode_id, 'lot_id': obj.bar_freight_lot_id.lot_id}) + if obj.pad_product_id: + datas['data'].append( + {'current_location_id': obj.pad_freight_barcode_id, 'lot_id': obj.pad_freight_lot_id.lot_id}) + if obj.chuck_product_id: + datas['data'].append( + {'current_location_id': obj.chuck_freight_barcode_id, 'lot_id': obj.chuck_freight_lot_id.lot_id}) + # 创建刀具物料出库库存移动记录 + product_id.create_tool_material_stock_moves(datas) + # 将刀具物料出库库单的状态更改为就绪 + picking_id.action_confirm() + # 修改刀具物料出库移动历史记录 + product_id.write_tool_material_stock_move_lines(datas) + # 设置数量,并验证完成 + picking_id.action_set_quantities_to_reservation() + picking_id.button_validate() + + def _get_name_stock1(self, picking_type_id): + name = picking_type_id.sequence_id.prefix + stock_id = self.env['stock.picking'].sudo().search( + [('name', 'like', name), ('picking_type_id', '=', picking_type_id.id)], + limit=1, + order="id desc" + ) + if not stock_id: + num = "%03d" % 1 + else: + m = int(stock_id.name[-3:]) + 1 + num = "%03d" % m + return name + str(num) + class ProductProduct(models.Model): _inherit = 'product.product' @@ -853,13 +897,6 @@ class ProductProduct(models.Model): 'product_id': product_id[0].id, 'company_id': self.env.company.id }) - # 获取位置对象 - location_inventory_ids = self.env['stock.location'].search([('name', 'in', ('Production', '生产'))]) - stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')]) - # 创建功能刀具该批次/序列号 库存移动和移动历史 - stock_lot.create_stock_quant(location_inventory_ids[-1], stock_location_id, functional_tool_assembly.id, - obj.assembly_order_code, obj, obj.after_tool_groups_id) - return stock_lot def get_stock_lot_name(self, obj): @@ -878,39 +915,37 @@ class ProductProduct(models.Model): num = "%03d" % m return '%s-%s' % (code, num) - def tool_material_stock_moves(self, tool_material, assembly_order_code): - """ - 对刀具物料进行库存移动到 刀具组装位置 - """ - # 获取位置对象 - location_inventory_id = tool_material.quant_ids.location_id[-1] - stock_location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) - # 创建功能刀具该批次/序列号 库存移动和移动历史 - tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, assembly_order_code, False, - False) + def create_tool_material_stock_moves(self, datas): + picking_id = datas['picking_id'] + data = datas['data'] + stock_move_ids = [] + for res in data: + if res: + # 创建库存移动记录 + stock_move_id = self.env['stock.move'].sudo().create({ + 'name': picking_id.name, + 'picking_id': picking_id.id, + 'product_id': res['lot_id'].product_id.id, + 'location_id': picking_id.location_id.id, + 'location_dest_id': picking_id.location_dest_id.id, + 'product_uom_qty': 1.00, + 'reserved_availability': 1.00 + }) + stock_move_ids.append(stock_move_id) + return stock_move_ids - def material_stock_moves(self, shelf_location_barcode_id, lot_id, assembly_order_code): - # 创建库存移动记录 - stock_move_id = self.env['stock.move'].sudo().create({ - 'name': assembly_order_code, - 'product_id': self.id, - 'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id, - 'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id, - 'product_uom_qty': 1.00, - 'state': 'done' - }) - - # 创建移动历史记录 - stock_move_line_id = self.env['stock.move.line'].sudo().create({ - 'product_id': self.id, - 'move_id': stock_move_id.id, - 'lot_id': lot_id.lot_id.id, - 'current_location_id': shelf_location_barcode_id.id, - 'install_tool_time': fields.Datetime.now(), - 'qty_done': 1.0, - 'state': 'done', - }) - return stock_move_id, stock_move_line_id + def write_tool_material_stock_move_lines(self, datas): + picking_id = datas['picking_id'] + data = datas['data'] + move_line_ids = picking_id.move_line_ids + for move_line_id in move_line_ids: + for res in data: + if move_line_id.lot_id.product_id == res['lot_id'].product_id: + move_line_id.write({ + 'current_location_id': res.get('current_location_id').id, + 'lot_id': res.get('lot_id').id + }) + return True class StockLot(models.Model): From 0b267cc88a84e9014e05689b0848518375c9c30e Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 2 Jul 2024 09:32:50 +0800 Subject: [PATCH 02/20] 1 --- sf_tool_management/models/base.py | 9 +++- sf_tool_management/wizard/wizard.py | 74 +++++++++++++++-------------- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 182141cf..20c1e45d 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -776,7 +776,7 @@ class FunctionalToolDismantle(models.Model): dismantle_person = fields.Char('拆解人', readonly=True) image = fields.Binary('图片', readonly=True) - scrap_id = fields.Char('报废单号', readonly=True) + scrap_ids = fields.One2many('stock.scrap', 'functional_tool_dismantle_id', string='报废单号', readonly=True) grinding_id = fields.Char('磨削单号', readonly=True) state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True) @@ -941,7 +941,6 @@ class FunctionalToolDismantle(models.Model): lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)]) if not lot: raise ValidationError('Rfid为【%s】的功能刀具序列号不存在!' % self.handle_rfid) - functional_tool_assembly = self.functional_tool_id.functional_tool_name_id if self.scrap_boolean: # 刀柄报废 入库到Scrap lot.create_stock_quant(location, location_dest_scrap_ids[-1], False, code, False, False) @@ -1043,3 +1042,9 @@ class ProductProduct(models.Model): }) return stock_move_id, stock_move_line_id + + +class CustomStockScrap(models.Model): + _inherit = 'stock.scrap' + + functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string="功能刀具拆解单") diff --git a/sf_tool_management/wizard/wizard.py b/sf_tool_management/wizard/wizard.py index 005d8f84..111211c2 100644 --- a/sf_tool_management/wizard/wizard.py +++ b/sf_tool_management/wizard/wizard.py @@ -836,7 +836,7 @@ class StockPicking(models.Model): 'origin': obj.assembly_order_code }) # =============刀具物料出库=================== - product_id = self.env['product.product'] + stock_move_id = self.env['stock.move'] datas = {'data': [], 'picking_id': picking_id} if obj.handle_code_id: datas['data'].append( @@ -857,11 +857,11 @@ class StockPicking(models.Model): datas['data'].append( {'current_location_id': obj.chuck_freight_barcode_id, 'lot_id': obj.chuck_freight_lot_id.lot_id}) # 创建刀具物料出库库存移动记录 - product_id.create_tool_material_stock_moves(datas) + stock_move_id.create_tool_material_stock_moves(datas) # 将刀具物料出库库单的状态更改为就绪 picking_id.action_confirm() # 修改刀具物料出库移动历史记录 - product_id.write_tool_material_stock_move_lines(datas) + stock_move_id.write_tool_material_stock_move_lines(datas) # 设置数量,并验证完成 picking_id.action_set_quantities_to_reservation() picking_id.button_validate() @@ -881,6 +881,42 @@ class StockPicking(models.Model): return name + str(num) +class StockMove(models.Model): + _inherit = 'stock.move' + + def create_tool_material_stock_moves(self, datas): + picking_id = datas['picking_id'] + data = datas['data'] + stock_move_ids = [] + for res in data: + if res: + # 创建库存移动记录 + stock_move_id = self.env['stock.move'].sudo().create({ + 'name': picking_id.name, + 'picking_id': picking_id.id, + 'product_id': res['lot_id'].product_id.id, + 'location_id': picking_id.location_id.id, + 'location_dest_id': picking_id.location_dest_id.id, + 'product_uom_qty': 1.00, + 'reserved_availability': 1.00 + }) + stock_move_ids.append(stock_move_id) + return stock_move_ids + + def write_tool_material_stock_move_lines(self, datas): + picking_id = datas['picking_id'] + data = datas['data'] + move_line_ids = picking_id.move_line_ids + for move_line_id in move_line_ids: + for res in data: + if move_line_id.lot_id.product_id == res['lot_id'].product_id: + move_line_id.write({ + 'current_location_id': res.get('current_location_id').id, + 'lot_id': res.get('lot_id').id + }) + return True + + class ProductProduct(models.Model): _inherit = 'product.product' @@ -915,38 +951,6 @@ class ProductProduct(models.Model): num = "%03d" % m return '%s-%s' % (code, num) - def create_tool_material_stock_moves(self, datas): - picking_id = datas['picking_id'] - data = datas['data'] - stock_move_ids = [] - for res in data: - if res: - # 创建库存移动记录 - stock_move_id = self.env['stock.move'].sudo().create({ - 'name': picking_id.name, - 'picking_id': picking_id.id, - 'product_id': res['lot_id'].product_id.id, - 'location_id': picking_id.location_id.id, - 'location_dest_id': picking_id.location_dest_id.id, - 'product_uom_qty': 1.00, - 'reserved_availability': 1.00 - }) - stock_move_ids.append(stock_move_id) - return stock_move_ids - - def write_tool_material_stock_move_lines(self, datas): - picking_id = datas['picking_id'] - data = datas['data'] - move_line_ids = picking_id.move_line_ids - for move_line_id in move_line_ids: - for res in data: - if move_line_id.lot_id.product_id == res['lot_id'].product_id: - move_line_id.write({ - 'current_location_id': res.get('current_location_id').id, - 'lot_id': res.get('lot_id').id - }) - return True - class StockLot(models.Model): _inherit = 'stock.lot' From cbc8a419849cf602b0f4088e731bd9216734d9d6 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 2 Jul 2024 17:32:27 +0800 Subject: [PATCH 03/20] =?UTF-8?q?1=E3=80=81=E6=B7=BB=E5=8A=A0=E6=8B=86?= =?UTF-8?q?=E8=A7=A3=E7=9A=84=E4=BB=93=E5=BA=93=E7=AE=A1=E7=90=86=E5=9C=B0?= =?UTF-8?q?=E7=82=B9=EF=BC=9B2=E3=80=81=E4=BC=98=E5=8C=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=88=80=E5=85=B7=E6=8B=86=E8=A7=A3=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E7=AE=A1=E7=90=86=EF=BC=9B3=E3=80=81=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_dlm_management/data/stock_data.xml | 10 + sf_tool_management/models/base.py | 190 +++++++++++++------ sf_tool_management/views/tool_base_views.xml | 19 +- sf_tool_management/wizard/wizard.py | 62 +----- 4 files changed, 166 insertions(+), 115 deletions(-) diff --git a/sf_dlm_management/data/stock_data.xml b/sf_dlm_management/data/stock_data.xml index 3d2c4527..be2a36e0 100644 --- a/sf_dlm_management/data/stock_data.xml +++ b/sf_dlm_management/data/stock_data.xml @@ -22,6 +22,16 @@ + + 拆解 + + internal + DJCJ + true + true + + + 刀具组装入库 diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 20c1e45d..12f7e79e 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -933,79 +933,55 @@ class FunctionalToolDismantle(models.Model): self.rfid, self.functional_tool_id.current_location)) # 目标重复校验 self.location_duplicate_check() - location = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) - location_dest = self.env['stock.location'].search([('name', '=', '刀具房')]) + datas = {'scrap': [], 'picking': []} # =================刀柄是否[报废]拆解======= - location_dest_scrap_ids = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))]) if self.handle_rfid: lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)]) if not lot: - raise ValidationError('Rfid为【%s】的功能刀具序列号不存在!' % self.handle_rfid) + raise ValidationError('Rfid为【%s】的刀柄序列号不存在!' % self.handle_rfid) if self.scrap_boolean: # 刀柄报废 入库到Scrap - lot.create_stock_quant(location, location_dest_scrap_ids[-1], False, code, False, False) + datas['scrap'].append({'lot_id': lot}) lot.tool_material_status = '报废' else: # 刀柄不报废 入库到刀具房 - lot.create_stock_quant(location, location_dest, False, code, False, False) + datas['picking'].append({'lot_id': lot, 'destination': self.env['sf.shelf.location']}) lot.tool_material_status = '可用' - # ==============功能刀具[报废]拆解================ if self.dismantle_cause in ['寿命到期报废', '崩刀报废']: # 除刀柄外物料报废 入库到Scrap if self.integral_product_id: - self.integral_product_id.dismantle_stock_moves(False, self.integral_lot_id, location, - location_dest_scrap_ids[-1], code) + datas['scrap'].append({'lot_id': self.integral_lot_id}) elif self.blade_product_id: - self.blade_product_id.dismantle_stock_moves(False, self.blade_lot_id, location, - location_dest_scrap_ids[-1], code) + datas['scrap'].append({'lot_id': self.blade_lot_id}) if self.bar_product_id: - self.bar_product_id.dismantle_stock_moves(False, self.bar_lot_id, location, - location_dest_scrap_ids[-1], code) + datas['scrap'].append({'lot_id': self.bar_lot_id}) elif self.pad_product_id: - self.pad_product_id.dismantle_stock_moves(False, self.pad_lot_id, location, - location_dest_scrap_ids[-1], code) + datas['scrap'].append({'lot_id': self.pad_lot_id}) if self.chuck_product_id: - self.chuck_product_id.dismantle_stock_moves(False, self.chuck_lot_id, location, - location_dest_scrap_ids[-1], code) - # ===========功能刀具[磨削]拆解============== - # elif self.dismantle_cause in ['刀具需磨削']: - # location_dest = self.env['stock.location'].search([('name', '=', '磨削房')]) - # # 除刀柄外物料拆解 入库到具体库位 - # if self.integral_product_id: - # self.integral_product_id.dismantle_stock_moves(False, location, location_dest) - # elif self.blade_product_id: - # self.blade_product_id.dismantle_stock_moves(False, location, location_dest) - # if self.bar_product_id: - # self.bar_product_id.dismantle_stock_moves(False, location, location_dest) - # elif self.pad_product_id: - # self.pad_product_id.dismantle_stock_moves(False, location, location_dest) - # if self.chuck_product_id: - # self.chuck_product_id.dismantle_stock_moves(False, location, location_dest) + datas['scrap'].append({'lot_id': self.chuck_lot_id}) # ==============功能刀具[更换,磨削]拆解============== elif self.dismantle_cause in ['更换为其他刀具', '刀具需磨削']: # 除刀柄外物料拆解 入库到具体货位 if self.integral_freight_id: - self.integral_product_id.dismantle_stock_moves(self.integral_freight_id, self.integral_lot_id, location, - location_dest, code) + datas['picking'].append({'lot_id': self.integral_lot_id, 'destination': self.integral_freight_id}) elif self.blade_freight_id: - self.blade_product_id.dismantle_stock_moves(self.blade_freight_id, self.blade_lot_id, location, - location_dest, code) + datas['picking'].append({'lot_id': self.blade_lot_id, 'destination': self.blade_freight_id}) if self.bar_freight_id: - self.bar_product_id.dismantle_stock_moves(self.bar_freight_id, self.bar_lot_id, location, - location_dest, code) + datas['picking'].append({'lot_id': self.bar_lot_id, 'destination': self.bar_freight_id}) elif self.pad_freight_id: - self.pad_product_id.dismantle_stock_moves(self.pad_freight_id, self.pad_lot_id, location, - location_dest, code) + datas['picking'].append({'lot_id': self.pad_lot_id, 'destination': self.pad_freight_id}) if self.chuck_freight_id: - self.chuck_product_id.dismantle_stock_moves(self.chuck_freight_id, self.chuck_lot_id, location, - location_dest, code) - # ===============删除功能刀具的Rfid字段的值, 赋值给Rfid(已拆解)字段===== + datas['picking'].append({'lot_id': self.chuck_lot_id, 'destination': self.chuck_freight_id}) + self.create_tool_picking_scrap(datas) + # ===============修改功能刀具数据===== self.functional_tool_id.write({ 'rfid_dismantle': self.functional_tool_id.rfid, 'rfid': '', 'functional_tool_status': '已拆除' }) + # 创建功能刀具拆解移动记录 + location_dismantle_id = self.env['stock.location'].search([('name', '=', '拆解')]) # 修改拆解单的值 self.write({ 'rfid_dismantle': self.rfid, @@ -1016,31 +992,120 @@ class FunctionalToolDismantle(models.Model): }) logging.info('【%s】刀具拆解成功!' % self.name) + def create_tool_picking_scrap(self, datas): + scrap_data = datas['scrap'] + picking_data = datas['picking'] + if scrap_data: + for data in scrap_data: + if data: + self.env['stock.scrap'].create_tool_dismantle_stock_scrap(data['lot_id'], self) + if picking_data: + picking_id = self.env['stock.picking'].create_tool_dismantle_picking(self) + self.env['stock.move'].create_tool_stock_move({'data': picking_data, 'picking_id': picking_id}) + # 将刀具物料出库库单的状态更改为就绪 + picking_id.action_confirm() + # 修改刀具物料出库移动历史记录 + self.env['stock.move'].write_tool_stock_move_line({'data': picking_data, 'picking_id': picking_id}) + # 设置数量,并验证完成 + picking_id.action_set_quantities_to_reservation() + picking_id.button_validate() -class ProductProduct(models.Model): - _inherit = 'product.product' - def dismantle_stock_moves(self, shelf_location_id, lot_id, location_id, location_dest_id, code): - # 创建功能刀具拆解单产品库存移动记录 - stock_move_id = self.env['stock.move'].sudo().create({ - 'name': code, - 'product_id': self.id, +class StockPicking(models.Model): + _inherit = 'stock.picking' + + def create_tool_dismantle_picking(self, obj): + """ + 创建刀具物料入库单 + """ + # 获取名称为内部调拨的作业类型 + picking_type_id = self.env['stock.picking.type'].sudo().search([('name', '=', '内部调拨')]) + location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) + location_dest_id = self.env['stock.location'].search([('name', '=', '刀具房')]) + if not location_id: + raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点') + if not location_dest_id: + raise ValidationError('缺少名称为【刀具房】的仓库管理地点') + # 创建刀具物料出库单 + picking_id = self.env['stock.picking'].create({ + 'name': self._get_name_stock1(picking_type_id), + 'picking_type_id': picking_type_id.id, 'location_id': location_id.id, 'location_dest_id': location_dest_id.id, + 'origin': obj.code + }) + + return picking_id + + +class StockMove(models.Model): + _inherit = 'stock.move' + + def create_tool_stock_move(self, datas): + picking_id = datas['picking_id'] + data = datas['data'] + stock_move_ids = [] + for res in data: + if res: + # 创建库存移动记录 + stock_move_id = self.env['stock.move'].sudo().create({ + 'name': picking_id.name, + 'picking_id': picking_id.id, + 'product_id': res['lot_id'].product_id.id, + 'location_id': picking_id.location_id.id, + 'location_dest_id': picking_id.location_dest_id.id, + 'product_uom_qty': 1.00, + 'reserved_availability': 1.00 + }) + stock_move_ids.append(stock_move_id) + return stock_move_ids + + def write_tool_stock_move_line(self, datas): + picking_id = datas['picking_id'] + data = datas['data'] + move_line_ids = picking_id.move_line_ids + for move_line_id in move_line_ids: + for res in data: + if move_line_id.lot_id.product_id == res['lot_id'].product_id: + move_line_id.write({ + 'destination_location_id': res.get('destination').id, + 'lot_id': res.get('lot_id').id + }) + return True + + def create_functional_tool_stock_move(self, location_inventory_id, stock_location_id, functional_tool_assembly_id, + name, obj, + tool_groups_id): + """ + 对功能刀具拆解过程的功能刀具进行库存移动,以及创建移动历史 + """ + # 创建库存移动记录 + stock_move_id = self.env['stock.move'].sudo().create({ + 'name': name, + 'product_id': self.product_id.id, + 'location_id': location_inventory_id.id, + 'location_dest_id': stock_location_id.id, 'product_uom_qty': 1.00, 'state': 'done' }) + # 创建移动历史记录 stock_move_line_id = self.env['stock.move.line'].sudo().create({ - 'product_id': self.id, - 'lot_id': lot_id.id, + 'product_id': self.product_id.id, + 'functional_tool_name_id': functional_tool_assembly_id, + 'lot_id': self.id, 'move_id': stock_move_id.id, - 'destination_location_id': shelf_location_id.id if shelf_location_id else False, 'install_tool_time': fields.Datetime.now(), 'qty_done': 1.0, 'state': 'done', + 'functional_tool_type_id': False if not obj else obj.functional_tool_type_id.id, + 'diameter': None if not obj else obj.after_assembly_functional_tool_diameter, + 'knife_tip_r_angle': None if not obj else obj.after_assembly_knife_tip_r_angle, + 'code': '' if not obj else obj.code, + 'rfid': '' if not obj else obj.rfid, + 'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name, + 'tool_groups_id': False if not tool_groups_id else tool_groups_id.id }) - return stock_move_id, stock_move_line_id @@ -1048,3 +1113,22 @@ class CustomStockScrap(models.Model): _inherit = 'stock.scrap' functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string="功能刀具拆解单") + + def create_tool_dismantle_stock_scrap(self, lot, dismantle_id): + location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) + scrap_location_id = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))]) + if not location_id: + raise ValidationError('缺少名称为【刀具组装位置】的仓库管理地点') + if not scrap_location_id: + raise ValidationError('缺少名称为【Scrap】或【Scrap】的仓库管理地点') + stock_scrap_id = self.create({ + 'product_id': lot.product_id.id, + 'lot_id': lot.id, + 'location_id': location_id.id, + 'scrap_location_id': scrap_location_id.id, + 'functional_tool_dismantle_id': dismantle_id.id, + 'origin': dismantle_id.code + }) + # 完成报废单 + stock_scrap_id.action_validate() + return stock_scrap_id diff --git a/sf_tool_management/views/tool_base_views.xml b/sf_tool_management/views/tool_base_views.xml index 31fe53c9..42f2c3ca 100644 --- a/sf_tool_management/views/tool_base_views.xml +++ b/sf_tool_management/views/tool_base_views.xml @@ -711,10 +711,14 @@ - - - - + + + + @@ -791,8 +795,8 @@ attrs="{'readonly': [('state', '=', '已拆解')]}"/> - + + @@ -879,6 +883,9 @@ + + + diff --git a/sf_tool_management/wizard/wizard.py b/sf_tool_management/wizard/wizard.py index 111211c2..4edd3617 100644 --- a/sf_tool_management/wizard/wizard.py +++ b/sf_tool_management/wizard/wizard.py @@ -622,9 +622,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 封装功能刀具数据,用于创建功能刀具记录 desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly) # 创建功能刀具组装入库单 - self.env['stock.picking'].create_stocking_picking(stock_lot, functional_tool_assembly, self) + self.env['stock.picking'].create_tool_stocking_picking(stock_lot, functional_tool_assembly, self) # 创建刀具物料出库单 - self.env['stock.picking'].create_stocking_picking1(self) + self.env['stock.picking'].create_tool_stocking_picking1(self) # ============================创建功能刀具列表、安全库存记录=============================== # 创建功能刀具列表记录 @@ -770,7 +770,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel): class StockPicking(models.Model): _inherit = 'stock.picking' - def create_stocking_picking(self, stock_lot, functional_tool_assembly, obj): + def create_tool_stocking_picking(self, stock_lot, functional_tool_assembly, obj): """ 创建功能刀具组装入库单 """ @@ -821,7 +821,7 @@ class StockPicking(models.Model): num = "%03d" % m return name + str(num) - def create_stocking_picking1(self, obj): + def create_tool_stocking_picking1(self, obj): """ 创建刀具物料出库单 """ @@ -874,10 +874,10 @@ class StockPicking(models.Model): order="id desc" ) if not stock_id: - num = "%03d" % 1 + num = "%05d" % 1 else: m = int(stock_id.name[-3:]) + 1 - num = "%03d" % m + num = "%05d" % m return name + str(num) @@ -950,53 +950,3 @@ class ProductProduct(models.Model): m = int(stock_lot_id.name[-3:]) + 1 num = "%03d" % m return '%s-%s' % (code, num) - - -class StockLot(models.Model): - _inherit = 'stock.lot' - - def create_stock_quant(self, location_inventory_id, stock_location_id, functional_tool_assembly_id, name, obj, - tool_groups_id): - """ - 对功能刀具组装过程的功能刀具和刀具物料进行库存移动,以及创建移动历史 - """ - - # 创建库存移动记录 - stock_move_id = self.env['stock.move'].sudo().create({ - 'name': name, - 'product_id': self.product_id.id, - 'location_id': location_inventory_id.id, - 'location_dest_id': stock_location_id.id, - 'product_uom_qty': 1.00, - 'state': 'done' - }) - - # 创建移动历史记录 - stock_move_line_id = self.env['stock.move.line'].sudo().create({ - 'product_id': self.product_id.id, - 'functional_tool_name_id': functional_tool_assembly_id, - 'lot_id': self.id, - 'move_id': stock_move_id.id, - 'install_tool_time': fields.Datetime.now(), - 'qty_done': 1.0, - 'state': 'done', - 'functional_tool_type_id': False if not obj else obj.functional_tool_type_id.id, - 'diameter': None if not obj else obj.after_assembly_functional_tool_diameter, - 'knife_tip_r_angle': None if not obj else obj.after_assembly_knife_tip_r_angle, - 'code': '' if not obj else obj.code, - 'rfid': '' if not obj else obj.rfid, - 'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name, - 'tool_groups_id': False if not tool_groups_id else tool_groups_id.id - }) - return stock_move_id, stock_move_line_id - -# class StockQuant(models.Model): -# _inherit = 'stock.quant' -# -# @api.model_create_multi -# def create(self, vals_list): -# records = super(StockQuant, self).create(vals_list) -# for record in records: -# if record.lot_id.product_id.categ_id.name == '刀具': -# record.lot_id.enroll_tool_material_stock() -# return records From 9ec37f5d5b359538eaa8dfc73d3e709af96576f7 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 3 Jul 2024 09:45:55 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E9=9D=A2?= =?UTF-8?q?=E5=8A=A0=E5=B7=A5=E4=BA=A7=E7=BA=BF=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/controllers/controllers.py | 24 +++++++++---------- sf_manufacturing/models/mrp_workorder.py | 5 ++-- .../views/mrp_production_addional_change.xml | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py index dd97531f..fde6814b 100644 --- a/sf_manufacturing/controllers/controllers.py +++ b/sf_manufacturing/controllers/controllers.py @@ -229,12 +229,12 @@ class Manufacturing_Connect(http.Controller): # request.env['sf.production.plan'].sudo().search([('production_id', '=', production_id)]).write( # {'actual_end_time': workorder.date_finished, # 'state': 'finished'}) - # production_obj = request.env['mrp.production'].sudo().search([('name', '=', production_id)]) - # if production_obj: - # production_obj.sudo().work_order_state = '已完成' - # production_obj.write({'state': 'done'}) - # request.env['sale.order'].sudo().search( - # [('name', '=', production_obj.origin)]).write({'schedule_status': 'to deliver'}) + # production_obj = request.env['mrp.production'].sudo().search([('name', '=', production_id)]) + # if production_obj: + # production_obj.sudo().work_order_state = '已完成' + # production_obj.write({'state': 'done'}) + # request.env['sale.order'].sudo().search( + # [('name', '=', production_obj.origin)]).write({'schedule_status': 'to deliver'}) except Exception as e: res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} @@ -471,10 +471,10 @@ class Manufacturing_Connect(http.Controller): workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc') if workorder: for order in workorder: - if order.production_id.production_line_state == '待上产线': + if order.production_line_state == '待上产线': logging.info( - '制造订单产线状态:%s' % order.production_id.production_line_state) - order.production_id.write({'production_line_state': '已上产线'}) + '制造订单产线状态:%s' % order.production_line_state) + order.write({'production_line_state': '已上产线'}) workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( [ ('rfid_code', '=', rfid_code), ('type', '=', '上产线'), @@ -528,10 +528,10 @@ class Manufacturing_Connect(http.Controller): workorder = request.env['mrp.workorder'].sudo().search(domain, order='id asc') if workorder: for order in workorder: - if order.production_id.production_line_state == '已上产线': + if order.production_line_state == '已上产线': logging.info( - '制造订单产线状态:%s' % order.production_id.production_line_state) - order.production_id.write({'production_line_state': '已下产线'}) + '制造订单产线状态:%s' % order.production_line_state) + order.write({'production_line_state': '已下产线'}) workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( [ ('rfid_code', '=', rfid_code), ('type', '=', '下产线'), diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 09bde519..46bcde47 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -193,8 +193,9 @@ class ResMrpWorkOrder(models.Model): production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id', string='生产线', store=True, tracking=True) - production_line_state = fields.Selection(related='production_id.production_line_state', - string='上/下产线', store=True, tracking=True) + production_line_state = fields.Selection( + [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], + string='上/下产线', default='待上产线', tracking=True) detection_report = fields.Binary('检测报告', readonly=True) is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False) is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False) diff --git a/sf_manufacturing/views/mrp_production_addional_change.xml b/sf_manufacturing/views/mrp_production_addional_change.xml index b65dfb2f..b5e348b9 100644 --- a/sf_manufacturing/views/mrp_production_addional_change.xml +++ b/sf_manufacturing/views/mrp_production_addional_change.xml @@ -87,7 +87,7 @@ - + From bb33a1d0937e7c706360c3995613665ae3c40f0a Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 3 Jul 2024 10:37:02 +0800 Subject: [PATCH 05/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E9=9D=A2?= =?UTF-8?q?=E5=B7=A5=E5=8D=95=E4=BA=A7=E7=BA=BF=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/controllers/controllers.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py index fde6814b..9f76f065 100644 --- a/sf_manufacturing/controllers/controllers.py +++ b/sf_manufacturing/controllers/controllers.py @@ -473,8 +473,12 @@ class Manufacturing_Connect(http.Controller): for order in workorder: if order.production_line_state == '待上产线': logging.info( - '制造订单产线状态:%s' % order.production_line_state) - order.write({'production_line_state': '已上产线'}) + '工单产线状态:%s' % order.production_line_state) + panel_workorder = request.env['mrp.workorder'].sudo().search( + [('rfid_code', '=', rfid_code), + ('processing_panel', '=', order.processing_panel)]) + if panel_workorder: + panel_workorder.write({'production_line_state': '已上产线'}) workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( [ ('rfid_code', '=', rfid_code), ('type', '=', '上产线'), @@ -530,8 +534,12 @@ class Manufacturing_Connect(http.Controller): for order in workorder: if order.production_line_state == '已上产线': logging.info( - '制造订单产线状态:%s' % order.production_line_state) - order.write({'production_line_state': '已下产线'}) + '工单产线状态:%s' % order.production_line_state) + panel_workorder = request.env['mrp.workorder'].sudo().search( + [('rfid_code', '=', rfid_code), + ('processing_panel', '=', order.processing_panel)]) + if panel_workorder: + panel_workorder.write({'production_line_state': '已下产线'}) workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( [ ('rfid_code', '=', rfid_code), ('type', '=', '下产线'), From 6c6fe44d45371a52e7751abe5cef5ad50980da1f Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 3 Jul 2024 10:53:29 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E5=88=B6=E9=80=A0=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=8E=BB=E6=8E=89=E4=B8=8A/=E4=B8=8B=E4=BA=A7=E7=BA=BF?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 95242b54..73782a9c 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -55,9 +55,9 @@ class MrpProduction(models.Model): glb_file = fields.Binary("glb模型文件") production_line_id = fields.Many2one('sf.production.line', string='生产线', tracking=True) plan_start_processing_time = fields.Datetime('计划开始加工时间') - production_line_state = fields.Selection( - [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], - string='上/下产线', default='待上产线', tracking=True) + # production_line_state = fields.Selection( + # [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], + # string='上/下产线', default='待上产线', tracking=True) # 工序状态 # Todo 研究下用法 process_state = fields.Selection([ From 4a86871039e7ae0ec14048c253fbb4d3cdf66831 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 3 Jul 2024 17:17:48 +0800 Subject: [PATCH 07/20] =?UTF-8?q?1=E3=80=81=E5=8A=9F=E8=83=BD=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=BB=84=E8=A3=85=E5=8D=95=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E8=B0=83=E6=8B=A8=E5=8D=95=E8=B7=B3=E8=BD=AC=E6=8C=89?= =?UTF-8?q?=E9=92=AE=EF=BC=9B=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7=E6=8B=86?= =?UTF-8?q?=E8=A7=A3=E5=8D=95=E6=B7=BB=E5=8A=A0=E8=B0=83=E6=8B=A8=E5=8D=95?= =?UTF-8?q?=E8=B7=B3=E8=BD=AC=E6=8C=89=E9=92=AE=E5=92=8C=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=88=80=E5=85=B7=E7=A7=BB=E5=8A=A8=E8=B7=B3=E8=BD=AC=E6=8C=89?= =?UTF-8?q?=E9=92=AE=EF=BC=9B2=E3=80=81=E5=8A=9F=E8=83=BD=E5=88=80?= =?UTF-8?q?=E5=85=B7=E6=8B=86=E8=A7=A3=E6=A8=A1=E5=9E=8B=EF=BC=8Cform?= =?UTF-8?q?=E8=A7=86=E5=9B=BE=E6=B7=BB=E5=8A=A0=E6=8A=A5=E5=BA=9Fpage?= =?UTF-8?q?=E9=A1=B5=E5=AD=98=E6=94=BE=E5=88=80=E5=85=B7=E7=89=A9=E6=96=99?= =?UTF-8?q?=E6=8A=A5=E5=BA=9F=E5=8D=95=EF=BC=8C=E4=BC=98=E5=8C=96=E6=8B=86?= =?UTF-8?q?=E8=A7=A3=E6=B5=81=E7=A8=8B=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=88=80=E5=85=B7=E6=8B=86=E8=A7=A3=E7=A7=BB=E5=8A=A8=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=EF=BC=9B3=E3=80=81=E5=8A=9F=E8=83=BD=E5=88=80?= =?UTF-8?q?=E5=85=B7=E5=87=BA=E5=85=A5=E5=BA=93=E5=88=97=E8=A1=A8=E8=A7=86?= =?UTF-8?q?=E5=9B=BE=E6=B7=BB=E5=8A=A0=E6=8B=86=E8=A7=A3=E5=8D=95=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC=E9=93=BE=E6=8E=A5=EF=BC=9B4=E3=80=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=88=80=E5=85=B7=E5=AE=89=E5=85=A8=E5=BA=93=E5=AD=98?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=B7=BB=E5=8A=A0=E5=90=8D=E7=A7=B0=E5=94=AF?= =?UTF-8?q?=E4=B8=80=E9=AA=8C=E8=AF=81=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E8=AE=A1=E7=AE=97=E6=96=B9=E6=B3=95=EF=BC=9B5?= =?UTF-8?q?=E3=80=81=E4=BC=98=E5=8C=96=E5=8A=9F=E8=83=BD=E5=88=80=E5=85=B7?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=88=B0cloud=E7=9A=84=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E8=A7=A3=E5=86=B3=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_tool_management/models/base.py | 103 +++++++++++++----- sf_tool_management/models/functional_tool.py | 41 ++++--- .../models/functional_tool_enroll.py | 12 +- .../views/functional_tool_views.xml | 16 +-- sf_tool_management/views/tool_base_views.xml | 52 ++++++++- 5 files changed, 158 insertions(+), 66 deletions(-) diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 12f7e79e..b77e6469 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -669,6 +669,20 @@ class FunctionalToolAssembly(models.Model): :return: """ + picking_num = fields.Integer('调拨单数量', compute='compute_picking_num', store=True) + + @api.depends('assemble_status') + def compute_picking_num(self): + for item in self: + picking_ids = self.env['stock.picking'].sudo().search([('origin', '=', item.assembly_order_code)]) + item.picking_num = len(picking_ids) + + def open_tool_stock_picking(self): + action = self.env.ref('stock.action_picking_tree_all') + result = action.read()[0] + result['domain'] = [('origin', '=', self.assembly_order_code)] + return result + @api.model_create_multi def create(self, vals): obj = super(FunctionalToolAssembly, self).create(vals) @@ -758,7 +772,7 @@ class FunctionalToolDismantle(models.Model): num = "%03d" % m return 'GNDJ-CJD-%s-%s' % (datetime, num) - functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True, + functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True, tracking=True, domain=[('functional_tool_status', '!=', '已拆除'), ('current_location', '=', '刀具房')]) tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True, @@ -778,6 +792,16 @@ class FunctionalToolDismantle(models.Model): scrap_ids = fields.One2many('stock.scrap', 'functional_tool_dismantle_id', string='报废单号', readonly=True) grinding_id = fields.Char('磨削单号', readonly=True) + picking_id = fields.Many2one('stock.picking', string='刀具物料调拨单') + picking_num = fields.Integer('调拨单数量', default=0, compute='compute_picking_num', store=True) + + @api.depends('picking_id') + def compute_picking_num(self): + for item in self: + if item.picking_id: + item.picking_num = 1 + else: + item.picking_num = 0 state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True) active = fields.Boolean('有效', default=True) @@ -791,7 +815,14 @@ class FunctionalToolDismantle(models.Model): handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True) handle_lot_id = fields.Many2one('stock.lot', string='刀柄序列号', compute='_compute_functional_tool_num', store=True) - scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True) + scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True, compute='compute_scrap_boolean', + store=True) + + @api.depends('dismantle_cause') + def compute_scrap_boolean(self): + for item in self: + if item.dismantle_cause not in ['寿命到期报废', '崩刀报废']: + item.scrap_boolean = False # 整体式 integral_product_id = fields.Many2one('product.product', string='整体式刀具', @@ -974,20 +1005,19 @@ class FunctionalToolDismantle(models.Model): if self.chuck_freight_id: datas['picking'].append({'lot_id': self.chuck_lot_id, 'destination': self.chuck_freight_id}) self.create_tool_picking_scrap(datas) - # ===============修改功能刀具数据===== + # ===============创建功能刀具拆解移动记录===== + self.env['stock.move'].create_functional_tool_stock_move(self) + # 修改功能刀具数据 self.functional_tool_id.write({ 'rfid_dismantle': self.functional_tool_id.rfid, 'rfid': '', 'functional_tool_status': '已拆除' }) - # 创建功能刀具拆解移动记录 - location_dismantle_id = self.env['stock.location'].search([('name', '=', '拆解')]) # 修改拆解单的值 self.write({ - 'rfid_dismantle': self.rfid, 'dismantle_data': fields.Datetime.now(), 'dismantle_person': self.env.user.name, - 'rfid': '', + 'rfid': '%s(已拆解)' % self.rfid, 'state': '已拆解' }) logging.info('【%s】刀具拆解成功!' % self.name) @@ -1001,6 +1031,7 @@ class FunctionalToolDismantle(models.Model): self.env['stock.scrap'].create_tool_dismantle_stock_scrap(data['lot_id'], self) if picking_data: picking_id = self.env['stock.picking'].create_tool_dismantle_picking(self) + self.picking_id = picking_id.id self.env['stock.move'].create_tool_stock_move({'data': picking_data, 'picking_id': picking_id}) # 将刀具物料出库库单的状态更改为就绪 picking_id.action_confirm() @@ -1010,6 +1041,27 @@ class FunctionalToolDismantle(models.Model): picking_id.action_set_quantities_to_reservation() picking_id.button_validate() + def action_open_reference1(self): + self.ensure_one() + return { + 'res_model': self._name, + 'type': 'ir.actions.act_window', + 'views': [[False, "form"]], + 'res_id': self.id, + } + + def open_function_tool_stock_move_line(self): + action = self.env.ref('sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_act') + result = action.read()[0] + result['domain'] = [('functional_tool_dismantle_id', '=', self.id), ('qty_done', '>', 0)] + return result + + def open_tool_stock_picking(self): + action = self.env.ref('stock.action_picking_tree_all') + result = action.read()[0] + result['domain'] = [('origin', '=', self.code)] + return result + class StockPicking(models.Model): _inherit = 'stock.picking' @@ -1073,38 +1125,39 @@ class StockMove(models.Model): }) return True - def create_functional_tool_stock_move(self, location_inventory_id, stock_location_id, functional_tool_assembly_id, - name, obj, - tool_groups_id): + def create_functional_tool_stock_move(self, dismantle_id): """ 对功能刀具拆解过程的功能刀具进行库存移动,以及创建移动历史 """ + location_dismantle_id = self.env['stock.location'].search([('name', '=', '拆解')]) + if not location_dismantle_id: + raise ValidationError('缺少名称为【拆解】的仓库管理地点') + tool_id = dismantle_id.functional_tool_id # 创建库存移动记录 stock_move_id = self.env['stock.move'].sudo().create({ - 'name': name, - 'product_id': self.product_id.id, - 'location_id': location_inventory_id.id, - 'location_dest_id': stock_location_id.id, + 'name': dismantle_id.code, + 'product_id': tool_id.barcode_id.product_id.id, + 'location_id': tool_id.current_location_id.id, + 'location_dest_id': location_dismantle_id.id, 'product_uom_qty': 1.00, 'state': 'done' }) # 创建移动历史记录 stock_move_line_id = self.env['stock.move.line'].sudo().create({ - 'product_id': self.product_id.id, - 'functional_tool_name_id': functional_tool_assembly_id, - 'lot_id': self.id, + 'product_id': tool_id.barcode_id.product_id.id, + 'functional_tool_dismantle_id': dismantle_id.id, + 'lot_id': tool_id.barcode_id.id, 'move_id': stock_move_id.id, - 'install_tool_time': fields.Datetime.now(), 'qty_done': 1.0, 'state': 'done', - 'functional_tool_type_id': False if not obj else obj.functional_tool_type_id.id, - 'diameter': None if not obj else obj.after_assembly_functional_tool_diameter, - 'knife_tip_r_angle': None if not obj else obj.after_assembly_knife_tip_r_angle, - 'code': '' if not obj else obj.code, - 'rfid': '' if not obj else obj.rfid, - 'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name, - 'tool_groups_id': False if not tool_groups_id else tool_groups_id.id + 'functional_tool_type_id': tool_id.sf_cutting_tool_type_id.id, + 'diameter': tool_id.functional_tool_diameter, + 'knife_tip_r_angle': tool_id.knife_tip_r_angle, + 'code': tool_id.code, + 'rfid': tool_id.rfid, + 'functional_tool_name': tool_id.name, + 'tool_groups_id': tool_id.tool_groups_id.id }) return stock_move_id, stock_move_line_id diff --git a/sf_tool_management/models/functional_tool.py b/sf_tool_management/models/functional_tool.py index 18f0a466..4e791fe5 100644 --- a/sf_tool_management/models/functional_tool.py +++ b/sf_tool_management/models/functional_tool.py @@ -252,9 +252,7 @@ class FunctionalCuttingToolEntity(models.Model): def open_safety_stock(self): action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act') result = action.read()[0] - result['domain'] = [('name', '=', self.name), ('diameter', '=', self.functional_tool_diameter), - ('knife_tip_r_angle', '=', self.knife_tip_r_angle), - ('coarse_middle_thin', '=', self.coarse_middle_thin)] + result['domain'] = [('id', '=', self.safe_inventory_id.id)] return result def tool_inventory_displacement_out(self): @@ -372,6 +370,7 @@ class StockMoveLine(models.Model): _order = 'date desc' functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单') + functional_tool_dismantle_id = fields.Many2one('sf.functional.tool.dismantle', string='功能刀具拆解单') functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True, group_expand='_read_group_functional_tool_type_id') functional_tool_name = fields.Char('刀具名称') @@ -392,6 +391,9 @@ class StockMoveLine(models.Model): if self.functional_tool_name_id: action = self.functional_tool_name_id.action_open_reference1() return action + if self.functional_tool_dismantle_id: + action = self.functional_tool_dismantle_id.action_open_reference1() + return action elif self.move_id: action = self.move_id.action_open_reference() if action['res_model'] != 'stock.move': @@ -409,13 +411,14 @@ class RealTimeDistributionOfFunctionalTools(models.Model): _inherit = ['mail.thread'] _description = '功能刀具安全库存' - name = fields.Char('名称', readonly=True, compute='_compute_name', store=True) + name = fields.Char('名称', compute='_compute_num', store=True) functional_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True) - tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=False, required=True) - sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False, - group_expand='_read_mrs_cutting_tool_type_ids', store=True) - diameter = fields.Float(string='刀具直径(mm)', readonly=False) - knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=False) + tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_num', store=True) + sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', + compute='_compute_num', store=True, + group_expand='_read_mrs_cutting_tool_type_ids') + diameter = fields.Float(string='刀具直径(mm)', compute='_compute_num', store=True) + knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', compute='_compute_num', store=True) tool_stock_num = fields.Integer(string='刀具房数量', compute='_compute_stock_num', store=True) side_shelf_num = fields.Integer(string='线边刀库数量', compute='_compute_stock_num', store=True) on_tool_stock_num = fields.Integer(string='机内刀库数量', compute='_compute_stock_num', store=True) @@ -460,22 +463,18 @@ class RealTimeDistributionOfFunctionalTools(models.Model): active = fields.Boolean(string='已归档', default=True) - @api.onchange('functional_name_id') - def _onchange_num(self): + @api.depends('functional_name_id', 'functional_name_id.diameter', 'functional_name_id.angle', + 'functional_name_id.functional_cutting_tool_model_id') + def _compute_num(self): for item in self: if item.functional_name_id: item.tool_groups_id = item.functional_name_id.tool_groups_id.id item.sf_cutting_tool_type_id = item.functional_name_id.functional_cutting_tool_model_id.id item.diameter = item.functional_name_id.diameter item.knife_tip_r_angle = item.functional_name_id.angle - - @api.depends('functional_name_id') - def _compute_name(self): - for obj in self: - if obj.tool_groups_id: - obj.name = obj.functional_name_id.name + item.name = item.functional_name_id.name else: - obj.sudo().name = '' + item.sudo().name = '' @api.constrains('min_stock_num', 'max_stock_num') def _check_stock_num(self): @@ -583,4 +582,10 @@ class RealTimeDistributionOfFunctionalTools(models.Model): for vals in vals_list: vals['status_create'] = False records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list) + for item in records: + if item: + record = self.search([('functional_name_id', '=', item.functional_name_id.id)]) + if len(record) > 1: + raise ValidationError( + '功能刀具名称为【%s】的安全库存已经存在,请勿重复创建!!!' % item.functional_name_id.name) return records diff --git a/sf_tool_management/models/functional_tool_enroll.py b/sf_tool_management/models/functional_tool_enroll.py index 9c5b1417..ba3553e1 100644 --- a/sf_tool_management/models/functional_tool_enroll.py +++ b/sf_tool_management/models/functional_tool_enroll.py @@ -37,14 +37,10 @@ class ToolDatasync(models.Model): def _cron_tool_datasync_all(self): try: - self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all() - - self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all() - self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all() - + self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all() self.env['sf.fixture.material.search'].sudo().sync_enroll_fixture_material_all() - + self.env['stock.lot'].sudo().sync_enroll_fixture_material_stock_all() self.env['sf.functional.cutting.tool.entity'].sudo().esync_enroll_functional_tool_entity_all() logging.info("已全部同步完成!!!") # self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all() @@ -106,7 +102,7 @@ class StockLot(models.Model): logging.info("没有刀具物料序列号信息") except Exception as e: logging.info("刀具物料序列号同步失败:%s" % e) - + class ToolMaterial(models.Model): _inherit = 'sf.tool.material.search' @@ -198,7 +194,7 @@ class FunctionalCuttingToolEntity(models.Model): for item in objs_all: val = { 'id': item.id, - 'code': item.code, + 'code': False if not item.code else item.code.split('-', 1)[1], 'name': item.name, 'rfid': item.rfid, 'tool_groups_name': item.tool_groups_id.name, diff --git a/sf_tool_management/views/functional_tool_views.xml b/sf_tool_management/views/functional_tool_views.xml index 7211548c..103583c2 100644 --- a/sf_tool_management/views/functional_tool_views.xml +++ b/sf_tool_management/views/functional_tool_views.xml @@ -29,7 +29,6 @@ - @@ -61,13 +60,9 @@ +

@@ -763,10 +775,25 @@
+
+ + +

@@ -777,12 +804,13 @@ - - + + + @@ -883,8 +911,22 @@ - - + + + + + + + + + + + + + + From d60fefb2ec2bec9ccfde0aac89a2e2430bb436aa Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 3 Jul 2024 17:33:29 +0800 Subject: [PATCH 08/20] 1 --- sf_tool_management/views/tool_base_views.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_tool_management/views/tool_base_views.xml b/sf_tool_management/views/tool_base_views.xml index c020d33c..c180c917 100644 --- a/sf_tool_management/views/tool_base_views.xml +++ b/sf_tool_management/views/tool_base_views.xml @@ -775,7 +775,7 @@
From 869e3e4b4f8c7815508b2c96209f3b5c3295846d Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Thu, 4 Jul 2024 16:12:27 +0800 Subject: [PATCH 09/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E2=80=9D=E5=88=B6?= =?UTF-8?q?=E9=80=A0=E8=AE=A2=E5=8D=95=E5=AE=8C=E5=B7=A5=E5=90=8E=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84=E6=88=90=E5=93=81=E5=85=A5=E5=BA=93=E5=8D=95?= =?UTF-8?q?=E8=BF=98=E6=98=AF=E7=AD=89=E5=BE=85=E7=8A=B6=E6=80=81-?= =?UTF-8?q?=E5=BA=94=E8=AF=A5=E6=98=AF=E5=B0=B1=E7=BB=AA=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_bf_connect/models/jd_eclp.py | 3 +++ sf_manufacturing/models/mrp_production.py | 2 +- sf_manufacturing/models/mrp_workorder.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sf_bf_connect/models/jd_eclp.py b/sf_bf_connect/models/jd_eclp.py index 7879938e..ec14f7e1 100644 --- a/sf_bf_connect/models/jd_eclp.py +++ b/sf_bf_connect/models/jd_eclp.py @@ -161,6 +161,9 @@ class JdEclp(models.Model): url2 = config['bfm_url'] + '/api/get/jd/no' response = requests.post(url2, json=json2, data=None) # _logger.info('调用成功2', response.json()['result']['wbNo']) + tem_ret = response.json().get('result') + if not tem_ret: + raise ValidationError('京东物流返回异常,请联系管理员') self.carrier_tracking_ref = response.json()['result'].get('wbNo') if not self.carrier_tracking_ref: raise ValidationError('物流下单未成功,请联系管理员') diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 73782a9c..b226b034 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -633,7 +633,7 @@ class MrpProduction(models.Model): logging.info('qty_produced:%s' % production.qty_produced) production.write({ 'date_finished': fields.Datetime.now(), - 'product_qty': production.product_qty if production.qty_produced < 1.0 else production.qty_produced, + 'product_qty': production.qty_produced, 'priority': '0', 'is_locked': True, 'state': 'done', diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 46bcde47..30903894 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1016,7 +1016,7 @@ class ResMrpWorkOrder(models.Model): move_raw_id.quantity_done = move_raw_id.product_uom_qty record.process_state = '已完工' record.production_id.process_state = '已完工' - if record.routing_type in ['解除装夹', '表面工艺']: + 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']), From b0da7977f52776f2f13c09ed65e64c444481cdc0 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Thu, 4 Jul 2024 16:19:20 +0800 Subject: [PATCH 10/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E2=80=9C=E5=B7=B2?= =?UTF-8?q?=E7=BB=8F=E6=8E=92=E7=A8=8B=E7=9A=84=E5=88=B6=E9=80=A0=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E5=8F=96=E6=B6=88=E6=8E=92=E7=A8=8B=E5=90=8E=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=B2=A1=E6=9C=89=E5=9B=9E=E9=80=80=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_production.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index b226b034..36bdb13d 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -114,6 +114,8 @@ class MrpProduction(models.Model): if ( production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排': production.state = 'confirmed' + elif production.state == 'pending_cam' and production.schedule_state == '未排': + production.state = 'confirmed' elif production.state == 'to_close' and production.schedule_state == '已排': production.state = 'pending_cam' From 87153fab3f6ce2c259607fab75dcb6611d04cd0b Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Thu, 4 Jul 2024 17:21:39 +0800 Subject: [PATCH 11/20] =?UTF-8?q?=E5=89=8D=E7=BD=AE=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=91=BD=E5=90=8D=E5=A2=9E=E5=8A=A0=E5=8A=A0?= =?UTF-8?q?=E5=B7=A5=E9=9D=A2=E6=A0=87=E8=AF=86=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E6=96=87=E4=BB=B6=E8=A6=86=E7=9B=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_workorder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 30903894..4b9371c2 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -164,7 +164,8 @@ class ResMrpWorkOrder(models.Model): 保存名称 """ for record in self: - record.save_name = record.production_id.name.replace('/', '_') + tem_name = record.production_id.name.replace('/', '_') + record.save_name = tem_name + '_' + record.processing_panel schedule_state = fields.Selection(related='production_id.schedule_state', store=True) # 工件装夹信息 From fd225fa0e1f144e92e1f953e8a88e7d4379bb0b2 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Fri, 5 Jul 2024 11:26:02 +0800 Subject: [PATCH 12/20] =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E4=B8=AD=E5=BF=83?= =?UTF-8?q?=E7=9A=84=E5=8F=82=E6=95=B0=E4=BF=AE=E6=94=B9=E9=9C=80=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0sns=E6=A8=A1=E5=9D=97("=E8=AE=B0=E5=BD=95=E5=A4=87?= =?UTF-8?q?=E6=B3=A8")?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_workcenter.py | 38 +++++++++++++++---- .../views/mrp_workcenter_views.xml | 14 +++++++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/sf_manufacturing/models/mrp_workcenter.py b/sf_manufacturing/models/mrp_workcenter.py index 7d70ae5e..f07dd53a 100644 --- a/sf_manufacturing/models/mrp_workcenter.py +++ b/sf_manufacturing/models/mrp_workcenter.py @@ -5,24 +5,48 @@ from odoo.addons.resource.models.resource import Intervals class ResWorkcenter(models.Model): - _inherit = "mrp.workcenter" + _name = "mrp.workcenter" + _inherit = ['mrp.workcenter', 'mail.thread'] # 生产线显示 production_line_show = fields.Char(string='生产线名称') - equipment_id = fields.Many2one( - 'maintenance.equipment', string="设备", - ) + equipment_id = fields.Many2one('maintenance.equipment', string="设备", tracking=True) production_line_id = fields.Many2one('sf.production.line', string='生产线', related='equipment_id.production_line_id', store=True) - is_process_outsourcing = fields.Boolean('工艺外协') - users_ids = fields.Many2many("res.users", 'users_workcenter') + users_ids = fields.Many2many("res.users", 'users_workcenter', tracking=True) + def write(self, vals): + if 'users_ids' in vals: + old_users = self.users_ids + res = super(ResWorkcenter, self).write(vals) + new_users = self.users_ids + added_users = new_users - old_users + removed_users = old_users - new_users + if added_users or removed_users: + message = "增加 → %s \n 移除 → %s (可操作用户)" % ( + ','.join(added_users.mapped('name')), ','.join(removed_users.mapped('name'))) + self.message_post(body=message) + return res + return super(ResWorkcenter, self).write(vals) + name = fields.Char('Work Center', related='resource_id.name', store=True, readonly=False, tracking=True) + time_efficiency = fields.Float('Time Efficiency', related='resource_id.time_efficiency', default=100, store=True, + readonly=False, tracking=True) + default_capacity = fields.Float( + 'Capacity', default=1.0, + help="Default number of pieces (in product UoM) that can be produced in parallel (at the same time) at this work center. For example: the capacity is 5 and you need to produce 10 units, then the operation time listed on the BOM will be multiplied by two. However, note that both time before and after production will only be counted once.", + tracking=True) + oee_target = fields.Float( + string='OEE Target', help="Overall Effective Efficiency Target in percentage", default=90, tracking=True) + + time_start = fields.Float('Setup Time', tracking=True) + time_stop = fields.Float('Cleanup Time', tracking=True) + costs_hour = fields.Float(string='Cost per hour', help='Hourly processing cost.', default=0.0, tracking=True) equipment_status = fields.Selection( - [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"),("空闲", "空闲"),("封存(报废)", "封存(报废)")], + [("正常", "正常"), ("故障停机", "故障停机"), ("计划维保", "计划维保"), ("空闲", "空闲"), ("封存(报废)", "封存(报废)")], string="设备状态", related='equipment_id.state') # @api.depends('equipment_id') diff --git a/sf_manufacturing/views/mrp_workcenter_views.xml b/sf_manufacturing/views/mrp_workcenter_views.xml index 9aad2a99..ad433bf6 100644 --- a/sf_manufacturing/views/mrp_workcenter_views.xml +++ b/sf_manufacturing/views/mrp_workcenter_views.xml @@ -24,6 +24,20 @@
+ + custom.model.form.view.inherit + mrp.workcenter + + + +
+ + +
+
+
+
+ mrp.workcenter.view.kanban.inherit.mrp.workorder mrp.workcenter From b071b14bbd3699cf5f0d159db47529d81a224d76 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Fri, 5 Jul 2024 11:36:48 +0800 Subject: [PATCH 13/20] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_workcenter.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sf_manufacturing/models/mrp_workcenter.py b/sf_manufacturing/models/mrp_workcenter.py index f07dd53a..64cf2d8d 100644 --- a/sf_manufacturing/models/mrp_workcenter.py +++ b/sf_manufacturing/models/mrp_workcenter.py @@ -24,8 +24,9 @@ class ResWorkcenter(models.Model): added_users = new_users - old_users removed_users = old_users - new_users if added_users or removed_users: - message = "增加 → %s \n 移除 → %s (可操作用户)" % ( - ','.join(added_users.mapped('name')), ','.join(removed_users.mapped('name'))) + message = "增加 → %s ; 移除 → %s (可操作用户)" % ( + # ','.join(added_users.mapped('name')), ','.join(removed_users.mapped('name'))) + added_users.mapped('name'), removed_users.mapped('name')) self.message_post(body=message) return res return super(ResWorkcenter, self).write(vals) From 1c8644983bdd19f03f65992adc7ccd3b5a480f70 Mon Sep 17 00:00:00 2001 From: hy <1298386937@qq.com> Date: Fri, 5 Jul 2024 16:02:32 +0800 Subject: [PATCH 14/20] =?UTF-8?q?=E5=8E=BB=E9=99=A4=20=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=9D=A1=E8=AE=BE=E7=BD=AE=E6=B0=B4=E5=8D=B0?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=E5=88=87=E6=8D=A2=E4=BA=A7=E5=93=813D?= =?UTF-8?q?=E5=9B=BEbug=20=E4=BF=AE=E6=94=B9=E8=A1=A8=E6=A0=BC=E4=B8=8B?= =?UTF-8?q?=E6=8B=89=E6=A1=86=E4=BC=9A=E8=A2=AB=E8=A1=A8=E6=A0=BC=E4=B8=8B?= =?UTF-8?q?=E9=9D=A2=E6=95=B0=E6=8D=AE=E6=A1=86=E8=A6=86=E7=9B=96=E7=9A=84?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/js/custom_form_status_indicator.js | 58 +++++++++---------- .../static/src/scss/custom_style.scss | 9 ++- .../static/src/js/3d_viewer.js | 9 ++- 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/jikimo_frontend/static/src/js/custom_form_status_indicator.js b/jikimo_frontend/static/src/js/custom_form_status_indicator.js index 306142d4..912c8efa 100644 --- a/jikimo_frontend/static/src/js/custom_form_status_indicator.js +++ b/jikimo_frontend/static/src/js/custom_form_status_indicator.js @@ -5,7 +5,7 @@ import {patch} from '@web/core/utils/patch'; import {_t} from "@web/core/l10n/translation"; import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator"; import {ListRenderer} from "@web/views/list/list_renderer"; -import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field"; +// import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field"; import {Field} from "@web/views/fields/field"; @@ -153,34 +153,34 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', { // 根据进度条设置水印 -const statusbar_params = { - '已完工': 'bg-primary', - '完成': 'bg-primary', - '采购订单': 'bg-primary', - '作废': 'bg-danger', - '封存(报废)': 'bg-danger', -} -patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', { - setup() { - owl.onMounted(this.ribbons); - return this._super(...arguments); - }, - ribbons() { - try { - const dom = $('.o_form_sheet.position-relative') - const status = statusbar_params[this.currentName] - if(status && dom.length) { - dom.prepend(`
-
- ${this.currentName} -
-
`) - } - } catch (e) { - console.log(e) - } - } -}) +// const statusbar_params = { +// '已完工': 'bg-primary', +// '完成': 'bg-primary', +// '采购订单': 'bg-primary', +// '作废': 'bg-danger', +// '封存(报废)': 'bg-danger', +// } +// patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', { +// setup() { +// owl.onMounted(this.ribbons); +// return this._super(...arguments); +// }, +// ribbons() { +// try { +// const dom = $('.o_form_sheet.position-relative') +// const status = statusbar_params[this.currentName] +// if(status && dom.length) { +// dom.prepend(`
+//
+// ${this.currentName} +//
+//
`) +// } +// } catch (e) { +// console.log(e) +// } +// } +// }) $(function () { document.addEventListener('click', function () { diff --git a/jikimo_frontend/static/src/scss/custom_style.scss b/jikimo_frontend/static/src/scss/custom_style.scss index 0b6fb8bb..cbd1bb4d 100644 --- a/jikimo_frontend/static/src/scss/custom_style.scss +++ b/jikimo_frontend/static/src/scss/custom_style.scss @@ -530,4 +530,11 @@ div:has(.o_required_modifier) > label::before { // 修复表格内容覆盖表头bug .o_list_renderer .o_list_table tbody th { position: unset; -} \ No newline at end of file +} + +// 修改表格下拉框会被表格下面数据框覆盖的bug +.tab-pane .o_field_widget { + position: relative; + z-index: 1; +} + diff --git a/web_widget_model_viewer/static/src/js/3d_viewer.js b/web_widget_model_viewer/static/src/js/3d_viewer.js index 15374070..4ed9dcc1 100644 --- a/web_widget_model_viewer/static/src/js/3d_viewer.js +++ b/web_widget_model_viewer/static/src/js/3d_viewer.js @@ -10,11 +10,18 @@ import {session} from "@web/session"; // var QWeb = core.qweb; -import {Component} from "@odoo/owl"; +import {Component, onPatched} from "@odoo/owl"; export class StepViewer extends Component { setup() { this.props.url = this.formatUrl(); + onPatched(() => { + this.props.url = this.formatUrl(); + const dom = $(this.__owl__.bdom.parentEl).children('model-viewer') + if(dom && dom.length) { + dom.attr('src', this.formatUrl()) + } + }) } formatUrl() { From 1672a3982e1b3895f62e31aace7299b7290fdec5 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Fri, 5 Jul 2024 17:09:32 +0800 Subject: [PATCH 15/20] =?UTF-8?q?1=E3=80=81=E5=AE=8C=E6=88=90=20SF?= =?UTF-8?q?=E6=9D=90=E6=96=99=E6=9D=90=E6=96=99=E5=9E=8B=E5=8F=B7=E7=BC=BA?= =?UTF-8?q?=E9=99=B7=E4=BC=98=E5=8C=96=20=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/models/common.py | 10 +++---- sf_base/views/common_view.xml | 6 ++-- sf_sale/models/sale_order.py | 54 +++++++++++++++++------------------ 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/sf_base/models/common.py b/sf_base/models/common.py index 6fd7d814..888f3eaf 100644 --- a/sf_base/models/common.py +++ b/sf_base/models/common.py @@ -61,12 +61,10 @@ class MrsMaterialModel(models.Model): supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商') active = fields.Boolean('有效', default=True) - @api.onchange('gain_way') - def _check_gain_way(self): - if not self.gain_way: - raise UserError("请选择获取方式") - if self.gain_way in ['外协', '采购']: - if not self.supplier_ids: + @api.constrains("gain_way") + def _check_supplier_ids(self): + for item in self: + if item.gain_way in ('外协', '采购') and not item.supplier_ids: raise UserError("请添加供应商") diff --git a/sf_base/views/common_view.xml b/sf_base/views/common_view.xml index 74e916a8..a7cbcf9e 100644 --- a/sf_base/views/common_view.xml +++ b/sf_base/views/common_view.xml @@ -251,7 +251,7 @@ - + @@ -270,9 +270,9 @@ - + - + diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index f47f8c8d..2791c760 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -256,33 +256,33 @@ class ResPartnerToSale(models.Model): # if obj: # raise UserError('该邮箱已存在,请重新输入') - @api.model - def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): - if self._context.get('is_customer'): - if self.env.user.has_group('sf_base.group_sale_director'): - domain = [('customer_rank', '>', 0)] - elif self.env.user.has_group('sf_base.group_sale_salemanager'): - customer = self.env['res.partner'].search( - [('customer_rank', '>', 0), ('user_id', '=', self.env.user.id)]) - if customer: - ids = [t.id for t in customer] - domain = [('id', 'in', ids)] - else: - domain = [('id', '=', False)] - return self._search(domain, limit=limit, access_rights_uid=name_get_uid) - elif self._context.get('is_supplier') or self.env.user.has_group('sf_base.group_purchase_director'): - if self.env.user.has_group('sf_base.group_purchase_director'): - domain = [('supplier_rank', '>', 0)] - elif self.env.user.has_group('sf_base.group_purchase'): - supplier = self.env['res.partner'].search( - [('supplier_rank', '>', 0), ('purchase_user_id', '=', self.env.user.id)]) - if supplier: - ids = [t.id for t in supplier] - domain = [('id', 'in', ids)] - else: - domain = [('id', '=', False)] - return self._search(domain, limit=limit, access_rights_uid=name_get_uid) - return super()._name_search(name, args, operator, limit, name_get_uid) + # @api.model + # def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): + # if self._context.get('is_customer'): + # if self.env.user.has_group('sf_base.group_sale_director'): + # domain = [('customer_rank', '>', 0)] + # elif self.env.user.has_group('sf_base.group_sale_salemanager'): + # customer = self.env['res.partner'].search( + # [('customer_rank', '>', 0), ('user_id', '=', self.env.user.id)]) + # if customer: + # ids = [t.id for t in customer] + # domain = [('id', 'in', ids)] + # else: + # domain = [('id', '=', False)] + # return self._search(domain, limit=limit, access_rights_uid=name_get_uid) + # elif self._context.get('is_supplier') or self.env.user.has_group('sf_base.group_purchase_director'): + # if self.env.user.has_group('sf_base.group_purchase_director'): + # domain = [('supplier_rank', '>', 0)] + # elif self.env.user.has_group('sf_base.group_purchase'): + # supplier = self.env['res.partner'].search( + # [('supplier_rank', '>', 0), ('purchase_user_id', '=', self.env.user.id)]) + # if supplier: + # ids = [t.id for t in supplier] + # domain = [('id', 'in', ids)] + # else: + # domain = [('id', '=', False)] + # return self._search(domain, limit=limit, access_rights_uid=name_get_uid) + # return super()._name_search(name, args, operator, limit, name_get_uid) @api.onchange('user_id') def _get_salesman(self): From ed4903b6f17a8e9f5775c3604efd537af0d7f260 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 9 Jul 2024 10:18:13 +0800 Subject: [PATCH 16/20] =?UTF-8?q?=E8=A7=A3=E9=99=A4=E8=A3=85=E5=A4=B9?= =?UTF-8?q?=E5=A4=84=E6=89=93=E5=8D=B0=E6=88=90=E5=93=81=E4=BA=8C=E7=BB=B4?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/mrp_workorder.py | 10 ++++++++++ sf_manufacturing/models/stock.py | 1 + sf_manufacturing/views/mrp_workorder_view.xml | 2 ++ 3 files changed, 13 insertions(+) diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 4b9371c2..16ae67f3 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1093,6 +1093,16 @@ class ResMrpWorkOrder(models.Model): # logging.info('button_send_program_again error:%s' % e) # raise UserError("重新下发nc程序失败,请联系管理员") + def print_method(self): + """ + 解除装夹处调用关联制造订单的关联序列号的打印方法 + """ + if self.production_id: + if self.production_id.lot_producing_id: + self.production_id.lot_producing_id.print_single_method() + else: + raise UserError("无关联制造订单或关联序列号,无法打印。请检查!") + class CNCprocessing(models.Model): _name = 'sf.cnc.processing' diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index 9234060f..c6c8ec6b 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -404,6 +404,7 @@ class ProductionLot(models.Model): def print_single_method(self): + print('self.name========== %s' % self.name) self.ensure_one() qr_code_data = self.qr_code_image if not qr_code_data: diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index dc5b4a56..70cf0448 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -165,6 +165,8 @@ +