This commit is contained in:
zty 2025-03-05 18:36:10 +08:00
commit c8ba7dc563
23 changed files with 572 additions and 162 deletions

View File

@ -12,7 +12,7 @@ from apps.hrm.models import Certificate, ClockRecord, Employee, NotWorkRemark, A
from apps.system.serializers import DeptSimpleSerializer, UserSimpleSerializer
from django.db import transaction
from django.core.cache import cache
from apps.utils.tools import check_id_number_e, get_info_from_id
from apps.utils.tools import check_id_number_strict, get_info_from_id
from rest_framework.exceptions import ParseError
from django.conf import settings
import datetime
@ -54,7 +54,7 @@ class EmployeeSimpleSerializer(CustomModelSerializer):
class EmployeeCreateUpdateSerializer(CustomModelSerializer):
id_number = serializers.CharField(
label="身份证号", validators=[check_id_number_e])
label="身份证号", validators=[check_id_number_strict])
class Meta:
model = Employee

View File

@ -11,7 +11,9 @@ class MaterialBatchFilter(filters.FilterSet):
"material": ["exact"],
"material__type": ["exact", "in"],
"material__process": ["exact", "in"],
"count": ["exact", "gte", "lte"]
"count": ["exact", "gte", "lte"],
"state": ["exact", "in"],
"defect": ["exact"]
}

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2025-03-04 08:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inm', '0028_mioitem_count_tested'),
]
operations = [
migrations.AlterField(
model_name='mioitem',
name='batch',
field=models.TextField(verbose_name='批次号'),
),
]

View File

@ -116,7 +116,7 @@ class MIOItem(BaseModel):
WareHouse, on_delete=models.CASCADE, verbose_name='仓库')
material = models.ForeignKey(
Material, verbose_name='物料', on_delete=models.CASCADE)
batch = models.CharField('批次号', max_length=50)
batch = models.TextField('批次号')
count = models.DecimalField('出入数量', max_digits=12, decimal_places=3)
count_tested = models.PositiveIntegerField('已检数', null=True, blank=True)
test_date = models.DateField('检验日期', null=True, blank=True)

View File

@ -144,10 +144,10 @@ class RoutePackSerializer(CustomModelSerializer):
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS + ['state', 'ticket']
def update(self, instance, validated_data):
if validated_data['material'] != instance.material:
raise ParseError('不可变更产品')
return super().update(instance, validated_data)
# def update(self, instance, validated_data):
# if validated_data['material'] != instance.material:
# raise ParseError('不可变更产品')
# return super().update(instance, validated_data)
class RouteSerializer(CustomModelSerializer):

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2025-02-28 01:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0044_testitem_cd_expr'),
]
operations = [
migrations.AlterField(
model_name='defect',
name='code',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='标识'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2025-03-03 07:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0045_alter_defect_code'),
]
operations = [
migrations.AlterField(
model_name='testitem',
name='description',
field=models.TextField(blank=True, null=True, verbose_name='描述'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2025-03-04 07:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0046_alter_testitem_description'),
]
operations = [
migrations.AddField(
model_name='ftestwork',
name='count_ok_full',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='完全合格数量'),
),
]

View File

@ -15,7 +15,7 @@ class Defect(CommonAModel):
DEFECT_OK_B = 20
DEFECT_NOTOK = 30
name = models.CharField(max_length=50, verbose_name="名称")
code = models.CharField(max_length=50, verbose_name="标识")
code = models.CharField(max_length=50, verbose_name="标识", null=True, blank=True)
cate = models.CharField(max_length=50, verbose_name="分类", choices=(("尺寸", "尺寸"), ("外观", "外观"), ("内质", "内质")))
okcate= models.PositiveSmallIntegerField(verbose_name="不合格分类",
choices=((DEFECT_OK, "合格"), (DEFECT_OK_B, "合格B类"), (DEFECT_NOTOK, "不合格")),
@ -130,7 +130,7 @@ class TestItem(CommonAModel):
tags = models.JSONField('检测类型', default=list, blank=True)
mcate_tags = models.JSONField('物料系列标签', default=list, blank=True)
sort = models.FloatField('排序', default=1)
description = models.TextField('描述', default='')
description = models.TextField('描述', null=True, blank=True)
readonly = models.BooleanField('只读', default=False)
formula = models.TextField('计算公式', null=True, blank=True)
affects = models.JSONField('影响项列表', default=list, blank=True)
@ -151,7 +151,7 @@ QC_TRACE_CHOICES = (
class Qct(CommonAModel):
name = models.CharField(max_length=50, verbose_name="名称")
number = models.CharField(max_length=20, verbose_name="编号")
tags = models.JSONField('检测类型', default=list, blank=True)
tags = models.JSONField('检测类型', default=list, blank=True) # process 和 inm
testitems = models.ManyToManyField(TestItem, verbose_name="检测项", blank=True, through='qm.qcttestitem')
defects = models.ManyToManyField(Defect, verbose_name="缺陷项", blank=True, through='qm.qctdefect')
materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat')
@ -168,6 +168,16 @@ class Qct(CommonAModel):
def qct_mats(self):
return QctMat.objects.filter(qct=self)
@classmethod
def get(self, material:Material, cate:str):
try:
qctmat = QctMat.objects.get(material=material, qct__is_deleted=False, qct__tags__contains=cate)
except QctMat.DoesNotExist:
qctmat = None
except QctMat.MultipleObjectsReturned:
raise ParseError("存在多个质检表,请手动选择")
return qctmat.qct if qctmat else None
class QctTestItem(BaseModel):
qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE, related_name="qcttestitem")
testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True)
@ -225,6 +235,7 @@ class FtestWork(CommonBDModel):
count_sampling = models.PositiveIntegerField('抽检数量', default=0)
count_sampling_ok = models.PositiveIntegerField('抽检合格数量', default=0)
count_ok = models.PositiveIntegerField('合格数量', default=0)
count_ok_full = models.PositiveIntegerField('完全合格数量', null=True, blank=True)
count_notok = models.PositiveIntegerField('不合格数量', default=0)
need_update_wm = models.BooleanField('是否更新车间库存', default=True)
count_notok_json = models.JSONField('不合格项数量统计', default=dict, null=False, blank=True)
@ -250,7 +261,10 @@ class FtestWork(CommonBDModel):
def cal_count(self):
self.count_notok = FtestworkDefect.objects.filter(
ftestwork=self, defect__okcate=30).aggregate(total=Sum("count"))["total"] or 0
count_notok_full = FtestworkDefect.objects.filter(
ftestwork=self).exclude(defect__okcate=10).aggregate(total=Sum("count"))["total"] or 0
self.count_ok = self.count - self.count_notok
self.count_ok_full = self.count - count_notok_full
if self.type2 == 20: #全检
self.count_sampling = self.count
self.count_sampling_ok = self.count_ok
@ -306,6 +320,25 @@ class Ftest(CommonBDModel):
FtestDefect.objects.create(ftest=ftest, defect=defect)
return ftest
# @classmethod
# def cal_count_notok(cls, ftestwork: FtestWork):
# count = Ftest.objects.filter(ftest_work=ftestwork).count()
# mlogb.count_real = count
# count_notok = 0
# tqs = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False)
# tqs_a = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).values("ftest__defect_main").annotate(xcount=Count('id'))
# defects = {defect.id: defect for defect in Defect.objects.filter(id__in=tqs.values_list("ftest__defect_main", flat=True))}
# md_ids = []
# for t in tqs_a:
# md, _ = MlogbDefect.objects.get_or_create(mlogb=mlogb, defect=defects[t["ftest__defect_main"]])
# md.count = t["xcount"]
# md.save()
# md_ids.append(md.id)
# count_notok += t["xcount"]
# MlogbDefect.objects.filter(mlogb=mlogb).exclude(id__in=md_ids).delete()
# mlogb.count_notok = count_notok
# mlogb.count_ok = count - mlogb.count_notok
# mlogb.save()
class FtestItem(BaseModel):
"""

View File

@ -16,15 +16,15 @@ class DefectSerializer(CustomModelSerializer):
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS
def create(self, validated_data):
code = validated_data["code"]
if Defect.objects.get_queryset(all=True).filter(code=code).exists():
raise ValidationError("缺陷标识已存在")
return super().create(validated_data)
# def create(self, validated_data):
# code = validated_data["code"]
# if Defect.objects.get_queryset(all=True).filter(code=code).exists():
# raise ValidationError("缺陷标识已存在")
# return super().create(validated_data)
def update(self, instance, validated_data):
validated_data.pop("code", None)
return super().update(instance, validated_data)
# def update(self, instance, validated_data):
# validated_data.pop("code", None)
# return super().update(instance, validated_data)
class TestItemSerializer(CustomModelSerializer):
process_name = serializers.CharField(source="process.name", read_only=True)
@ -155,6 +155,7 @@ class FtestWorkCreateUpdateSerializer(CustomModelSerializer):
def validate(self, attrs):
qct = attrs.get("qct", None)
ftestworkdefect = attrs.get("ftestworkdefect", [])
type2 = attrs.get('type2', 20)
if type2 == 20: # 如果是全检
attrs['count_sampling'] = attrs['count']
@ -168,7 +169,9 @@ class FtestWorkCreateUpdateSerializer(CustomModelSerializer):
attrs['material'] = wm.material
attrs['batch'] = wm.batch
count_notok_json = attrs.get('count_notok_json', None)
if qct is None: # 没有qct时按原有逻辑处理
if qct or ftestworkdefect: # 没有qct时按原有逻辑处理
pass
else:
if count_notok_json is None:
raise ValidationError('不合格项不能为空')
count_notok = 0
@ -200,23 +203,30 @@ class FtestWorkCreateUpdateSerializer(CustomModelSerializer):
with transaction.atomic():
ins: FtestWork = super().create(validated_data)
for ftestworkdefect in ftestworkdefect:
FtestworkDefect.objects.create(ftestwork=ins, **ftestworkdefect)
if ftestworkdefect:
if ftestworkdefect['count'] > 0:
FtestworkDefect.objects.create(ftestwork=ins, **ftestworkdefect)
if ins.qct or ftestworkdefect:
ins.cal_count()
return ins
def update(self, instance, validated_data):
ftestworkdefect = validated_data.pop("ftestworkdefect", [])
ins = super().update(instance, validated_data)
ins:FtestWork = super().update(instance, validated_data)
with transaction.atomic():
fd_ids = []
for item in ftestworkdefect:
try:
ins = FtestworkDefect.objects.get(ftestwork=ins, defect=item["defect"])
except FtestworkDefect.DoesNotExist:
raise ParseError("新的缺陷项!")
ins.count = item["count"]
ins.save()
if ftestworkdefect:
if item["count"] > 0:
try:
ins = FtestworkDefect.objects.get(ftestwork=ins, defect=item["defect"])
except FtestworkDefect.DoesNotExist:
raise ParseError("新的缺陷项!")
except FtestworkDefect.MultipleObjectsReturned:
raise ParseError("缺陷项重复!")
ins.count = item["count"]
ins.save()
fd_ids.append(ins.id)
FtestworkDefect.objects.filter(ftestwork=ins).exclude(id__in=fd_ids).delete()
if ins.qct or ftestworkdefect:
ins.cal_count()
return ins

View File

@ -23,8 +23,9 @@ def ftestwork_submit_validate(ins: FtestWork):
def ftestwork_submit(ins:FtestWork, user: User):
wm:WMaterial = ins.wm
fwd_qs = FtestworkDefect.objects.filter(ftestwork=ins)
if ins.need_update_wm:
if ins.qct is None:
if ins.qct is None or not fwd_qs.exists():
if wm.state == WMaterial.WM_TEST:
# 更新对应的车间库存
wm.count = wm.count - ins.count
@ -101,16 +102,20 @@ def ftestwork_submit(ins:FtestWork, user: User):
# 此时调用了qct表
for item in FtestworkDefect.objects.filter(ftestwork=ins):
item:FtestworkDefect = item
if item.count > 0 and item.defect.okcate == Defect.DEFECT_NOTOK:
if item.count > 0:
wm.count = wm.count - item.count
if wm.count < 0:
raise ParseError("数量不足,扣减失败")
wm.save()
wmstate = WMaterial.WM_OK
if item.defect.okcate == Defect.DEFECT_NOTOK:
wmstate = WMaterial.WM_NOTOK
wmx, new_create = WMaterial.objects.get_or_create(
material=wm.material,
batch=wm.batch,
mgroup=wm.mgroup,
belong_dept=wm.belong_dept,
state=WMaterial.WM_NOTOK,
state=wmstate,
notok_sign=None,
defect=item.defect,
defaults={
@ -120,7 +125,6 @@ def ftestwork_submit(ins:FtestWork, user: User):
if not new_create:
wmx.count = wmx.count + item.count
wmx.save()
wm.save()
ins.submit_user = user
ins.submit_time = timezone.now()
ins.save()

View File

@ -12,7 +12,7 @@ from rest_framework.exceptions import ParseError, ValidationError
from django.db import transaction
from apps.third.dahua import dhClient
from apps.third.tapis import dhapis
from apps.utils.tools import check_id_number_e, check_phone_e
from apps.utils.tools import check_id_number_strict, check_phone_e
from apps.wf.serializers import TicketSimpleSerializer
from apps.rpm.services import rpj_member_come, rpj_certificate_in
from apps.rpm.models import RpjLog
@ -138,7 +138,7 @@ class RemployeeCreateSerializer(CustomModelSerializer):
rparty = serializers.PrimaryKeyRelatedField(queryset=Rparty.objects.all(), label='相关方ID', required=False)
phone = serializers.CharField(label="手机号", validators=[check_phone_e])
photo = serializers.CharField(label='照片地址', required=True)
id_number = serializers.CharField(label="身份证号", validators=[check_id_number_e], required=True)
id_number = serializers.CharField(label="身份证号", validators=[check_id_number_strict], required=True)
class Meta:
model = Remployee

View File

@ -250,6 +250,23 @@ def check_id_number(idcard):
return False, Errors[0]
def check_id_number_strict(id_card: str):
"""校验 18 位中国身份证号码是否合法"""
if not re.match(r'^\d{17}[\dXx]$', id_card):
return False
# 系数和校验码
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
check_codes = "10X98765432"
# 计算校验码
total = sum(int(id_card[i]) * weights[i] for i in range(17))
expected_check_code = check_codes[total % 11]
if expected_check_code == id_card[-1].upper():
return id_card
raise ValidationError('身份证号校验失败')
def check_phone_e(phone):
re_phone = r'^1\d{10}$'
if not re.match(re_phone, phone):

View File

@ -4,7 +4,7 @@ from apps.hrm.serializers import EmployeeSimpleSerializer
from apps.system.models import Dept
from apps.utils.fields import MyFilePathField
from apps.utils.serializers import CustomModelSerializer
from apps.utils.tools import check_id_number_e, check_phone_e
from apps.utils.tools import check_id_number_strict, check_phone_e
from apps.vm.models import Visit, Visitor, Vpeople
from rest_framework import serializers
from rest_framework.exceptions import ParseError
@ -59,7 +59,7 @@ class VisitorCreateSerializer(CustomModelSerializer):
phone = serializers.CharField(label="手机号", validators=[check_phone_e])
photo = serializers.CharField(label='照片地址', required=True)
id_number = serializers.CharField(
label="身份证号", validators=[check_id_number_e], required=True)
label="身份证号", validators=[check_id_number_strict], required=True)
class Meta:
model = Visitor

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.12 on 2025-02-28 01:11
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('qm', '0044_testitem_cd_expr'),
('wpm', '0088_auto_20250224_0938'),
]
operations = [
migrations.CreateModel(
name='MlogbDefect',
fields=[
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('count', models.PositiveIntegerField(default=0, verbose_name='数量')),
('defect', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.defect', verbose_name='缺陷')),
('mlogb', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.mlogb', verbose_name='生产记录')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2025-03-03 06:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0089_mlogbdefect'),
]
operations = [
migrations.AddField(
model_name='mlogbdefect',
name='floor',
field=models.IntegerField(blank=True, null=True, verbose_name='层数'),
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.12 on 2025-03-03 09:08
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0046_alter_testitem_description'),
('wpm', '0090_mlogbdefect_floor'),
]
operations = [
migrations.AddField(
model_name='mlog',
name='qct',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='qm.qct', verbose_name='所用质检表'),
),
migrations.AddField(
model_name='mlogbdefect',
name='count_test',
field=models.IntegerField(blank=True, null=True, verbose_name='抽检数'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.12 on 2025-03-04 06:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0091_auto_20250303_1708'),
]
operations = [
migrations.AddField(
model_name='mlog',
name='count_ok_full',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='完全合格数'),
),
migrations.AddField(
model_name='mlogb',
name='count_ok_full',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='完全合格数'),
),
]

View File

@ -10,6 +10,7 @@ from apps.pum.models import Supplier
from django.db.models import Sum, Subquery
from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import ParseError
from django.db.models import Count
# Create your models here.
@ -171,6 +172,7 @@ class Mlog(CommonADModel):
fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:仅二级;20:二三级;30:一二级')
mtype = models.PositiveSmallIntegerField('生产类型', default=10, help_text='10:自生产;20:外协生产', choices=((10, '自生产'), (20, '外协生产')))
is_fix = models.BooleanField('是否用于返修', default=False)
qct = models.ForeignKey("qm.qct", verbose_name='所用质检表', on_delete=models.SET_NULL, null=True, blank=True)
supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True)
work_start_time = models.DateTimeField('生产开始时间', null=True, blank=True)
work_end_time = models.DateTimeField('生产结束时间', null=True, blank=True)
@ -205,6 +207,7 @@ class Mlog(CommonADModel):
count_break = models.PositiveIntegerField('加工碎料数', default=0)
count_ok = models.PositiveIntegerField('合格数', default=0)
count_ok_full = models.PositiveIntegerField('完全合格数', null=True, blank=True)
count_notok = models.PositiveIntegerField('不合格数', default=0)
count_break_t = models.PositiveIntegerField('检验碎料数', default=0)
@ -288,6 +291,10 @@ class Mlog(CommonADModel):
return ['create_by', 'update_by',
'create_time', 'update_time', 'id']
@property
def mlogdefect(self):
return MlogbDefect.objects.filter(mlogb__mlog=self)
@classmethod
def count_fields(cls):
mlog_count_fields = []
@ -332,6 +339,7 @@ class Mlogb(BaseModel):
count_break_t = models.PositiveIntegerField('检验碎料数', default=0)
count_real = models.PositiveIntegerField('实际生产数', default=0)
count_ok = models.PositiveIntegerField('合格数量', default=0)
count_ok_full = models.PositiveIntegerField('完全合格数', null=True, blank=True)
count_notok = models.PositiveIntegerField('不合格数', default=0)
count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0)
@ -358,6 +366,33 @@ class Mlogb(BaseModel):
elif self.material_out:
return "out", self.material_out.tracking
@property
def mlogbdefect(self):
return MlogbDefect.objects.filter(mlogb=self)
def cal_count_notok(self):
count_notok = MlogbDefect.objects.filter(defect__okcate=30, mlogb=self).aggregate(total=Sum("count"))["total"] or 0
count_notok_full = MlogbDefect.objects.filter(mlogb=self).exclude(defect__okcate=10).aggregate(total=Sum("count"))["total"] or 0
self.count_notok = count_notok
self.count_ok = self.count_real - count_notok
self.count_ok_full = self.count_real - count_notok_full
self.save(update_fields=["count_ok", "count_notok", "count_ok_full"])
mlog = self.mlog
if mlog:
count_notok = MlogbDefect.objects.filter(defect__okcate=30, mlogb__mlog=mlog).aggregate(total=Sum("count"))["total"] or 0
count_notok_full = MlogbDefect.objects.filter(mlogb__mlog=mlog).exclude(defect__okcate=10).aggregate(total=Sum("count"))["total"] or 0
mlog.count_ok_full = self.count_real - count_notok_full
mlog.count_notok = count_notok
mlog.count_ok = self.count_real - count_notok
mlog.save(update_fields=["count_ok", "count_notok", "count_ok_full"])
class MlogbDefect(BaseModel):
mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE)
defect = models.ForeignKey("qm.Defect", verbose_name='缺陷', on_delete=models.CASCADE)
count_test = models.IntegerField("抽检数", null=True, blank=True)
floor = models.IntegerField("层数", null=True, blank=True)
count = models.PositiveIntegerField('数量', default=0)
class Mlogbw(BaseModel):
"""TN: 单个产品生产/检验日志
"""
@ -372,6 +407,29 @@ class Mlogbw(BaseModel):
on_delete=models.PROTECT, null=True, blank=True, related_name="mlogbw_ftest")
note = models.TextField('备注', null=True, blank=True)
@classmethod
def cal_count_notok(cls, mlogb: Mlog):
from apps.qm.models import Defect
count = Mlogbw.objects.filter(mlogb=mlogb).count()
if mlogb.material_in:
mlogb.count_use = count
elif mlogb.material_out:
mlogb.count_real = count
count_notok = 0
tqs = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False)
tqs_a = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).values("ftest__defect_main").annotate(xcount=Count('id'))
defects = {defect.id: defect for defect in Defect.objects.filter(id__in=tqs.values_list("ftest__defect_main", flat=True))}
md_ids = []
for t in tqs_a:
md, _ = MlogbDefect.objects.get_or_create(mlogb=mlogb, defect=defects[t["ftest__defect_main"]])
md.count = t["xcount"]
md.save()
md_ids.append(md.id)
count_notok += t["xcount"]
MlogbDefect.objects.filter(mlogb=mlogb).exclude(id__in=md_ids).delete()
mlogb.count_notok = count_notok
mlogb.count_ok = count - mlogb.count_notok
mlogb.save()
class Handover(CommonADModel):
"""

View File

@ -6,7 +6,7 @@ from datetime import datetime
from .models import (SfLog, StLog, SfLogExp, WMaterial, Mlog,
Handover, Handoverb, Mlogb, AttLog,
OtherLog, Fmlog, BatchSt, Mlogbw, Handoverbw)
OtherLog, Fmlog, BatchSt, Mlogbw, Handoverbw, MlogbDefect)
from apps.system.models import Dept, User
from apps.system.serializers import UserSimpleSerializer
from apps.pm.models import Mtask, Mtaskb
@ -18,11 +18,13 @@ from django.db import transaction
from django.utils import timezone
from django.core.cache import cache
from django.utils.timezone import localdate
from apps.qm.models import NotOkOption, Ftest
from apps.qm.models import NotOkOption, Qct
from apps.wf.serializers import TicketSimpleSerializer
from apps.wpmw.models import Wpr
from apps.qm.serializers import FtestProcessSerializer
import logging
from apps.qm.models import Defect
from apps.utils.snowflake import idWorker
mylogger = logging.getLogger("log")
class OtherLogSerializer(CustomModelSerializer):
@ -201,6 +203,13 @@ class WMaterialSerializer(CustomModelSerializer):
ret['count_cando'] = ret['count'] - ret['count_working']
return ret
class MlogbDefectSerializer(CustomModelSerializer):
defect_name = serializers.CharField(source="defect.name", read_only=True)
defect_okcate = serializers.CharField(source="defect.okcate", read_only=True)
class Meta:
model = MlogbDefect
fields = ["id", "defect_name", "count", "mlogb", "defect", "floor", "count_test", "defect_okcate"]
read_only_fields = EXCLUDE_FIELDS_BASE + ["mlogb"]
class MlogbSerializer(CustomModelSerializer):
material_out_ = MaterialSimpleSerializer(
@ -215,15 +224,6 @@ class MlogbSerializer(CustomModelSerializer):
extra_kwargs = {
'material_out': {'required': True, 'allow_null': False}}
class MlogbDetailSerializer(CustomModelSerializer):
material_out_name = serializers.StringRelatedField(
source='material_out', read_only=True)
material_in_name = serializers.StringRelatedField(source='material_in', read_only=True)
material_out_tracking = serializers.IntegerField(source="material_out.tracking", read_only=True)
class Meta:
model = Mlogb
fields = '__all__'
class MlogListSerializer(CustomModelSerializer):
mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True)
@ -269,6 +269,18 @@ class MlogListSerializer(CustomModelSerializer):
model = Mlog
fields = '__all__'
class MlogbDetailSerializer(CustomModelSerializer):
material_out_name = serializers.StringRelatedField(
source='material_out', read_only=True)
material_in_name = serializers.StringRelatedField(source='material_in', read_only=True)
material_out_tracking = serializers.IntegerField(source="material_out.tracking", read_only=True)
mlogbdefect = MlogbDefectSerializer(many=True, read_only=True)
class Meta:
model = Mlogb
fields = '__all__'
class MlogSerializer(CustomModelSerializer):
mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True)
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
@ -313,6 +325,7 @@ class MlogSerializer(CustomModelSerializer):
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
mlogdefect = MlogbDefectSerializer(many=True)
class Meta:
model = Mlog
fields = '__all__'
@ -327,6 +340,7 @@ class MlogSerializer(CustomModelSerializer):
def create(self, validated_data):
material_out = validated_data['material_out']
mtask:Mtask = validated_data.get('mtask', None)
mlogdefect = validated_data.pop('mlogdefect', [])
if mtask and mtask.state != Mtask.MTASK_ASSGINED:
raise ParseError('该任务非下达中不可选择')
with transaction.atomic():
@ -380,15 +394,28 @@ class MlogSerializer(CustomModelSerializer):
'mtask': instance.mtask, 'material_out': instance.material_out,
'count_real': instance.count_real,
'count_ok': instance.count_ok, 'count_notok': instance.count_notok,
'count_break_t': instance.count_break_t
'count_break_t': instance.count_break_t,
'qct': instance.qct
}
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
add_dict_2[f.name] = getattr(instance, f.name)
need_mdfect = False
if instance.qct or mlogdefect:
need_mdfect = True
else:
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
add_dict_2[f.name] = getattr(instance, f.name)
ddict = {}
if wm_in:
ddict = {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom}
Mlogb.objects.get_or_create(**add_dict_2, defaults=ddict)
mlogb, _ = Mlogb.objects.get_or_create(**add_dict_2, defaults=ddict)
if need_mdfect:
mlogb_defect_objects = [
MlogbDefect(**{**item, "mlogb": mlogb, "id": idWorker.get_id()})
for item in mlogdefect if item["count"] > 0
]
if mlogb_defect_objects:
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
mlogb.cal_count_notok()
return instance
def update(self, instance, validated_data):
@ -396,6 +423,7 @@ class MlogSerializer(CustomModelSerializer):
raise ParseError('不支持的填写类型')
validated_data.pop('mtask', None)
validated_data.pop('mgroup', None)
mlogdefect = validated_data.pop('mlogdefect', [])
if instance.mtask:
validated_data.pop('handle_date', None)
# validated_data.pop('handle_user', None)
@ -423,6 +451,7 @@ class MlogSerializer(CustomModelSerializer):
minx.count_use = instance.count_use
minx.count_break = instance.count_break
minx.count_pn_jgqbl = instance.count_pn_jgqbl
minx.qct = instance.qct
minx.save()
Mlogb.objects.filter(mlog=instance, material_in__isnull=False).exclude(id=minx.id).delete()
@ -452,11 +481,24 @@ class MlogSerializer(CustomModelSerializer):
if wm_in:
mox.batch_ofrom = wm_in.batch
mox.material_ofrom = wm_in.material_ofrom
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
setattr(mox, f.name, getattr(instance, f.name))
need_mdefect=False
if instance.qct or mlogdefect:
need_mdefect = True
else:
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
setattr(mox, f.name, getattr(instance, f.name))
mox.save()
Mlogb.objects.filter(mlog=instance, material_out__isnull=False).exclude(id=mox.id).delete()
if need_mdefect:
MlogbDefect.objects.filter(mlogb__mlog=instance).delete()
mlogb_defect_objects = [
MlogbDefect(**{**item, "mlogb": mox, "id": idWorker.get_id()})
for item in mlogdefect if item["count"] > 0
]
if mlogb_defect_objects:
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
mox.cal_count_notok()
return instance
def validate(self, attrs):
@ -565,6 +607,8 @@ class MlogInitSerializer(CustomModelSerializer):
raise ParseError('外协必须选择外协单位')
if attrs.get('work_end_time', None):
attrs['handle_date'] = localdate(attrs['work_end_time'])
if attrs["material_out"]:
attrs["qct"] = Qct.get(attrs["material_out"], "process")
return attrs
class MlogChangeSerializer(CustomModelSerializer):
@ -688,45 +732,89 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer):
return mlogbw
class MlogbOutUpdateSerializer(CustomModelSerializer):
mlogbdefect = MlogbDefectSerializer(many=True, required=False)
class Meta:
model = Mlogb
fields = "__all__"
read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out',
'count_use', 'count_break', 'count_pn_jgqbl']
'count_use', 'count_break', 'count_pn_jgqbl', 'mlogbdefect', "qct"]
# def create(self, validated_data):
# material_out:Material = validated_data["material_out"]
# mlogbdefect = validated_data.pop("mlogbdefect", [])
# with transaction.atomic():
# ins = super().create(validated_data)
# if mlogbdefect and material_out.tracking == Material.MA_TRACKING_BATCH:
# count_notok = 0
# mlogbdefect_new = [item for item in mlogbdefect if item["count"] > 0]
# for item in mlogbdefect_new:
# defect:Defect = item["defect"]
# MlogbDefect.objects.create(mlogb=ins, **item)
# if defect.cate == Defect.DEFECT_NOTOK:
# count_notok +=1
# ins.count_notok = count_notok
# ins.count_ok = ins.count_real - ins.count_notok
# ins.save()
# else:
# raise ParseError("mlogbdefect仅支持批次件")
# return ins
@transaction.atomic
def update(self, instance, validated_data):
mlogbdefect = validated_data.pop("mlogbdefect", [])
with transaction.atomic():
ins:Mlogb = super().update(instance, validated_data)
if (ins.qct or mlogbdefect) and ins.material_out.tracking == Material.MA_TRACKING_BATCH:
MlogbDefect.objects.filter(mlogb=ins).delete()
mlogb_defect_objects = [
MlogbDefect(**{**item, "mlogb": ins, "id": idWorker.get_id()})
for item in mlogbdefect if item["count"] > 0
]
if mlogb_defect_objects:
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
ins.cal_count_notok()
return ins
def validate(self, attrs):
count_notok_json = attrs.get('count_notok_json', [])
# count_notok_json字段处理
if count_notok_json:
# 先置0字段
mlogbdefect = attrs.get("mlogbdefect", [])
if mlogbdefect:
attrs.pop("count_notok_json", None)
for i in attrs:
if 'count_n_' in i:
i = 0
count_notok_dict = {}
for item in count_notok_json:
notok = item['notok']
count = item['count']
full_notok = f'count_n_{notok}'
if not hasattr(Mlogb, full_notok):
raise ParseError(f'{notok}-该不合格项不存在')
if full_notok in count_notok_dict:
count_notok_dict[full_notok] = count_notok_dict[full_notok] + count
else:
count_notok_dict[full_notok] = count
for k, v in count_notok_dict.items():
attrs[k] = v
count_notok = 0
for i in attrs:
if 'count_n_' in i:
if not hasattr(Mlogb, i):
raise ParseError(f'{i}不存在')
count_notok = count_notok + attrs[i]
attrs['count_notok'] = count_notok
if attrs['count_real'] >= attrs['count_ok'] + attrs['count_notok']:
pass
attrs.pop(i, None)
else:
raise ParseError('生产数量不能小于合格数量')
count_notok_json = attrs.get('count_notok_json', [])
# count_notok_json字段处理
if count_notok_json:
# 先置0字段
for i in attrs:
if 'count_n_' in i:
i = 0
count_notok_dict = {}
for item in count_notok_json:
notok = item['notok']
count = item['count']
full_notok = f'count_n_{notok}'
if not hasattr(Mlogb, full_notok):
raise ParseError(f'{notok}-该不合格项不存在')
if full_notok in count_notok_dict:
count_notok_dict[full_notok] = count_notok_dict[full_notok] + count
else:
count_notok_dict[full_notok] = count
for k, v in count_notok_dict.items():
attrs[k] = v
count_notok = 0
for i in attrs:
if 'count_n_' in i:
if not hasattr(Mlogb, i):
raise ParseError(f'{i}不存在')
count_notok = count_notok + attrs[i]
attrs['count_notok'] = count_notok
if attrs['count_real'] >= attrs['count_ok'] + attrs['count_notok']:
pass
else:
raise ParseError('生产数量不能小于合格数量')
return attrs
class MlogRevertSerializer(serializers.Serializer):
@ -818,7 +906,7 @@ class HandoverSerializer(CustomModelSerializer):
# raise ParseError(f'第{ind+1}物料与交接部门不一致')
if attrs["material"] != wm.material:
raise ParseError(f'{ind+1}物料与交接物料不一致')
if (wm.notok_sign or wm.defect) and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]:
if wm.state != WMaterial.WM_OK and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]:
raise ParseError(f'{ind+1}物料不合格,不能进行正常/检验交接')
if wm.count_xtest is not None:
raise ParseError(f'{ind+1}物料检验中,不能进行交接')

View File

@ -11,7 +11,7 @@ from apps.system.models import User
from apps.pm.models import Mtask
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw, MlogbDefect
from apps.mtm.services_2 import cal_material_count
from apps.wf.models import Ticket
from apps.utils.thread import MyThread
@ -170,6 +170,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
for mi in m_ins.all():
m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi))
if mi.count_pn_jgqbl > 0:
raise ParseError("暂不支持加工前不良")
m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl, mi))
else:
m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog)]
@ -232,29 +233,34 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
process = mgroup.process
into_wm_mgroup = process.into_wm_mgroup
need_store_notok = process.store_notok
m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
stored_notok = need_store_notok
stored_mgroup = need_store_notok
if m_outs.exists():
m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo) for mo in m_outs.all()]
if mlogb_out_qs.exists():
m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok_full if mo.count_ok_full is not None else mo.count_ok, mlog.count_real_eweight, None, mo) for mo in mlogb_out_qs.all()]
if need_store_notok:
for item in m_outs:
if item.material_out.tracking == Material.MA_TRACKING_SINGLE:
# 获取所有主要的不合格项
bw_qs = Mlogbw.objects.filter(mlogb=item)
defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct()
defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)}
# 过滤并统计相关数据
filtered_bw_qs = bw_qs.filter(
ftest__defect_main__id__in=defects_map.keys()
).values('ftest__defect_main__id').annotate(xcount=Count('id'))
# 整理结果
for defect_data in filtered_bw_qs:
defect_id = defect_data['ftest__defect_main__id']
xcount = defect_data['xcount']
if xcount > 0:
defect = defects_map[defect_id]
m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item))
for item in mlogb_out_qs:
mbd_qs = MlogbDefect.objects.filter(mlogb=item)
if item.qct is not None or mbd_qs.exists():
if item.material_out.tracking == Material.MA_TRACKING_SINGLE:
Mlogbw.cal_count_notok(item)
for itemx in MlogbDefect.objects.filter(mlogb=item):
m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item))
# # 获取所有主要的不合格项/先暂时保留
# bw_qs = Mlogbw.objects.filter(mlogb=item)
# defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct()
# defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)}
# # 过滤并统计相关数据
# filtered_bw_qs = bw_qs.filter(
# ftest__defect_main__id__in=defects_map.keys()
# ).values('ftest__defect_main__id').annotate(xcount=Count('id'))
# # 整理结果
# for defect_data in filtered_bw_qs:
# defect_id = defect_data['ftest__defect_main__id']
# xcount = defect_data['xcount']
# if xcount > 0:
# defect = defects_map[defect_id]
# m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item))
else:
for f in Mlogb._meta.fields:
if 'count_n_' in f.name and getattr(item, f.name) > 0:
@ -274,9 +280,13 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
if process.type == Process.PRO_PROD:
wm_state = WMaterial.WM_REPAIRED # 返修只有返修完成品
elif process.type == Process.PRO_TEST:
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or (
isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B]
) else WMaterial.WM_NOTOK
else:
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or (
isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B]
) else WMaterial.WM_NOTOK
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None,
'notok_sign': None, 'defect': None, 'state': wm_state}
if isinstance(notok_sign_or_defect, Defect):
@ -357,29 +367,35 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
if material_out or is_fix: # 产物退回
# 有多个产物的情况
# 需要考虑不合格品退回的情况
m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
if m_outs.exists():
mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
if mlogb_out_qs.exists():
m_outs_list = [
(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo)
for mo in m_outs.all()]
(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok_full if mo.count_ok_full is not None else mo.count_ok, mlog.count_real_eweight, None, mo)
for mo in mlogb_out_qs.all()]
if stored_notok:
for item in m_outs:
if item.material_out.tracking == Material.MA_TRACKING_SINGLE:
# 获取所有主要的不合格项
bw_qs = Mlogbw.objects.filter(mlogb=item)
defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct()
defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)}
# 过滤并统计相关数据
filtered_bw_qs = bw_qs.filter(
ftest__defect_main__id__in=defects_map.keys()
).values('ftest__defect_main__id').annotate(xcount=Count('id'))
# 整理结果
for defect_data in filtered_bw_qs:
defect_id = defect_data['ftest__defect_main__id']
xcount = defect_data['xcount']
if xcount > 0:
defect = defects_map[defect_id]
m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item))
for item in mlogb_out_qs:
mbd_qs = MlogbDefect.objects.filter(mlogb=item)
if item.qct is not None or mbd_qs.exists():
if item.material_out.tracking == Material.MA_TRACKING_SINGLE:
Mlogbw.cal_count_notok(item)
for itemx in MlogbDefect.objects.filter(mlogb=item):
m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item))
# if item.material_out.tracking == Material.MA_TRACKING_SINGLE:
# # 获取所有主要的不合格项
# bw_qs = Mlogbw.objects.filter(mlogb=item)
# defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct()
# defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)}
# # 过滤并统计相关数据
# filtered_bw_qs = bw_qs.filter(
# ftest__defect_main__id__in=defects_map.keys()
# ).values('ftest__defect_main__id').annotate(xcount=Count('id'))
# # 整理结果
# for defect_data in filtered_bw_qs:
# defect_id = defect_data['ftest__defect_main__id']
# xcount = defect_data['xcount']
# if xcount > 0:
# defect = defects_map[defect_id]
# m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item))
else:
for f in Mlogb._meta.fields:
if 'count_n_' in f.name and getattr(item, f.name) > 0:
@ -398,9 +414,13 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
if process.type == Process.PRO_PROD:
wm_state = WMaterial.WM_REPAIRED
else: # 检验工序正常生成
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or (
isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B]
) else WMaterial.WM_NOTOK
else:
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or (
isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B]
) else WMaterial.WM_NOTOK
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': None, 'defect': None, 'state': wm_state}
if isinstance(notok_sign_or_defect, Defect):
lookup['defect'] = notok_sign_or_defect
@ -446,6 +466,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
for mi in m_ins.all():
m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in, mi))
if mi.count_pn_jgqbl > 0:
raise ParseError("暂不支持加工前不良")
m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl, mi))
else:
m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in, mlog)]

View File

@ -31,7 +31,7 @@ def get_alldata_with_batch_gx(batch: str):
"""
光芯获取batch的统计数据
"""
pass
return None, None
def get_alldata_with_batch(batch: str):
"""
@ -74,7 +74,10 @@ def get_alldata_with_batch(batch: str):
data["棒料成型_出料人"] = ";".join([item.name for item in data["棒料成型_出料人"]])
data["棒料成型_切料人"] = list(set(data["棒料成型_切料人"]))
data["棒料成型_切料人"] = ";".join([item.name for item in data["棒料成型_切料人"]])
data["棒料成型_合格率"] = round((data["棒料成型_count_ok"] * 100/ data["棒料成型_count_real"]), 1)
try:
data["棒料成型_合格率"] = round((data["棒料成型_count_ok"] * 100/ data["棒料成型_count_real"]), 1)
except ZeroDivisionError:
data["棒料成型_合格率"] = 0
# 管料成型数据
mgroup_glcx = Mgroup.objects.get(name="管料成型")
@ -126,7 +129,8 @@ def get_alldata_with_batch(batch: str):
data["七车间入库_车间执行人"] = list(set(data["七车间入库_车间执行人"]))
data["七车间入库_车间执行人"] = ";".join([item.name for item in data["七车间入库_车间执行人"]])
data["七车间入库_仓库执行人"] = list(set(data["七车间入库_仓库执行人"]))
data["七车间入库_仓库执行人"].remove(None)
if None in data["七车间入库_仓库执行人"]:
data["七车间入库_仓库执行人"].remove(None)
data["七车间入库_仓库执行人"] = ";".join([item.name for item in data["七车间入库_仓库执行人"]])
# 十车间入库检验

View File

@ -16,7 +16,7 @@ from apps.utils.mixins import CustomListModelMixin, BulkCreateModelMixin, BulkDe
from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter
from .models import (SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb,
Mlogbw, AttLog, OtherLog, Fmlog, BatchSt)
Mlogbw, AttLog, OtherLog, Fmlog, BatchSt, MlogbDefect)
from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer,
MlogRevertSerializer,
MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer,
@ -30,10 +30,11 @@ from .services import mlog_submit, handover_submit, mlog_revert
from apps.wpm.services import mlog_submit_validate, generate_new_batch
from apps.wf.models import State
from apps.wpmw.models import Wpr
from apps.qm.models import QctMat, Ftest
from apps.qm.models import Qct, Ftest, TestItem
from apps.enm.models import EnStat
from django.db.models import Q
from apps.utils.tools import convert_ordereddict
from django.db.models import Count
# Create your views here.
@ -180,7 +181,20 @@ class MlogViewSet(CustomModelViewSet):
'material_in__number', 'material_in__specification', 'batch', 'material_in__model',
'material_out__name', 'material_out__number', 'material_out__specification', 'material_out__model',]
def add_info_for_item(self, data):
if data.get("oinfo_json", {}):
czx_dict = dict(TestItem.objects.filter(id__in=data.get("oinfo_json", {}).keys()).values_list('id', 'name'))
data["oinfo_json_"] = {czx_dict.get(k, k): v for k, v in data.get("oinfo_json", {}).items()}
return data
def add_info_for_list(self, data):
czx_dict = {}
for item in data:
czx_dict.update(item.get("oinfo_json", {}))
czx_dict = dict(TestItem.objects.filter(id__in=czx_dict.keys()).values_list('id', 'name'))
for item in data:
if item.get("oinfo_json", None):
item["oinfo_json_"] = {czx_dict.get(k, k): v for k, v in item.get("oinfo_json", {}).items()}
if self.request.query_params.get('with_mlogb', False):
data_dict = {item['id']: {**item, "mlogb_full": [], "mlogb": []} for item in data}
mlogb_qs = Mlogb.objects.filter(mlog__id__in=data_dict.keys()).select_related("material_in", "material_out").order_by("create_time")
@ -191,7 +205,7 @@ class MlogViewSet(CustomModelViewSet):
data_dict[item_dict["mlog"]]["mlogb_full"].append(item_dict)
if item.get("material_out", None):
data_dict[item_dict["mlog"]]["mlogb"].append(item_dict)
return list(data_dict.values())
data = list(data_dict.values())
return data
@transaction.atomic
@ -591,13 +605,14 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
d_count_real = mlogbin.count_use
d_count_ok = mlogbin.count_use
# 找寻质检表
if material_out.tracking == Material.MA_TRACKING_SINGLE:
if is_fix and mgroup.process.type == Process.PRO_PROD:
# 如果是生产返修,则忽略质检
pass
else:
qctmat = QctMat.objects.filter(material=material_out, qct__is_deleted=False).order_by("-create_time").first()
mlogbout.qct = qctmat.qct if qctmat else None
if is_fix and mgroup.process.type == Process.PRO_PROD:
# 如果是生产返修,则忽略质检
pass
elif mlogbout.qct is None:
mlogbout.qct = Qct.get(mlogbout.material_out, "process") if mlog.qct is None else mlog.qct
if mlogbout.qct is not None and mlog.qct is None:
mlog.qct = mlogbout.qct
mlog.save(update_fields=["qct"])
mlogbout.count_real = d_count_real
mlogbout.count_ok = d_count_ok
mlogbout.save()
@ -671,23 +686,12 @@ class MlogbwViewSet(CustomModelViewSet):
raise ParseError('请指定所属消耗/产出明细')
return super().filter_queryset(queryset)
def cal_mlogb_count(self, mlogb):
count = Mlogbw.objects.filter(mlogb=mlogb).count()
# 此处先不管检验问题
if mlogb.material_in:
mlogb.count_use = count
elif mlogb.material_out:
mlogb.count_real = count
mlogb.count_notok = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).count()
mlogb.count_ok = count - mlogb.count_notok
mlogb.save()
@transaction.atomic
def perform_create(self, serializer):
ins:Mlogbw = serializer.save()
route:Route = ins.mlogb.mlog.route
mlogb:Mlogb = ins.mlogb
self.cal_mlogb_count(mlogb)
Mlogbw.cal_count_notok(mlogb)
# 如果是输入且输出追踪到个,需同步创建
material_in:Material = mlogb.material_in
if material_in is not None:
@ -704,7 +708,7 @@ class MlogbwViewSet(CustomModelViewSet):
@transaction.atomic
def perform_update(self, serializer):
mlogbw = serializer.save()
self.cal_mlogb_count(mlogbw.mlogb)
Mlogbw.cal_count_notok(mlogbw.mlogb)
@transaction.atomic
def perform_destroy(self, instance:Mlogbw):
@ -725,4 +729,4 @@ class MlogbwViewSet(CustomModelViewSet):
mbws = Mlogbw.objects.filter(Q(wpr=instance.wpr)|Q(number__contains=instance.number), mlogb=mlogb_to)
Ftest.objects.filter(id__in=mbws.values_list('ftest__id', flat=True)).delete()
mbws.delete()
self.cal_mlogb_count(mlogb_to)
Mlogbw.cal_count_notok(mlogb)