from apps.cm.models import LableMat, LabelTemplate from rest_framework.decorators import action from apps.cm.serializers import TidSerializer, LabelMatSerializer, LabelTemplateSerializer, Tid2Serializer, CoderSendSerializer from apps.cm.coder import CoderClient from apps.inm.models import MaterialBatch, MIOItem from apps.wpm.models import WMaterial from rest_framework.exceptions import ParseError, NotFound from rest_framework.response import Response from apps.utils.viewsets import CustomGenericViewSet, RetrieveModelMixin, CustomListModelMixin, CustomModelViewSet from apps.cm.filters import LabelTemplateFilter # Create your views here. SPLIT_FIELD = "#" class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericViewSet): perms_map = {"post": "*", "get": "*"} serializer_class = LabelMatSerializer queryset = LableMat.objects.all() select_related_fields = ["material", "material_origin", "supplier"] @action(methods=["post"], detail=False, serializer_class=TidSerializer) def get_from_mb(self, request, pk=None): """ 从仓库明细获取物料标签 从仓库明细获取物料标签 """ tid = request.data.get("tid") label_template = request.data.get("label_template", None) label_template_name = request.data.get("label_template_name", None) extra_data = request.data.get("extra_data", {}) try: mb = MaterialBatch.objects.get(id=tid) except MaterialBatch.DoesNotExist: raise NotFound("仓库明细不存在") obj, _ = LableMat.objects.get_or_create(state=mb.state, material=mb.material, batch=mb.batch, defect=mb.defect, defaults={"supplier": mb.supplier}) rdata = LabelMatSerializer(obj).data rdata["code_label"] = f"mat{SPLIT_FIELD}{obj.id}" if label_template or label_template_name: tdata = {**rdata, **extra_data} commands = LabelTemplate.gen_commands(label_template, label_template_name, tdata) rdata["commands"] = commands return Response(rdata) @action(methods=["post"], detail=False, serializer_class=TidSerializer) def get_from_wm(self, request, pk=None): """ 从车间库存明细获取物料标签 从车间库存明细获取物料标签 """ tid = request.data.get("tid") label_template = request.data.get("label_template", None) label_template_name = request.data.get("label_template_name", None) extra_data = request.data.get("extra_data", {}) try: wm = WMaterial.objects.get(id=tid) except WMaterial.DoesNotExist: raise NotFound("车间库存不存在") obj, _ = LableMat.objects.get_or_create(state=wm.state, material=wm.material, batch=wm.batch, notok_sign=wm.notok_sign, defect=wm.defect, material_origin=wm.material_origin) rdata = LabelMatSerializer(obj).data rdata["code_label"] = f"mat{SPLIT_FIELD}{obj.id}" if label_template or label_template_name: tdata = {**rdata, **extra_data} commands = LabelTemplate.gen_commands(label_template, label_template_name, tdata) rdata["commands"] = commands return Response(rdata) @action(methods=["post"], detail=False, serializer_class=TidSerializer) def get_from_mioitem(self, request, pk=None): """ 从出入库明细获取物料标签 从出入库明细获取物料标签 """ tid = request.data.get("tid") label_template = request.data.get("label_template", None) label_template_name = request.data.get("label_template_name", None) extra_data = request.data.get("extra_data", {}) try: mioitem: MIOItem = MIOItem.objects.get(id=tid) except MIOItem.DoesNotExist: raise NotFound("出入库明细不存在") obj, _ = LableMat.objects.get_or_create(state=10, material=mioitem.material, batch=mioitem.batch, defaults={"supplier": mioitem.mio.supplier}) rdata = LabelMatSerializer(obj).data rdata["code_label"] = f"mat{SPLIT_FIELD}{obj.id}" if label_template or label_template_name: tdata = {**rdata, **extra_data} commands = LabelTemplate.gen_commands(label_template, label_template_name, tdata) rdata["commands"] = commands return Response(rdata) class LabelTemplateViewSet(CustomModelViewSet): """ list: 标签模板 标签模板 """ queryset = LabelTemplate.objects.all() serializer_class = LabelTemplateSerializer filterset_class = LabelTemplateFilter @action(methods=["post"], detail=False, serializer_class=Tid2Serializer, perms_map={"post": "*"}) def commands(self, request, *args, **kwargs): """ 获取标签指令 获取标签指令 """ label_template = request.data.get("label_template", None) label_template_name = request.data.get("label_template_name", None) data = request.data.get("data", {}) return Response({"commands": LabelTemplate.gen_commands(label_template, label_template_name, data)}) @action(methods=["post"], detail=True, serializer_class=CoderSendSerializer, perms_map={"post": "*"}) def send_to_coder(self, request, pk=None, *args, **kwargs): """ 下发指令到伟迪捷 1880 喷码机 (统一走 CQI + JDI 队列模式) body 传 tdata_list (列表, 至少一条), 每条对应一个产品。 每次调用先 CQI 清空队列, 再按顺序 JDI 入队 N 条; 喷码机每个外部触发(光电)消费一条, 喷一个产品。 每条 tdata 走模板 commands, 解析为 <字段>=<内容> 合并成一帧 JDI; commands 中不含 '=' 的元素, 会绑定到默认 coder_field 上。 """ sr = CoderSendSerializer(data=request.data) sr.is_valid(raise_exception=True) vdata = sr.validated_data lt: LabelTemplate = self.get_object() ip = vdata.get("coder_ip") port = vdata.get("coder_port") or 3100 field = vdata.get("coder_field") or "1" batched = [] for tdata in vdata["tdata_list"]: commands = LabelTemplate.gen_commands(lt.id, None, tdata) if not commands: raise ParseError("模板未生成任何指令") fields = {} for item in commands: text = str(item) if "=" in text: k, v = text.split("=", 1) fields[k.strip()] = v else: fields[field] = text batched.append(fields) client = CoderClient(ip=ip, port=port) coder_jobname = vdata.get("coder_jobname") client.clear_queue() if coder_jobname: client.select_job(coder_jobname) client.clear_queue() for fields in batched: client.push_queue(fields) return Response({"queued": len(batched), "fields": batched, "ip": ip, "port": port, "jobname": coder_jobname})