from rest_framework.decorators import action from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet from apps.utils.mixins import CustomListModelMixin, CustomRetrieveModelMixin, ComplexQueryMixin, BulkUpdateModelMixin from apps.wpmw.models import Wpr, WprDefect from apps.qm.models import FtestItem from apps.wpmw.serializers import WprSerializer, WprNewSerializer, WprDetailSerializer, WproutListSerializer, WprChangeNumberSerializer, WprPreInfoSerializer 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(BulkUpdateModelMixin, CustomListModelMixin, CustomRetrieveModelMixin, ComplexQueryMixin, CustomGenericViewSet): """动态产品 动态产品 """ perms_map = {"get": "*", "put": "*", "patch": "*"} 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","wm__batch"] annotate_dict = { "number_prefix": RawSQL("regexp_replace(wpmw_wpr.number, '(\\d+)$', '')", []), "number_suffix": RawSQL("COALESCE(NULLIF(regexp_replace(wpmw_wpr.number, '.*?(\\d+)$', '\\1'), ''), '0')::bigint", []), } def add_info_for_list(self, data): parent_ids = [item["wpr_from"] for item in data if item.get("wpr_from", False)] if parent_ids: parent_data = Wpr.objects.filter(id__in=parent_ids).values("id", "number", "data") parent_map = {item["id"]: item for item in parent_data} for item in data: if item["wpr_from"]: item["wpr_from_"] = parent_map[item["wpr_from"]] return data 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=WprChangeNumberSerializer) @transaction.atomic def change_number(self, request, *args, **kwargs): """修改编号""" sr = WprChangeNumberSerializer(data=request.data) sr.is_valid(raise_exception=True) vdata = sr.validated_data new_number = vdata["new_number"] old_number = vdata["old_number"] if Wpr.objects.filter(number=new_number).exists(): raise ParseError("新编号已存在,不可使用") wpr = Wpr.objects.get(number=old_number) from apps.wpm.models import Mlogbw, Handoverbw from apps.inm.models import MIOItemw Wpr.objects.filter(id=wpr.id).update(number=new_number) Mlogbw.objects.filter(wpr=wpr).update(number=new_number) Handoverbw.objects.filter(wpr=wpr).update(number=new_number) MIOItemw.objects.filter(wpr=wpr).update(number=new_number) return Response() @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 LIKE %s AND translate( substring(number_out FROM LENGTH(%s) + 2), '0123456789', '' ) = '' order by number_out desc limit 1 """ params = ( f"{prefix}-%", prefix ) number_outs = [] wpr_qs_last = query_one_dict(query, [params]) 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 LIKE %s AND translate( substring(mioitemw.number_out FROM LENGTH(%s) + 2), '0123456789', '' ) = '' order by mioitemw.number_out desc limit 1 """ mioitemw_last = query_one_dict(query2, [params]) 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=["patch"], detail=True, perms_map={"patch": "*"}, serializer_class=WprPreInfoSerializer) def update_pre_info(self, request, *args, **kwargs): """更新预处理信息""" wpr = self.get_object() sr = WprPreInfoSerializer(data=request.data) sr.is_valid(raise_exception=True) raw_info = sr.validated_data from apps.utils.tools import update_dict wpr.pre_info = update_dict(wpr.pre_info or {}, raw_info) wpr.save(update_fields=["pre_info"]) return Response({"pre_info": wpr.pre_info}) @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()