from rest_framework.decorators import action from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet from apps.utils.mixins import CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin from apps.wpmw.models import Wpr, WprDefect from apps.wpmw.serializers import WprSerializer, WprNewSerializer, WprDetailSerializer, WproutListSerializer from rest_framework.response import Response from apps.mtm.models import Material from rest_framework.exceptions import ParseError from django.db import transaction from apps.wpmw.filters import WprFilter from apps.utils.sql import query_one_dict from django.db.models.expressions import RawSQL class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, CustomGenericViewSet): """动态产品 动态产品 """ perms_map = {"get": "*"} select_related_fields = ["wm", "mb", "material", "wm__material_ofrom"] prefetch_related_fields = ["defects"] queryset = Wpr.objects.all() serializer_class = WprSerializer retrieve_serializer_class = WprDetailSerializer filterset_class = WprFilter ordering = ["number", "create_time"] ordering_fields = ["number", "create_time", "update_time"] search_fields = ["number", "material__name", "material__model", "material__specification", "number_out"] annotate_dict = { "number_prefix": RawSQL("regexp_replace(number, '(\\d+)$', '')", []), "number_suffix": RawSQL("COALESCE(NULLIF(regexp_replace(number, '.*?(\\d+)$', '\\1'), ''), '0')::bigint", []), } def filter_queryset(self, queryset): qs = super().filter_queryset(queryset) if "mb__isnull" in self.request.query_params or "wm__isnull" in self.request.query_params: pass else: qs.exclude(mb=None, wm=None) return qs @action(methods=["post"], detail=False, perms_map={"post": "*"}, serializer_class=WprNewSerializer) def new_number(self, request, *args, **kwargs): """获取新的编号""" data = request.data year = data.get("year") month = data.get("month") material_start = data.get("material_start") wps_qs = Wpr.objects.filter(material_start=material_start, create_time__year=year, create_time__month=month).order_by("create_time") wpr_last = wps_qs.order_by("number").last() count = wps_qs.count() last_number = wpr_last.number if count > 0 else None last_number_count = int(last_number.split("-")[-1].lstrip("0")) mat = Material.objects.get(id=material_start) return Response({"count": count, "last_number": last_number, "material_model": mat.model, "last_number_count": last_number_count}) @action(methods=["get"], detail=False, perms_map={"get": "*"}) def number_out_last(self, request, *args, **kwargs): """获取最新的出库对外编号 获取最新的出库对外编号(get请求传入prefix参数和with_unsubmit参数,with_unsubmit默认为yes,表示是否包含未出库的记录,prefix为前缀,如'WPR-2023-0)""" from apps.inm.models import MIOItemw prefix = request.query_params.get("prefix", None) if not prefix: raise ParseError("请传入前缀参数") with_unsubmit = request.query_params.get("with_unsubmit", "yes") # wpr_qs_last = Wpr.objects.filter(number_out__startswith=prefix).order_by("number_out").last() # 使用原始sql query = """ SELECT id, number_out FROM wpmw_wpr WHERE number_out ~ %s order by number_out desc limit 1 """ pattern = f"^{prefix}[0-9]+$" number_outs = [] wpr_qs_last = query_one_dict(query, [pattern]) if wpr_qs_last: number_outs.append(wpr_qs_last["number_out"]) # 查找未出库的记录 if with_unsubmit == "yes": # mioitemw_last = MIOItemw.objects.filter( # number_out__isnull=False, number_out__startswith=prefix).order_by("number_out").last() query2 = """ select mioitemw.id, mioitemw.number_out from inm_mioitemw mioitemw left join inm_mioitem mioitem on mioitem.id = mioitemw.mioitem_id left join inm_mio mio on mio.id = mioitem.mio_id where mio.submit_time is null and mioitemw.number_out ~ %s order by mioitemw.number_out desc limit 1 """ mioitemw_last = query_one_dict(query2, [pattern]) if mioitemw_last: number_outs.append(mioitemw_last["number_out"]) if number_outs: number_outs.sort() number_out_last = number_outs[-1] number_int_last = number_out_last.lstrip(prefix).lstrip("0") try: number_int_last = int(number_int_last) except ValueError: raise ParseError(f"找到 {number_int_last}, 请检查前缀格式") return Response({"number_out_last": number_out_last, "number_out_int_last": int(number_int_last)}) else: return Response({"number_out_last": None}) @action(methods=["post"], detail=False, perms_map={"post": "*"}, serializer_class=WproutListSerializer) @transaction.atomic def assgin_number_out(self, request, *args, **kwargs): """分配出库对外编号 分配出库对外编号""" sr = WproutListSerializer(data=request.data) sr.is_valid(raise_exception=True) vdata = sr.validated_data items = vdata["items"] number_outs = [i["number_out"] for i in items] existing_numbers = Wpr.objects.filter(number_out__in=number_outs, number_out__isnull=False).values_list("number_out", flat=True) if existing_numbers.exists(): used_numbers = list(existing_numbers) raise ParseError(f"以下对外编号已被使用: {used_numbers[0]} 共{len(used_numbers)}个") for i in items: wpr = Wpr.objects.get(id=i["id"]) wpr.number_out = i["number_out"] wpr.save() return Response()