views.py 33 KB

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