From adafce85bde79c7105934ddd265bc48492c7580c Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Tue, 11 Jun 2024 16:56:20 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=B7=A5=E5=8D=95,=E5=B7=A5=E4=BB=B6?= =?UTF-8?q?=E9=85=8D=E9=80=81=E6=96=B0=E5=A2=9Esns=E5=8F=8A=E7=BB=99?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=AD=97=E6=AE=B5=E6=B7=BB=E5=8A=A0tracking(?= =?UTF-8?q?=E8=B7=9F=E8=B8=AA)=E5=8F=8A=E4=BC=98=E5=8C=96=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=202.=E4=BC=98=E5=8C=96agv=EF=BC=9A=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E4=B8=8D=E5=8F=AF=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mrp_workorder/models/mrp_workorder.py | 58 ++++++++++++------- mrp_workorder/views/mrp_workorder_views.xml | 7 +++ sf_manufacturing/models/agv_setting.py | 13 ++++- sf_manufacturing/models/mrp_production.py | 6 +- sf_manufacturing/models/mrp_workorder.py | 40 ++++++++----- sf_manufacturing/models/product_template.py | 4 +- sf_manufacturing/views/agv_setting_views.xml | 19 +++--- sf_manufacturing/views/mrp_workorder_view.xml | 40 +++++++++---- sf_sale/models/quick_easy_order.py | 25 ++++---- sf_sale/models/quick_easy_order_old.py | 23 ++++---- sf_sale/views/quick_easy_order_view.xml | 5 ++ 11 files changed, 157 insertions(+), 83 deletions(-) diff --git a/mrp_workorder/models/mrp_workorder.py b/mrp_workorder/models/mrp_workorder.py index 81be5f2d..01363bb5 100644 --- a/mrp_workorder/models/mrp_workorder.py +++ b/mrp_workorder/models/mrp_workorder.py @@ -27,7 +27,7 @@ class MrpWorkcenter(models.Model): class MrpProductionWorkcenterLine(models.Model): _name = 'mrp.workorder' - _inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin'] + _inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin', 'mail.thread', 'mail.activity.mixin'] quality_point_ids = fields.Many2many('quality.point', compute='_compute_quality_point_ids', store=True) quality_point_count = fields.Integer('Steps', compute='_compute_quality_point_count') @@ -47,14 +47,17 @@ class MrpProductionWorkcenterLine(models.Model): is_last_lot = fields.Boolean('Is Last lot', compute='_compute_is_last_lot') is_first_started_wo = fields.Boolean('Is The first Work Order', compute='_compute_is_last_unfinished_wo') - is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', store=False) + is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', + store=False) lot_id = fields.Many2one(related='current_quality_check_id.lot_id', readonly=False) move_id = fields.Many2one(related='current_quality_check_id.move_id', readonly=False) move_line_id = fields.Many2one(related='current_quality_check_id.move_line_id', readonly=False) move_line_ids = fields.One2many(related='move_id.move_line_ids') - quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", readonly=False) + quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", + readonly=False) qty_done = fields.Float(related='current_quality_check_id.qty_done', readonly=False) - test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', related='current_quality_check_id.test_type_id') + test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', + related='current_quality_check_id.test_type_id') test_type = fields.Char(related='test_type_id.technical_name') user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False) worksheet_page = fields.Integer('Worksheet page') @@ -65,7 +68,8 @@ class MrpProductionWorkcenterLine(models.Model): def _compute_quality_point_ids(self): for workorder in self: quality_points = workorder.operation_id.quality_point_ids - quality_points = quality_points.filtered(lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids) + quality_points = quality_points.filtered( + lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids) workorder.quality_point_ids = quality_points @api.depends('operation_id') @@ -91,7 +95,8 @@ class MrpProductionWorkcenterLine(models.Model): @api.depends('check_ids') def _compute_finished_product_check_ids(self): for wo in self: - wo.finished_product_check_ids = wo.check_ids.filtered(lambda c: c.finished_product_sequence == wo.qty_produced) + wo.finished_product_check_ids = wo.check_ids.filtered( + lambda c: c.finished_product_sequence == wo.qty_produced) def write(self, values): res = super().write(values) @@ -138,7 +143,8 @@ class MrpProductionWorkcenterLine(models.Model): self.finished_lot_id = self.env['stock.lot'].create({ 'product_id': self.product_id.id, 'company_id': self.company_id.id, - 'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env['ir.sequence'].next_by_code('stock.lot.serial'), + 'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[ + 'ir.sequence'].next_by_code('stock.lot.serial'), }) def _create_subsequent_checks(self): @@ -152,7 +158,7 @@ class MrpProductionWorkcenterLine(models.Model): """ # Create another quality check if necessary next_check = self.current_quality_check_id.next_check_id - if next_check.component_id != self.current_quality_check_id.product_id or\ + if next_check.component_id != self.current_quality_check_id.product_id or \ next_check.point_id != self.current_quality_check_id.point_id: # TODO: manage reservation here @@ -279,7 +285,8 @@ class MrpProductionWorkcenterLine(models.Model): if self.current_quality_check_id: team = self.current_quality_check_id.team_id else: - team = self.env['quality.alert.team'].search(['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1) + team = self.env['quality.alert.team'].search( + ['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1) return { 'type': 'ir.actions.act_window', 'res_model': 'quality.check', @@ -320,7 +327,8 @@ class MrpProductionWorkcenterLine(models.Model): production = wo.production_id move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel')) - move_finished_ids = wo.move_finished_ids.filtered(lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id) + move_finished_ids = wo.move_finished_ids.filtered( + lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id) previous_check = self.env['quality.check'] for point in wo.quality_point_ids: # Check if we need a quality control for this point @@ -342,11 +350,13 @@ class MrpProductionWorkcenterLine(models.Model): if point.test_type == 'register_byproducts': moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id) if not moves: - moves = production.move_finished_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id) + moves = production.move_finished_ids.filtered( + lambda m: not m.operation_id and m.product_id == point.component_id) elif point.test_type == 'register_consumed_materials': moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id) if not moves: - moves = production.move_raw_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id) + moves = production.move_raw_ids.filtered( + lambda m: not m.operation_id and m.product_id == point.component_id) else: check = self.env['quality.check'].create(values) previous_check.next_check_id = check @@ -363,8 +373,10 @@ class MrpProductionWorkcenterLine(models.Model): processed_move |= moves # Generate quality checks associated with unreferenced components - moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id) - quality_team_id = self.env['quality.alert.team'].search(['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id + moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: ( + move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id) + quality_team_id = self.env['quality.alert.team'].search( + ['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id for move in moves_without_check: values = { 'production_id': production.id, @@ -412,7 +424,8 @@ class MrpProductionWorkcenterLine(models.Model): backorder = False # Trigger the backorder process if we produce less than expected - if float_compare(self.qty_producing, self.qty_remaining, precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo: + if float_compare(self.qty_producing, self.qty_remaining, + precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo: backorder = self.production_id._split_productions()[1:] for workorder in backorder.workorder_ids: if workorder.product_tracking == 'serial': @@ -423,7 +436,8 @@ class MrpProductionWorkcenterLine(models.Model): else: if self.operation_id: backorder = (self.production_id.procurement_group_id.mrp_production_ids - self.production_id).filtered( - lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ('cancel', 'done') + lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ( + 'cancel', 'done') )[:1] else: index = list(self.production_id.workorder_ids).index(self) @@ -442,7 +456,8 @@ class MrpProductionWorkcenterLine(models.Model): wo.current_quality_check_id._update_component_quantity() if not self.env.context.get('no_start_next'): if self.operation_id: - return backorder.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).open_tablet_view() + return backorder.workorder_ids.filtered( + lambda wo: wo.operation_id == self.operation_id).open_tablet_view() else: index = list(self.production_id.workorder_ids).index(self) return backorder.workorder_ids[index].open_tablet_view() @@ -466,7 +481,8 @@ class MrpProductionWorkcenterLine(models.Model): def open_tablet_view(self): self.ensure_one() - if not self.is_user_working and self.working_state != 'blocked' and self.state in ('ready', 'waiting', 'progress', 'pending'): + if not self.is_user_working and self.working_state != 'blocked' and self.state in ( + 'ready', 'waiting', 'progress', 'pending'): self.button_start() action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action") action['target'] = 'fullscreen' @@ -521,7 +537,8 @@ class MrpProductionWorkcenterLine(models.Model): data = { 'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0], 'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list), - 'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[0] if self.operation_id else {}, + 'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[ + 0] if self.operation_id else {}, 'working_state': self.workcenter_id.working_state, 'views': { 'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id, @@ -553,7 +570,8 @@ class MrpProductionWorkcenterLine(models.Model): return { 'duration': self.duration, - 'position': bisect_left(last30op, self.duration), # which position regarded other workorders ranked by duration + 'position': bisect_left(last30op, self.duration), + # which position regarded other workorders ranked by duration 'quality_score': score, 'show_rainbow': show_rainbow, } diff --git a/mrp_workorder/views/mrp_workorder_views.xml b/mrp_workorder/views/mrp_workorder_views.xml index 37702c00..8c208f19 100644 --- a/mrp_workorder/views/mrp_workorder_views.xml +++ b/mrp_workorder/views/mrp_workorder_views.xml @@ -27,6 +27,13 @@ + +
+ + + +
+
diff --git a/sf_manufacturing/models/agv_setting.py b/sf_manufacturing/models/agv_setting.py index 64af1d90..06f9edba 100644 --- a/sf_manufacturing/models/agv_setting.py +++ b/sf_manufacturing/models/agv_setting.py @@ -2,7 +2,8 @@ import requests import logging import time -from odoo import fields, models +from odoo import fields, models, api +from odoo.exceptions import UserError class AgvSetting(models.Model): @@ -59,11 +60,17 @@ class AgvTaskRoute(models.Model): ('F01', '搬运'), ], string='任务类型', default="F01") route_type = fields.Selection([ ('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型') - start_site_id = fields.Many2one('sf.agv.site', '起点接驳站位置编号') - end_site_id = fields.Many2one('sf.agv.site', '终点接驳站位置编号') + start_site_id = fields.Many2one('sf.agv.site', '起点接驳站') + end_site_id = fields.Many2one('sf.agv.site', '终点接驳站') destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线') active = fields.Boolean('有效', default=True) + @api.constrains('end_site_id') + def _check_end_site_id(self): + if self.end_site_id: + if self.end_site_id == self.start_site_id: + raise UserError("您选择的终点接驳站与起点接驳站重复,请重新选择") + class Center_controlInterfaceLog(models.Model): _name = 'center_control.interface.log' diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 3e155f78..6048be00 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -53,13 +53,13 @@ class MrpProduction(models.Model): active = fields.Boolean(string='已归档', default=True) programming_no = fields.Char('编程单号') work_state = fields.Char('业务状态') - programming_state = fields.Char('编程状态') + programming_state = fields.Char('编程状态', tracking=True) glb_file = fields.Binary("glb模型文件") - production_line_id = fields.Many2one('sf.production.line', string='生产线') + production_line_id = fields.Many2one('sf.production.line', string='生产线', tracking=True) plan_start_processing_time = fields.Datetime('计划开始加工时间') production_line_state = fields.Selection( [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], - string='上/下产线', default='待上产线') + string='上/下产线', default='待上产线', tracking=True) # 工序状态 # Todo 研究下用法 process_state = fields.Selection([ diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 366fa212..7eea98da 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -102,7 +102,7 @@ class ResMrpWorkOrder(models.Model): Z10_axis = fields.Float(default=0) X_deviation_angle = fields.Integer(string="X轴偏差度", default=0) test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格', - string="检测结果") + string="检测结果", tracking=True) cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序") cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序") tray_code = fields.Char(string="托盘编码") @@ -133,7 +133,7 @@ class ResMrpWorkOrder(models.Model): return action supplier_id = fields.Many2one('res.partner', string='外协供应商') - equipment_id = fields.Many2one('maintenance.equipment', string='加工设备') + equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True) is_ok = fields.Boolean(string='是否合格') # 加工人 processing_user_id = fields.Many2one('res.users', string='加工人') @@ -195,15 +195,15 @@ class ResMrpWorkOrder(models.Model): rfid_code_old = fields.Char('RFID码(已解除)') production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id', - string='生产线', store=True) + string='生产线', store=True, tracking=True) production_line_state = fields.Selection(related='production_id.production_line_state', - string='上/下产线', store=True) + string='上/下产线', store=True, tracking=True) detection_report = fields.Binary('检测报告', readonly=True) is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False) is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False) reason = fields.Selection( [("programming", "编程"), ("clamping", "返工"), ("cutter", "刀具"), ("operate computer", "操机"), - ("technology", "工艺"), ("customer redrawing", "客户改图"), ("other", "其他"), ], string="原因") + ("technology", "工艺"), ("customer redrawing", "客户改图"), ("other", "其他"), ], string="原因", tracking=True) detailed_reason = fields.Text('详细原因') @api.onchange('rfid_code') @@ -1346,19 +1346,33 @@ class WorkPieceDelivery(models.Model): @api.model def create(self, vals): - if vals.get('name', '/') == '/' or vals.get('name', '/') is False: - vals['name'] = self.env['ir.sequence'].next_by_code('sf.workpiece.delivery') or '/' - else: + if vals['route_id'] and vals.get('type') is None: vals['type'] = '运送空料架' + else: + if vals.get('name', '/') == '/' or vals.get('name', '/') is False: + vals['name'] = self.env['ir.sequence'].next_by_code('sf.workpiece.delivery') or '/' obj = super(WorkPieceDelivery, self).create(vals) + if obj.type == '运送空料架': + if obj.name is False: + obj.name = "运送空料架路线:%s-%s" % ( + obj.feeder_station_start_id.name, obj.feeder_station_destination_id.name) return obj - @api.constrains('name') - def _check_name(self): + @api.constrains('route_id') + def _check_route_id(self): if self.type == '运送空料架': - wd = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id)]) - if wd: - raise UserError("该名称已存在") + if self.route_id and self.name is False: + route = self.sudo().search( + [('route_id', '=', self.route_id.id), ('id', '!=', self.id), ('name', 'ilike', '运送空料架路线')]) + if route: + raise UserError("该任务路线已存在,请重新选择") + + # @api.constrains('name') + # def _check_name(self): + # if self.type == '运送空料架': + # wd = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id)]) + # if wd: + # raise UserError("该名称已存在") def action_delivery_history(self): return { diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index 9179d991..b7793896 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -7,8 +7,8 @@ import os from odoo import models, fields, api, _ from odoo.exceptions import ValidationError from odoo.modules import get_resource_path -# from OCC.Extend.DataExchange import read_step_file -# from OCC.Extend.DataExchange import write_stl_file +from OCC.Extend.DataExchange import read_step_file +from OCC.Extend.DataExchange import write_stl_file class ResProductMo(models.Model): diff --git a/sf_manufacturing/views/agv_setting_views.xml b/sf_manufacturing/views/agv_setting_views.xml index 9a4bf25e..377bee74 100644 --- a/sf_manufacturing/views/agv_setting_views.xml +++ b/sf_manufacturing/views/agv_setting_views.xml @@ -7,9 +7,9 @@ sf.agv.site - - - + + + @@ -34,12 +34,14 @@ sf.agv.task.route - + - - + + - + @@ -73,7 +75,8 @@ center_control.interface.log - + + diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index 6c907c3a..083eca14 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -683,9 +683,9 @@ sf.workpiece.delivery - - - + + + @@ -695,9 +695,6 @@ - - - @@ -710,7 +707,9 @@ 工件配送 sf.workpiece.delivery - {'search_default_on_up':1} + {'search_default_filter_to_be_issued': 1, + 'search_default_filter_waiting_delivery': 1} + tree,form [('type','in',['上产线','下产线']),('workorder_state','=','done'),('is_manual_work','=',false)] @@ -724,23 +723,39 @@ sf.workpiece.delivery -
-
- + + + + + +