diff --git a/apps/mtm/filters.py b/apps/mtm/filters.py index 138b48de..08d67141 100644 --- a/apps/mtm/filters.py +++ b/apps/mtm/filters.py @@ -2,13 +2,11 @@ from django_filters import rest_framework as filters from apps.mtm.models import Goal, Material, Route, RoutePack from django.db.models.expressions import F from rest_framework.exceptions import ParseError - +from django.db.models import Sum, Q, Value, F, ExpressionWrapper, DecimalField +from django.db.models.functions import Coalesce class MaterialFilter(filters.FilterSet): tag = filters.CharFilter(method='filter_tag', label="low_inm:库存不足") - count__gt = filters.NumberFilter(field_name='count', lookup_expr='gt') - count_mb__gt = filters.NumberFilter(field_name='count_mb', lookup_expr='gt') - count_wm__gt = filters.NumberFilter(field_name='count_wm', lookup_expr='gt') class Meta: model = Material @@ -30,7 +28,7 @@ class MaterialFilter(filters.FilterSet): def filter_tag(self, queryset, name, value): if value == 'low_inm': - queryset = queryset.exclude(count_safe=None).exclude(count_safe__lte=0).filter( + queryset = Material.annotate_count(queryset.exclude(count_safe=None).exclude(count_safe__lte=0)).filter( count__lte=F('count_safe')) return queryset diff --git a/apps/mtm/models.py b/apps/mtm/models.py index c81b87ed..8746b87d 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -6,6 +6,8 @@ from collections import defaultdict, deque from django.db.models import Q from datetime import datetime, timedelta from django.utils import timezone +from django.db.models import Sum, Q, Value, F, ExpressionWrapper, DecimalField +from django.db.models.functions import Coalesce class Process(CommonBModel): """ @@ -123,7 +125,26 @@ class Material(CommonAModel): def fname(self): return f'{self.name}|{self.specification if self.specification else ""}|{self.model if self.model else ""}|{self.process.name if self.process else ""}' - + @staticmethod + def annotate_count(qs): + return qs.annotate( + count_mb=Coalesce( + Sum('mb_m__count', filter=Q(mb_m__state=10, mb_m__count__gt=0)), + Value(0), + output_field=DecimalField() + ), + count_wm=Coalesce( + Sum('wm_m__count', filter=Q(wm_m__state=10, wm_m__count__gt=0)), + Value(0), + output_field=DecimalField() + ) + ).annotate( + count=ExpressionWrapper( + F('count_wm') + F('count_mb'), + output_field=DecimalField() + ) + ) + class Shift(CommonBModel): """TN:班次 """ diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index db0877e3..f7ccf8d8 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -38,13 +38,15 @@ class MaterialSerializer(CustomModelSerializer): count = serializers.SerializerMethodField() def get_count_mb(self, obj): - return getattr(obj, 'count_mb', 0) + return getattr(obj, 'count_mb', None) def get_count_wm(self, obj): - return getattr(obj, 'count_wm', 0) + return getattr(obj, 'count_wm', None) def get_count(self, obj): - return getattr(obj, 'count_mb', 0) + getattr(obj, 'count_wm', 0) + if hasattr(obj, 'count_mb') and hasattr(obj, 'count_wm'): + return getattr(obj, 'count_mb', 0) + getattr(obj, 'count_wm', 0) + return None class Meta: model = Material diff --git a/apps/mtm/views.py b/apps/mtm/views.py index e958e01b..27632473 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -44,24 +44,8 @@ class MaterialViewSet(CustomModelViewSet): def get_queryset(self): qs = super().get_queryset() - if self.action in ["list", "retrieve"]: - return qs.annotate( - count_mb=Coalesce( - Sum('mb_m__count', filter=Q(mb_m__state=10)), - Value(0), - output_field=DecimalField() - ), - count_wm=Coalesce( - Sum('wm_m__count', filter=Q(wm_m__state=10)), - Value(0), - output_field=DecimalField() - ) - ).annotate( - count=ExpressionWrapper( - F('count_wm') + F('count_mb'), - output_field=DecimalField() - ) - ) + if self.action in ["list", "retrieve"] and self.request.query_params.get('wiith_count', None) == 'yes': + return Material.annotate_count(qs) return qs def perform_destroy(self, instance): diff --git a/apps/pum/serializers.py b/apps/pum/serializers.py index a9058785..675c9b7b 100644 --- a/apps/pum/serializers.py +++ b/apps/pum/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from apps.utils.serializers import CustomModelSerializer from apps.utils.constants import EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS -from rest_framework.exceptions import ValidationError +from rest_framework.exceptions import ValidationError, ParseError from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem, SupplierAudit from apps.mtm.serializers import MaterialSerializer, MaterialSimpleSerializer @@ -151,4 +151,10 @@ class SupplierAuditSerializer(CustomModelSerializer): class Meta: model = SupplierAudit fields = "__all__" - read_only_fields = EXCLUDE_FIELDS_BASE + ['ticket'] \ No newline at end of file + read_only_fields = EXCLUDE_FIELDS_BASE + ['ticket'] + + def create(self, validated_data): + name = validated_data["name"] + if Supplier.objects.filter(name=name).exists(): + raise ParseError('供应商名称已存在') + return super().create(validated_data) \ No newline at end of file diff --git a/apps/pum/views.py b/apps/pum/views.py index 2a48665b..37793033 100644 --- a/apps/pum/views.py +++ b/apps/pum/views.py @@ -12,6 +12,7 @@ from rest_framework.response import Response from django.utils import timezone from apps.pum.services import PumService from apps.wf.mixins import TicketMixin +from apps.wf.models import Ticket # Create your views here. @@ -42,6 +43,13 @@ class SupplierAuditViewSet(TicketMixin, CustomModelViewSet): search_fields = ['name', 'material_name', 'material_cate'] workflow_key = "wf_supplieraudit" + @staticmethod + def add_supplier(ticket: Ticket, transition, new_ticket_data: dict): + supplieraudit = SupplierAudit.objects.get(ticket=ticket) + if Supplier.objects.filter(name=supplieraudit.name).exists(): + raise ParseError('供应商名称已存在') + Supplier.objects.create(name=supplieraudit.name) + class PuPlanViewSet(CustomModelViewSet): """ list: 采购计划 diff --git a/apps/qm/migrations/0055_alter_ftestitem_ftest.py b/apps/qm/migrations/0055_alter_ftestitem_ftest.py new file mode 100644 index 00000000..e10e0194 --- /dev/null +++ b/apps/qm/migrations/0055_alter_ftestitem_ftest.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.12 on 2025-11-26 01:53 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0054_alter_ptest_val_xj'), + ] + + operations = [ + migrations.AlterField( + model_name='ftestitem', + name='ftest', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items_ftest', to='qm.ftest', verbose_name='关联检验'), + ), + ] diff --git a/apps/wf/serializers.py b/apps/wf/serializers.py index 58e4b8d9..a81e7361 100755 --- a/apps/wf/serializers.py +++ b/apps/wf/serializers.py @@ -94,7 +94,7 @@ class TicketSimpleSerializer(CustomModelSerializer): class TicketCreateSerializer(CustomModelSerializer): - transition = serializers.PrimaryKeyRelatedField(queryset=Transition.objects.all(), write_only=True) + transition = serializers.PrimaryKeyRelatedField(queryset=Transition.objects.all(), write_only=True, allow_null=True) title = serializers.CharField(allow_blank=True, required=False) class Meta: diff --git a/apps/wpm/migrations/0125_auto_20251126_0953.py b/apps/wpm/migrations/0125_auto_20251126_0953.py new file mode 100644 index 00000000..6539cab9 --- /dev/null +++ b/apps/wpm/migrations/0125_auto_20251126_0953.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.12 on 2025-11-26 01:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0124_auto_20251020_1009'), + ] + + operations = [ + migrations.AlterField( + model_name='mlogbw', + name='number', + field=models.TextField(db_index=True, verbose_name='单个编号'), + ), + migrations.AddIndex( + model_name='mlogb', + index=models.Index(condition=models.Q(('material_out__isnull', False)), fields=['material_out'], name='mlogb_mat_out_not_null'), + ), + migrations.AddIndex( + model_name='mlogb', + index=models.Index(condition=models.Q(('material_in__isnull', False)), fields=['material_in'], name='mlogb_mat_in_not_null'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index a5b905df..56460adb 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -441,6 +441,20 @@ class Mlogb(BaseModel): need_inout = models.BooleanField('是否需要出入库', default=True) number_from = models.TextField('来源个编号', null=True, blank=True) + class Meta: + indexes = [ + models.Index( + fields=["material_out"], + name="mlogb_mat_out_not_null", + condition=Q(material_out__isnull=False), + ), + models.Index( + fields=["material_in"], + name="mlogb_mat_in_not_null", + condition=Q(material_in__isnull=False), + ), + ] + def get_tracking(self): if self.material_in: @@ -502,7 +516,7 @@ class MlogbDefect(BaseModel): class Mlogbw(BaseModel): """TN: 单个产品生产/检验日志 """ - number = models.TextField('单个编号') + number = models.TextField('单个编号', db_index=True) mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE, related_name="w_mlogb") mlogbw_from = models.ForeignKey("self", verbose_name='来源个', on_delete=models.CASCADE, null=True, blank=True, related_name="w_mlogbw_from") wpr = models.ForeignKey("wpmw.wpr", verbose_name='关联产品', on_delete=models.SET_NULL diff --git a/apps/wpmw/migrations/0009_alter_wpr_number.py b/apps/wpmw/migrations/0009_alter_wpr_number.py new file mode 100644 index 00000000..033dc7e0 --- /dev/null +++ b/apps/wpmw/migrations/0009_alter_wpr_number.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2025-11-26 01:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpmw', '0008_wpr_data'), + ] + + operations = [ + migrations.AlterField( + model_name='wpr', + name='number', + field=models.CharField(blank=True, db_index=True, max_length=50, null=True, verbose_name='编号'), + ), + ] diff --git a/apps/wpmw/models.py b/apps/wpmw/models.py index af092087..8478da90 100644 --- a/apps/wpmw/models.py +++ b/apps/wpmw/models.py @@ -16,7 +16,7 @@ class Wpr(BaseModel): TN: 动态产品 """ - number = models.CharField("编号", max_length=50, null=True, blank=True) + number = models.CharField("编号", max_length=50, null=True, blank=True, db_index=True) number_out = models.CharField("对外编号", max_length=50, null=True, blank=True, unique=True) version = models.PositiveIntegerField("版本号", default=9999) state = models.PositiveSmallIntegerField('状态', default=10, choices=WmStateOption.choices) diff --git a/changelog.md b/changelog.md index 2ff4afd8..536b772e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,90 @@ +## 3.0.2025120109 +- feat: 新增功能 + - 供应商审核通过后即可添加供应商 [caoqianming] + - 校验SupplierAudit供应商名称已存在 [caoqianming] + - material list 如需获取库存数据需指定传参 [caoqianming] + - 添加部分索引 [caoqianming] + - srm -model-Papersecret 增加 organization 申请部门字段 [TianyangZhang] + - 优化mlogbw list接口速度 [caoqianming] + - srm-patent修改字段类型 [TianyangZhang] + - resignation添加ticketrelate_name [caoqianming] + - base get_object加锁时注意is_deleted过滤采用base_manager [caoqianming] + - base wf 调用方法支持静态方法 [caoqianming] + - mlogbw关于wpr的校验修改以支持手动新增 [caoqianming] + - resignatioin提交时调用的方法 [caoqianming] + - ResignationSerializer create bug [caoqianming] + - base ticketmixin添加ticket_auto_submit_on_create [caoqianming] + - resignation添加ticketMixin [caoqianming] + - base wfmixin 修改时校验 [caoqianming] + - base ticketDetail添加create_by_name [caoqianming] + - 短信发送功能未开启 [caoqianming] + - 批次号格式错误的校验 [caoqianming] + - mioitemcreate时接收count_send [caoqianming] + - mioitemw增加筛选条件 [caoqianming] + - wpr_bxerp优化mlogbw的获取 [caoqianming] + - do_out报错更明确 [caoqianming] + - 优化ana batchwork [caoqianming] + - 改版交接支持new_wm [caoqianming] + - ofm-models borrowRecord 增加借阅数量 [TianyangZhang] + - ofm-models fix bug [TianyangZhang] + - feat : ofm -vehicle fix bug [TianyangZhang] + - ofm 修改车辆model 字段 [TianyangZhang] + - ofm-service fix bug [TianyangZhang] + - feat:ofm-service 修改 bug [TianyangZhang] + - ofm -修改 view 字段 [TianyangZhang] + - ofm 修改 ofm 字段 并重新生成迁移文件 [TianyangZhang] + - base workflow添加分类字段 [caoqianming] + - ofm-views 修改 车辆字段 [TianyangZhang] + - ofm-vehicle 修改车辆审批申请 改完按时间段进行选择 [TianyangZhang] + - mioitem添加count_send字段 [caoqianming] + - 校验改版时选择的改版物料 [caoqianming] + - 导入物料明细支持直接从名称等匹配 [caoqianming] + - 增强新批次号校验 [caoqianming] + - 提供修改编号的接口 [caoqianming] + - supplieraudit采用新工作流挂载方式 [caoqianming] + - base 添加ticketmixin可集成到viewset下以支持工作流 [caoqianming] + - base 可跳过短信发送 [caoqianming] + - 反向操作时忽略明细校验 [caoqianming] + - 拦截new_batch的错误 [caoqianming] + - fix 修改 srm 的 views [TianyangZhang] + - base wfservice创建出工单时处理人为提交人 [caoqianming] + - feat:srm fix serializer [TianyangZhang] + - base handle_ticket 完善transition校验 [caoqianming] + - DatasetRecord添加filter [caoqianming] + - handover添加selectfield [caoqianming] + - 交接记录返回material_changed_fname [caoqianming] + - 改版交接必须为合批操作 [caoqianming] + - fix srm serializer [TianyangZhang] + - srm-service 去掉 platform belong_dept [TianyangZhang] + - add new model platform '平台审批' [TianyangZhang] + - base 创建数据时检验不包含id [caoqianming] + - 添加供应商审核 [caoqianming] + - base 开始编写ticketMixin可自动挂载 [caoqianming] + - ResignationSerializer返回employee_id_number [caoqianming] + - base 添加EuModelViewSet [caoqianming] + - 离职申请支持删除 [caoqianming] + - Resignationserializer返回employee_name [caoqianming] + - base handle_ticket 默认参数 [caoqianming] + - 优化bind_resignation [caoqianming] + - base 优化wf create [caoqianming] + - ResignationViewSet添加RetrieveModelMixin [caoqianming] + - bind_resignation bug [caoqianming] + - 返回TicketSimpleSerializer [caoqianming] +- fix: 问题修复 + - fix : srm 修改 paperrecord 字段 cor_author 字段类型 [TianyangZhang] + - fix:srm 修改论文审批 反存 论文台账 主要修改model 字段类型 [TianyangZhang] + - srm 修改专利台账 [TianyangZhang] + - base wfmixin gen_ticket_data保存t_id转为str [caoqianming] + - fix : 修改ofm -views -vehicle && services [TianyangZhang] + - format_json_with_placeholders 处理decimal [caoqianming] + - base wf工作流分类接口detail错误 [caoqianming] + - do_in 可直接取用wm [caoqianming] + - material get_queryset忘记return qs [caoqianming] + - material增加count__gt等查询条件 [caoqianming] + - mioitem create时校验是否混批的bug [caoqianming] + - base handle_ticket处理ticket_title [caoqianming] + - bind_resignation bug [caoqianming] + - clean_data关于material的处理 [caoqianming] ## 3.0.2025110710 - feat: 新增功能 - material count字段完全由计算可得 [caoqianming] diff --git a/server/settings.py b/server/settings.py index 9156c344..b3b51179 100755 --- a/server/settings.py +++ b/server/settings.py @@ -35,7 +35,7 @@ sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) ALLOWED_HOSTS = ['*'] SYS_NAME = '星途工厂综合管理系统' -SYS_VERSION = '3.0.2025110710' +SYS_VERSION = '3.0.2025120109' X_FRAME_OPTIONS = 'SAMEORIGIN' # Application definition