AGV任务调度开发

This commit is contained in:
胡尧
2024-08-14 17:34:50 +08:00
parent 0b85f29262
commit f7e4ce416a
10 changed files with 256 additions and 131 deletions

View File

@@ -31,8 +31,7 @@ class AgvScheduling(models.Model):
('配送中', '配送中'),
('已配送', '已配送'),
('已取消', '已取消')], string='状态', default='待下发', tracking=True)
workorder_ids = fields.One2many('mrp.workorder', string='关联工单')
delivery_workpieces = fields.Char('配送工件', required=True, index=True)
workorder_ids = fields.Many2many('mrp.workorder', 'sf_agv_scheduling_mrp_workorder_ref', string='关联工单')
task_create_time = fields.Datetime('任务创建时间')
task_delivery_time = fields.Datetime('任务下发时间')
task_completion_time = fields.Datetime('任务完成时间')
@@ -41,13 +40,12 @@ class AgvScheduling(models.Model):
@api.depends('agv_route_type')
def _compute_delivery_workpieces(self):
for record in self:
record.delivery_workpieces = ''.join(record.workorder_ids.mapped('production_id.name'))
if record.agv_route_type == '运送空料架':
record.delivery_workpieces_display = '/'
record.delivery_workpieces = '/'
else:
record.delivery_workpieces_display = record.delivery_workpieces
record.delivery_workpieces = ''.join(record.workorder_ids.mapped('production_id.name'))
delivery_workpieces_display = fields.Char('配送工件', compute=_compute_delivery_workpieces)
delivery_workpieces = fields.Char('配送工件', compute=_compute_delivery_workpieces)
@api.depends('task_completion_time', 'task_delivery_time')
def _compute_task_duration(self):
@@ -64,28 +62,35 @@ class AgvScheduling(models.Model):
vals['name'] = self.env['ir.sequence'].next_by_code('sf.agv.scheduling') or _('New')
return super().create(vals_list)
def add_scheduling(self, agv_start_site_id, agv_route_type, productions, deliveries=None):
""" add_scheduling(agv_start_site_id, agv_route_type, productions, deliveries) -> agv_scheduling
def add_scheduling(self, agv_start_site_id, agv_route_type, workorders):
""" add_scheduling(agv_start_site_id, agv_route_type, workorders) -> agv_scheduling
新增AGV调度
params:
agv_start_site_id: AGV起点接驳站ID
agv_route_type: AGV任务类型
productions: 制造订
deliveries: 工件配送单
workorders: 工
"""
# 如果存在配送工件完全相同的AGV调度任务则不新增
if self.sudo().search([
('delivery_workpieces', '=', ''.join(productions.mapped('name'))),
if not workorders:
raise UserError(_('工单不能为空'))
# 如果存在相同任务类型工单的AGV调度任务则提示错误
agv_scheduling = self.sudo().search([
('workorder_ids', 'in', workorders.ids),
('agv_route_type', '=', agv_route_type),
('state', 'in', ['待下发', '配送中'])
], limit=1):
raise RepeatTaskException('已存在相同的AGV调度任务请勿重复下发')
], limit=1)
if agv_scheduling:
# 计算agv_scheduling.workorder_ids与workorders的交集
repetitive_workorders = agv_scheduling.workorder_ids & workorders
raise RepeatTaskException(
'制造订单号【%s】已存在与【%s】AGV调度任务请勿重复下发' %
(','.join(repetitive_workorders.mapped('production_id.name')), agv_scheduling.name)
)
vals = {
'start_site_id': agv_start_site_id,
'agv_route_type': agv_route_type,
'delivery_workpieces': ''.join(productions.mapped('name')),
'workpiece_delivery_ids': deliveries.mapped('id') if deliveries else [],
'workorder_ids': workorders.ids,
# 'workpiece_delivery_ids': deliveries.mapped('id') if deliveries else [],
'task_create_time': fields.Datetime.now()
}
# 如果只有唯一任务路线,则自动赋予终点接驳站跟任务名称
@@ -95,26 +100,52 @@ class AgvScheduling(models.Model):
])
if len(agv_routes) == 1:
vals.update({'end_site_id': agv_routes[0].end_site_id.id, 'agv_route_name': agv_routes[0].name})
else:
# 判断终点接驳站是否为空闲
idle_routes = agv_routes.filtered(lambda r: r.end_site_id.state == '空闲')
if idle_routes:
# 将空闲的路线按照终点接驳站名称排序
idle_routes = sorted(idle_routes, key=lambda r: r.end_site_id.name)
vals.update({'end_site_id': idle_routes[0].end_site_id.id, 'agv_route_name': idle_routes[0].name})
try:
dispatch = self.env['sf.agv.scheduling'].sudo().create(vals)
scheduling = self.env['sf.agv.scheduling'].sudo().create(vals)
# 触发空闲接驳站状态更新,触发新任务下发
if scheduling.end_site_id.state == '空闲':
scheduling.dispatch_scheduling(scheduling.end_site_id.id, scheduling.end_site_id.state)
except Exception as e:
_logger.error('添加AGV调度任务失败: %s', e)
raise UserError(_('添加AGV调度任务失败: %s', e))
return dispatch
return scheduling
def on_site_state_change(self, agv_site_id, agv_site_state):
agv_schedulings = self.env['sf.agv.scheduling'].sudo().search([('state', '=', '待下发')], order='id asc')
for scheduling in agv_schedulings:
if scheduling.end_site_id.id == agv_site_id and scheduling.site_state == '空闲':
# 下发AGV调度任务并修改接驳站状态为占用
# self._delivery_avg()
# 修改AGV调度任务信息
scheduling.state = '配送中'
scheduling.task_delivery_time = fields.Datetime.now()
scheduling.site_state = agv_site_state
# 更新接驳站状态
self.env['sf.agv.site'].update_site_state(scheduling.end_site_id.name, True)
"""
响应AGV接驳站站点状态变化
params:
agv_site_id: 接驳站ID
agv_site_state: 站点状态('空闲', '占用'
"""
if agv_site_state == '空闲':
# 查询终点接驳站为agv_site_id的AGV路线
task_routes = self.env['sf.agv.task.route'].sudo().search([('end_site_id', '=', agv_site_id)])
agv_scheduling = self.env['sf.agv.scheduling'].sudo().search(
[('state', '=', '待下发'), ('agv_route_type', 'in', task_routes.mapped('route_type'))],
order='id asc',
limit=1
)
# 下发AGV调度任务并修改接驳站状态为占用
agv_scheduling.dispatch_scheduling(agv_site_id, agv_site_state)
# 更新接驳站状态
self.env['sf.agv.site'].update_site_state({agv_scheduling.end_site_id.name: '占用'}, False)
else:
# 如果终点接驳站变为占用,则认为任务完成
agv_scheduling = self.env['sf.agv.scheduling'].sudo().search(
[('state', '=', '配送中'), ('end_site_id', '=', agv_site_id)],
order='id asc',
limit=1
)
agv_scheduling.finish_scheduling()
def _delivery_avg(self):
config = self.env['res.config.settings'].get_values()
@@ -190,3 +221,36 @@ class AgvScheduling(models.Model):
if rec.state != '待下发':
raise UserError('只有待下发状态的AGV调度任务才能取消')
rec.state = '已取消'
def finish_scheduling(self):
"""
完成调度任务
"""
for rec in self:
if rec.state != '配送中':
return False
rec.state = '已配送'
rec.task_completion_time = fields.Datetime.now()
def dispatch_scheduling(self, agv_end_site_id, agv_site_state):
"""
下发调度任务
"""
for rec in self:
if rec.state != '待下发':
return False
# rec._delivery_avg()
rec.state = '配送中'
rec.task_delivery_time = fields.Datetime.now()
rec.site_state = agv_site_state
rec.end_site_id = agv_end_site_id
class ResMrpWorkOrder(models.Model):
_inherit = 'mrp.workorder'
agv_scheduling_ids = fields.Many2many(
'sf.agv.scheduling',
'sf_agv_scheduling_mrp_workorder_ref',
string='AGV调度',
domain=[('state', '!=', '已取消')])