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 @@
+