diff --git a/apps/qm/migrations/0018_auto_20240812_1048.py b/apps/qm/migrations/0018_auto_20240812_1048.py new file mode 100644 index 00000000..1bbd93f7 --- /dev/null +++ b/apps/qm/migrations/0018_auto_20240812_1048.py @@ -0,0 +1,42 @@ +# Generated by Django 3.2.12 on 2024-08-12 02:48 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0050_auto_20240701_0936'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('qm', '0017_alter_testitem_field_type'), + ] + + operations = [ + migrations.AddField( + model_name='ftestwork', + name='count_notok_json', + field=models.JSONField(blank=True, default=dict, verbose_name='不合格项数量统计'), + ), + migrations.AddField( + model_name='ftestwork', + name='submit_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='提交时间'), + ), + migrations.AddField( + model_name='ftestwork', + name='submit_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='提交人'), + ), + migrations.AddField( + model_name='ftestwork', + name='wm', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wpm.wmaterial', verbose_name='关联车间库存'), + ), + migrations.AlterField( + model_name='ftestwork', + name='count', + field=models.IntegerField(verbose_name='检验数量'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 9a980c39..498c2659 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -2,7 +2,7 @@ from django.db import models from apps.system.models import CommonAModel, CommonADModel, User from apps.utils.models import CommonBDModel, BaseModel from apps.mtm.models import Material, Mgroup, Team -from apps.wpm.models import SfLog +from apps.wpm.models import SfLog, WMaterial from django.utils.translation import gettext_lazy as _ class NotOkOption(models.TextChoices): @@ -38,6 +38,19 @@ class NotOkOption(models.TextChoices): md = "md", _("麻点") xh = "xh", _("线痕") b = "b", _("扁") + zb = "zb", _("棕边") + hqbx = "hqbx", _("黑圈变形") + dj = "dj", _("倒角") + ps = "ps", _("破损") + lq = "lq", _("蓝圈") + hqnj = "hqnj", _("黑圈内径") + hqnjyd = "hqnjyd", _("黑圈内径圆度") + hqwj = "hqwj", _("黑圈外径") + hqwjyd = "hqwjyd", _("黑圈外径圆度") + wj = "cpwj", _("外径") + yd = "cpyd", _("圆度") + txd = "cptxd", _("同心度") + hd = "hq", _("厚度") wz = "wz", _("未知") @@ -90,14 +103,18 @@ class FtestWork(CommonBDModel): """ type = models.CharField('检验类型', max_length=20, choices=FTEST_TYPE_CHOICES, default='prod') type2 = models.PositiveSmallIntegerField('检验类型2', choices=((10, '抽检'), (20, '全检')), default=10) + wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL, null=True, blank=True) test_date = models.DateField('检验日期') material = models.ForeignKey( Material, verbose_name='产品', on_delete=models.CASCADE) batch = models.CharField('生产批次', max_length=20) - count = models.IntegerField('总数量') + count = models.IntegerField('检验数量') count_sampling = models.IntegerField('抽检数量', default=0) count_ok = models.IntegerField('合格数量', default=0) count_notok = models.IntegerField('不合格数量', default=0) + count_notok_json = models.JSONField('不合格项数量统计', default=dict, null=False, blank=True) + submit_time = models.DateTimeField('提交时间', null=True, blank=True) + submit_user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='提交人', null=True, blank=True) class Ftest(CommonBDModel): diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index ebf69783..07268f65 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -1,9 +1,10 @@ -from apps.qm.models import QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest +from apps.qm.models import QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest, NotOkOption from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers +from rest_framework.exceptions import ValidationError from apps.system.models import Dept, Dictionary -from apps.wpm.models import SfLog +from apps.wpm.models import SfLog, WMaterial from django.db import transaction @@ -61,7 +62,29 @@ class QuaStatUpdateSerializer(CustomModelSerializer): class FtestWorkCreateUpdateSerializer(CustomModelSerializer): class Meta: model = FtestWork - fields = ['id', 'test_date', 'material', 'batch', 'count', 'count_sampling', 'count_ok', 'count_notok'] + fields = ['id', 'wm', 'test_date', 'count', 'count_sampling', 'count_ok', 'count_notok', 'count_notok_json'] + + def validate(self, attrs): + if 'wm' not in attrs: + raise ValidationError('请选择车间库存') + wm:WMaterial = attrs['wm'] + attrs['material'] = wm.material + attrs['batch'] = wm.batch + count_notok_json = attrs.get('count_notok_json', None) + if count_notok_json is None: + raise ValidationError('不合格项不能为Null') + count_notok = 0 + for k, v in count_notok_json.items(): + k_2 = k.replace('count_n_', '') + if k not in NotOkOption.values(): + raise ValidationError(f'不支持的不合格项{k_2}') + if isinstance(v, int) and v >= 0: + count_notok = count_notok + v + else: + raise ValidationError(f'不合格项{k_2}必须为非负整数') + attrs['count_notok'] = count_notok + return attrs + class FtestWorkSerializer(CustomModelSerializer): material_name = serializers.StringRelatedField( diff --git a/apps/qm/services.py b/apps/qm/services.py new file mode 100644 index 00000000..77f2b380 --- /dev/null +++ b/apps/qm/services.py @@ -0,0 +1,42 @@ +from apps.qm.models import FtestWork +from apps.wpm.models import WMaterial +from apps.system.models import User +from rest_framework.exceptions import ParseError +from django.utils import timezone + + +def ftestwork_submit(ins:FtestWork, user: User): + wm:WMaterial = ins.wm + # 更新对应的车间库存 + wm.count = wm.count - ins.count_notok + if wm.count >= 0: + # 已检测的数量 + wm.count_xtest = wm.count_xtest + ins.count + wm.save() + else: + raise ParseError("车间库存不足") + # 生成合格的 + count_ok = ins.count_ok + if count_ok > 0: + wm_ok = WMaterial() + wm_ok.material = wm.material + wm_ok.count = count_ok + wm_ok.batch = wm.batch + wm_ok.mgroup = wm.mgroup + wm_ok.belong_dept = wm.belong_dept + wm_ok.save() + # 生成不合格的 + count_notok_json = ins.count_notok_json + for k, v in count_notok_json.items(): + if v > 0: + wm_n = WMaterial() + wm_n.material = wm.material + wm_n.count = v + wm_n.batch = wm.batch + wm_n.mgroup = wm.mgroup + wm_n.belong_dept = wm.belong_dept + wm_n.notok_sign = k.replace('count_n_', '') + wm_n.save() + ins.submit_user = user + ins.submit_time = timezone.now() + ins.save() \ No newline at end of file diff --git a/apps/qm/views.py b/apps/qm/views.py index 17a8da2c..682fd92d 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -1,7 +1,9 @@ from django.shortcuts import render from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin from rest_framework.decorators import action +from rest_framework.exceptions import ParseError from rest_framework.views import APIView +from rest_framework.serializers import Serializer from apps.qm.models import QuaStat, TestItem, Ftest, Ptest, FtestWork from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer, FtestSerializer, PtestSerializer, \ FtestWorkCreateUpdateSerializer, FtestWorkSerializer @@ -15,6 +17,7 @@ from apps.wpm.models import SfLog from apps.qm.filters import QuaStatFilter, TestItemFilter from django.db import transaction from apps.qm.models import NotOkOption +from apps.qm.services import ftestwork_submit # Create your views here. class NotOkOptionView(APIView): @@ -124,3 +127,27 @@ class FtestWorkViewSet(CustomModelViewSet): update_serializer_class = FtestWorkCreateUpdateSerializer select_related_fields = ['material'] filterset_fields = ['material', 'batch'] + + def update(self, request, *args, **kwargs): + ins:FtestWork = self.get_object() + if ins.submit_time is not None: + raise ParseError('已提交无法修改') + return super().update(request, *args, **kwargs) + + def destroy(self, request, *args, **kwargs): + ins:FtestWork = self.get_object() + if ins.submit_time is not None: + raise ParseError('已提交无法删除') + return super().destroy(request, *args, **kwargs) + + @action(methods=['post'], detail=True, perms_map={'post': 'ftestwork.submit'}, serializer_class=Serializer) + @transaction.atomic + def submit(self, request, *args, **kwargs): + """提交检验工作 + + 提交检验工作 + """ + ins:FtestWork = self.get_object() + if ins.submit_time is not None: + ftestwork_submit(ins, request.user) + return Response() \ No newline at end of file