From 5d8f0f83b2229b56540698db5a543273d774b982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Wed, 7 Aug 2024 17:44:43 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0AGV=E8=B0=83=E5=BA=A6?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=B7=A5=E5=8D=95=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E7=AD=9B=E9=80=89?= =?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_machine_connect/models/__init__.py | 1 + sf_machine_connect/models/mrp_workorder.py | 38 ++++++++++++++ .../views/WorkCenterBarcodes.xml | 1 + sf_manufacturing/__manifest__.py | 2 +- sf_manufacturing/controllers/controllers.py | 2 +- sf_manufacturing/models/__init__.py | 1 + sf_manufacturing/models/agv_dispatch.py | 50 +++++++++++++++++++ sf_manufacturing/models/agv_setting.py | 13 ++++- sf_manufacturing/models/mrp_workcenter.py | 2 + sf_manufacturing/models/mrp_workorder.py | 3 ++ sf_manufacturing/security/ir.model.access.csv | 2 + sf_manufacturing/views/agv_dispatch_views.xml | 50 +++++++++++++++++++ sf_manufacturing/views/agv_setting_views.xml | 7 +-- .../views/mrp_workcenter_views.xml | 1 + 14 files changed, 167 insertions(+), 6 deletions(-) create mode 100644 sf_machine_connect/models/mrp_workorder.py create mode 100644 sf_manufacturing/models/agv_dispatch.py create mode 100644 sf_manufacturing/views/agv_dispatch_views.xml diff --git a/sf_machine_connect/models/__init__.py b/sf_machine_connect/models/__init__.py index ef61fd83..01ae60ae 100644 --- a/sf_machine_connect/models/__init__.py +++ b/sf_machine_connect/models/__init__.py @@ -2,3 +2,4 @@ from . import ftp_client from . import ftp_operate from . import py2opcua from . import res_config_setting +from . import mrp_workorder diff --git a/sf_machine_connect/models/mrp_workorder.py b/sf_machine_connect/models/mrp_workorder.py new file mode 100644 index 00000000..21cc96ac --- /dev/null +++ b/sf_machine_connect/models/mrp_workorder.py @@ -0,0 +1,38 @@ +import re + +from odoo import fields, models, api + + +class ResMrpWorkOrder(models.Model): + _inherit = 'mrp.workorder' + + mixed_search_field = fields.Char(string='坯料产品名称/RFID') + + @api.model + def web_read_group(self, domain, fields, groupby, limit=None, offset=0, orderby=False, + lazy=True, expand=False, expand_limit=None, expand_orderby=False): + domain = domain or [] + for index, item in enumerate(domain): + if isinstance(item, list): + if item[0] == 'mixed_search_field': + if self._is_rfid_code(item[2]): + domain[index] = ['rfid_code', item[1], item[2]] + else: + domain[index] = ['product_tmpl_name', item[1], item[2]] + + return super(ResMrpWorkOrder, self).web_read_group(domain, fields, groupby, limit=limit, offset=offset, orderby=orderby, + lazy=lazy, expand=expand, expand_limit=expand_limit, expand_orderby=expand_orderby) + + def _is_rfid_code(self, tag): + """ + 判断是否是rfid_code + """ + # 基于长度判断(假设RFID标签长度为10到16个字符) + if not 10 <= len(tag) <= 16: + return False + + # 基于字符集判断(仅包含数字和字母) + if not re.match("^[0-9]*$", tag): + return False + + return True \ No newline at end of file diff --git a/sf_machine_connect/views/WorkCenterBarcodes.xml b/sf_machine_connect/views/WorkCenterBarcodes.xml index 9e5d3982..97fee70e 100644 --- a/sf_machine_connect/views/WorkCenterBarcodes.xml +++ b/sf_machine_connect/views/WorkCenterBarcodes.xml @@ -26,6 +26,7 @@ + diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 39da4482..a4199939 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -21,6 +21,7 @@ 'wizard/rework_wizard_views.xml', 'wizard/production_wizard_views.xml', 'views/mrp_views_menus.xml', + 'views/agv_dispatch_views.xml', 'views/stock_lot_views.xml', 'views/mrp_production_addional_change.xml', 'views/mrp_routing_workcenter_view.xml', @@ -30,7 +31,6 @@ 'views/model_type_view.xml', 'views/agv_setting_views.xml', 'views/sf_maintenance_equipment.xml', - ], 'assets': { diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py index babda164..037730bc 100644 --- a/sf_manufacturing/controllers/controllers.py +++ b/sf_manufacturing/controllers/controllers.py @@ -429,7 +429,7 @@ class Manufacturing_Connect(http.Controller): logging.info('LocationChange error:%s' % e) return json.JSONEncoder().encode(res) - @http.route('/AutoDeviceApi/AGVToProduct', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, + @http.route('/AutoDeviceApi/AGVToProduct', type='json', auth='public', methods=['GET', 'POST'], csrf=False, cors="*") def AGVToProduct(self, **kw): """ diff --git a/sf_manufacturing/models/__init__.py b/sf_manufacturing/models/__init__.py index 3de23ef3..0b212cdb 100644 --- a/sf_manufacturing/models/__init__.py +++ b/sf_manufacturing/models/__init__.py @@ -9,3 +9,4 @@ from . import stock from . import res_user from . import production_line_base from . import agv_setting +from . import agv_dispatch diff --git a/sf_manufacturing/models/agv_dispatch.py b/sf_manufacturing/models/agv_dispatch.py new file mode 100644 index 00000000..f82b3f07 --- /dev/null +++ b/sf_manufacturing/models/agv_dispatch.py @@ -0,0 +1,50 @@ +from odoo import models, fields, api +from odoo.exceptions import ValidationError + + +class AgvDispatch(models.Model): + _name = 'sf.agv.dispatch' + _description = 'agv调度' + + name = fields.Char('任务单号') + + def _get_agv_route_type_selection(self): + return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection'] + + agv_route_type = fields.Selection(selection=_get_agv_route_type_selection, string='任务类型') + agv_route_name = fields.Char('任务路线名称') + start_site_id = fields.Many2one('sf.agv.site', '起点接驳站') + end_site_id = fields.Many2one('sf.agv.site', '终点接驳站') + site_state = fields.Selection([ + ('占用', '占用'), + ('空闲', '空闲')], string='终点接驳站状态') + state = fields.Selection([ + ('待下发', '待下发'), + ('配送中', '配送中'), + ('已配送', '已配送'), + ('已取消', '已取消')], string='状态', default='待下发') + workpiece_delivery_ids = fields.One2many('sf.workpiece.delivery', 'agv_dispatch_id', string='工件配送单') + delivery_workpieces = fields.Char('配送工件', compute='_compute_delivery_workpieces') + + @api.depends('workpiece_delivery_ids') + def _compute_delivery_workpieces(self): + for rec in self: + rec.delivery_workpieces = '\\'.join(rec.workpiece_delivery_ids.mapped('name')) + + task_create_time = fields.Datetime('任务创建时间') + task_delivery_time = fields.Datetime('任务下发时间') + task_completion_time = fields.Datetime('任务完成时间') + task_duration = fields.Char('任务时长', compute='_compute_task_duration') + + @api.depends('task_completion_time', 'task_delivery_time') + def _compute_task_duration(self): + for rec in self: + if rec.task_completion_time and rec.task_delivery_time: + rec.task_duration = str(rec.task_completion_time - rec.task_delivery_time) + else: + rec.task_duration = '' + + def add_queue(self, vals): + if not vals.get('agv_route_type') or vals.get('agv_route_type') not in self._get_agv_route_type_selection(): + raise ValidationError('无效的路线类型!') + self.env['sf.agv.dispatch'].sudo().create(vals) diff --git a/sf_manufacturing/models/agv_setting.py b/sf_manufacturing/models/agv_setting.py index 06f9edba..833b2659 100644 --- a/sf_manufacturing/models/agv_setting.py +++ b/sf_manufacturing/models/agv_setting.py @@ -11,12 +11,14 @@ class AgvSetting(models.Model): _description = 'agv站点' name = fields.Char('位置编号') - owning_region = fields.Char('所属区域') + # owning_region = fields.Char('所属区域') state = fields.Selection([ ('占用', '占用'), ('空闲', '空闲')], string='状态') divide_the_work = fields.Char('主要分工') active = fields.Boolean('有效', default=True) + region = fields.Many2one(string='所属区域', comodel_name='mrp.workcenter', tracking=True, + domain=[('is_agv_dispatch', '=', True)]) def update_site_state(self): # 调取中控的接驳站接口并修改对应站点的状态 @@ -71,6 +73,15 @@ class AgvTaskRoute(models.Model): if self.end_site_id == self.start_site_id: raise UserError("您选择的终点接驳站与起点接驳站重复,请重新选择") + region = fields.Many2one(string='所属区域', comodel_name='mrp.workcenter', domain=[('is_agv_dispatch', '=', True)], + compute="_compute_region") + + @api.depends('end_site_id') + def _compute_region(self): + for record in self: + if record.end_site_id: + record.region = record.end_site_id.region + class Center_controlInterfaceLog(models.Model): _name = 'center_control.interface.log' diff --git a/sf_manufacturing/models/mrp_workcenter.py b/sf_manufacturing/models/mrp_workcenter.py index 64cf2d8d..8fb62e7d 100644 --- a/sf_manufacturing/models/mrp_workcenter.py +++ b/sf_manufacturing/models/mrp_workcenter.py @@ -124,6 +124,8 @@ class ResWorkcenter(models.Model): res[wc_id] = [(datetime.fromtimestamp(s), datetime.fromtimestamp(e)) for s, e, _ in final_intervals_wc] return res + # AGV是否可配送 + is_agv_dispatch = fields.Boolean(string="AGV配送", tracking=True) class ResWorkcenterProductivity(models.Model): _inherit = 'mrp.workcenter.productivity' diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 8f045703..060b06cf 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -1744,6 +1744,9 @@ class WorkPieceDelivery(models.Model): else: obj.delivery_duration = 0.0 + # agv调度单 + agv_dispatch_id = fields.Many2one('sf.agv.dispatch', 'agv调度单') + class CMMprogram(models.Model): _name = 'sf.cmm.program' diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index 9b5b5e28..2fd16b53 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -150,5 +150,7 @@ access_sf_processing_panel_group_sf_order_user,sf_processing_panel_group_sf_orde access_sf_production_wizard_group_sf_order_user,sf_production_wizard_group_sf_order_user,model_sf_production_wizard,sf_base.group_sf_order_user,1,1,1,0 access_sf_processing_panel_group_plan_dispatch,sf_processing_panel_group_plan_dispatch,model_sf_processing_panel,sf_base.group_plan_dispatch,1,1,1,0 +access_sf_agv_dispatch_admin,sf_agv_dispatch_admin,model_sf_agv_dispatch,base.group_system,1,1,1,1 + diff --git a/sf_manufacturing/views/agv_dispatch_views.xml b/sf_manufacturing/views/agv_dispatch_views.xml new file mode 100644 index 00000000..5cf608b6 --- /dev/null +++ b/sf_manufacturing/views/agv_dispatch_views.xml @@ -0,0 +1,50 @@ + + + + + + agv调度 + sf.agv.dispatch + + + + + + + + + + + + + + + + + + + AGV调度 + sf.agv.dispatch + tree + + + + + + + + + + + \ No newline at end of file diff --git a/sf_manufacturing/views/agv_setting_views.xml b/sf_manufacturing/views/agv_setting_views.xml index 377bee74..66f728f0 100644 --- a/sf_manufacturing/views/agv_setting_views.xml +++ b/sf_manufacturing/views/agv_setting_views.xml @@ -8,7 +8,7 @@ - + @@ -40,8 +40,9 @@ - + + + diff --git a/sf_manufacturing/views/mrp_workcenter_views.xml b/sf_manufacturing/views/mrp_workcenter_views.xml index ad433bf6..61242cba 100644 --- a/sf_manufacturing/views/mrp_workcenter_views.xml +++ b/sf_manufacturing/views/mrp_workcenter_views.xml @@ -182,6 +182,7 @@ + From a79500d0ad9d33211a3b1e27f66a6ad38f5c6d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=B0=A7?= Date: Thu, 8 Aug 2024 17:47:03 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0agv=E8=B0=83=E5=BA=A6?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/__manifest__.py | 1 + sf_manufacturing/data/agv_dispatch_data.xml | 12 ++ sf_manufacturing/models/agv_dispatch.py | 48 ++++-- sf_manufacturing/models/agv_setting.py | 8 +- sf_manufacturing/models/mrp_workorder.py | 149 ++++++++---------- sf_manufacturing/views/agv_setting_views.xml | 4 +- sf_manufacturing/views/mrp_workorder_view.xml | 12 +- .../wizard/workpiece_delivery_views.xml | 14 +- .../wizard/workpiece_delivery_wizard.py | 46 +++++- 9 files changed, 168 insertions(+), 126 deletions(-) create mode 100644 sf_manufacturing/data/agv_dispatch_data.xml diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index a4199939..f17a40df 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -15,6 +15,7 @@ 'data/stock_data.xml', 'data/empty_racks_data.xml', 'data/panel_data.xml', + 'data/agv_dispatch_data.xml', 'security/group_security.xml', 'security/ir.model.access.csv', 'wizard/workpiece_delivery_views.xml', diff --git a/sf_manufacturing/data/agv_dispatch_data.xml b/sf_manufacturing/data/agv_dispatch_data.xml new file mode 100644 index 00000000..32b76406 --- /dev/null +++ b/sf_manufacturing/data/agv_dispatch_data.xml @@ -0,0 +1,12 @@ + + + + + AGV调度 + sf.agv.dispatch + B%(year)s%(month)s%(day)s + 4 + + + + \ No newline at end of file diff --git a/sf_manufacturing/models/agv_dispatch.py b/sf_manufacturing/models/agv_dispatch.py index f82b3f07..74c981f1 100644 --- a/sf_manufacturing/models/agv_dispatch.py +++ b/sf_manufacturing/models/agv_dispatch.py @@ -1,20 +1,24 @@ -from odoo import models, fields, api -from odoo.exceptions import ValidationError +from odoo import models, fields, api, _ +from odoo.exceptions import UserError + +import logging + +_logger = logging.getLogger(__name__) class AgvDispatch(models.Model): _name = 'sf.agv.dispatch' _description = 'agv调度' - name = fields.Char('任务单号') + name = fields.Char('任务单号', index=True, copy=False) def _get_agv_route_type_selection(self): return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection'] - agv_route_type = fields.Selection(selection=_get_agv_route_type_selection, string='任务类型') + agv_route_type = fields.Selection(selection=_get_agv_route_type_selection, string='任务类型', required=True) agv_route_name = fields.Char('任务路线名称') - start_site_id = fields.Many2one('sf.agv.site', '起点接驳站') - end_site_id = fields.Many2one('sf.agv.site', '终点接驳站') + start_site_id = fields.Many2one('sf.agv.site', '起点接驳站', required=True) + end_site_id = fields.Many2one('sf.agv.site', '终点接驳站', tracking=True) site_state = fields.Selection([ ('占用', '占用'), ('空闲', '空闲')], string='终点接驳站状态') @@ -22,7 +26,8 @@ class AgvDispatch(models.Model): ('待下发', '待下发'), ('配送中', '配送中'), ('已配送', '已配送'), - ('已取消', '已取消')], string='状态', default='待下发') + ('已取消', '已取消')], string='状态', default='待下发', tracking=True) + productions = fields.Char('制造订单', compute='_compute_productions') workpiece_delivery_ids = fields.One2many('sf.workpiece.delivery', 'agv_dispatch_id', string='工件配送单') delivery_workpieces = fields.Char('配送工件', compute='_compute_delivery_workpieces') @@ -44,7 +49,28 @@ class AgvDispatch(models.Model): else: rec.task_duration = '' - def add_queue(self, vals): - if not vals.get('agv_route_type') or vals.get('agv_route_type') not in self._get_agv_route_type_selection(): - raise ValidationError('无效的路线类型!') - self.env['sf.agv.dispatch'].sudo().create(vals) + @api.model_create_multi + def create(self, vals_list): + # We generate a standard reference + for vals in vals_list: + vals['name'] = self.env['ir.sequence'].next_by_code('sf.agv.dispatch') or _('New') + return super().create(vals_list) + + def add_queue(self, agv_start_site_id, agv_route_type, production_ids, delivery_ids): + """ + 根据参数增加AGV调度任务 + """ + vals = { + 'start_site_id': agv_start_site_id, + 'agv_route_type': agv_route_type, + 'productions': '、'.join(production_ids.mapped('name')), + 'workpiece_delivery_ids': delivery_ids or [], + 'task_create_time': fields.Datetime.now() + } + try: + dispatch = self.env['sf.agv.dispatch'].sudo().create(vals) + except Exception as e: + _logger.error('添加AGV调度任务失败: %s', e) + raise UserError(e) + + return dispatch diff --git a/sf_manufacturing/models/agv_setting.py b/sf_manufacturing/models/agv_setting.py index 833b2659..8fe22715 100644 --- a/sf_manufacturing/models/agv_setting.py +++ b/sf_manufacturing/models/agv_setting.py @@ -17,7 +17,7 @@ class AgvSetting(models.Model): ('空闲', '空闲')], string='状态') divide_the_work = fields.Char('主要分工') active = fields.Boolean('有效', default=True) - region = fields.Many2one(string='所属区域', comodel_name='mrp.workcenter', tracking=True, + workcenter_id = fields.Many2one(string='所属区域', comodel_name='mrp.workcenter', tracking=True, domain=[('is_agv_dispatch', '=', True)]) def update_site_state(self): @@ -73,14 +73,16 @@ class AgvTaskRoute(models.Model): if self.end_site_id == self.start_site_id: raise UserError("您选择的终点接驳站与起点接驳站重复,请重新选择") - region = fields.Many2one(string='所属区域', comodel_name='mrp.workcenter', domain=[('is_agv_dispatch', '=', True)], + workcenter_id = fields.Many2one(string='所属区域', comodel_name='mrp.workcenter', domain=[('is_agv_dispatch', '=', True)], compute="_compute_region") @api.depends('end_site_id') def _compute_region(self): for record in self: if record.end_site_id: - record.region = record.end_site_id.region + record.workcenter_id = record.end_site_id.workcenter_id + else: + record.workcenter_id = None class Center_controlInterfaceLog(models.Model): diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 060b06cf..792ecb9f 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -634,25 +634,33 @@ class ResMrpWorkOrder(models.Model): k, item), 'cmm_ids': False if route.routing_type != 'CNC加工' else self.env['sf.cmm.program']._json_cmm_program(k, item), - 'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self._json_workpiece_delivery_list( - production) + # 'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self._json_workpiece_delivery_list( + # production) }] return workorders_values_str - def _json_workpiece_delivery_list(self, production): - up_route = self.env['sf.agv.task.route'].search([('route_type', '=', '上产线')], limit=1, order='id asc') - down_route = self.env['sf.agv.task.route'].search([('route_type', '=', '下产线')], limit=1, order='id asc') + def _json_workpiece_delivery_list(self): + # 修改在装夹工单完成后,生成上产线的工件配送单 + + # up_route = self.env['sf.agv.task.route'].search([('route_type', '=', '上产线')], limit=1, order='id asc') + # down_route = self.env['sf.agv.task.route'].search([('route_type', '=', '下产线')], limit=1, order='id asc') return [ [0, '', - {'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '上产线', - 'route_id': up_route.id, - 'feeder_station_start_id': up_route.start_site_id.id, - 'feeder_station_destination_id': up_route.end_site_id.id}], - [0, '', - {'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '下产线', - 'route_id': down_route.id, - 'feeder_station_start_id': down_route.start_site_id.id, - 'feeder_station_destination_id': down_route.end_site_id.id}]] + { + 'production_id': self.production_id.id, + 'production_line_id': self.production_id.production_line_id.id, + 'type': '上产线', + # 'route_id': up_route.id, + # 'feeder_station_start_id': agv_start_site_id, + # 'feeder_station_destination_id': up_route.end_site_id.id + } + ], + # [0, '', + # {'production_id': production.id, 'production_line_id': production.production_line_id.id, 'type': '下产线', + # 'route_id': down_route.id, + # 'feeder_station_start_id': down_route.start_site_id.id, + # 'feeder_station_destination_id': down_route.end_site_id.id}] + ] # 拼接工单对象属性值(表面工艺) def _json_workorder_surface_process_str(self, production, route, process_parameter, supplier_id): @@ -1182,6 +1190,8 @@ class ResMrpWorkOrder(models.Model): raw_move.write({'state': 'done'}) record.production_id.button_mark_done1() # record.production_id.state = 'done' + # 生成工件配送单 + record.workpiece_delivery_ids = record._json_workpiece_delivery_list() # 将FTP的检测报告文件下载到临时目录 def download_reportfile_tmp(self, workorder, reportpath): @@ -1485,7 +1495,7 @@ class SfWorkOrderBarcodes(models.Model): class WorkPieceDelivery(models.Model): _name = "sf.workpiece.delivery" - _inherit = ['mail.thread', 'mail.activity.mixin'] + _inherit = ['mail.thread', 'mail.activity.mixin', "barcodes.barcode_events_mixin"] _description = '工件配送' name = fields.Char('单据编码') @@ -1501,11 +1511,14 @@ class WorkPieceDelivery(models.Model): feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站') task_delivery_time = fields.Datetime('任务下发时间') task_completion_time = fields.Datetime('任务完成时间') - type = fields.Selection( - [('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型') + + def _get_agv_route_type_selection(self): + return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection'] + + type = fields.Selection(selection=_get_agv_route_type_selection, string='类型') delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration') status = fields.Selection( - [('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送'), ('已取消', '已取消')], string='状态', + [('待下发', '待下发'), ('已下发', '已下发'), ('已配送', '已配送'), ('已取消', '已取消')], string='状态', default='待下发', tracking=True) is_cnc_program_down = fields.Boolean('程序是否下发', default=False, tracking=True) @@ -1564,82 +1577,41 @@ class WorkPieceDelivery(models.Model): production_ids = [] is_cnc_down = 0 is_not_production_line = 0 - is_not_route = 0 same_production_line_id = None same_route_id = None - down_status = '待下发' - production_type = None - num = 0 + production_type = '上产线' + max_num = 4 # 最大配送数量 + if len(self) > max_num: + raise UserError('仅限于配送1-4个制造订单,请重新选择') for item in self: - num += 1 - if production_type is None: - production_type = item.type - if item.type == "运送空料架": - if num >= 2: - raise UserError('仅选择一条路线进行配送,请重新选择') - else: - delivery_ids.append(item.id) - else: - if num > 4: - raise UserError('仅限于配送1-4个制造订单,请重新选择') - if item.status in ['待配送', '已配送']: - raise UserError('请选择状态为【待下发】的制造订单进行配送') - if item.route_id: - if same_route_id is None: - same_route_id = item.route_id.id - if item.route_id.id != same_route_id: - is_not_route += 1 - # else: - # raise UserError('请选择【任务路线】再进行配送') - # if item.production_id.production_line_state == '已下产线' and item.state == '待下发' and item.type == '下产线': - # raise UserError('该制造订单已下产线,无需配送') - if production_type != item.type: - raise UserError('请选择类型为%s的制造订单进行配送' % production_type) - if down_status != item.status: - up_workpiece = self.search([('type', '=', '上产线'), ('production_id', '=', item.production_id), - ('status', '=', '待下发')]) - if up_workpiece: - raise UserError('您所选择的制造订单暂未上产线,请在上产线后再进行配送') - else: - raise UserError('请选择状态为【待下发】的制造订单进行配送') - - if same_production_line_id is None: - same_production_line_id = item.production_line_id.id - if item.production_line_id.id != same_production_line_id: - is_not_production_line += 1 - if item.is_cnc_program_down is False: - is_cnc_down += 1 - if is_cnc_down == 0 and is_not_production_line == 0 and is_not_route == 0: - delivery_ids.append(item.id) - production_ids.append(item.production_id.id) + if item.status != '待下发': + raise UserError('请选择状态为【待下发】的制造订单进行配送') + if same_production_line_id is None: + same_production_line_id = item.production_line_id.id + if item.production_line_id.id != same_production_line_id: + is_not_production_line += 1 + if item.is_cnc_program_down is False: + is_cnc_down += 1 + if is_cnc_down == 0 and is_not_production_line == 0: + delivery_ids.append(item.id) + production_ids.append(item.production_id.id) if is_cnc_down >= 1: raise UserError('您所选择制造订单的【CNC程序】暂未下发,请在程序下发后再进行配送') if is_not_production_line >= 1: raise UserError('您所选择制造订单的【目的生产线】不一致,请重新确认') - if is_not_route >= 1: - raise UserError('您所选择制造订单的【任务路线】不一致,请重新确认') - is_free = self._check_avgsite_state() - if is_free is True: - if delivery_ids: - return { - 'name': _('确认'), - 'type': 'ir.actions.act_window', - 'view_mode': 'form', - 'res_model': 'sf.workpiece.delivery.wizard', - 'target': 'new', - 'context': { - 'default_delivery_ids': [(6, 0, delivery_ids)], - 'default_production_ids': [(6, 0, production_ids)], - 'default_destination_production_line_id': same_production_line_id, - 'default_route_id': same_route_id, - 'default_type': production_type, - }} - else: - if production_type == '运送空料架': - raise UserError("您所选择的【任务路线】的【终点接驳站】已占用,请在该接驳站空闲时进行配送") - else: - raise UserError( - "您所选择制造订单的【任务路线】的【终点接驳站】已占用,请在该接驳站空闲时或选择其他路线进行配送") + if delivery_ids: + return { + 'name': _('确认'), + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'sf.workpiece.delivery.wizard', + 'target': 'new', + 'context': { + 'default_delivery_ids': [(6, 0, delivery_ids)], + 'default_production_ids': [(6, 0, production_ids)], + 'default_type': production_type, + }} + # 验证agv站点是否可用 def _check_avgsite_state(self): @@ -1747,6 +1719,9 @@ class WorkPieceDelivery(models.Model): # agv调度单 agv_dispatch_id = fields.Many2one('sf.agv.dispatch', 'agv调度单') + def on_barcode_scanned(self, barcode): + logging.info('Rfid:%s' % barcode) + class CMMprogram(models.Model): _name = 'sf.cmm.program' diff --git a/sf_manufacturing/views/agv_setting_views.xml b/sf_manufacturing/views/agv_setting_views.xml index 66f728f0..62e3c623 100644 --- a/sf_manufacturing/views/agv_setting_views.xml +++ b/sf_manufacturing/views/agv_setting_views.xml @@ -8,7 +8,7 @@ - + @@ -42,7 +42,7 @@ - + diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index 805dcb1f..60c0b8a0 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -643,15 +643,15 @@ - + + - + - - - + + + diff --git a/sf_manufacturing/wizard/workpiece_delivery_views.xml b/sf_manufacturing/wizard/workpiece_delivery_views.xml index a8d00d72..96ccfc7f 100644 --- a/sf_manufacturing/wizard/workpiece_delivery_views.xml +++ b/sf_manufacturing/wizard/workpiece_delivery_views.xml @@ -9,23 +9,17 @@ - +
- - + + +
- - - - -
- 是否确定配送 -
diff --git a/sf_manufacturing/wizard/workpiece_delivery_wizard.py b/sf_manufacturing/wizard/workpiece_delivery_wizard.py index 9f36622c..c8728f01 100644 --- a/sf_manufacturing/wizard/workpiece_delivery_wizard.py +++ b/sf_manufacturing/wizard/workpiece_delivery_wizard.py @@ -20,11 +20,14 @@ class WorkpieceDeliveryWizard(models.TransientModel): feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站') feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站') workcenter_id = fields.Many2one(string='所属区域', comodel_name='mrp.workcenter', tracking=True) + confirm_button = fields.Char('按钮名称') @api.onchange('type') def _onchange_type(self): - routes = self.env['sf.agv.task.route'].search([('route_type', '=', self.type)]) if self.type: + routes = self.env['sf.agv.task.route'].search([('route_type', '=', self.type)]) + if self.workcenter_id: + routes = routes.filtered(lambda a: a.start_site_id.workcenter_id.id == self.workcenter_id.id) start_site_ids = routes.mapped('start_site_id.id') workcenter_ids = routes.mapped('end_site_id.workcenter_id.id') if workcenter_ids: From f0a4cf1d0fe6c9014b9c04a99f5ecbb05ac1e929 Mon Sep 17 00:00:00 2001 From: hy <1298386937@qq.com> Date: Thu, 15 Aug 2024 15:01:10 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E5=BC=B9=E7=AA=97=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E8=81=9A=E7=84=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/wizard/workpiece_delivery_views.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sf_manufacturing/wizard/workpiece_delivery_views.xml b/sf_manufacturing/wizard/workpiece_delivery_views.xml index a6dfe8e9..499f6af5 100644 --- a/sf_manufacturing/wizard/workpiece_delivery_views.xml +++ b/sf_manufacturing/wizard/workpiece_delivery_views.xml @@ -21,6 +21,11 @@