views.py 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. from rest_framework import viewsets
  2. from utils.page import MyPageNumberPagination
  3. from utils.md5 import Md5
  4. from rest_framework.filters import OrderingFilter
  5. from django_filters.rest_framework import DjangoFilterBackend
  6. from rest_framework.response import Response
  7. from rest_framework.exceptions import APIException
  8. from django.http import StreamingHttpResponse
  9. from rest_framework.settings import api_settings
  10. from django.db import transaction
  11. from rest_framework import status
  12. from reportcenter.models import flowModel as flowlist
  13. from .models import bigScreenModel
  14. from bound.models import BoundBatchModel
  15. from . import serializers
  16. from .filter import FlowFilter, MaterialChangeHistoryFilter, batchLogFilter, ContainerDetailLogFilter,bigScreenFilter,batchfilter
  17. from .files import FileFlowListRenderCN, MaterialChangeHistoryRenderCN, batchLogRenderCN, ContainerDetailLogRenderCN,FileBatchListRenderCN
  18. from container.models import MaterialChangeHistory,batchLogModel,ContainerDetailLogModel
  19. """
  20. path(r'MaterialChangeHistory/', views.MaterialChangeHistoryViewSet.as_view({"get": "list", }), name="management"),
  21. path(r'MaterialChangeHistory/file/', views.MaterialChangeHistoryDownloadView.as_view({"get": "list"}), name="flowfile"),
  22. path(r'batchLog/', views.batchLogViewSet.as_view({"get": "list", }), name="management"),
  23. path(r'batchLog/file/', views.batchLogDownloadView.as_view({"get": "list"}), name="flowfile"),
  24. path(r'ContainerDetailLog/', views.ContainerDetailLogViewSet.as_view({"get": "list", }), name="management"),
  25. path(r'ContainerDetailLog/file/', views.ContainerDetailLogDownloadView.as_view({"get": "list"}), name="flowfile"),
  26. """
  27. from django.utils import timezone
  28. from datetime import datetime, timedelta
  29. from rest_framework.decorators import action
  30. from rest_framework.response import Response
  31. from django.db.models import Q, Max, Min
  32. from decimal import Decimal
  33. from django.db.models import Sum
  34. from django.db.models import OuterRef, Subquery
  35. from operation_log.views import log_success_operation, log_failure_operation
  36. def format_decimal(value):
  37. """格式化Decimal值为字符串,避免科学计数法"""
  38. if isinstance(value, Decimal):
  39. # 格式化为字符串,保留小数点后6位,但去除尾部多余的0
  40. return format(value.normalize(), 'f')
  41. return str(value)
  42. class MaterialChangeHistoryViewSet(viewsets.ModelViewSet):
  43. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  44. ordering_fields = ['id', "change_time", "create_time", "update_time", ]
  45. filter_class = MaterialChangeHistoryFilter
  46. pagination_class = MyPageNumberPagination
  47. def get_queryset(self):
  48. return MaterialChangeHistory.objects.all()
  49. def get_serializer_class(self):
  50. if self.action in ['list', 'create']:
  51. return serializers.MaterialChangeHistorySerializer
  52. else:
  53. return self.http_method_not_allowed(request=self.request)
  54. def summary_complex(self, request):
  55. """
  56. 获取物料库存变动汇总数据(支持分页)
  57. 请求参数路由上提供:
  58. - start_time: 开始时间(可选)
  59. - end_time: 结束时间(可选)
  60. - material_ids: 物料ID列表(可选)
  61. - page: 页码(可选)
  62. - page_size: 每页数量(可选)
  63. """
  64. # 获取请求参数 "POST /reportcenter/MaterialChangeHistory/?page=1&page_size=11&goods_code__icontains=UZ
  65. start_time = request.query_params.get('start_time') if request.query_params.get('start_time') else None
  66. end_time = request.quary_params.get('end_time') if request.query_params.get('end_time') else None
  67. material_ids_code = request.query_params.get('goods_code__icontains') if request.query_params.get('goods_code__icontains') else None
  68. # 记录查询时间范围
  69. query_time_range = {}
  70. # 如果没有提供时间段,使用当前月份
  71. if not start_time or not end_time:
  72. today = timezone.now().date()
  73. start_time = datetime(today.year, today.month, 1)
  74. end_time = start_time + timedelta(days=32)
  75. end_time = datetime(end_time.year, end_time.month, 1) - timedelta(days=1)
  76. end_time = datetime.combine(end_time, datetime.max.time())
  77. query_time_range['default_time_range'] = True
  78. else:
  79. query_time_range['default_time_range'] = False
  80. # 转换为datetime对象
  81. if isinstance(start_time, str):
  82. start_time = datetime.fromisoformat(start_time)
  83. if isinstance(end_time, str):
  84. end_time = datetime.fromisoformat(end_time)
  85. # 存储查询时间范围用于返回
  86. query_time_range['start_time'] = start_time.isoformat()
  87. query_time_range['end_time'] = end_time.isoformat()
  88. # 创建基础查询集
  89. queryset = MaterialChangeHistory.objects.filter(
  90. change_time__gte=start_time,
  91. change_time__lte=end_time
  92. )
  93. # 如果有物料ID过滤
  94. if material_ids_code:
  95. queryset = queryset.filter(goods_code__icontains=material_ids_code)
  96. print(f"过滤物料编码包含: {material_ids_code},剩余条目数: {queryset.count()}")
  97. # 获取期初数量(时间段开始时的库存)
  98. opening_subquery = MaterialChangeHistory.objects.filter(
  99. goods_code=OuterRef('goods_code'),
  100. change_time__lt=start_time
  101. ).order_by('-change_time').values('closing_quantity')[:1]
  102. opening_data = MaterialChangeHistory.objects.filter(
  103. change_time__lt=start_time
  104. )
  105. if material_ids_code:
  106. opening_data = opening_data.filter(goods_code__icontains=material_ids_code)
  107. opening_data = opening_data.values('goods_code').annotate(
  108. opening_quantity=Subquery(opening_subquery)
  109. )
  110. # 获取期末数量(时间段结束时的库存)
  111. closing_subquery = MaterialChangeHistory.objects.filter(
  112. goods_code=OuterRef('goods_code'),
  113. change_time__lte=end_time
  114. ).order_by('-change_time').values('closing_quantity')[:1]
  115. closing_data = MaterialChangeHistory.objects.filter(
  116. change_time__lte=end_time
  117. )
  118. if material_ids_code:
  119. closing_data = closing_data.filter(goods_code__icontains=material_ids_code)
  120. closing_data = closing_data.values('goods_code').annotate(
  121. closing_quantity=Subquery(closing_subquery)
  122. )
  123. # 计算期间出入库总量
  124. period_data = queryset.values('goods_code').annotate(
  125. total_in=Sum('in_quantity'),
  126. total_out=Sum('out_quantity')
  127. )
  128. # 构建结果字典
  129. result = {}
  130. for item in opening_data:
  131. material_code = item['goods_code']
  132. goods=MaterialChangeHistory.objects.filter(goods_code=material_code).first()
  133. result.setdefault(material_code, {
  134. 'material_code': material_code,
  135. 'goods_code': goods.goods_code if goods else 'N/A',
  136. 'goods_desc': goods.goods_desc if goods else 'N/A',
  137. 'goods_unit': goods.goods_unit if goods else 'N/A',
  138. 'opening_quantity': item['opening_quantity'] or Decimal('0'),
  139. 'closing_quantity': Decimal('0'),
  140. 'total_in': Decimal('0'),
  141. 'total_out': Decimal('0'),
  142. 'net_change': Decimal('0'), # 新增:净含量变化
  143. 'theoretical_change': Decimal('0'), # 新增:理论变化量
  144. 'is_consistent': True # 新增:一致性校验
  145. })
  146. for item in closing_data:
  147. material_code = item['goods_code']
  148. goods=MaterialChangeHistory.objects.filter(goods_code=material_code).first()
  149. if material_code in result:
  150. result[material_code]['closing_quantity'] = item['closing_quantity'] or Decimal('0')
  151. else:
  152. result[material_code] = {
  153. 'material_code': material_code,
  154. 'goods_code': goods.goods_code if goods else 'N/A',
  155. 'goods_desc': goods.goods_desc if goods else 'N/A',
  156. 'goods_unit': goods.goods_unit if goods else 'N/A',
  157. 'opening_quantity': Decimal('0'),
  158. 'closing_quantity': item['closing_quantity'] or Decimal('0'),
  159. 'total_in': Decimal('0'),
  160. 'total_out': Decimal('0'),
  161. 'net_change': Decimal('0'),
  162. 'theoretical_change': Decimal('0'),
  163. 'is_consistent': True
  164. }
  165. for item in period_data:
  166. material_code = item['goods_code']
  167. goods=MaterialChangeHistory.objects.filter(goods_code=material_code).first()
  168. if material_code in result:
  169. result[material_code]['total_in'] = item['total_in'] or Decimal('0')
  170. result[material_code]['total_out'] = item['total_out'] or Decimal('0')
  171. else:
  172. result[material_code] = {
  173. 'material_code': material_code,
  174. 'goods_code': goods.goods_code if goods else 'N/A',
  175. 'goods_desc': goods.goods_desc if goods else 'N/A',
  176. 'goods_unit': goods.goods_unit if goods else 'N/A',
  177. 'opening_quantity': Decimal('0'),
  178. 'closing_quantity': Decimal('0'),
  179. 'total_in': item['total_in'] or Decimal('0'),
  180. 'total_out': item['total_out'] or Decimal('0'),
  181. 'net_change': Decimal('0'),
  182. 'theoretical_change': Decimal('0'),
  183. 'is_consistent': True
  184. }
  185. # 计算净含量变化和理论变化量,并进行一致性校验
  186. for material_code, data in result.items():
  187. # 计算净含量变化(期末 - 期初)
  188. net_change = data['closing_quantity'] - data['opening_quantity']
  189. data['net_change'] = net_change
  190. # 计算理论变化量(入库 - 出库)
  191. theoretical_change = data['total_in'] - data['total_out']
  192. data['theoretical_change'] = theoretical_change
  193. # 检查是否一致(允许小数点后3位的差异)
  194. tolerance = Decimal('0.001')
  195. is_consistent = abs(net_change - theoretical_change) <= tolerance
  196. data['is_consistent'] = is_consistent
  197. # 转换为列表格式
  198. result_list = list(result.values())
  199. # 应用分页
  200. paginator = MyPageNumberPagination()
  201. page = paginator.paginate_queryset(result_list, request)
  202. # 构建响应数据
  203. response_data = {
  204. 'query_time_range': query_time_range,
  205. 'count': len(result_list),
  206. 'next': paginator.get_next_link(),
  207. 'previous': paginator.get_previous_link(),
  208. 'results': page
  209. }
  210. return Response(response_data)
  211. def export_summary(self, request):
  212. """
  213. 导出物料库存变动汇总数据为CSV
  214. """
  215. # 重用summary方法获取数据
  216. start_time = request.query_params.get('start_time') or None
  217. end_time = request.query_params.get('end_time') or None
  218. material_ids_code = request.query_params.get('goods_code__icontains') or None
  219. response = self.summary_all( start_time=start_time, end_time=end_time, material_ids_code=material_ids_code)
  220. data = response.data
  221. query_time_range = data['query_time_range']
  222. # 创建CSV响应
  223. from django.http import HttpResponse
  224. import csv
  225. response = HttpResponse(content_type='text/csv')
  226. response['Content-Disposition'] = 'attachment; filename="material_change_summary.csv"'
  227. try:
  228. log_success_operation(
  229. request=request,
  230. operation_content="下载物料库存变动汇总文件",
  231. operation_level="download",
  232. operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
  233. module_name="报表中心"
  234. )
  235. except Exception as e:
  236. pass
  237. # 创建CSV写入器
  238. csv_writer = csv.writer(response)
  239. # 写入表头
  240. headers = [
  241. '开始时间','结束时间',
  242. '存货编码', '存货名称', '计量单位',
  243. '期初数量', '期末数量', '期间变化',
  244. '入库数量', '出库数量', '出入库差异',
  245. '对比结果'
  246. ]
  247. csv_writer.writerow(headers)
  248. # 写入数据行
  249. for item in data['results']:
  250. # 处理对比结果的显示
  251. is_consistent = "一致" if item['is_consistent'] else "不一致"
  252. row = [
  253. query_time_range.get('start_time', ''),
  254. query_time_range.get('end_time', ''),
  255. item['goods_code'],
  256. item['goods_desc'],
  257. item['goods_unit'],
  258. # 数量字段格式化为字符串,避免科学计数法
  259. format_decimal(item['opening_quantity']),
  260. format_decimal(item['closing_quantity']),
  261. format_decimal(item['net_change']),
  262. format_decimal(item['total_in']),
  263. format_decimal(item['total_out']),
  264. format_decimal(item['theoretical_change']),
  265. is_consistent
  266. ]
  267. csv_writer.writerow(row)
  268. return response
  269. def summary_all(self, start_time=None, end_time=None, material_ids_code=None):
  270. """
  271. 获取物料库存变动汇总数据(支持分页)
  272. """
  273. # 获取请求参数
  274. # 记录查询时间范围
  275. query_time_range = {}
  276. # 如果没有提供时间段,使用当前月份
  277. if not start_time or not end_time:
  278. today = timezone.now().date()
  279. start_time = datetime(today.year, today.month, 1)
  280. end_time = start_time + timedelta(days=32)
  281. end_time = datetime(end_time.year, end_time.month, 1) - timedelta(days=1)
  282. end_time = datetime.combine(end_time, datetime.max.time())
  283. query_time_range['default_time_range'] = True
  284. else:
  285. query_time_range['default_time_range'] = False
  286. # 转换为datetime对象
  287. if isinstance(start_time, str):
  288. start_time = datetime.fromisoformat(start_time)
  289. if isinstance(end_time, str):
  290. end_time = datetime.fromisoformat(end_time)
  291. # 存储查询时间范围用于返回
  292. query_time_range['start_time'] = start_time.isoformat()
  293. query_time_range['end_time'] = end_time.isoformat()
  294. # 创建基础查询集
  295. queryset = MaterialChangeHistory.objects.filter(
  296. change_time__gte=start_time,
  297. change_time__lte=end_time
  298. )
  299. # 如果有物料ID过滤
  300. if material_ids_code:
  301. queryset = queryset.filter(goods_code__icontains=material_ids_code)
  302. # 获取每个物料的期初和期末数量(直接从过滤集中获取)
  303. material_codes = queryset.values_list('goods_code', flat=True).distinct()
  304. opening_closing_data = {}
  305. for code in material_codes:
  306. # 获取该物料在时间段内的第一条记录(最早记录)
  307. first_record = queryset.filter(goods_code=code).order_by('change_time').first()
  308. # 获取该物料在时间段内的最后一条记录(最晚记录)
  309. last_record = queryset.filter(goods_code=code).order_by('-change_time').first()
  310. # 期初数量 = 第一条记录的期初数量
  311. # 期末数量 = 最后一条记录的期末数量
  312. opening_closing_data[code] = {
  313. 'opening_quantity': first_record.opening_quantity,
  314. 'closing_quantity': last_record.closing_quantity
  315. }
  316. # 计算期间出入库总量
  317. period_data = queryset.values('goods_code').annotate(
  318. total_in=Sum('in_quantity'),
  319. total_out=Sum('out_quantity')
  320. )
  321. # 构建结果字典
  322. result = {}
  323. for item in period_data:
  324. material_code = item['goods_code']
  325. goods = MaterialChangeHistory.objects.filter(goods_code=material_code).first()
  326. # 获取该物料的期初和期末数量
  327. oc_data = opening_closing_data.get(material_code, {
  328. 'opening_quantity': Decimal('0'),
  329. 'closing_quantity': Decimal('0')
  330. })
  331. result[material_code] = {
  332. 'material_code': material_code,
  333. 'goods_code': goods.goods_code if goods else 'N/A',
  334. 'goods_desc': goods.goods_desc if goods else 'N/A',
  335. 'goods_unit': goods.goods_unit if goods else 'N/A',
  336. 'opening_quantity': oc_data['opening_quantity'],
  337. 'closing_quantity': oc_data['closing_quantity'],
  338. 'total_in': item['total_in'] or Decimal('0'),
  339. 'total_out': item['total_out'] or Decimal('0'),
  340. 'net_change': Decimal('0'), # 后面计算
  341. 'theoretical_change': Decimal('0'), # 后面计算
  342. 'is_consistent': True
  343. }
  344. # 计算净含量变化和理论变化量,并进行一致性校验
  345. for material_code, data in result.items():
  346. # 净含量变化 = 期末 - 期初
  347. net_change = data['closing_quantity'] - data['opening_quantity']
  348. data['net_change'] = net_change
  349. # 理论变化量 = 入库 - 出库
  350. theoretical_change = data['total_in'] - data['total_out']
  351. data['theoretical_change'] = theoretical_change
  352. # 检查是否一致(允许小数点后3位的差异)
  353. tolerance = Decimal('0.001')
  354. data['is_consistent'] = abs(net_change - theoretical_change) <= tolerance
  355. # 转换为列表格式
  356. result_list = list(result.values())
  357. # 应用分页
  358. response_data = {
  359. 'query_time_range': query_time_range,
  360. 'count': len(result_list),
  361. 'results': result_list # 返回所有结果,不分页
  362. }
  363. return Response(response_data)
  364. def summary(self, request):
  365. """
  366. 获取物料库存变动汇总数据(支持分页)
  367. """
  368. # 获取请求参数
  369. start_time = request.query_params.get('start_time') or None
  370. end_time = request.query_params.get('end_time') or None
  371. material_ids_code = request.query_params.get('goods_code__icontains') or None
  372. # 记录查询时间范围
  373. query_time_range = {}
  374. # 如果没有提供时间段,使用当前月份
  375. if not start_time or not end_time:
  376. today = timezone.now().date()
  377. start_time = datetime(today.year, today.month, 1)
  378. end_time = start_time + timedelta(days=32)
  379. end_time = datetime(end_time.year, end_time.month, 1) - timedelta(days=1)
  380. end_time = datetime.combine(end_time, datetime.max.time())
  381. query_time_range['default_time_range'] = True
  382. else:
  383. query_time_range['default_time_range'] = False
  384. # 转换为datetime对象
  385. if isinstance(start_time, str):
  386. start_time = datetime.fromisoformat(start_time)
  387. if isinstance(end_time, str):
  388. end_time = datetime.fromisoformat(end_time)
  389. # 存储查询时间范围用于返回
  390. query_time_range['start_time'] = start_time.isoformat()
  391. query_time_range['end_time'] = end_time.isoformat()
  392. # 创建基础查询集
  393. queryset = MaterialChangeHistory.objects.filter(
  394. change_time__gte=start_time,
  395. change_time__lte=end_time
  396. )
  397. # 如果有物料ID过滤
  398. if material_ids_code:
  399. queryset = queryset.filter(goods_code__icontains=material_ids_code)
  400. # 获取每个物料的期初和期末数量(直接从过滤集中获取)
  401. material_codes = queryset.values_list('goods_code', flat=True).distinct()
  402. opening_closing_data = {}
  403. for code in material_codes:
  404. # 获取该物料在时间段内的第一条记录(最早记录)
  405. first_record = queryset.filter(goods_code=code).order_by('change_time').first()
  406. # 获取该物料在时间段内的最后一条记录(最晚记录)
  407. last_record = queryset.filter(goods_code=code).order_by('-change_time').first()
  408. # 期初数量 = 第一条记录的期初数量
  409. # 期末数量 = 最后一条记录的期末数量
  410. opening_closing_data[code] = {
  411. 'opening_quantity': first_record.opening_quantity,
  412. 'closing_quantity': last_record.closing_quantity
  413. }
  414. # 计算期间出入库总量
  415. period_data = queryset.values('goods_code').annotate(
  416. total_in=Sum('in_quantity'),
  417. total_out=Sum('out_quantity')
  418. )
  419. # 构建结果字典
  420. result = {}
  421. for item in period_data:
  422. material_code = item['goods_code']
  423. goods = MaterialChangeHistory.objects.filter(goods_code=material_code).first()
  424. # 获取该物料的期初和期末数量
  425. oc_data = opening_closing_data.get(material_code, {
  426. 'opening_quantity': Decimal('0'),
  427. 'closing_quantity': Decimal('0')
  428. })
  429. result[material_code] = {
  430. 'material_code': material_code,
  431. 'goods_code': goods.goods_code if goods else 'N/A',
  432. 'goods_desc': goods.goods_desc if goods else 'N/A',
  433. 'goods_unit': goods.goods_unit if goods else 'N/A',
  434. 'opening_quantity': oc_data['opening_quantity'],
  435. 'closing_quantity': oc_data['closing_quantity'],
  436. 'total_in': item['total_in'] or Decimal('0'),
  437. 'total_out': item['total_out'] or Decimal('0'),
  438. 'net_change': Decimal('0'), # 后面计算
  439. 'theoretical_change': Decimal('0'), # 后面计算
  440. 'is_consistent': True
  441. }
  442. # 计算净含量变化和理论变化量,并进行一致性校验
  443. for material_code, data in result.items():
  444. # 净含量变化 = 期末 - 期初
  445. net_change = data['closing_quantity'] - data['opening_quantity']
  446. data['net_change'] = net_change
  447. # 理论变化量 = 入库 - 出库
  448. theoretical_change = data['total_in'] - data['total_out']
  449. data['theoretical_change'] = theoretical_change
  450. # 检查是否一致(允许小数点后3位的差异)
  451. tolerance = Decimal('0.001')
  452. data['is_consistent'] = abs(net_change - theoretical_change) <= tolerance
  453. # 转换为列表格式
  454. result_list = list(result.values())
  455. # 应用分页
  456. paginator = MyPageNumberPagination()
  457. page = paginator.paginate_queryset(result_list, request)
  458. # 构建响应数据
  459. response_data = {
  460. 'query_time_range': query_time_range,
  461. 'count': len(result_list),
  462. 'next': paginator.get_next_link(),
  463. 'previous': paginator.get_previous_link(),
  464. 'results': page
  465. }
  466. return Response(response_data)
  467. class MaterialChangeHistoryDownloadView(viewsets.ModelViewSet):
  468. renderer_classes = (MaterialChangeHistoryRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
  469. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  470. ordering_fields = ['id', "change_time", "create_time", "update_time", ]
  471. filter_class = MaterialChangeHistoryFilter
  472. def get_project(self):
  473. try:
  474. id = self.kwargs.get('pk')
  475. return id
  476. except:
  477. return None
  478. def get_queryset(self):
  479. id = self.get_project()
  480. if self.request.user:
  481. if id is None:
  482. return MaterialChangeHistory.objects.filter()
  483. else:
  484. return MaterialChangeHistory.objects.filter(id=id)
  485. else:
  486. return MaterialChangeHistory.objects.none()
  487. def get_serializer_class(self):
  488. if self.action in ['list']:
  489. return serializers.MaterialChangeHistorySerializer
  490. else:
  491. return self.http_method_not_allowed(request=self.request)
  492. def get_render(self, data):
  493. # lang = self.request.META.get('HTTP_LANGUAGE')
  494. # if lang:
  495. # if lang == 'zh-hans':
  496. # return FileListRenderCN().render(data)
  497. # else:
  498. # return FileListRenderEN().render(data)
  499. # else:
  500. # return FileListRenderEN().render(data)
  501. return MaterialChangeHistoryRenderCN().render(data)
  502. def list(self, request, *args, **kwargs):
  503. from datetime import datetime
  504. dt = datetime.now()
  505. data = (
  506. serializers.MaterialChangeHistorySerializer(instance).data
  507. for instance in self.filter_queryset(self.get_queryset())
  508. )
  509. renderer = self.get_render(data)
  510. response = StreamingHttpResponse(
  511. renderer,
  512. content_type="text/csv"
  513. )
  514. response['Content-Disposition'] = "attachment; filename='MaterialChangeHistory_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
  515. try:
  516. log_success_operation(
  517. request=request,
  518. operation_content="下载物料变动历史文件",
  519. operation_level="download",
  520. operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
  521. module_name="报表中心"
  522. )
  523. except Exception as e:
  524. pass
  525. return response
  526. class batchLogViewSet(viewsets.ModelViewSet):
  527. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  528. ordering_fields = ['id', "create_time", "update_time", ]
  529. filter_class = batchLogFilter
  530. pagination_class = MyPageNumberPagination
  531. def get_queryset(self):
  532. return batchLogModel.objects.all()
  533. def get_serializer_class(self):
  534. if self.action in ['list', 'create']:
  535. return serializers.batchLogSerializer
  536. else:
  537. return self.http_method_not_allowed(request=self.request)
  538. class batchLogDownloadView(viewsets.ModelViewSet):
  539. renderer_classes = (batchLogRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
  540. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  541. ordering_fields = ['id', "create_time", "update_time", ]
  542. filter_class = batchLogFilter
  543. def get_project(self):
  544. try:
  545. id = self.kwargs.get('pk')
  546. return id
  547. except:
  548. return None
  549. def get_queryset(self):
  550. id = self.get_project()
  551. if self.request.user:
  552. if id is None:
  553. return batchLogModel.objects.filter()
  554. else:
  555. return batchLogModel.objects.filter(id=id)
  556. else:
  557. return batchLogModel.objects.none()
  558. def get_serializer_class(self):
  559. if self.action in ['list']:
  560. return serializers.batchLogSerializer
  561. else:
  562. return self.http_method_not_allowed(request=self.request)
  563. def get_render(self, data):
  564. # lang = self.request.META.get('HTTP_LANGUAGE')
  565. # if lang:
  566. # if lang == 'zh-hans':
  567. # return FileListRenderCN().render(data)
  568. # else:
  569. # return FileListRenderEN().render(data)
  570. # else:
  571. # return FileListRenderEN().render(data)
  572. return batchLogRenderCN().render(data)
  573. def list(self, request, *args, **kwargs):
  574. from datetime import datetime
  575. dt = datetime.now()
  576. data = (
  577. serializers.batchLogSerializer(instance).data
  578. for instance in self.filter_queryset(self.get_queryset()))
  579. renderer = self.get_render(data)
  580. response = StreamingHttpResponse(
  581. renderer,
  582. content_type="text/csv"
  583. )
  584. response['Content-Disposition'] = "attachment; filename='batchLog_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
  585. try:
  586. log_success_operation(
  587. request=request,
  588. operation_content="下载批次日志文件",
  589. operation_level="download",
  590. operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
  591. module_name="报表中心"
  592. )
  593. except Exception as e:
  594. pass
  595. return response
  596. class ContainerDetailLogViewSet(viewsets.ModelViewSet):
  597. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  598. ordering_fields = ['id', "create_time", "update_time", ]
  599. filter_class = ContainerDetailLogFilter
  600. pagination_class = MyPageNumberPagination
  601. def get_queryset(self):
  602. return ContainerDetailLogModel.objects.all()
  603. def get_serializer_class(self):
  604. if self.action in ['list', 'create']:
  605. return serializers.ContainerDetailLogSerializer
  606. else:
  607. return self.http_method_not_allowed(request=self.request)
  608. class ContainerDetailLogDownloadView(viewsets.ModelViewSet):
  609. renderer_classes = (ContainerDetailLogRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
  610. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  611. ordering_fields = ['id', "create_time", "update_time", ]
  612. filter_class = ContainerDetailLogFilter
  613. def get_project(self):
  614. try:
  615. id = self.kwargs.get('pk')
  616. return id
  617. except:
  618. return None
  619. def get_queryset(self):
  620. id = self.get_project()
  621. if self.request.user:
  622. if id is None:
  623. return ContainerDetailLogModel.objects.filter()
  624. else:
  625. return ContainerDetailLogModel.objects.filter(id=id)
  626. else:
  627. return ContainerDetailLogModel.objects.none()
  628. def get_serializer_class(self):
  629. if self.action in ['list']:
  630. return serializers.ContainerDetailLogSerializer
  631. else:
  632. return self.http_method_not_allowed(request=self.request)
  633. def get_render(self, data):
  634. # lang = self.request.META.get('HTTP_LANGUAGE')
  635. # if lang:
  636. # if lang == 'zh-hans':
  637. # return FileListRenderCN().render(data)
  638. # else:
  639. # return FileListRenderEN().render(data)
  640. # else:
  641. # return FileListRenderEN().render(data)
  642. return ContainerDetailLogRenderCN().render(data)
  643. def list(self, request, *args, **kwargs):
  644. from datetime import datetime
  645. dt = datetime.now()
  646. data = (
  647. serializers.ContainerDetailLogSerializer(instance).data
  648. for instance in self.filter_queryset(self.get_queryset()))
  649. renderer = self.get_render(data)
  650. response = StreamingHttpResponse(
  651. renderer,
  652. content_type="text/csv"
  653. )
  654. response['Content-Disposition'] = "attachment; filename='ContainerDetailLog_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
  655. try:
  656. log_success_operation(
  657. request=request,
  658. operation_content="下载托盘详情日志文件",
  659. operation_level="download",
  660. operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
  661. module_name="报表中心"
  662. )
  663. except Exception as e:
  664. pass
  665. return response
  666. class FileListDownloadView(viewsets.ModelViewSet):
  667. renderer_classes = (FileFlowListRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
  668. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  669. ordering_fields = ['id', "document_date" ]
  670. filter_class = FlowFilter
  671. def get_project(self):
  672. try:
  673. id = self.kwargs.get('pk')
  674. return id
  675. except:
  676. return None
  677. def get_queryset(self):
  678. id = self.get_project()
  679. if self.request.user:
  680. if id is None:
  681. return flowlist.objects.filter()
  682. else:
  683. return flowlist.objects.filter(id=id)
  684. else:
  685. return flowlist.objects.none()
  686. def get_serializer_class(self):
  687. if self.action in ['list']:
  688. return serializers.flowSerializer
  689. else:
  690. return self.http_method_not_allowed(request=self.request)
  691. def get_render(self, data):
  692. # lang = self.request.META.get('HTTP_LANGUAGE')
  693. # if lang:
  694. # if lang == 'zh-hans':
  695. # return FileListRenderCN().render(data)
  696. # else:
  697. # return FileListRenderEN().render(data)
  698. # else:
  699. # return FileListRenderEN().render(data)
  700. return FileFlowListRenderCN().render(data)
  701. def list(self, request, *args, **kwargs):
  702. from datetime import datetime
  703. dt = datetime.now()
  704. data = (
  705. serializers.flowSerializer(instance).data
  706. for instance in self.filter_queryset(self.get_queryset())
  707. )
  708. renderer = self.get_render(data)
  709. response = StreamingHttpResponse(
  710. renderer,
  711. content_type="text/csv"
  712. )
  713. response['Content-Disposition'] = "attachment; filename='stocklist_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
  714. try:
  715. log_success_operation(
  716. request=request,
  717. operation_content="下载库存流水文件",
  718. operation_level="download",
  719. operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
  720. module_name="报表中心"
  721. )
  722. except Exception as e:
  723. pass
  724. return response
  725. class FlowsStatsViewSet(viewsets.ModelViewSet):
  726. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  727. ordering_fields = ['id', "create_time", "update_time", ]
  728. filter_class = FlowFilter
  729. pagination_class = MyPageNumberPagination
  730. """
  731. list:
  732. Response a data list(all)
  733. post:
  734. Create a new data(create)
  735. """
  736. def get_project(self):
  737. try:
  738. id = self.kwargs.get('pk')
  739. return id
  740. except:
  741. return None
  742. def get_queryset(self):
  743. id = self.get_project()
  744. if self.request.user:
  745. if id is None:
  746. return flowlist.objects.filter()
  747. else:
  748. return flowlist.objects.filter(id=id)
  749. else:
  750. return flowlist.objects.none()
  751. def get_serializer_class(self):
  752. if self.action in ['list', 'create', ]:
  753. return serializers.flowSerializer
  754. # elif self.action in ['retrieve','update',]:
  755. # return serializers.stocklistpartialSerializer
  756. else:
  757. return self.http_method_not_allowed(request=self.request)
  758. class BatchListViewSet(viewsets.ModelViewSet):
  759. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  760. ordering_fields = ['id', "create_time", "update_time", ]
  761. filter_class = batchfilter
  762. pagination_class = MyPageNumberPagination
  763. """
  764. list:
  765. Response a data list(all)
  766. post:
  767. Create a new data(create)
  768. """
  769. def get_project(self):
  770. try:
  771. id = self.kwargs.get('pk')
  772. return id
  773. except:
  774. return None
  775. def get_queryset(self):
  776. id = self.get_project()
  777. if self.request.user:
  778. if id is None:
  779. return BoundBatchModel.objects.filter()
  780. else:
  781. return BoundBatchModel.objects.filter(id=id)
  782. else:
  783. return BoundBatchModel.objects.none()
  784. def get_serializer_class(self):
  785. if self.action in ['list']:
  786. return serializers.batchlistSerializer
  787. # elif self.action in ['retrieve','update',]:
  788. # return serializers.stocklistpartialSerializer
  789. else:
  790. return self.http_method_not_allowed(request=self.request)
  791. class BatchFileViewSet(viewsets.ModelViewSet):
  792. renderer_classes = (FileBatchListRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
  793. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  794. ordering_fields = [ "bound_month" ,"bound_batch_order", "update_time", ]
  795. filter_class = batchfilter
  796. def get_project(self):
  797. try:
  798. id = self.kwargs.get('pk')
  799. return id
  800. except:
  801. return None
  802. def get_queryset(self):
  803. id = self.get_project()
  804. if self.request.user:
  805. if id is None:
  806. return BoundBatchModel.objects.filter()
  807. else:
  808. return BoundBatchModel.objects.filter(id=id)
  809. else:
  810. return BoundBatchModel.objects.none()
  811. def get_serializer_class(self):
  812. if self.action in ['list']:
  813. return serializers.batchlistSerializer
  814. else:
  815. return self.http_method_not_allowed(request=self.request)
  816. def get_render(self, data):
  817. return FileBatchListRenderCN().render(data)
  818. def list(self, request, *args, **kwargs):
  819. from datetime import datetime
  820. dt = datetime.now()
  821. data = (
  822. serializers.batchlistSerializer(instance).data
  823. for instance in self.filter_queryset(self.get_queryset())
  824. )
  825. renderer = self.get_render(data)
  826. response = StreamingHttpResponse(
  827. renderer,
  828. content_type="text/csv"
  829. )
  830. response['Content-Disposition'] = "attachment; filename='批次报表_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
  831. try:
  832. log_success_operation(
  833. request=request,
  834. operation_content="下载批次列表文件",
  835. operation_level="download",
  836. operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
  837. module_name="报表中心"
  838. )
  839. except Exception as e:
  840. pass
  841. return response
  842. class bigScreenModelViewSet(viewsets.ModelViewSet):
  843. filter_backends = [DjangoFilterBackend, OrderingFilter, ]
  844. ordering_fields = ['id', "create_time", "update_time", ]
  845. filter_class = bigScreenFilter
  846. pagination_class = MyPageNumberPagination
  847. def get_project(self):
  848. try:
  849. id = self.kwargs.get('pk')
  850. return id
  851. except:
  852. return None
  853. def get_queryset(self):
  854. id = self.get_project()
  855. if self.request.user:
  856. if id is None:
  857. return bigScreenModel.objects.filter()
  858. else:
  859. return bigScreenModel.objects.filter(id=id)
  860. else:
  861. return bigScreenModel.objects.none()
  862. def get_serializer_class(self):
  863. if self.action in ['list', 'create', ]:
  864. return serializers.bigScreenSerializer
  865. # elif self.action in ['retrieve','update',]:
  866. # return serializers.stocklistpartialSerializer
  867. else:
  868. return self.http_method_not_allowed(request=self.request)