178 lines
6.4 KiB
Python
178 lines
6.4 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
库区分层数据模型
|
||
管理每个动作点的分层信息和货物状态
|
||
"""
|
||
|
||
from sqlalchemy import Column, String, Integer, Boolean, Text, DateTime, ForeignKey, UniqueConstraint
|
||
from sqlalchemy.orm import relationship
|
||
from sqlalchemy.dialects.mysql import CHAR
|
||
from .base import BaseModel
|
||
import datetime
|
||
|
||
|
||
class OperatePointLayer(BaseModel):
|
||
"""
|
||
库区分层数据模型
|
||
每个动作点可以有多个层,每层可以独立存放货物
|
||
"""
|
||
__tablename__ = 'vwed_operate_point_layer'
|
||
|
||
id = Column(CHAR(64), primary_key=True, comment='层ID')
|
||
operate_point_id = Column(CHAR(64), ForeignKey('vwed_operate_point.id'), nullable=False, comment='动作点ID')
|
||
station_name = Column(String(64), nullable=False, comment='动作点名称')
|
||
# storage_location_name = Column(String(64), nullable=False, comment='库位名称')
|
||
area_name = Column(String(64), nullable=True, comment='库区名称')
|
||
scene_id = Column(String(64), nullable=False, comment='场景ID(冗余字段)')
|
||
layer_index = Column(Integer, nullable=False, comment='层索引(从1开始)')
|
||
layer_name = Column(String(64), comment='库位名称')
|
||
|
||
# 货物状态
|
||
is_occupied = Column(Boolean, nullable=False, default=False, comment='是否占用')
|
||
goods_content = Column(String(100), nullable=False, default='', comment='货物内容')
|
||
goods_weight = Column(Integer, comment='货物重量(克)')
|
||
goods_volume = Column(Integer, comment='货物体积(立方厘米)')
|
||
|
||
# 层状态
|
||
is_locked = Column(Boolean, nullable=False, default=False, comment='是否锁定')
|
||
is_disabled = Column(Boolean, nullable=False, default=False, comment='是否禁用')
|
||
is_empty_tray = Column(Boolean, nullable=False, default=False, comment='是否空托盘')
|
||
locked_by = Column(String(128), nullable=True, comment='锁定者')
|
||
tags = Column(String(100), nullable=False, default='', comment='标签')
|
||
|
||
# 层属性
|
||
max_weight = Column(Integer, comment='最大承重(克)')
|
||
max_volume = Column(Integer, comment='最大体积(立方厘米)')
|
||
layer_height = Column(Integer, comment='层高(毫米)')
|
||
|
||
# 时间信息
|
||
goods_stored_at = Column(DateTime, comment='货物存放时间')
|
||
goods_retrieved_at = Column(DateTime, comment='货物取出时间')
|
||
last_access_at = Column(DateTime, comment='最后访问时间')
|
||
|
||
# 扩展信息
|
||
tags = Column(String(255), comment='层标签', nullable=True)
|
||
description = Column(Text, comment='层描述', nullable=True)
|
||
config_json = Column(Text, comment='层配置JSON', nullable=True)
|
||
|
||
# 关联关系
|
||
operate_point = relationship("OperatePoint", back_populates="layers")
|
||
|
||
# 唯一约束:同一个动作点的层索引不能重复
|
||
__table_args__ = (
|
||
UniqueConstraint('operate_point_id', 'layer_index', name='uk_operate_point_layer'),
|
||
)
|
||
|
||
def __repr__(self):
|
||
return f"<OperatePointLayer(id={self.id}, operate_point_id={self.operate_point_id}, station_name={self.station_name}, area_name={self.area_name}, scene_id={self.scene_id}, layer_index={self.layer_index})>"
|
||
|
||
def can_store_goods(self, weight=None, volume=None):
|
||
"""
|
||
检查是否可以存放货物
|
||
|
||
Args:
|
||
weight: 货物重量(克)
|
||
volume: 货物体积(立方厘米)
|
||
|
||
Returns:
|
||
bool: 是否可以存放
|
||
"""
|
||
if self.is_disabled or self.is_locked or self.is_occupied:
|
||
return False
|
||
|
||
# 检查重量限制
|
||
if weight is not None and self.max_weight is not None:
|
||
if weight > self.max_weight:
|
||
return False
|
||
|
||
# 检查体积限制
|
||
if volume is not None and self.max_volume is not None:
|
||
if volume > self.max_volume:
|
||
return False
|
||
|
||
return True
|
||
|
||
def can_retrieve_goods(self):
|
||
"""检查是否可以取货"""
|
||
return (not self.is_disabled and
|
||
not self.is_locked and
|
||
self.is_occupied)
|
||
|
||
def store_goods(self, content, weight=None, volume=None):
|
||
"""
|
||
存放货物
|
||
|
||
Args:
|
||
content: 货物内容
|
||
weight: 货物重量(克)
|
||
volume: 货物体积(立方厘米)
|
||
|
||
Returns:
|
||
bool: 是否成功
|
||
"""
|
||
if not self.can_store_goods(weight, volume):
|
||
return False
|
||
|
||
self.is_occupied = True
|
||
self.goods_content = content
|
||
self.goods_weight = weight
|
||
self.goods_volume = volume
|
||
self.goods_stored_at = datetime.datetime.now()
|
||
self.last_access_at = datetime.datetime.now()
|
||
|
||
return True
|
||
|
||
def retrieve_goods(self):
|
||
"""
|
||
取出货物
|
||
|
||
Returns:
|
||
dict: 货物信息
|
||
"""
|
||
if not self.can_retrieve_goods():
|
||
return None
|
||
|
||
goods_info = {
|
||
'content': self.goods_content,
|
||
'weight': self.goods_weight,
|
||
'volume': self.goods_volume,
|
||
'stored_at': self.goods_stored_at
|
||
}
|
||
|
||
# 清空货物信息
|
||
self.is_occupied = False
|
||
self.goods_content = ''
|
||
self.goods_weight = None
|
||
self.goods_volume = None
|
||
self.goods_retrieved_at = datetime.datetime.now()
|
||
self.last_access_at = datetime.datetime.now()
|
||
|
||
return goods_info
|
||
|
||
def get_remaining_capacity(self):
|
||
"""获取剩余容量信息"""
|
||
result = {}
|
||
|
||
if self.max_weight is not None:
|
||
used_weight = self.goods_weight if self.goods_weight is not None else 0
|
||
result['remaining_weight'] = self.max_weight - used_weight
|
||
|
||
if self.max_volume is not None:
|
||
used_volume = self.goods_volume if self.goods_volume is not None else 0
|
||
result['remaining_volume'] = self.max_volume - used_volume
|
||
|
||
return result
|
||
|
||
def is_overweight(self):
|
||
"""检查是否超重"""
|
||
if self.max_weight is None or self.goods_weight is None:
|
||
return False
|
||
return self.goods_weight > self.max_weight
|
||
|
||
def is_overflow(self):
|
||
"""检查是否超体积"""
|
||
if self.max_volume is None or self.goods_volume is None:
|
||
return False
|
||
return self.goods_volume > self.max_volume |