views.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. from rest_framework import viewsets
  2. from utils.page import MyPageNumberPagination
  3. from utils.datasolve import sumOfList, transportation_calculate
  4. from utils.md5 import Md5
  5. from rest_framework.filters import OrderingFilter
  6. from django_filters.rest_framework import DjangoFilterBackend
  7. from rest_framework.response import Response
  8. from rest_framework.exceptions import APIException
  9. from django.utils import timezone
  10. from django.db import transaction
  11. import logging
  12. from rest_framework import status
  13. from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,ContainerWCSModel,TaskModel
  14. from bound.models import BoundBatchModel,BoundDetailModel,BoundListModel
  15. from bin.views import LocationAllocation
  16. from bin.models import LocationModel
  17. # from .files import FileListRenderCN, FileDetailRenderCN
  18. from .serializers import ContainerDetailGetSerializer,ContainerDetailPostSerializer
  19. from .serializers import ContainerListGetSerializer,ContainerListPostSerializer
  20. from .serializers import ContainerOperationGetSerializer,ContainerOperationPostSerializer
  21. from .serializers import TaskGetSerializer,TaskPostSerializer
  22. from .filter import ContainerDetailFilter,ContainerListFilter,ContainerOperationFilter,TaskFilter
  23. # 以后添加模
  24. from warehouse.models import ListModel as warehouse
  25. from staff.models import ListModel as staff
  26. from rest_framework.permissions import AllowAny
  27. logger = logging.getLogger(__name__)
  28. class ContainerListViewSet(viewsets.ModelViewSet):
  29. """
  30. retrieve:
  31. Response a data list(get)
  32. list:
  33. Response a data list(all)
  34. create:
  35. Create a data line(post)
  36. delete:
  37. Delete a data line(delete)
  38. """
  39. # authentication_classes = [] # 禁用所有认证类
  40. # permission_classes = [AllowAny] # 允许任意访问
  41. pagination_class = MyPageNumberPagination
  42. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  43. ordering_fields = ['id', "create_time", "update_time", ]
  44. filter_class = ContainerListFilter
  45. def get_project(self):
  46. try:
  47. id = self.kwargs.get('pk')
  48. return id
  49. except:
  50. return None
  51. def get_queryset(self):
  52. id = self.get_project()
  53. if self.request.user:
  54. if id is None:
  55. return ContainerListModel.objects.filter()
  56. else:
  57. return ContainerListModel.objects.filter( id=id)
  58. else:
  59. return ContainerListModel.objects.none()
  60. def get_serializer_class(self):
  61. if self.action in ['list', 'destroy','retrieve']:
  62. return ContainerListGetSerializer
  63. elif self.action in ['create', 'update']:
  64. return ContainerListPostSerializer
  65. else:
  66. return self.http_method_not_allowed(request=self.request)
  67. def create(self, request, *args, **kwargs):
  68. data = self.request.data
  69. order_month = str(timezone.now().strftime('%Y%m'))
  70. data['month'] = order_month
  71. data['last_operate'] = str(timezone.now())
  72. serializer = self.get_serializer(data=data)
  73. serializer.is_valid(raise_exception=True)
  74. serializer.save()
  75. headers = self.get_success_headers(serializer.data)
  76. return Response(serializer.data, status=200, headers=headers)
  77. def update(self, request, pk):
  78. qs = self.get_object()
  79. data = self.request.data
  80. serializer = self.get_serializer(qs, data=data)
  81. serializer.is_valid(raise_exception=True)
  82. serializer.save()
  83. headers = self.get_success_headers(serializer.data)
  84. return Response(serializer.data, status=200, headers=headers)
  85. class TaskViewSet(viewsets.ModelViewSet):
  86. """
  87. retrieve:
  88. Response a data list(get)
  89. list:
  90. Response a data list(all)
  91. create:
  92. Create a data line(post)
  93. delete:
  94. Delete a data line(delete)
  95. """
  96. pagination_class = MyPageNumberPagination
  97. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  98. ordering_fields = ['id', "create_time", "update_time", ]
  99. filter_class = TaskFilter
  100. def get_project(self):
  101. try:
  102. id = self.kwargs.get('pk')
  103. return id
  104. except:
  105. return None
  106. def get_queryset(self):
  107. id = self.get_project()
  108. if self.request.user:
  109. if id is None:
  110. return TaskModel.objects.filter()
  111. else:
  112. return TaskModel.objects.filter( id=id)
  113. else:
  114. return TaskModel.objects.none()
  115. def get_serializer_class(self):
  116. if self.action in ['list', 'destroy','retrieve']:
  117. return TaskGetSerializer
  118. elif self.action in ['create', 'update']:
  119. return TaskPostSerializer
  120. else:
  121. return self.http_method_not_allowed(request=self.request)
  122. def create(self, request, *args, **kwargs):
  123. data = self.request.data
  124. return Response(data, status=200, headers=headers)
  125. def update(self, request, pk):
  126. qs = self.get_object()
  127. data = self.request.data
  128. serializer = self.get_serializer(qs, data=data)
  129. serializer.is_valid(raise_exception=True)
  130. serializer.save()
  131. headers = self.get_success_headers(serializer.data)
  132. return Response(serializer.data, status=200, headers=headers)
  133. class ContainerWCSViewSet(viewsets.ModelViewSet):
  134. """
  135. retrieve:
  136. Response a data list(get)
  137. list:
  138. Response a data list(all)
  139. create:
  140. Create a data line(post)
  141. delete:
  142. Delete a data line(delete)
  143. """
  144. authentication_classes = [] # 禁用所有认证类
  145. permission_classes = [AllowAny] # 允许任意访问
  146. def get_container_wcs(self, request, *args, **kwargs):
  147. data = self.request.data
  148. container = data.get('container_number')
  149. current_location = data.get('current_location')
  150. logger.info(f"请求托盘:{container},请求位置:{current_location}")
  151. if current_location =="203":
  152. current_location ="in1"
  153. elif current_location=="103":
  154. current_location="in2"
  155. data_return = {}
  156. try:
  157. container_obj = ContainerListModel.objects.filter(container_code=container).first()
  158. if not container_obj:
  159. data_return = {
  160. 'code': '400',
  161. 'message': '托盘编码不存在',
  162. 'data': data
  163. }
  164. return Response(data_return, status=status.HTTP_400_BAD_REQUEST)
  165. # 更新容器数据(部分更新)
  166. serializer = ContainerListPostSerializer(
  167. container_obj,
  168. data=data,
  169. partial=True # 允许部分字段更新
  170. )
  171. serializer.is_valid(raise_exception=True)
  172. serializer.save()
  173. # 检查是否已在目标位置
  174. if current_location == str(container_obj.target_location):
  175. logger.info(f"托盘 {container} 已在目标位置")
  176. data_return = {
  177. 'code': '200',
  178. 'message': '当前位置已是目标位置',
  179. 'data': data
  180. }
  181. else:
  182. current_task = ContainerWCSModel.objects.filter(
  183. container=container,
  184. tasktype='inbound'
  185. ).first()
  186. if current_task:
  187. data_return = {
  188. 'code': '200',
  189. 'message': '任务已存在,重新下发',
  190. 'data': current_task.to_dict()
  191. }
  192. else:
  193. # 库位分配
  194. container_code = container
  195. print(f"开始生成库位,托盘编码:{container_code}")
  196. allocator = LocationAllocation() # 创建实例
  197. location_list_cnumber = allocator.get_location_by_status(container_code, current_location) # 获取库位列表
  198. if not location_list_cnumber:
  199. print("❌ 通用库位获取失败,请检查托盘编码")
  200. return
  201. print(f"[1]库位:{location_list_cnumber}")
  202. update_location_status = allocator.update_location_status(location_list_cnumber.location_code, 'reserved') # 更新库位状态
  203. if not update_location_status:
  204. print("❌ 库位状态更新失败,请检查托盘编码")
  205. return
  206. print(f"[2]发送任务,库位状态更新成功!")
  207. update_location_group_status = allocator.update_location_group_status(location_list_cnumber.location_code) # 更新库位组状态
  208. if not update_location_group_status:
  209. print("❌ 库位组状态更新失败,请检查托盘编码")
  210. return
  211. print(f"[3]库位组状态更新成功!")
  212. update_batch_status = allocator.update_batch_status(container_code, '2') # 更新批次状态
  213. if not update_batch_status:
  214. print("❌ 批次状态更新失败,请检查批次号")
  215. return
  216. print(f"[4]批次状态更新成功!")
  217. update_location_group_batch = allocator.update_location_group_batch(location_list_cnumber, container_code) # 更新库位组的批次
  218. if not update_location_group_batch:
  219. print("❌ 库位组批次更新失败,请检查托盘编码")
  220. return
  221. print(f"[5]库位组批次更新成功!")
  222. update_location_container_link = allocator.update_location_container_link(location_list_cnumber.location_code, container_code) # 更新库位和托盘的关联关系
  223. if not update_location_container_link:
  224. print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
  225. return
  226. print(f"[7]库位和托盘的关联关系更新成功!")
  227. allocation_target_location = (
  228. location_list_cnumber.warehouse_code + '-'
  229. + f"{int(location_list_cnumber.row):02d}" + '-'
  230. + f"{int(location_list_cnumber.col):02d}" + '-'
  231. + f"{int(location_list_cnumber.layer):02d}"
  232. )
  233. self.generate_task(container, current_location, allocation_target_location) # 生成任务
  234. current_task = ContainerWCSModel.objects.get(
  235. container=container,
  236. tasktype='inbound'
  237. )
  238. data_return = {
  239. 'code': '200',
  240. 'message': '任务下发成功',
  241. 'data': current_task.to_dict()
  242. }
  243. container_obj.target_location = allocation_target_location
  244. container_obj.save()
  245. self.inport_update_task(current_task.id, container_obj.id)
  246. http_status = status.HTTP_200_OK if data_return['code'] == '200' else status.HTTP_400_BAD_REQUEST
  247. return Response(data_return, status=http_status)
  248. except Exception as e:
  249. logger.error(f"处理请求时发生错误: {str(e)}", exc_info=True)
  250. return Response(
  251. {'code': '500', 'message': '服务器内部错误', 'data': None},
  252. status=status.HTTP_500_INTERNAL_SERVER_ERROR
  253. )
  254. @transaction.atomic
  255. def generate_task(self, container, current_location, target_location):
  256. data_tosave = {
  257. 'container': container,
  258. 'current_location': current_location,
  259. 'month': timezone.now().strftime('%Y%m'),
  260. 'target_location': target_location,
  261. 'tasktype': 'inbound',
  262. 'status': 103,
  263. 'is_delete': False
  264. }
  265. # 生成唯一递增的 taskid
  266. last_task = ContainerWCSModel.objects.filter(
  267. month=data_tosave['month'],
  268. tasktype='inbound'
  269. ).order_by('-taskid').first()
  270. if last_task:
  271. last_id = int(last_task.taskid.split('-')[-1])
  272. new_id = f"{last_id + 1:04}"
  273. else:
  274. new_id = "0001"
  275. data_tosave['taskid'] = f"inbound-{data_tosave['month']}-{new_id}"
  276. logger.info(f"生成入库任务: {data_tosave['taskid']}")
  277. # 每月生成唯一递增的 taskNumber
  278. data_tosave['tasknumber'] = f"{data_tosave['month']}{new_id}"
  279. ContainerWCSModel.objects.create(**data_tosave)
  280. def update_container_wcs(self, request, *args, **kwargs):
  281. data = self.request.data
  282. container = data.get('container_number')
  283. current_location = data.get('current_location')
  284. logger.info(f"请求托盘:{container},请求位置:{current_location}")
  285. if current_location =="203":
  286. current_location ="in1"
  287. elif current_location=="103":
  288. current_location="in2"
  289. data_return = {}
  290. try:
  291. container_obj = ContainerListModel.objects.filter(container_code=container).first()
  292. if not container_obj:
  293. data_return = {
  294. 'code': '400',
  295. 'message': '托盘编码不存在',
  296. 'data': data
  297. }
  298. return Response(data_return, status=status.HTTP_400_BAD_REQUEST)
  299. # 更新容器数据(部分更新)
  300. serializer = ContainerListPostSerializer(
  301. container_obj,
  302. data=data,
  303. partial=True # 允许部分字段更新
  304. )
  305. serializer.is_valid(raise_exception=True)
  306. serializer.save()
  307. # 检查是否已在目标位置
  308. if current_location == str(container_obj.target_location):
  309. logger.info(f"托盘 {container} 已在目标位置")
  310. data_return = {
  311. 'code': '200',
  312. 'message': '当前位置已是目标位置',
  313. 'data': data
  314. }
  315. allocator = LocationAllocation() # 创建实例
  316. location_row = int(container_obj.target_location.split('-')[1])
  317. location_col = int(container_obj.target_location.split('-')[2])
  318. location_layer = int(container_obj.target_location.split('-')[3])
  319. coordinate = f"{location_row}-{location_col}-{location_layer}"
  320. print(f"坐标:{coordinate}")
  321. location_code = LocationModel.objects.filter(coordinate=coordinate).first().location_code
  322. container_code = container
  323. update_location_status = allocator.update_location_status(location_code, 'occupied') # 更新库位状态
  324. if not update_location_status:
  325. print("❌ 库位状态更新失败,请检查托盘编码")
  326. return
  327. print(f"[6]WCS到位,库位状态更新成功!")
  328. update_location_container_link = allocator.update_location_container_link(location_code, container_code) # 更新库位和托盘的关联关系
  329. if not update_location_container_link:
  330. print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
  331. return
  332. print(f"[7]库位和托盘的关联关系更新成功!")
  333. else:
  334. current_task = ContainerWCSModel.objects.filter(
  335. container=container,
  336. tasktype='inbound'
  337. ).first()
  338. if current_task:
  339. data_return = {
  340. 'code': '200',
  341. 'message': '任务已存在,重新下发',
  342. 'data': current_task.to_dict()
  343. }
  344. else:
  345. # 库位分配
  346. container_code = container
  347. print(f"开始生成库位,托盘编码:{container_code}")
  348. allocator = LocationAllocation() # 创建实例
  349. location_list_cnumber = allocator.get_location_by_status(container_code, current_location) # 获取库位列表
  350. if not location_list_cnumber:
  351. print("❌ 通用库位获取失败,请检查托盘编码")
  352. return
  353. print(f"[1]库位:{location_list_cnumber}")
  354. update_location_status = allocator.update_location_status(location_list_cnumber.location_code, 'reserved') # 更新库位状态
  355. if not update_location_status:
  356. print("❌ 库位状态更新失败,请检查托盘编码")
  357. return
  358. print(f"[2]发送任务,库位状态更新成功!")
  359. update_location_group_status = allocator.update_location_group_status(location_list_cnumber.location_code) # 更新库位组状态
  360. if not update_location_group_status:
  361. print("❌ 库位组状态更新失败,请检查托盘编码")
  362. return
  363. print(f"[3]库位组状态更新成功!")
  364. update_batch_status = allocator.update_batch_status(container_code, '2') # 更新批次状态
  365. if not update_batch_status:
  366. print("❌ 批次状态更新失败,请检查批次号")
  367. return
  368. print(f"[4]批次状态更新成功!")
  369. update_location_group_batch = allocator.update_location_group_batch(location_list_cnumber, container_code) # 更新库位组的批次
  370. if not update_location_group_batch:
  371. print("❌ 库位组批次更新失败,请检查托盘编码")
  372. return
  373. print(f"[5]库位组批次更新成功!")
  374. update_location_container_link = allocator.update_location_container_link(location_list_cnumber.location_code, container_code) # 更新库位和托盘的关联关系
  375. if not update_location_container_link:
  376. print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
  377. return
  378. print(f"[7]库位和托盘的关联关系更新成功!")
  379. # update_location_status = allocator.update_location_status(location_list_cnumber.location_code, 'occupied') # 更新库位状态
  380. # if not update_location_status:
  381. # print("❌ 库位状态更新失败,请检查托盘编码")
  382. # return
  383. # print(f"[6]WCS到位,库位状态更新成功!")
  384. # update_location_container_link = allocator.update_location_container_link(location_list_cnumber.location_code, container_code) # 更新库位和托盘的关联关系
  385. # if not update_location_container_link:
  386. # print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
  387. # return
  388. # print(f"[7]库位和托盘的关联关系更新成功!")
  389. allocation_target_location = (
  390. location_list_cnumber.warehouse_code + '-'
  391. + f"{int(location_list_cnumber.row):02d}" + '-' # 关键修改点
  392. + f"{int(location_list_cnumber.col):02d}" + '-'
  393. + f"{int(location_list_cnumber.layer):02d}"
  394. )
  395. self.generate_task(container, current_location, allocation_target_location) # 生成任务
  396. current_task = ContainerWCSModel.objects.get(
  397. container=container,
  398. tasktype='inbound'
  399. )
  400. data_return = {
  401. 'code': '200',
  402. 'message': '任务下发成功',
  403. 'data': current_task.to_dict()
  404. }
  405. container_obj.target_location = allocation_target_location
  406. container_obj.save()
  407. self.inport_update_task(current_task.id, container_obj.id)
  408. http_status = status.HTTP_200_OK if data_return['code'] == '200' else status.HTTP_400_BAD_REQUEST
  409. return Response(data_return, status=http_status)
  410. except Exception as e:
  411. logger.error(f"处理请求时发生错误: {str(e)}", exc_info=True)
  412. return Response(
  413. {'code': '500', 'message': '服务器内部错误', 'data': None},
  414. status=status.HTTP_500_INTERNAL_SERVER_ERROR
  415. )
  416. @transaction.atomic
  417. def inport_update_task(self, wcs_id,container_id):
  418. try:
  419. task_obj = ContainerWCSModel.objects.filter(id=wcs_id).first()
  420. if task_obj:
  421. container_detail_obj = ContainerDetailModel.objects.filter(container=container_id).all()
  422. if container_detail_obj:
  423. for detail in container_detail_obj:
  424. # 保存到数据库
  425. batch = BoundDetailModel.objects.filter(bound_batch_id=detail.batch.id).first()
  426. TaskModel.objects.create(
  427. task_wcs = task_obj,
  428. container_detail = detail,
  429. batch_detail = batch
  430. )
  431. logger.info(f"入库任务 {wcs_id} 已更新")
  432. else:
  433. logger.info(f"入库任务 {container_id} 批次不存在")
  434. else:
  435. logger.info(f"入库任务 {wcs_id} 不存在")
  436. except Exception as e:
  437. logger.error(f"处理入库任务时发生错误: {str(e)}", exc_info=True)
  438. return Response(
  439. {'code': '500', 'message': '服务器内部错误', 'data': None},
  440. status=status.HTTP_500_INTERNAL_SERVER_ERROR
  441. )
  442. # PDA组盘入库 将扫描到的托盘编码和批次信息保存到数据库
  443. # 1. 先查询托盘对象,如果不存在,则创建托盘对象
  444. # 2. 循环处理每个批次,查询批次对象,
  445. # 3. 更新批次数据(根据业务规则)
  446. # 4. 保存到数据库
  447. # 5. 保存操作记录到数据库
  448. class ContainerDetailViewSet(viewsets.ModelViewSet):
  449. """
  450. retrieve:
  451. Response a data list(get)
  452. list:
  453. Response a data list(all)
  454. create:
  455. Create a data line(post)
  456. delete:
  457. Delete a data line(delete)
  458. """
  459. # authentication_classes = [] # 禁用所有认证类
  460. # permission_classes = [AllowAny] # 允许任意访问
  461. pagination_class = MyPageNumberPagination
  462. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  463. ordering_fields = ['id', "create_time", "update_time", ]
  464. filter_class = ContainerDetailFilter
  465. def get_project(self):
  466. try:
  467. id = self.kwargs.get('pk')
  468. return id
  469. except:
  470. return None
  471. def get_queryset(self):
  472. id = self.get_project()
  473. if self.request.user:
  474. if id is None:
  475. return ContainerDetailModel.objects.filter( is_delete=False)
  476. else:
  477. return ContainerDetailModel.objects.filter( id=id, is_delete=False)
  478. else:
  479. return ContainerDetailModel.objects.none()
  480. def get_serializer_class(self):
  481. if self.action in ['list', 'destroy','retrieve']:
  482. return ContainerDetailGetSerializer
  483. elif self.action in ['create', 'update']:
  484. return ContainerDetailPostSerializer
  485. else:
  486. return self.http_method_not_allowed(request=self.request)
  487. def create(self, request, *args, **kwargs):
  488. data = self.request.data
  489. order_month = str(timezone.now().strftime('%Y%m'))
  490. data['month'] = order_month
  491. container_code = data.get('container')
  492. batches = data.get('batches', []) # 确保有默认空列表
  493. print('扫描到的托盘编码', container_code)
  494. # 处理托盘对象
  495. container_obj = ContainerListModel.objects.filter(container_code=container_code).first()
  496. if container_obj:
  497. data['container'] = container_obj.id
  498. logger.info(f"托盘 {container_code} 已存在")
  499. else:
  500. logger.info(f"托盘 {container_code} 不存在,创建托盘对象")
  501. serializer_list = ContainerListPostSerializer(data={'container_code': container_code})
  502. serializer_list.is_valid(raise_exception=True)
  503. serializer_list.save()
  504. data['container'] = serializer_list.data.get('id')
  505. # 循环处理每个批次
  506. for batch in batches:
  507. bound_number = batch.get('goods_code')
  508. goods_qty = batch.get('goods_qty')
  509. # 查询商品对象
  510. bound_obj = BoundBatchModel.objects.filter(bound_number=bound_number).first()
  511. if not bound_obj:
  512. # 如果商品不存在,返回错误,这里暂时在程序中进行提醒,后续需要改为前端弹窗提醒
  513. logger.error(f"批次 {bound_number} 不存在")
  514. # 跳出此次循环
  515. continue
  516. # return Response({"error": f"商品编码 {bound_number} 不存在"}, status=400)
  517. # 3. 更新批次数据(根据业务规则)
  518. try:
  519. last_qty = bound_obj.goods_in_qty
  520. bound_obj.goods_in_qty += batch.get("goods_qty", 0)
  521. if bound_obj.goods_in_qty >= bound_obj.goods_qty:
  522. bound_obj.goods_in_qty = bound_obj.goods_qty
  523. bound_obj.status = 1 # 批次状态为组盘完成
  524. print('批次id',bound_obj.id)
  525. bound_detail_obj = BoundDetailModel.objects.filter(bound_batch=bound_obj.id).first()
  526. if bound_detail_obj:
  527. bound_detail_obj.status = 1
  528. bound_detail_obj.save()
  529. print('入库申请id',bound_detail_obj.bound_list_id)
  530. # 入库申请全部批次入库完成
  531. bound_batch_all = BoundDetailModel.objects.filter(bound_list=bound_detail_obj.bound_list_id).all()
  532. if bound_batch_all.count() == bound_batch_all.filter(status=1).count():
  533. bound_list_obj = BoundListModel.objects.filter(id=bound_detail_obj.bound_list_id).first()
  534. print('当前状态',bound_list_obj.bound_status)
  535. bound_list_obj.bound_status = 102
  536. print('更新状态',bound_list_obj.bound_status)
  537. bound_list_obj.save()
  538. print('入库申请全部批次组盘完成')
  539. else:
  540. print('入库申请部分批次组盘完成')
  541. else:
  542. bound_obj.status = 0
  543. bound_obj.save() # 保存到数据库
  544. # 创建托盘详情记录(每个批次独立)
  545. print('新增个数',bound_obj.goods_in_qty-last_qty)
  546. if bound_obj.goods_in_qty-last_qty == goods_qty:
  547. detail_data = {
  548. "container": data['container'], # 托盘ID
  549. "batch": bound_obj.id, # 外键关联批次
  550. "goods_code": bound_obj.goods_code,
  551. "goods_desc": bound_obj.goods_desc,
  552. "goods_qty": goods_qty,
  553. "goods_weight": bound_obj.goods_weight,
  554. "status": 1,
  555. "month": data['month'],
  556. "creater": data.get('creater', 'zl') # 默认值兜底
  557. }
  558. serializer = self.get_serializer(data=detail_data)
  559. serializer.is_valid(raise_exception=True)
  560. serializer.save() # 必须保存到数据库
  561. operate_data = {
  562. "month" : data['month'],
  563. "container": data['container'], # 托盘ID
  564. "operation_type" : 'container',
  565. "batch" : bound_obj.id, # 外键关联批次
  566. "goods_code": bound_obj.goods_code,
  567. "goods_desc": bound_obj.goods_desc,
  568. "goods_qty": goods_qty,
  569. "goods_weight": bound_obj.goods_weight,
  570. "operator": data.get('creater', 'zl'), # 默认值兜底
  571. "timestamp": timezone.now(),
  572. "from_location": "container",
  573. "to_location": "container",
  574. "memo": "入库PDA组盘,pda入库"+str(bound_obj.goods_code)+"数量"+str(goods_qty)
  575. }
  576. serializer_operate = ContainerOperationPostSerializer(data=operate_data)
  577. serializer_operate.is_valid(raise_exception=True)
  578. serializer_operate.save() # 必须保存到数据库
  579. elif bound_obj.goods_in_qty-last_qty > 0:
  580. print('批次数量不一致')
  581. detail_data = {
  582. "container": data['container'], # 托盘ID
  583. "batch": bound_obj.id, # 外键关联批次
  584. "goods_code": bound_obj.goods_code,
  585. "goods_desc": bound_obj.goods_desc,
  586. "goods_qty": bound_obj.goods_in_qty-last_qty,
  587. "goods_weight": bound_obj.goods_weight,
  588. "status": 1,
  589. "month": data['month'],
  590. "creater": data.get('creater', 'zl') # 默认值兜底
  591. }
  592. serializer = self.get_serializer(data=detail_data)
  593. serializer.is_valid(raise_exception=True)
  594. serializer.save() # 必须保存到数据库
  595. operate_data = {
  596. "month" : data['month'],
  597. "container": data['container'], # 托盘ID
  598. "operation_type" : 'container',
  599. "batch" : bound_obj.id, # 外键关联批次
  600. "goods_code": bound_obj.goods_code,
  601. "goods_desc": bound_obj.goods_desc,
  602. "goods_qty": bound_obj.goods_in_qty-last_qty,
  603. "goods_weight": bound_obj.goods_weight,
  604. "operator": data.get('creater', 'zl'), # 默认值兜底
  605. "timestamp": timezone.now(),
  606. "from_location": "container",
  607. "to_location": "container",
  608. "memo": "入库PDA组盘,(数量不一致)pda入库"+str(bound_obj.goods_code)+"数量"+str(goods_qty)
  609. }
  610. serializer_operate = ContainerOperationPostSerializer(data=operate_data)
  611. serializer_operate.is_valid(raise_exception=True)
  612. serializer_operate.save() # 必须保存到数据库
  613. else :
  614. print('重复组盘')
  615. except Exception as e:
  616. print(f"更新批次 {bound_number} 失败: {str(e)}")
  617. continue
  618. # 将处理后的数据返回(或根据业务需求保存到数据库)
  619. res_data={
  620. "code": "200",
  621. "msg": "Success Create",
  622. "data": data
  623. }
  624. return Response(res_data, status=200)
  625. def update(self, request, pk):
  626. qs = self.get_object()
  627. data = self.request.data
  628. serializer = self.get_serializer(qs, data=data)
  629. serializer.is_valid(raise_exception=True)
  630. serializer.save()
  631. headers = self.get_success_headers(serializer.data)
  632. return Response(serializer.data, status=200, headers=headers)
  633. class ContainerOperateViewSet(viewsets.ModelViewSet):
  634. """
  635. retrieve:
  636. Response a data list(get)
  637. list:
  638. Response a data list(all)
  639. create:
  640. Create a data line(post)
  641. delete:
  642. Delete a data line(delete)
  643. """
  644. # authentication_classes = [] # 禁用所有认证类
  645. # permission_classes = [AllowAny] # 允许任意访问
  646. pagination_class = MyPageNumberPagination
  647. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  648. ordering_fields = ['id', "timestamp" ]
  649. filter_class = ContainerOperationFilter
  650. def get_project(self):
  651. try:
  652. id = self.kwargs.get('pk')
  653. return id
  654. except:
  655. return None
  656. def get_queryset(self):
  657. id = self.get_project()
  658. if self.request.user:
  659. if id is None:
  660. return ContainerOperationModel.objects.filter( is_delete=False)
  661. else:
  662. return ContainerOperationModel.objects.filter( id=id, is_delete=False)
  663. else:
  664. return ContainerOperationModel.objects.none()
  665. def get_serializer_class(self):
  666. if self.action in ['list', 'destroy','retrieve']:
  667. return ContainerOperationGetSerializer
  668. elif self.action in ['create', 'update']:
  669. return ContainerOperationPostSerializer
  670. else:
  671. return self.http_method_not_allowed(request=self.request)
  672. def create(self, request, *args, **kwargs):
  673. data = self.request.data
  674. serializer = self.get_serializer(data=data)
  675. serializer.is_valid(raise_exception=True)
  676. serializer.save()
  677. headers = self.get_success_headers(serializer.data)
  678. return Response(serializer.data, status=200, headers=headers)
  679. def update(self, request, pk):
  680. qs = self.get_object()
  681. data = self.request.data
  682. serializer = self.get_serializer(qs, data=data)
  683. serializer.is_valid(raise_exception=True)
  684. serializer.save()
  685. headers = self.get_success_headers(serializer.data)
  686. return Response(serializer.data, status=200, headers=headers)