|
@@ -11,7 +11,7 @@ from django.utils import timezone
|
|
|
from django.db import transaction
|
|
|
import logging
|
|
|
from rest_framework import status
|
|
|
-from .models import DeviceModel,LocationModel,LocationGroupModel,LocationContainerLink,LocationChangeLog
|
|
|
+from .models import DeviceModel,LocationModel,LocationGroupModel,LocationContainerLink,LocationChangeLog,alloction_pre
|
|
|
from bound.models import BoundBatchModel,BoundDetailModel,BoundListModel
|
|
|
|
|
|
|
|
@@ -26,15 +26,189 @@ logger = logging.getLogger(__name__)
|
|
|
# 库位分配
|
|
|
# 入库规则函数
|
|
|
# 逻辑根据批次下的托盘数目来找满足区间范围的库位,按照优先级排序,
|
|
|
+
|
|
|
+
|
|
|
+class locationViewSet(viewsets.ModelViewSet):
|
|
|
+ """
|
|
|
+ retrieve:
|
|
|
+ Response a data list(get)
|
|
|
+ list:
|
|
|
+ Response a data list(all)
|
|
|
+ create:
|
|
|
+ Create a data line(post)
|
|
|
+
|
|
|
+ delete:
|
|
|
+ Delete a data line(delete)
|
|
|
+
|
|
|
+ """
|
|
|
+ # authentication_classes = [] # 禁用所有认证类
|
|
|
+ # permission_classes = [AllowAny] # 允许任意访问
|
|
|
+
|
|
|
+ pagination_class = MyPageNumberPagination
|
|
|
+ filter_backends = [DjangoFilterBackend, OrderingFilter, ]
|
|
|
+ ordering_fields = ['id', "create_time", "update_time", ]
|
|
|
+ filter_class = LocationFilter
|
|
|
+
|
|
|
+ def get_project(self):
|
|
|
+ try:
|
|
|
+ id = self.kwargs.get('pk')
|
|
|
+ return id
|
|
|
+ except:
|
|
|
+ return None
|
|
|
+
|
|
|
+ def get_queryset(self):
|
|
|
+ id = self.get_project()
|
|
|
+ if self.request.user:
|
|
|
+ if id is None:
|
|
|
+ return LocationModel.objects.filter()
|
|
|
+ else:
|
|
|
+ return LocationModel.objects.filter( id=id)
|
|
|
+ else:
|
|
|
+ return LocationModel.objects.none()
|
|
|
+ def get_serializer_class(self):
|
|
|
+ if self.action == 'list':
|
|
|
+ return LocationListSerializer
|
|
|
+ elif self.action == 'update':
|
|
|
+ return LocationPostSerializer
|
|
|
+ elif self.action =='retrieve':
|
|
|
+ return LocationListSerializer
|
|
|
+
|
|
|
+ def update(self, request, *args, **kwargs):
|
|
|
+ qs = self.get_object()
|
|
|
+ data = self.request.data
|
|
|
+
|
|
|
+ location_code = data.get('location_code')
|
|
|
+ # 处理库位对象
|
|
|
+ location_obj = LocationModel.objects.filter(location_code=location_code).first()
|
|
|
+ if not location_obj:
|
|
|
+ logger.info(f"库位 {location_code} 不存在")
|
|
|
+ return Response(
|
|
|
+ {'code': '400', 'message': '库位不存在', 'data': None},
|
|
|
+ status=status.HTTP_400_BAD_REQUEST
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ data['id'] = location_obj.id
|
|
|
+ logger.info(f"库位 {location_code} 已存在")
|
|
|
+ serializer = self.get_serializer(qs, data=data)
|
|
|
+ serializer.is_valid(raise_exception=True)
|
|
|
+ serializer.save()
|
|
|
+ headers = self.get_success_headers(serializer.data)
|
|
|
+ self.handle_group_location_status(location_code,location_obj.location_group)
|
|
|
+ return Response(serializer.data, status=200, headers=headers)
|
|
|
+
|
|
|
+ def handle_group_location_status(self,location_code,location_group):
|
|
|
+ """
|
|
|
+ 处理库位组和库位的关联关系
|
|
|
+ :param location_code: 库位编码
|
|
|
+ :param location_group: 库位组编码
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ # 1. 获取库位空闲状态的库位数目
|
|
|
+ location_obj_number = LocationModel.objects.filter(
|
|
|
+ location_group=location_group,
|
|
|
+ status='available'
|
|
|
+ ).all().count()
|
|
|
+ # 2. 获取库位组对象
|
|
|
+ logger.info(f"库位组 {location_group} 下的库位数目:{location_obj_number}")
|
|
|
+ # 1. 获取库位和库位组的关联关系
|
|
|
+ location_group_obj = LocationGroupModel.objects.filter(
|
|
|
+ group_code=location_group
|
|
|
+ ).first()
|
|
|
+ if not location_group_obj:
|
|
|
+ logger.info(f"库位组 {location_group} 不存在")
|
|
|
+ return None
|
|
|
+ else:
|
|
|
+ if location_obj_number == 0:
|
|
|
+ # 库位组库位已满,更新库位组状态为full
|
|
|
+ location_group_obj.status = 'full'
|
|
|
+ location_group_obj.save()
|
|
|
+ elif location_obj_number < location_group_obj.max_capacity:
|
|
|
+ location_group_obj.status = 'occupied'
|
|
|
+ location_group_obj.save()
|
|
|
+ else:
|
|
|
+ location_group_obj.status = 'available'
|
|
|
+ location_group_obj.save()
|
|
|
+
|
|
|
+class locationGroupViewSet(viewsets.ModelViewSet):
|
|
|
+ """
|
|
|
+ retrieve:
|
|
|
+ Response a data list(get)
|
|
|
+ list:
|
|
|
+ Response a data list(all)
|
|
|
+ create:
|
|
|
+ Create a data line(post)
|
|
|
+
|
|
|
+ delete:
|
|
|
+ Delete a data line(delete)
|
|
|
+
|
|
|
+ """
|
|
|
+ # authentication_classes = [] # 禁用所有认证类
|
|
|
+ # permission_classes = [AllowAny] # 允许任意访问
|
|
|
+
|
|
|
+ pagination_class = MyPageNumberPagination
|
|
|
+ filter_backends = [DjangoFilterBackend, OrderingFilter, ]
|
|
|
+ ordering_fields = ['id', "create_time", "update_time", ]
|
|
|
+ filter_class = LocationGroupFilter
|
|
|
+
|
|
|
+ def get_project(self):
|
|
|
+ try:
|
|
|
+ id = self.kwargs.get('pk')
|
|
|
+ return id
|
|
|
+ except:
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+ def get_queryset(self):
|
|
|
+ id = self.get_project()
|
|
|
+ if self.request.user:
|
|
|
+ if id is None:
|
|
|
+ return LocationGroupModel.objects.filter()
|
|
|
+ else:
|
|
|
+ return LocationGroupModel.objects.filter(id=id)
|
|
|
+ else:
|
|
|
+ return LocationGroupModel.objects.none()
|
|
|
+ def get_serializer_class(self):
|
|
|
+ if self.action == 'list':
|
|
|
+ return LocationGroupListSerializer
|
|
|
+
|
|
|
+ elif self.action == 'update':
|
|
|
+ return LocationGroupPostSerializer
|
|
|
+
|
|
|
+ elif self.action =='retrieve':
|
|
|
+ return LocationGroupListSerializer
|
|
|
+
|
|
|
+ def update(self, request, *args, **kwargs):
|
|
|
+ data = self.request.data
|
|
|
+ order_month = str(timezone.now().strftime('%Y%m'))
|
|
|
+ data['month'] = order_month
|
|
|
+ group_code = data.get('group_code')
|
|
|
+ # 处理库位组对象
|
|
|
+ group_obj = LocationGroupModel.objects.filter(group_code=group_code).first()
|
|
|
+ if group_obj:
|
|
|
+ data['id'] = group_obj.id
|
|
|
+ logger.info(f"库位组 {group_code} 已存在")
|
|
|
+ else:
|
|
|
+ logger.info(f"库位组 {group_code} 不存在,创建库位组对象")
|
|
|
+ serializer_list = LocationGroupPostSerializer(data=data)
|
|
|
+ serializer_list.is_valid(raise_exception=True)
|
|
|
+ serializer_list.save()
|
|
|
+ data['id'] = serializer_list.data.get('id')
|
|
|
+ return Response(data, status=status.HTTP_201_CREATED)
|
|
|
+
|
|
|
class LocationAllocation:
|
|
|
# 入库规则函数
|
|
|
# fun:get_pallet_count_by_batch: 根据托盘码查询批次下托盘总数
|
|
|
+ # fun:get_left_locationGroup_number_by_type: 获取每层库位组剩余数量
|
|
|
# fun:get_location_type: 根据托盘数目获取库位类型
|
|
|
- # fun:updata_location_container_link: 更新库位和托盘的关联关系
|
|
|
+ # fun:update_location_container_link: 更新库位和托盘的关联关系
|
|
|
+ # fun:update_location_group_batch: 更新库位组的批次
|
|
|
+ # fun:update_batch_status: 更新批次状态yes/no
|
|
|
+ # fun:update_location_status: 更新库位状态和
|
|
|
+ # fun:up
|
|
|
# fun:get_batch_status: 获取批次状态
|
|
|
# fun:get_batch: 获取批次
|
|
|
# fun:get_location_list_remainder: 获取可用库位的c_number列表
|
|
|
- # fun:get_min_list_index: 获取最小的库位
|
|
|
+
|
|
|
# fun:get_location_by_type_remainder: 根据库位类型获取库位
|
|
|
# fun:get_location_by_type: 第一次入库,根据库位类型获取库位
|
|
|
# fun:get_location_by_status: 根据库位状态获取库位
|
|
@@ -66,29 +240,110 @@ class LocationAllocation:
|
|
|
return None
|
|
|
else:
|
|
|
print (f"容器 {container_code} 已组盘")
|
|
|
- batch_container_count = ContainerDetailModel.objects.filter(
|
|
|
+ batch_container = ContainerDetailModel.objects.filter(
|
|
|
batch = container_detail.batch.id,
|
|
|
status = 1
|
|
|
- ).count()
|
|
|
-
|
|
|
+ ).all()
|
|
|
+ # 统计批次下的不同托盘 item.contianer_id
|
|
|
+ batch_container_count = 0
|
|
|
+ container_ids = []
|
|
|
+ for item in batch_container:
|
|
|
+ if item.container_id not in container_ids:
|
|
|
+ batch_container_count = batch_container_count + 1
|
|
|
+ container_ids.append(item.container_id)
|
|
|
+ batch_item = BoundBatchModel.objects.filter( bound_number = container_detail.batch.bound_number).first()
|
|
|
+ if not batch_item:
|
|
|
+ print(f"批次号获取失败!")
|
|
|
+ return None
|
|
|
+ batch_item.container_number = batch_container_count
|
|
|
+ batch_item.save()
|
|
|
return batch_container_count
|
|
|
|
|
|
- def get_location_type(self,container_count):
|
|
|
- """
|
|
|
- 根据托盘数目获取库位类型
|
|
|
- :param container_count: 托盘数目
|
|
|
- :return: 库位类型
|
|
|
- """
|
|
|
- if container_count <= 1:
|
|
|
- return ["T1"]
|
|
|
- elif container_count <= 2:
|
|
|
- return ["T2"]
|
|
|
- elif container_count <= 4:
|
|
|
- return ["S4","T4"]
|
|
|
+ def get_left_locationGroup_number_by_type(self):
|
|
|
+ """
|
|
|
+ 获取每层库位组剩余数量
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 定义库位组和层号
|
|
|
+ group = ['T1', 'T2', 'S4', 'T4', 'T5']
|
|
|
+ layer = [1, 2, 3]
|
|
|
+ # 初始化结果列表,包含三个空字典对应三个层
|
|
|
+ left_number = [{} for _ in layer]
|
|
|
+
|
|
|
+ for item in group:
|
|
|
+ for idx, layer_num in enumerate(layer):
|
|
|
+ # 检查库位组是否存在(不考虑状态)
|
|
|
+ exists = LocationGroupModel.objects.filter(
|
|
|
+ group_type=item,
|
|
|
+ layer=layer_num
|
|
|
+ ).exists()
|
|
|
+
|
|
|
+ if not exists:
|
|
|
+ print(f"库位组 {item}_{layer_num} 不存在")
|
|
|
+ left_number[idx][item] = 0
|
|
|
+ else:
|
|
|
+ # 统计可用状态的库位组数量
|
|
|
+ count = LocationGroupModel.objects.filter(
|
|
|
+ group_type=item,
|
|
|
+ layer=layer_num,
|
|
|
+ status='available'
|
|
|
+ ).count()
|
|
|
+ left_number[idx][item] = count
|
|
|
+
|
|
|
+ return left_number
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"获取库位组剩余数量失败:{str(e)}")
|
|
|
+ print(f"获取库位组剩余数量失败:{str(e)}")
|
|
|
+ return None
|
|
|
+
|
|
|
+ def get_location_type(self,container_code):
|
|
|
+ """
|
|
|
+ :param container_code: 托盘码
|
|
|
+ :return: 库位类型列表
|
|
|
+ """
|
|
|
+ batch = self.get_batch(container_code)
|
|
|
+ if not batch:
|
|
|
+ print(f"类型分配中批次号获取失败!")
|
|
|
+ return None
|
|
|
+ location_solution = alloction_pre.objects.filter(batch_number=batch).first()
|
|
|
+ if not location_solution:
|
|
|
+ # 1. 获取托盘码对应批次号下所有的托盘数目
|
|
|
+ container_number = self.get_pallet_count_by_batch(container_code)
|
|
|
+ print (f"该批次下托盘总数:{container_number}")
|
|
|
+ # 2. 计算每层剩余的库位数目
|
|
|
+ layer_number=self.get_pallet_count_by_batch()
|
|
|
+ # 3. 查看最新库位分配方案
|
|
|
+ location_solution_last = alloction_pre.objects.filter().order_by('-id').first()
|
|
|
+ if not location_solution_last:
|
|
|
+ layer1_pressure =0
|
|
|
+ layer2_pressure =0
|
|
|
+ layer3_pressure =0
|
|
|
+ else:
|
|
|
+ layer1_pressure = location_solution_last.layer1_pressure
|
|
|
+ layer2_pressure = location_solution_last.layer2_pressure
|
|
|
+ layer3_pressure = location_solution_last.layer3_pressure
|
|
|
+ # 4. 根据工作压力和库位类型,使用贪心算法,(AGV只有两个库位,故只给考虑1 2 层工作压力,第三层仅作为1,2层的补充,不考虑压力)获取库位类型列表,完成任务之后更新压力/TODO:需要考虑库位类型和库位数量的关系
|
|
|
+ if layer1_pressure <=layer2_pressure:
|
|
|
+
|
|
|
+ print(f"库位类型:{location_type}")
|
|
|
+ # 5. 保存库位分配方案
|
|
|
+ alloction_pre.objects.create(
|
|
|
+ batch_number=batch,
|
|
|
+ layer1_pressure=layer1_pressure,
|
|
|
+ layer2_pressure=layer2_pressure,
|
|
|
+ layer3_pressure=layer3_pressure,
|
|
|
+
|
|
|
+ location_type=','.join(location_type)
|
|
|
+ )
|
|
|
+ return location_type
|
|
|
else:
|
|
|
- return ["T5"]
|
|
|
+ print(f"库位类型:{location_solution.location_type}")
|
|
|
+ return location_solution.location_type.split(",")
|
|
|
+
|
|
|
+
|
|
|
@transaction.atomic
|
|
|
- def updata_location_container_link(self,location_code,container_code):
|
|
|
+ def update_location_container_link(self,location_code,container_code):
|
|
|
"""
|
|
|
更新库位和托盘的关联关系
|
|
|
:param location_code: 库位编码
|
|
@@ -111,6 +366,7 @@ class LocationAllocation:
|
|
|
)
|
|
|
location_container_link.save()
|
|
|
print(f"更新库位和托盘的关联关系成功!")
|
|
|
+ return True
|
|
|
# 3. 更新库位和托盘的关联关系
|
|
|
else:
|
|
|
LocationContainerLink.objects.filter(location=location).update(location=location, container=container)
|
|
@@ -120,6 +376,142 @@ class LocationAllocation:
|
|
|
logger.error(f"更新库位和托盘的关联关系失败:{str(e)}")
|
|
|
print(f"更新库位和托盘的关联关系失败:{str(e)}")
|
|
|
return False
|
|
|
+ def update_location_group_batch(self,location,container_code):
|
|
|
+ """
|
|
|
+ :param location: 库位对象
|
|
|
+ :param container_code: 托盘码
|
|
|
+
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 1. 获取库位组
|
|
|
+ location_group = LocationGroupModel.objects.filter(
|
|
|
+ group_code=location.location_group
|
|
|
+ ).first()
|
|
|
+ if not location_group:
|
|
|
+ print(f"库位组获取失败!")
|
|
|
+ return False
|
|
|
+ # 2. 更新库位组的批次
|
|
|
+ bound_number=self.get_batch(container_code)
|
|
|
+ if not bound_number:
|
|
|
+ print(f"批次号获取失败!")
|
|
|
+ return False
|
|
|
+ location_group.current_batch = bound_number
|
|
|
+ location_group.save()
|
|
|
+ print(f"更新库位组的批次成功!")
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"更新库位组的批次失败:{str(e)}")
|
|
|
+ print(f"更新库位组的批次失败:{str(e)}")
|
|
|
+ return False
|
|
|
+ def update_location_status(self,location_code,status):
|
|
|
+ """
|
|
|
+ 更新库位状态
|
|
|
+ :param location_code: 库位编码
|
|
|
+ :param status: 库位状态
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 1. 获取库位
|
|
|
+ location = LocationModel.objects.filter(
|
|
|
+ location_code=location_code
|
|
|
+ ).first()
|
|
|
+ if not location:
|
|
|
+ print(f"库位获取失败!")
|
|
|
+ return False
|
|
|
+ # 2. 更新库位状态
|
|
|
+ location.status = status
|
|
|
+ location.save()
|
|
|
+ print(f"更新库位状态成功!")
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"更新库位状态失败:{str(e)}")
|
|
|
+ print(f"更新库位状态失败:{str(e)}")
|
|
|
+ return False
|
|
|
+ def update_location_group_status(self, location_code):
|
|
|
+ """
|
|
|
+ 更新库位组状态
|
|
|
+ :param location_code: 库位编码
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 1. 获取库位
|
|
|
+ location = LocationModel.objects.filter(
|
|
|
+ location_code=location_code
|
|
|
+ ).first()
|
|
|
+ if not location:
|
|
|
+ print(f"库位获取失败!")
|
|
|
+ return False
|
|
|
+
|
|
|
+ # 2. 获取库位组
|
|
|
+ location_group = LocationGroupModel.objects.filter(
|
|
|
+ group_code=location.location_group
|
|
|
+ ).first()
|
|
|
+ if not location_group:
|
|
|
+ print(f"库位组获取失败!")
|
|
|
+ return False
|
|
|
+ current=0
|
|
|
+ for location_item in location_group.location_items.all():
|
|
|
+ if location_item.status != 'available':
|
|
|
+ current=current + 1
|
|
|
+ # 3. 更新库位组状态
|
|
|
+ if current == 0:
|
|
|
+ location_group.status = 'available'
|
|
|
+ elif current == location_group.max_capacity:
|
|
|
+ location_group.status = 'full'
|
|
|
+ else:
|
|
|
+ location_group.status = 'occupied'
|
|
|
+
|
|
|
+ location_group.current_goods_quantity = sum(
|
|
|
+ [loc.current_quantity for loc in location_group.location_items.all()]
|
|
|
+ )
|
|
|
+ location_group.current_quantity = current
|
|
|
+
|
|
|
+ location_group.save()
|
|
|
+ print(f"更新库位组状态成功!")
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"更新库位组状态失败:{str(e)}")
|
|
|
+ print(f"更新库位组状态失败:{str(e)}")
|
|
|
+ def update_batch_status(self,container_code,status):
|
|
|
+ """
|
|
|
+ 更新批次状态
|
|
|
+ :param batch_id: 批次id
|
|
|
+ :param status: 批次状态
|
|
|
+ :return:
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # 1. 通过托盘码获取容器详情
|
|
|
+ container = ContainerListModel.objects.filter(
|
|
|
+ container_code=container_code
|
|
|
+ ).first()
|
|
|
+
|
|
|
+ if not container:
|
|
|
+ logger.error(f"托盘 {container_code} 不存在")
|
|
|
+ print(f"托盘 {container_code} 不存在")
|
|
|
+ return None
|
|
|
+ # 2. 获取关联的批次明细
|
|
|
+ container_detail = ContainerDetailModel.objects.filter(
|
|
|
+ container=container.id,
|
|
|
+ status=1
|
|
|
+ ).first()
|
|
|
+ if not container_detail:
|
|
|
+ print (f"容器 {container_code} 未组盘")
|
|
|
+ logger.error(f"容器 {container_code} 未组盘")
|
|
|
+ return None
|
|
|
+ else:
|
|
|
+ print (f"容器 {container_code} 已组盘")
|
|
|
+ # 3. 更新批次状态
|
|
|
+ batch = container_detail.batch
|
|
|
+ batch.status = status
|
|
|
+ batch.save()
|
|
|
+ print(f"更新批次状态成功!")
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"更新批次状态失败:{str(e)}")
|
|
|
+ print(f"更新批次状态失败:{str(e)}")
|
|
|
+ return False
|
|
|
+
|
|
|
def get_batch_status(self,container_code):
|
|
|
"""
|
|
|
获取批次状态
|
|
@@ -185,28 +577,19 @@ class LocationAllocation:
|
|
|
"""
|
|
|
if not location_list:
|
|
|
return None
|
|
|
+ min_c_number=1000
|
|
|
+ min_c_number_index=1000
|
|
|
|
|
|
- available_c_numbers = [
|
|
|
- loc.c_number for loc in location_list
|
|
|
- if loc.status == 'available'
|
|
|
- ]
|
|
|
-
|
|
|
- return available_c_numbers if available_c_numbers else None
|
|
|
- def get_min_list_index(self,list):
|
|
|
- """
|
|
|
- 获取最小的库位
|
|
|
- :param list: 库位列表
|
|
|
- :return: 最小库位
|
|
|
- """
|
|
|
- if not list:
|
|
|
+ for location in location_list:
|
|
|
+ if location.status != 'available':
|
|
|
+ continue
|
|
|
+ if int(location.c_number)<min_c_number:
|
|
|
+ min_c_number=int(location.c_number)
|
|
|
+ min_c_number_index=location_list.index(location)
|
|
|
+ if min_c_number_index==1000:
|
|
|
return None
|
|
|
- min_index = 0
|
|
|
- for i in range(len(list)):
|
|
|
- if list[i] < list[min_index]:
|
|
|
- min_index = i
|
|
|
- return min_index
|
|
|
-
|
|
|
-
|
|
|
+ else:
|
|
|
+ return min_c_number_index
|
|
|
@transaction.atomic
|
|
|
def get_location_by_type_remainder(self, batch, layer):
|
|
|
"""
|
|
@@ -252,11 +635,8 @@ class LocationAllocation:
|
|
|
else:
|
|
|
ordered_groups = location_groups.none()
|
|
|
|
|
|
- # 合并所有库位组中的库位
|
|
|
locations = []
|
|
|
-
|
|
|
locations.extend(ordered_groups.first().location_items.all()) # 假设location_items是关联字段
|
|
|
-
|
|
|
return locations if locations else None
|
|
|
@transaction.atomic
|
|
|
def get_location_by_status(self,container_code,start_location,layer):
|
|
@@ -273,199 +653,78 @@ class LocationAllocation:
|
|
|
if status == 1:
|
|
|
# 2. 获取库位组
|
|
|
print (f"第一次入库")
|
|
|
- container_number = self.get_pallet_count_by_batch(container_code)
|
|
|
- print (f"该批次下托盘总数:{container_number}")
|
|
|
- location_type_list = self.get_location_type(container_number)
|
|
|
+
|
|
|
+ location_type_list = self.get_location_type(container_code)
|
|
|
print(f"库位类型:{location_type_list}")
|
|
|
location_list = self.get_location_by_type(location_type_list,start_location,layer)
|
|
|
print(f"库位列表:{location_list}")
|
|
|
- location_list_remainder = self.get_location_list_remainder(location_list)
|
|
|
- print(f"库位列表剩余:{location_list_remainder}")
|
|
|
- if not location_list_remainder:
|
|
|
+ location_min_index = self.get_location_list_remainder(location_list)
|
|
|
+ print(f"库位安排到第{location_min_index+1}个库位:{location_list[location_min_index]}")
|
|
|
+ if not location_list[location_min_index]:
|
|
|
# 库位已满,返回None
|
|
|
return None
|
|
|
else:
|
|
|
- location_index = self.get_min_list_index(location_list_remainder)
|
|
|
- # 返回和托盘关联的库位、库位剩余、库位类型
|
|
|
- return location_list[location_index]
|
|
|
+
|
|
|
+ return location_list[location_min_index]
|
|
|
elif status == 2:
|
|
|
print(f"部分入库")
|
|
|
# 2. 获取库位组
|
|
|
location_list = self.get_location_by_type_remainder(self.get_batch(container_code),layer)
|
|
|
- location_list_remainder = self.get_location_list_remainder(location_list)
|
|
|
- if not location_list_remainder:
|
|
|
+ print(f"库位列表:{location_list}")
|
|
|
+ location_min_index = self.get_location_list_remainder(location_list)
|
|
|
+ print(f"库位安排到第{location_min_index+1}个库位:{location_list[location_min_index]}")
|
|
|
+ if not location_list[location_min_index]:
|
|
|
# 库位已满,返回None
|
|
|
return None
|
|
|
else:
|
|
|
- location_index = self.get_min_list_index(location_list_remainder)
|
|
|
- # 返回和托盘关联的库位、库位剩余、库位类型
|
|
|
- return location_list[location_index]
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-class locationViewSet(viewsets.ModelViewSet):
|
|
|
- """
|
|
|
- retrieve:
|
|
|
- Response a data list(get)
|
|
|
- list:
|
|
|
- Response a data list(all)
|
|
|
- create:
|
|
|
- Create a data line(post)
|
|
|
-
|
|
|
- delete:
|
|
|
- Delete a data line(delete)
|
|
|
-
|
|
|
- """
|
|
|
- # authentication_classes = [] # 禁用所有认证类
|
|
|
- # permission_classes = [AllowAny] # 允许任意访问
|
|
|
-
|
|
|
- pagination_class = MyPageNumberPagination
|
|
|
- filter_backends = [DjangoFilterBackend, OrderingFilter, ]
|
|
|
- ordering_fields = ['id', "create_time", "update_time", ]
|
|
|
- filter_class = LocationFilter
|
|
|
-
|
|
|
- def get_project(self):
|
|
|
- try:
|
|
|
- id = self.kwargs.get('pk')
|
|
|
- return id
|
|
|
- except:
|
|
|
- return None
|
|
|
-
|
|
|
- def get_queryset(self):
|
|
|
- id = self.get_project()
|
|
|
- if self.request.user:
|
|
|
- if id is None:
|
|
|
- return LocationModel.objects.filter()
|
|
|
- else:
|
|
|
- return LocationModel.objects.filter( id=id)
|
|
|
- else:
|
|
|
- return LocationModel.objects.none()
|
|
|
- def get_serializer_class(self):
|
|
|
- if self.action == 'list':
|
|
|
- return LocationListSerializer
|
|
|
- elif self.action == 'update':
|
|
|
- return LocationPostSerializer
|
|
|
- elif self.action =='retrieve':
|
|
|
- return LocationListSerializer
|
|
|
-
|
|
|
- def update(self, request, *args, **kwargs):
|
|
|
- qs = self.get_object()
|
|
|
- data = self.request.data
|
|
|
-
|
|
|
- location_code = data.get('location_code')
|
|
|
- # 处理库位对象
|
|
|
- location_obj = LocationModel.objects.filter(location_code=location_code).first()
|
|
|
- if not location_obj:
|
|
|
- logger.info(f"库位 {location_code} 不存在")
|
|
|
- return Response(
|
|
|
- {'code': '400', 'message': '库位不存在', 'data': None},
|
|
|
- status=status.HTTP_400_BAD_REQUEST
|
|
|
- )
|
|
|
- else:
|
|
|
- data['id'] = location_obj.id
|
|
|
- logger.info(f"库位 {location_code} 已存在")
|
|
|
- serializer = self.get_serializer(qs, data=data)
|
|
|
- serializer.is_valid(raise_exception=True)
|
|
|
- serializer.save()
|
|
|
- headers = self.get_success_headers(serializer.data)
|
|
|
- self.handle_group_location_status(location_code,location_obj.location_group)
|
|
|
- return Response(serializer.data, status=200, headers=headers)
|
|
|
-
|
|
|
- def handle_group_location_status(self,location_code,location_group):
|
|
|
+ return location_list[location_min_index]
|
|
|
+ elif status == 3:
|
|
|
+ print(f"全部入库")
|
|
|
+ # 2. 获取库位组
|
|
|
+ location_list = self.get_location_by_type_remainder(self.get_batch(container_code),layer)
|
|
|
+ return location_list
|
|
|
+
|
|
|
+
|
|
|
"""
|
|
|
- 处理库位组和库位的关联关系
|
|
|
- :param location_code: 库位编码
|
|
|
- :param location_group: 库位组编码
|
|
|
- :return:
|
|
|
+ 根据库位状态清除库位
|
|
|
+ :param container_code: 托盘码
|
|
|
+ :param start_location: 起始库位 if in1 优先考虑left_priority, if in2 优先考虑right_priority 就是获取库位组列表之后进行排序
|
|
|
+ :param layer: 层数 限定层数
|
|
|
+ :return: 库位列表
|
|
|
"""
|
|
|
- # 1. 获取库位空闲状态的库位数目
|
|
|
- location_obj_number = LocationModel.objects.filter(
|
|
|
- location_group=location_group,
|
|
|
- status='available'
|
|
|
- ).all().count()
|
|
|
- # 2. 获取库位组对象
|
|
|
- logger.info(f"库位组 {location_group} 下的库位数目:{location_obj_number}")
|
|
|
- # 1. 获取库位和库位组的关联关系
|
|
|
- location_group_obj = LocationGroupModel.objects.filter(
|
|
|
- group_code=location_group
|
|
|
- ).first()
|
|
|
- if not location_group_obj:
|
|
|
- logger.info(f"库位组 {location_group} 不存在")
|
|
|
- return None
|
|
|
- else:
|
|
|
- if location_obj_number == 0:
|
|
|
- # 库位组库位已满,更新库位组状态为full
|
|
|
- location_group_obj.status = 'full'
|
|
|
- location_group_obj.save()
|
|
|
- elif location_obj_number < location_group_obj.max_capacity:
|
|
|
- location_group_obj.status = 'occupied'
|
|
|
- location_group_obj.save()
|
|
|
+ # 1. 获取批次状态 102 为已组盘 103 为部分入库 104 为全部入库
|
|
|
+ status = self.get_batch_status(container_code)
|
|
|
+ #
|
|
|
+ if status == 1:
|
|
|
+ # 2. 获取库位组
|
|
|
+ print (f"第一次入库")
|
|
|
+ container_number = self.get_pallet_count_by_batch(container_code)
|
|
|
+ print (f"该批次下托盘总数:{container_number}")
|
|
|
+ location_type_list = self.get_location_type(container_number)
|
|
|
+ print(f"库位类型:{location_type_list}")
|
|
|
+ location_list = self.get_location_by_type(location_type_list,start_location,layer)
|
|
|
+ print(f"库位列表:{location_list}")
|
|
|
+ location_min_index = self.get_location_list_remainder(location_list)
|
|
|
+ print(f"库位安排到第{location_min_index+1}个库位:{location_list[location_min_index]}")
|
|
|
+ if not location_list[location_min_index]:
|
|
|
+ # 库位已满,返回None
|
|
|
+ return None
|
|
|
else:
|
|
|
- location_group_obj.status = 'available'
|
|
|
- location_group_obj.save()
|
|
|
-
|
|
|
-class locationGroupViewSet(viewsets.ModelViewSet):
|
|
|
- """
|
|
|
- retrieve:
|
|
|
- Response a data list(get)
|
|
|
- list:
|
|
|
- Response a data list(all)
|
|
|
- create:
|
|
|
- Create a data line(post)
|
|
|
-
|
|
|
- delete:
|
|
|
- Delete a data line(delete)
|
|
|
-
|
|
|
- """
|
|
|
- # authentication_classes = [] # 禁用所有认证类
|
|
|
- # permission_classes = [AllowAny] # 允许任意访问
|
|
|
-
|
|
|
- pagination_class = MyPageNumberPagination
|
|
|
- filter_backends = [DjangoFilterBackend, OrderingFilter, ]
|
|
|
- ordering_fields = ['id', "create_time", "update_time", ]
|
|
|
- filter_class = LocationGroupFilter
|
|
|
-
|
|
|
- def get_project(self):
|
|
|
- try:
|
|
|
- id = self.kwargs.get('pk')
|
|
|
- return id
|
|
|
- except:
|
|
|
- return None
|
|
|
-
|
|
|
-
|
|
|
- def get_queryset(self):
|
|
|
- id = self.get_project()
|
|
|
- if self.request.user:
|
|
|
- if id is None:
|
|
|
- return LocationGroupModel.objects.filter()
|
|
|
+ location_code = location_list[location_min_index].location_code
|
|
|
+ self.update_location_status(location_code,'occupied')
|
|
|
+ return location_list[location_min_index]
|
|
|
+ elif status == 2:
|
|
|
+ print(f"部分入库")
|
|
|
+ # 2. 获取库位组
|
|
|
+ location_list = self.get_location_by_type_remainder(self.get_batch(container_code),layer)
|
|
|
+ print(f"库位列表:{location_list}")
|
|
|
+ location_min_index = 1
|
|
|
+ print(f"库位安排到第{location_min_index+1}个库位:{location_list[location_min_index]}")
|
|
|
+ if not location_list[location_min_index]:
|
|
|
+ # 库位已满,返回None
|
|
|
+ return None
|
|
|
else:
|
|
|
- return LocationGroupModel.objects.filter(id=id)
|
|
|
- else:
|
|
|
- return LocationGroupModel.objects.none()
|
|
|
- def get_serializer_class(self):
|
|
|
- if self.action == 'list':
|
|
|
- return LocationGroupListSerializer
|
|
|
-
|
|
|
- elif self.action == 'update':
|
|
|
- return LocationGroupPostSerializer
|
|
|
-
|
|
|
- elif self.action =='retrieve':
|
|
|
- return LocationGroupListSerializer
|
|
|
-
|
|
|
- def update(self, request, *args, **kwargs):
|
|
|
- data = self.request.data
|
|
|
- order_month = str(timezone.now().strftime('%Y%m'))
|
|
|
- data['month'] = order_month
|
|
|
- group_code = data.get('group_code')
|
|
|
- # 处理库位组对象
|
|
|
- group_obj = LocationGroupModel.objects.filter(group_code=group_code).first()
|
|
|
- if group_obj:
|
|
|
- data['id'] = group_obj.id
|
|
|
- logger.info(f"库位组 {group_code} 已存在")
|
|
|
- else:
|
|
|
- logger.info(f"库位组 {group_code} 不存在,创建库位组对象")
|
|
|
- serializer_list = LocationGroupPostSerializer(data=data)
|
|
|
- serializer_list.is_valid(raise_exception=True)
|
|
|
- serializer_list.save()
|
|
|
- data['id'] = serializer_list.data.get('id')
|
|
|
- return Response(data, status=status.HTTP_201_CREATED)
|
|
|
+ location_code = location_list[location_min_index].location_code
|
|
|
+ self.update_location_status(location_code,'occupied')
|
|
|
+ return location_list[location_min_index]
|
|
|
+
|