diff --git a/apps/mtm/models.py b/apps/mtm/models.py index b3bae42b..b0788df6 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -229,7 +229,7 @@ class Mgroup(CommonBModel): # 如果当前时间在结束时间之前,属于前一天 else: return (w_s_time - timedelta(days=1)).date(), shift - # return w_s_time.date(), None + raise ParseError(f"工段{self.name}的班次规则未覆盖时间点{w_s_time.strftime('%H:%M:%S')}") class TeamMember(BaseModel): diff --git a/apps/rem/__init__.py b/apps/rem/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/rem/admin.py b/apps/rem/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/rem/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/rem/apps.py b/apps/rem/apps.py new file mode 100644 index 00000000..00b8212e --- /dev/null +++ b/apps/rem/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class RemConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.rem' diff --git a/apps/rem/migrations/0001_initial.py b/apps/rem/migrations/0001_initial.py new file mode 100644 index 00000000..9792300a --- /dev/null +++ b/apps/rem/migrations/0001_initial.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.12 on 2026-01-06 01:49 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('system', '0006_auto_20241213_1249'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Project', + 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='删除标记')), + ('name', models.TextField(verbose_name='项目名称')), + ('description', models.TextField(verbose_name='项目介绍')), + ('start_date', models.DateField(verbose_name='开始日期')), + ('end_date', models.DateField(verbose_name='结束日期')), + ('participants', models.TextField(blank=True, null=True, verbose_name='项目成员')), + ('note', models.TextField(blank=True, null=True, verbose_name='备注')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='project_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('files', models.ManyToManyField(blank=True, to='system.File', verbose_name='附件')), + ('leader', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='项目负责人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='project_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/rem/migrations/__init__.py b/apps/rem/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/rem/models.py b/apps/rem/models.py new file mode 100644 index 00000000..05b218ad --- /dev/null +++ b/apps/rem/models.py @@ -0,0 +1,15 @@ +from django.db import models +from apps.utils.models import CommonADModel +from apps.system.models import User, File +# Create your models here. + +class Project(CommonADModel): + name = models.TextField("项目名称") + description = models.TextField("项目介绍") + start_date = models.DateField("开始日期") + end_date = models.DateField("结束日期") + leader = models.ForeignKey(User, verbose_name="项目负责人", on_delete=models.CASCADE) + participants = models.TextField("项目成员", blank=True, null=True) + files = models.ManyToManyField(File, verbose_name="附件", blank=True) + note = models.TextField("备注", blank=True, null=True) + \ No newline at end of file diff --git a/apps/rem/serializers.py b/apps/rem/serializers.py new file mode 100644 index 00000000..8052891c --- /dev/null +++ b/apps/rem/serializers.py @@ -0,0 +1,17 @@ +from apps.rem.models import Project +from apps.utils.serializers import CustomModelSerializer +from apps.system.serializers import FileSerializer +from rest_framework import serializers + + +class ProjectSerializer(CustomModelSerializer): + leader_name = serializers.CharField(source="leader.name", read_only=True) + files_ = FileSerializer(source="files", many=True, read_only=True) + class Meta: + model = Project + fields = '__all__' + +class ProjectUpdateSerializer(CustomModelSerializer): + class Meta: + model = Project + fields = ["id", "participants", "files", "note"] \ No newline at end of file diff --git a/apps/rem/tests.py b/apps/rem/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/rem/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/rem/urls.py b/apps/rem/urls.py new file mode 100644 index 00000000..24393a13 --- /dev/null +++ b/apps/rem/urls.py @@ -0,0 +1,12 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from .views import ProjectViewSet + +API_BASE_URL = 'api/rem/' +HTML_BASE_URL = 'dhtml/rem/' + +router = DefaultRouter() +router.register('project', ProjectViewSet, basename='research_project') +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] \ No newline at end of file diff --git a/apps/rem/views.py b/apps/rem/views.py new file mode 100644 index 00000000..1bda3639 --- /dev/null +++ b/apps/rem/views.py @@ -0,0 +1,12 @@ +from django.shortcuts import render +from apps.utils.viewsets import CustomModelViewSet +from apps.rem.models import Project +from apps.rem.serializers import ProjectSerializer, ProjectUpdateSerializer +# Create your views here. + +class ProjectViewSet(CustomModelViewSet): + queryset = Project.objects.all() + serializer_class = ProjectSerializer + update_serializer_class = ProjectUpdateSerializer + select_related_fields = ['leader'] + search_fields = ["name", "description", "leader__name"] \ No newline at end of file diff --git a/apps/wpm/scripts/batch_gxerp.py b/apps/wpm/scripts/batch_gxerp.py index 8758d880..b5e15356 100644 --- a/apps/wpm/scripts/batch_gxerp.py +++ b/apps/wpm/scripts/batch_gxerp.py @@ -1,6 +1,6 @@ from apps.wpm.models import BatchSt import logging -from apps.qm.models import Defect +from apps.qm.models import Defect, FtestWork, FtestworkDefect from apps.wpm.models import Mlogb, MlogbDefect from apps.mtm.models import Mgroup import decimal @@ -117,24 +117,53 @@ def main(batch: str, mgroup_obj): data[f"外观检验_返修_缺陷_{item['defect__name']}"] = item["total"] data[f"外观检验_返修_缺陷_{item['defect__name']}_比例"] = round((item["total"] / data["外观检验_返修_count_real"])*100, 2) + # 车间库存抽检 + ft_qs = FtestWork.objects.filter(type2=FtestWork.TYPE2_SOME, wm__mgroup__name="外观检验", batch=batch, submit_time__isnull=False) + if ft_qs.exists(): + data["外观检验_车间库存抽检_日期"] = [] + data["外观检验_车间库存抽检_操作人"] = [] + data["外观检验_车间库存抽检_count_notok"] = 0 + for item in ft_qs: + if item.test_user: + data["外观检验_车间库存抽检_操作人"].append(item.test_user) + if item.test_date: + data["外观检验_车间库存抽检_日期"].append(item.test_date) + data["外观检验_车间库存抽检_count_notok"] += item.count_notok if item.count_notok else 0 + + data["外观检验_车间库存抽检_日期"] = list(set(data["外观检验_车间库存抽检_日期"])) + data["外观检验_车间库存抽检_日期"] = ";".join([item.strftime("%Y-%m-%d") for item in data["外观检验_车间库存抽检_日期"]]) + data["外观检验_车间库存抽检_操作人"] = list(set(data["外观检验_车间库存抽检_操作人"])) + data["外观检验_车间库存抽检_操作人"] = ";".join([item.name for item in data["外观检验_车间库存抽检_操作人"]]) + + # 车间库存抽检缺陷 + ftd_qs = FtestworkDefect.objects.filter(ftestwork__in=ft_qs, count__gt=0).values("defect__name").annotate(total=Sum("count")) + for item in ftd_qs: + data[f"外观检验_车间库存抽检_缺陷_{item['defect__name']}"] = item["total"] + if "外观检验_count_ok" in data: - data["外观检验_总合格数"] = data["外观检验_count_ok"] + data["外观检验_返修_count_ok"] if "外观检验_返修_count_ok" in data else 0 + data["外观检验_总合格数"] = data["外观检验_count_ok"] + data.get("外观检验_返修_count_ok", 0) try: data["外观检验_总合格率"] = round((data["外观检验_总合格数"] / data["外观检验_count_real"])*100, 2) except decimal.InvalidOperation: data["外观检验_总合格率"] = 0 - data["外观检验_完全总合格数"] = data["外观检验_count_ok_full"] + data["外观检验_返修_count_ok_full"] if "外观检验_返修_count_ok_full" in data else 0 + data["外观检验_完全总合格数"] = data["外观检验_count_ok_full"] + data.get("外观检验_返修_count_ok_full", 0) try: data["外观检验_完全总合格率"] = round((data["外观检验_完全总合格数"] / data["外观检验_count_real"])*100, 2) except decimal.InvalidOperation: data["外观检验_完全总合格率"] = 0 + data["外观检验_直通合格数"] = data["外观检验_总合格数"] - data.get("外观检验_车间库存抽检_count_notok", 0) if "尺寸检验_合格率" in data: try: data["外观检验_直通合格率"] = round((data["外观检验_总合格率"]* data["尺寸检验_合格率"])/100, 2) except decimal.InvalidOperation: data["外观检验_直通合格率"] = 0 + + try: + data["外观检验_直通合格率2"] = round((data["外观检验_直通合格数"]/data["尺寸检验_count_use"])*100, 2) + except (decimal.InvalidOperation, ZeroDivisionError): + data["外观检验_直通合格率2"] = 0 if "尺寸检验_完全合格率" in data: try: diff --git a/apps/wpmw/views.py b/apps/wpmw/views.py index 5aaa1eac..e99d2473 100644 --- a/apps/wpmw/views.py +++ b/apps/wpmw/views.py @@ -30,8 +30,8 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu 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", []), + "number_prefix": RawSQL("regexp_replace(wpmw_wpr.number, '(\\d+)$', '')", []), + "number_suffix": RawSQL("COALESCE(NULLIF(regexp_replace(wpmw_wpr.number, '.*?(\\d+)$', '\\1'), ''), '0')::bigint", []), } def filter_queryset(self, queryset): diff --git a/server/settings.py b/server/settings.py index b6b8b02e..a1ee9235 100755 --- a/server/settings.py +++ b/server/settings.py @@ -88,6 +88,7 @@ INSTALLED_APPS = [ 'apps.ofm', 'apps.srm', 'apps.asm', + 'apps.rem' ] MIDDLEWARE = [ diff --git a/server/urls.py b/server/urls.py index d83709ff..431852a8 100755 --- a/server/urls.py +++ b/server/urls.py @@ -78,6 +78,7 @@ urlpatterns = [ path('', include('apps.ofm.urls')), path('', include('apps.srm.urls')), path('', include('apps.asm.urls')), + path('', include('apps.rem.urls')), # 前端页面入口 path('', TemplateView.as_view(template_name="index.html")),