Files
test/sf_manufacturing/models/agv_scheduling.py
2024-08-09 17:32:46 +08:00

192 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from odoo import models, fields, api, _
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
class RepeatTaskException(UserError):
pass
class AgvScheduling(models.Model):
_name = 'sf.agv.scheduling'
_description = 'agv调度'
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='任务类型', required=True)
agv_route_name = fields.Char('任务路线名称')
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='终点接驳站状态', default='占用')
state = fields.Selection([
('待下发', '待下发'),
('配送中', '配送中'),
('已配送', '已配送'),
('已取消', '已取消')], string='状态', default='待下发', tracking=True)
workpiece_delivery_ids = fields.One2many('sf.workpiece.delivery', 'agv_scheduling_id', string='工件配送单')
delivery_workpieces = fields.Char('配送工件', required=True, index=True)
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('agv_route_type')
def _compute_delivery_workpieces(self):
for record in self:
if record.agv_route_type == '运送空料架':
record.delivery_workpieces_display = '/'
else:
record.delivery_workpieces_display = record.delivery_workpieces
delivery_workpieces_display = fields.Char('配送工件', compute=_compute_delivery_workpieces)
@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 = ''
@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.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
新增AGV调度
params:
agv_start_site_id: AGV起点接驳站ID
agv_route_type: AGV任务类型
productions: 制造订单
deliveries: 工件配送单
"""
# 如果存在配送工件完全相同的AGV调度任务则不新增
if self.sudo().search([
('delivery_workpieces', '=', ''.join(productions.mapped('name'))),
('agv_route_type', '=', agv_route_type),
('state', 'in', ['待下发', '配送中'])
], limit=1):
raise RepeatTaskException('已存在相同的AGV调度任务请勿重复下发')
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 [],
'task_create_time': fields.Datetime.now()
}
# 如果只有唯一任务路线,则自动赋予终点接驳站跟任务名称
agv_routes = self.env['sf.agv.task.route'].sudo().search([
('route_type', '=', agv_route_type),
('start_site_id', '=', agv_start_site_id)
])
if len(agv_routes) == 1:
vals.update({'end_site_id': agv_routes[0].end_site_id.id, 'agv_route_name': agv_routes[0].name})
try:
dispatch = self.env['sf.agv.scheduling'].sudo().create(vals)
except Exception as e:
_logger.error('添加AGV调度任务失败: %s', e)
raise UserError(_('添加AGV调度任务失败: %s', e))
return dispatch
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)
def _delivery_avg(self):
config = self.env['res.config.settings'].get_values()
positionCode_Arr = []
delivery_Arr = []
feeder_station_start = None
feeder_station_destination = None
route_id = None
for item in self:
if route_id is None:
route_id = item.route_id.id
if feeder_station_start is None:
feeder_station_start = item.feeder_station_start_id
if feeder_station_destination is None:
feeder_station_destination = item.feeder_station_destination_id
if item.type in ['上产线', '下产线']:
item.route_id = route_id
item.feeder_station_start_id = feeder_station_start.id
item.feeder_station_destination_id = feeder_station_destination.id
delivery_Arr.append(item.name)
else:
self = self.create(
{'name': self.env['ir.sequence'].next_by_code('sf.workpiece.delivery'),
'route_id': self.route_id.id,
'feeder_station_start_id': self.feeder_station_start_id.id,
'feeder_station_destination_id': self.feeder_station_destination_id.id})
delivery_Arr.append(self.name)
delivery_str = ','.join(map(str, delivery_Arr))
if feeder_station_start is not None:
positionCode_Arr.append({
'positionCode': feeder_station_start.name,
'code': '00'
})
if feeder_station_destination is not None:
positionCode_Arr.append({
'positionCode': feeder_station_destination.name,
'code': '00'
})
res = {'reqCode': delivery_str, 'reqTime': '', 'clientCode': '', 'tokenCode': '',
'taskTyp': 'F01', 'ctnrTyp': '', 'ctnrCode': '', 'wbCode': config['wbcode'],
'positionCodePath': positionCode_Arr,
'podCode': '',
'podDir': '', 'materialLot': '', 'priority': '', 'taskCode': '', 'agvCode': '', 'materialLot': '',
'data': ''}
try:
logging.info('AGV请求路径:%s' % config['agv_rcs_url'])
logging.info('AGV-json:%s' % res)
headers = {'Content-Type': 'application/json'}
ret = requests.post((config['agv_rcs_url']), json=res, headers=headers)
ret = ret.json()
logging.info('config-ret:%s' % ret)
if ret['code'] == 0:
req_codes = ret['reqCode'].split(',')
for delivery_item in self:
for req_code in req_codes:
if delivery_item.name == req_code.strip():
logging.info('delivery_item-name:%s' % delivery_item.name)
delivery_item.write({
'task_delivery_time': fields.Datetime.now(),
'status': '待配送'
})
if delivery_item.type == "上产线":
delivery_item.workorder_id.write({'is_delivery': True})
else:
raise UserError(ret['message'])
except Exception as e:
logging.info('config-e:%s' % e)
raise UserError("工件配送请求agv失败:%s" % e)
def button_cancel(self):
# 弹出二次确认窗口后执行
for rec in self:
if rec.state != '待下发':
raise UserError('只有待下发状态的AGV调度任务才能取消')
rec.state = '已取消'