From c8beedbceeb2ae301738ec42fc46fe2821a31c58 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 28 Nov 2023 14:57:19 +0800 Subject: [PATCH 01/43] =?UTF-8?q?feat:=20=E8=AE=A2=E5=8D=95=E9=9D=9E?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=B8=AD=E4=B8=8D=E5=8F=AF=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sam/views.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/sam/views.py b/apps/sam/views.py index e10abdc9..e7cab13e 100644 --- a/apps/sam/views.py +++ b/apps/sam/views.py @@ -60,6 +60,13 @@ class OrderViewSet(CustomModelViewSet): search_fields = ['number'] filter_fields = ['contract', 'customer'] + @transaction.atomic + def perform_destroy(self, instance): + order = instance.order + if order.state != Order.ORDER_CREATE: + raise ParseError('订单非创建中不可删除') + instance.delete() + @action(methods=['post'], detail=True, perms_map={'post': 'order.update'}, serializer_class=serializers.Serializer) @transaction.atomic def submit(self, request, *args, **kwargs): From 3ca0a3b5337401fe9eab90bb95e9539816c7506e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 28 Nov 2023 15:32:10 +0800 Subject: [PATCH 02/43] =?UTF-8?q?feat:=20equipment=20description=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=8F=AF=E4=B8=8D=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0009_alter_equipment_description.py | 18 ++++++++++++++++++ apps/em/models.py | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 apps/em/migrations/0009_alter_equipment_description.py diff --git a/apps/em/migrations/0009_alter_equipment_description.py b/apps/em/migrations/0009_alter_equipment_description.py new file mode 100644 index 00000000..90f4b9de --- /dev/null +++ b/apps/em/migrations/0009_alter_equipment_description.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2023-11-28 07:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('em', '0008_equipment_accuracy_level'), + ] + + operations = [ + migrations.AlterField( + model_name='equipment', + name='description', + field=models.CharField(blank=True, default='', max_length=200, verbose_name='描述'), + ), + ] diff --git a/apps/em/models.py b/apps/em/models.py index 27e3c1f6..df22f117 100644 --- a/apps/em/models.py +++ b/apps/em/models.py @@ -62,7 +62,8 @@ class Equipment(CommonBModel): count = models.PositiveIntegerField('数量', default=1) keeper = models.ForeignKey( User, verbose_name='责任人', on_delete=models.CASCADE, null=True, blank=True) - description = models.CharField('描述', max_length=200, default='', null=True) + description = models.CharField( + '描述', max_length=200, default='', blank=True) # 以下是计量检测设备单独字段 # mgmtype = models.IntegerField('管理类别', choices=mgmtype_choices, default=1) From 429c0b6d5b882f1e5289f3a32e0172b428249a23 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 29 Nov 2023 09:47:25 +0800 Subject: [PATCH 03/43] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0route=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/filters.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/mtm/filters.py b/apps/mtm/filters.py index ef51633a..7f753bdc 100644 --- a/apps/mtm/filters.py +++ b/apps/mtm/filters.py @@ -48,4 +48,6 @@ class RouteFilter(filters.FilterSet): "process": ["exact", "in"], "is_autotask": ["exact"], "mgroup": ["exact", "in", "isnull"], + "mgroup__name": ["exact", "contains"], + "mgroup__belong_dept__name": ["exact", "contains"] } From d9dcaf0d18a3b0216a774494996a81389d2bf34d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 29 Nov 2023 10:29:02 +0800 Subject: [PATCH 04/43] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/filters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/mtm/filters.py b/apps/mtm/filters.py index 7f753bdc..8f718a4c 100644 --- a/apps/mtm/filters.py +++ b/apps/mtm/filters.py @@ -49,5 +49,6 @@ class RouteFilter(filters.FilterSet): "is_autotask": ["exact"], "mgroup": ["exact", "in", "isnull"], "mgroup__name": ["exact", "contains"], + "mgroup__belong_dept": ["exact"], "mgroup__belong_dept__name": ["exact", "contains"] } From ab0bc60c234ed0c86c17e36e4bf331369e3bd279 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 29 Nov 2023 10:57:28 +0800 Subject: [PATCH 05/43] =?UTF-8?q?feat:=20utask=E5=A2=9E=E5=8A=A0=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/pm/serializers.py b/apps/pm/serializers.py index 2fa97378..f7fe2c7d 100644 --- a/apps/pm/serializers.py +++ b/apps/pm/serializers.py @@ -12,6 +12,7 @@ from apps.wpm.models import Mlog class UtaskSerializer(CustomModelSerializer): material_ = MaterialSimpleSerializer(source='material', read_only=True) + mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) belong_dept = serializers.PrimaryKeyRelatedField( queryset=Dept.objects.all(), required=False) From e07034919def83b204f36135d2e12f5347e8c564 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 29 Nov 2023 16:12:21 +0800 Subject: [PATCH 06/43] =?UTF-8?q?feat:=20mgroup=E5=A2=9E=E5=8A=A0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/mtm/views.py b/apps/mtm/views.py index 62f47fd6..2c3e960a 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -51,7 +51,8 @@ class MgroupViewSet(CustomModelViewSet): queryset = Mgroup.objects.all() serializer_class = MgroupSerializer select_related_fields = ['create_by', 'belong_dept', 'process'] - filterset_fields = ['belong_dept', 'process', 'cate', 'belong_dept__name'] + filterset_fields = ['belong_dept', 'process', + 'cate', 'belong_dept__name', 'name'] search_fields = ['number'] ordering = ['sort', 'create_time'] From eb665c7943153b1bfdb3e36b6e0a2973d0dded1a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 29 Nov 2023 16:23:07 +0800 Subject: [PATCH 07/43] =?UTF-8?q?feat:=20mlog=E5=A2=9E=E5=8A=A0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/views.py | 9 +++++++-- apps/wpm/filters.py | 7 ++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/mtm/views.py b/apps/mtm/views.py index 2c3e960a..2de4cdf7 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -51,8 +51,13 @@ class MgroupViewSet(CustomModelViewSet): queryset = Mgroup.objects.all() serializer_class = MgroupSerializer select_related_fields = ['create_by', 'belong_dept', 'process'] - filterset_fields = ['belong_dept', 'process', - 'cate', 'belong_dept__name', 'name'] + filterset_fields = { + "belong_dept": ["exact"], + "process": ["exact"], + "cate": ["exact"], + "belong_dept__name": ["exact", "contains"], + "name": ["exact", "contains"] + } search_fields = ['number'] ordering = ['sort', 'create_time'] diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index 46952252..808249f9 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -50,9 +50,10 @@ class MlogFilter(filters.FilterSet): "batch": ["exact"], "handle_date": ["exact"], "handle_user": ["exact"], - "mtask__mgroup__belong_dept__name": ["exact"], - "mgroup__belong_dept__name": ["exact", "in"], - "mgroup__name": ["exact", "in"], + "mgroup": ["exact"], + "mtask__mgroup__belong_dept__name": ["exact", "contains", "in"], + "mgroup__belong_dept__name": ["exact", "in", "contains"], + "mgroup__name": ["exact", "in", "contains"], "submit_time": ["isnull"] } From 3a24e6f85838313b658b5f2467c5a475a3464823 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 29 Nov 2023 16:52:00 +0800 Subject: [PATCH 08/43] =?UTF-8?q?feat:=20handover=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=80=81=E6=96=99=E5=B7=A5=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/filters.py | 4 +++- .../migrations/0036_handover_send_mgroup.py | 20 +++++++++++++++++++ apps/wpm/models.py | 3 +++ apps/wpm/serializers.py | 3 ++- apps/wpm/views.py | 3 ++- 5 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 apps/wpm/migrations/0036_handover_send_mgroup.py diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index 808249f9..3db2843b 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -70,5 +70,7 @@ class HandoverFilter(filters.FilterSet): "recive_dept__name": ["exact"], "send_date": ["exact"], "material__type": ["exact", "in"], - "submit_time": ["isnull"] + "submit_time": ["isnull"], + "mlog": ["isnull"], + "send_mgroup": ["exact"] } diff --git a/apps/wpm/migrations/0036_handover_send_mgroup.py b/apps/wpm/migrations/0036_handover_send_mgroup.py new file mode 100644 index 00000000..6a1d51a3 --- /dev/null +++ b/apps/wpm/migrations/0036_handover_send_mgroup.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.12 on 2023-11-29 08:51 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0025_auto_20231120_1139'), + ('wpm', '0035_otherlog'), + ] + + operations = [ + migrations.AddField( + model_name='handover', + name='send_mgroup', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.mgroup', verbose_name='送料工段'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 42c14bc6..c250ace7 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -164,6 +164,9 @@ class Handover(CommonADModel): send_date = models.DateField('送料日期') send_user = models.ForeignKey( User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user', null=True, blank=True) + send_mgroup = models.ForeignKey( + Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True + ) send_dept = models.ForeignKey( Dept, verbose_name='送料部门', on_delete=models.CASCADE, related_name='handover_send_dept') batch = models.CharField('批次号', max_length=50) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 6e51b876..2a0e76bd 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -298,7 +298,8 @@ class DeptBatchSerializer(serializers.Serializer): class HandoverSerializer(CustomModelSerializer): - material = serializers.PrimaryKeyRelatedField(required=True, label='物料ID', queryset=Material.objects.all()) + material = serializers.PrimaryKeyRelatedField( + required=True, label='物料ID', queryset=Material.objects.all()) send_user_name = serializers.CharField( source='send_user.name', read_only=True) recive_user_name = serializers.CharField( diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 094781ff..c059bb1d 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -283,7 +283,7 @@ class HandoverViewSet(CustomModelViewSet): @action(methods=['post'], detail=False, perms_map={'post': 'handover.create'}, serializer_class=GenHandoverSerializer) @transaction.atomic - def gen_by_mlogs(self, request): + def gen_by_mlog(self, request): """从生产日志生成交接记录 从生产日志生成交接记录 @@ -306,6 +306,7 @@ class HandoverViewSet(CustomModelViewSet): count=mlog.count_real, count_eweight=mlog.count_real_eweight, mlog=mlog, + mgroup=mlog.mgroup, create_by=user ) return Response() From a7ff21bb8041a25f015456543b7cf4132144492d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 10:15:31 +0800 Subject: [PATCH 09/43] =?UTF-8?q?fix:=20handover=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=80=81=E6=96=99=E5=B7=A5=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index c059bb1d..927e70c1 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -306,7 +306,7 @@ class HandoverViewSet(CustomModelViewSet): count=mlog.count_real, count_eweight=mlog.count_real_eweight, mlog=mlog, - mgroup=mlog.mgroup, + send_mgroup=mlog.mgroup, create_by=user ) return Response() From abb3fef89f3f64736b67f1970ad7a07aee1dad37 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 10:47:38 +0800 Subject: [PATCH 10/43] =?UTF-8?q?feat:=20=E4=BA=A4=E6=8E=A5=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0037_auto_20231130_1047.py | 29 +++++++++++++++++++ apps/wpm/models.py | 4 +-- apps/wpm/serializers.py | 5 ++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 apps/wpm/migrations/0037_auto_20231130_1047.py diff --git a/apps/wpm/migrations/0037_auto_20231130_1047.py b/apps/wpm/migrations/0037_auto_20231130_1047.py new file mode 100644 index 00000000..9fdad285 --- /dev/null +++ b/apps/wpm/migrations/0037_auto_20231130_1047.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.12 on 2023-11-30 02:47 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('mtm', '0025_auto_20231120_1139'), + ('wpm', '0036_handover_send_mgroup'), + ] + + operations = [ + migrations.AlterField( + model_name='handover', + name='material', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料'), + preserve_default=False, + ), + migrations.AlterField( + model_name='handover', + name='send_user', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='handover_send_user', to='system.user', verbose_name='交送人'), + preserve_default=False, + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index c250ace7..f16db38b 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -163,7 +163,7 @@ class Handover(CommonADModel): """ send_date = models.DateField('送料日期') send_user = models.ForeignKey( - User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user', null=True, blank=True) + User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user') send_mgroup = models.ForeignKey( Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True ) @@ -171,7 +171,7 @@ class Handover(CommonADModel): Dept, verbose_name='送料部门', on_delete=models.CASCADE, related_name='handover_send_dept') batch = models.CharField('批次号', max_length=50) material = models.ForeignKey( - Material, verbose_name='物料', on_delete=models.CASCADE, null=True, blank=True) + Material, verbose_name='物料', on_delete=models.CASCADE) count = models.PositiveIntegerField('送料数', default=0) count_eweight = models.FloatField('单数重量', default=0) recive_dept = models.ForeignKey( diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 2a0e76bd..a79ad203 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -306,6 +306,11 @@ class HandoverSerializer(CustomModelSerializer): source='recive_user.name', read_only=True) material_ = MaterialSimpleSerializer(source='material', read_only=True) + def validate(self, attrs): + if attrs.get('mlog', None): + attrs['send_mgroup'] = attrs['mlog'].mgroup + return super().validate(attrs) + class Meta: model = Handover fields = '__all__' From 73a463dd2f563dcc039a67fa7dd369f27e87d1ab Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 13:38:20 +0800 Subject: [PATCH 11/43] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0mtask=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/filters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/pm/filters.py b/apps/pm/filters.py index 373d3ab5..8ce6e260 100644 --- a/apps/pm/filters.py +++ b/apps/pm/filters.py @@ -55,6 +55,7 @@ class MtaskFilter(filters.FilterSet): "material_out__type": ["exact"], "material_out__is_hidden": ["exact"], "mgroup__belong_dept__name": ["exact"], + "mgroup__belong_dept": ["exact"], "utask": ["exact"] } From 9dc31b366b74bc9073c03a1de3871fd7a90e12ea Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 14:14:52 +0800 Subject: [PATCH 12/43] fix: handover submit bug --- apps/wpm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 927e70c1..1bab03c0 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -241,7 +241,7 @@ class HandoverViewSet(CustomModelViewSet): @action(methods=['post'], detail=True, perms_map={'post': 'handover.submit'}, serializer_class=Serializer) @transaction.atomic - def submit(self, request): + def submit(self, request, *args, **kwargs): """交接记录提交(变动车间库存) 交接记录提交 From 81e97c4789e0b5444d949be842910d22e4454b08 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 14:48:47 +0800 Subject: [PATCH 13/43] =?UTF-8?q?feat:=20=E6=97=A5=E5=BF=97=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E6=97=B6=E9=97=B4=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index a09eeed8..b066a1a2 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -144,6 +144,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): return if now is None: now = timezone.now() + if now.date() < mlog.handle_date: + raise ParseError('不可提交未来的日志') belong_dept = mlog.mgroup.belong_dept material_out = mlog.material_out material_in = mlog.material_in From 3e041ec93b36cd8079fe09239ae6ac4611499e7c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 16:00:38 +0800 Subject: [PATCH 14/43] =?UTF-8?q?fix:=20=E4=BB=BB=E5=8A=A1=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E6=8E=A5=E5=8F=A3=E6=94=B9=E4=B8=BA=E5=8D=95=E4=B8=AA?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index efba844f..565e26a3 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -158,18 +158,19 @@ class MtaskViewSet(CustomModelViewSet): raise ParseError('该任务非创建中不可删除') return super().perform_destroy(instance) - @action(methods=['post'], detail=False, perms_map={'post': 'mtask.submit'}, serializer_class=PkSerializer) + @action(methods=['post'], detail=True, perms_map={'post': 'mtask.submit'}, serializer_class=PkSerializer) @transaction.atomic def submit(self, request, *args, **kwargs): """提交任务(根据任务ID) 提交任务后不可更新日志 """ - ids = request.data.get('ids', []) + mtask: Mtask = self.get_object() user = request.user - mtasks = Mtask.objects.filter( - id__in=ids, state=Mtask.MTASK_ASSGINED) - PmService.mtasks_submit(mtasks, user) + if mtask.state == Mtask.MTASK_ASSGINED: + PmService.mtasks_submit(Mtask.objects.filter(id=mtask.id), user) + else: + raise ParseError('该任务状态不可提交') return Response() @action(methods=['post'], detail=True, perms_map={'post': 'mtask.submit'}, serializer_class=Serializer) From cc0a2719dee764604007f82025caa06427418e12 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 16:30:07 +0800 Subject: [PATCH 15/43] =?UTF-8?q?feat:=20mtask=E5=A2=9E=E5=8A=A0submit=5Ft?= =?UTF-8?q?ime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/migrations/0016_auto_20231130_1628.py | 26 +++++++++++++++++++ apps/pm/models.py | 4 +++ apps/pm/services.py | 8 ++++-- apps/pm/views.py | 8 +++--- apps/wpm/services.py | 4 +-- 5 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 apps/pm/migrations/0016_auto_20231130_1628.py diff --git a/apps/pm/migrations/0016_auto_20231130_1628.py b/apps/pm/migrations/0016_auto_20231130_1628.py new file mode 100644 index 00000000..fa8412a4 --- /dev/null +++ b/apps/pm/migrations/0016_auto_20231130_1628.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.12 on 2023-11-30 08:28 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('pm', '0015_utask_count_day'), + ] + + operations = [ + migrations.AddField( + model_name='mtask', + name='submit_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='提交时间'), + ), + migrations.AddField( + model_name='mtask', + name='submit_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mtask_submit_user', to=settings.AUTH_USER_MODEL, verbose_name='提交人'), + ), + ] diff --git a/apps/pm/models.py b/apps/pm/models.py index 770ffca2..b3022d7c 100644 --- a/apps/pm/models.py +++ b/apps/pm/models.py @@ -75,6 +75,10 @@ class Mtask(CommonADModel): Utask, verbose_name='关联大任务', on_delete=models.CASCADE, related_name='mtask_utask', null=True, blank=True) peifen_kg = models.FloatField('配粉料数', default=0) + submit_time = models.DateTimeField('提交时间', null=True, blank=True) + submit_user = models.ForeignKey( + 'system.user', verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='mtask_submit_user') + @property def related(self): """ diff --git a/apps/pm/services.py b/apps/pm/services.py index e96e9512..fce4ff6a 100644 --- a/apps/pm/services.py +++ b/apps/pm/services.py @@ -251,14 +251,14 @@ class PmService: change_order_state_when_schedue(orderitemIds) @classmethod - def mtasks_submit(cls, mtasks: QuerySet[Mtask], user: User): + def mtask_submit(cls, mtask: Mtask, user: User): """ 锁定生产任务 """ from apps.wpm.models import Mlog from apps.wpm.services import mlog_submit, update_mtask now = timezone.now() - for mtask in mtasks: + if mtask.state == Mtask.MTASK_ASSGINED: mlogs = Mlog.objects.filter(mtask=mtask) if mlogs.count() == 0: raise ParseError(f'{mtask.mgroup.name}_未填写日志') @@ -266,4 +266,8 @@ class PmService: mlog_submit(mlog, user, now) update_mtask(mtask) mtask.state = Mtask.MTASK_DONE + mtask.submit_time = now + mtask.submit_user = user mtask.save() + else: + raise ParseError('该任务状态不可提交') diff --git a/apps/pm/views.py b/apps/pm/views.py index 565e26a3..0725254f 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -167,10 +167,7 @@ class MtaskViewSet(CustomModelViewSet): """ mtask: Mtask = self.get_object() user = request.user - if mtask.state == Mtask.MTASK_ASSGINED: - PmService.mtasks_submit(Mtask.objects.filter(id=mtask.id), user) - else: - raise ParseError('该任务状态不可提交') + PmService.mtask_submit(mtask, user) return Response() @action(methods=['post'], detail=True, perms_map={'post': 'mtask.submit'}, serializer_class=Serializer) @@ -182,5 +179,6 @@ class MtaskViewSet(CustomModelViewSet): """ mtask = self.get_object() mtasks = mtask.related - PmService.mtasks_submit(mtasks) + for mtask in mtasks: + PmService.mtask_submit(mtask, self.request.user) return Response() diff --git a/apps/wpm/services.py b/apps/wpm/services.py index b066a1a2..5c561f4d 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -187,7 +187,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): def update_mtask(mtask: Mtask): from apps.pm.models import Utask - res = Mlog.objects.filter(mtask=mtask).aggregate(sum_count_real=Sum( + res = Mlog.objects.filter(mtask=mtask).exclude(submit_time=None).aggregate(sum_count_real=Sum( 'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok')) mtask.count_real = res['sum_count_real'] if res['sum_count_real'] else 0 mtask.count_ok = res['sum_count_ok'] if res['sum_count_ok'] else 0 @@ -203,7 +203,7 @@ def update_mtask(mtask: Mtask): if utask.count_ok > 0 and utask.state == Utask.UTASK_ASSGINED: utask.state = Utask.UTASK_WORKING if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_DONE).count() == 0: - utask.state = Mtask.MTASK_DONE + utask.state = Utask.UTASK_DONE utask.save() From d94424131f1a1cce3fb4c0179b88f879db39f4d6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 17:05:34 +0800 Subject: [PATCH 16/43] =?UTF-8?q?feat:=20materialbatch=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/filters.py | 2 ++ apps/inm/views.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/inm/filters.py b/apps/inm/filters.py index 8fd8edd9..097b76e5 100644 --- a/apps/inm/filters.py +++ b/apps/inm/filters.py @@ -9,5 +9,7 @@ class MaterialBatchFilter(filters.FilterSet): fields = { "warehouse": ["exact"], "material": ["exact"], + "material__type": ["exact", "in"], + "material__process": ["exact", "in"], "count": ["exact", "gte", "lte"] } diff --git a/apps/inm/views.py b/apps/inm/views.py index ff055cf4..3be9d42f 100644 --- a/apps/inm/views.py +++ b/apps/inm/views.py @@ -49,7 +49,8 @@ class MaterialBatchViewSet(ListModelMixin, CustomGenericViewSet): retrieve_serializer_class = MaterialBatchDetailSerializer select_related_fields = ['warehouse', 'material'] filterset_class = MaterialBatchFilter - search_fields = ['material__name'] + search_fields = ['material__name', 'material__number', + 'material__model', 'material__specification', 'batch'] class MioDoViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, CustomGenericViewSet): From 6e8d78a5e9b93c5c7d7c8df1e296093e9cd2799d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 30 Nov 2023 17:10:42 +0800 Subject: [PATCH 17/43] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/wpm/models.py b/apps/wpm/models.py index f16db38b..c535fe2e 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -129,9 +129,9 @@ class Mlog(CommonADModel): handle_date = models.DateField('操作日期') handle_user = models.ForeignKey( - User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True) + User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True) # 成型人 handle_user_2 = models.ForeignKey( - User, verbose_name='操作人2', on_delete=models.CASCADE, related_name='mlog_handle_user_2', null=True, blank=True) + User, verbose_name='操作人2', on_delete=models.CASCADE, related_name='mlog_handle_user_2', null=True, blank=True) # 切料人 handle_users = models.ManyToManyField( User, verbose_name='操作人(多选)', blank=True) handle_leader = models.ForeignKey( From 6dfa2b1696432bb551a7e627f030147aec4e0d68 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 09:50:40 +0800 Subject: [PATCH 18/43] =?UTF-8?q?fix:=20route=E5=88=9B=E5=BB=BA=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/serializers.py | 50 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index a783f6a7..6e8926d1 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -124,15 +124,16 @@ class RouteSerializer(CustomModelSerializer): fields = '__all__' read_only_fields = EXCLUDE_FIELDS - # def validate(self, attrs): - # material = attrs['material'] - # if material.type != Material.MA_TYPE_GOOD: - # raise ValidationError('请选择最终产品') - # return super().validate(attrs) + def validate(self, attrs): + if 'mgroup' in attrs and attrs['mgroup']: + attrs['process'] = attrs['mgroup'].process + if attrs.get('process', None) is None: + raise ParseError('未提供操作工序') + return super().validate(attrs) def gen_material_out(self, instance): """ - 废弃不用了 + 自动形成物料 """ name = f'{instance.material.name}-中' instance.material_out, _ = Material.objects.get_or_create(type=Material.MA_TYPE_HALFGOOD, parent=instance.material, process=instance.process, @@ -140,6 +141,7 @@ class RouteSerializer(CustomModelSerializer): 'is_hidden': True, 'name': name, 'number': instance.material.number, 'specification': instance.material.specification, + 'model': instance.material.model, 'type': Material.MA_TYPE_HALFGOOD, 'create_by': self.request.user, 'update_by': self.request.user, @@ -147,24 +149,40 @@ class RouteSerializer(CustomModelSerializer): instance.save() def create(self, validated_data): - process = validated_data.get('process', None) + process = validated_data['process'] if process and Route.objects.filter(material=validated_data['material'], process=process).exists(): raise ValidationError('已选择该工序') with transaction.atomic(): instance = super().create(validated_data) - # if 'material_out' in validated_data and validated_data['material_out'] and instance.material: - # pass - # else: - # self.gen_material_out(instance) + material_out = instance.material_out + if material_out: + if material_out.process is None: + material_out.process = instance.process + if instance.material: + material_out.parent = instance.material + material_out.save() + elif material_out.process != process: + raise ParseError('物料工序错误!请重新选择') + else: + if instance.material: + self.gen_material_out() return instance def update(self, instance, validated_data): validated_data.pop('material', None) - validated_data.pop('process', None) + process = validated_data.pop('process', None) with transaction.atomic(): instance = super().update(instance, validated_data) - # if 'material_out' in validated_data and validated_data['material_out'] and instance.material: - # pass - # else: - # self.gen_material_out(instance) + material_out = instance.material_out + if material_out: + if material_out.process is None: + material_out.process = instance.process + if instance.material: + material_out.parent = instance.material + material_out.save() + elif material_out.process != process: + raise ParseError('物料工序错误!请重新选择') + else: + if instance.material: + self.gen_material_out() return instance From 68c28918398cff377ad4cf17c739e24b4f9efe28 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 09:53:11 +0800 Subject: [PATCH 19/43] =?UTF-8?q?fix:=20route=E5=88=9B=E5=BB=BA=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index 6e8926d1..f13b0679 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -150,7 +150,8 @@ class RouteSerializer(CustomModelSerializer): def create(self, validated_data): process = validated_data['process'] - if process and Route.objects.filter(material=validated_data['material'], process=process).exists(): + material = validated_data.get('material', None) + if material and process and Route.objects.filter(material=material, process=process).exists(): raise ValidationError('已选择该工序') with transaction.atomic(): instance = super().create(validated_data) From c827c7d55d96ba8f34bcec489d7eee7ba6f7a203 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 10:28:34 +0800 Subject: [PATCH 20/43] =?UTF-8?q?fix:=20route=E5=88=9B=E5=BB=BA=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index f13b0679..93485e14 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -158,7 +158,7 @@ class RouteSerializer(CustomModelSerializer): material_out = instance.material_out if material_out: if material_out.process is None: - material_out.process = instance.process + material_out.process = process if instance.material: material_out.parent = instance.material material_out.save() @@ -177,7 +177,7 @@ class RouteSerializer(CustomModelSerializer): material_out = instance.material_out if material_out: if material_out.process is None: - material_out.process = instance.process + material_out.process = process if instance.material: material_out.parent = instance.material material_out.save() From dc47570a5b95e0f17abc9dd5bca32fd0a865d6be Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 11:33:23 +0800 Subject: [PATCH 21/43] =?UTF-8?q?feat:=20wm=E5=A2=9E=E5=8A=A0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/serializers.py | 4 +++- apps/wpm/views.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index 93485e14..7ad7228e 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -15,10 +15,12 @@ class ShiftSerializer(CustomModelSerializer): class MaterialSimpleSerializer(CustomModelSerializer): + process_name = serializers.CharField(source='process.name', read_only=True) + class Meta: model = Material fields = ['id', 'name', 'number', 'model', - 'specification', 'type', 'cate', 'brothers'] + 'specification', 'type', 'cate', 'brothers', 'process_name'] class MaterialSerializer(CustomModelSerializer): diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 1bab03c0..b13d51e0 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -102,7 +102,7 @@ class WMaterialViewSet(ListModelMixin, CustomGenericViewSet): perms_map = {'get': '*'} queryset = WMaterial.objects.all() serializer_class = WMaterialSerializer - select_related_fields = ['material', 'belong_dept'] + select_related_fields = ['material', 'belong_dept', 'material__process'] search_fields = ['material__name', 'material__number', 'material__specification'] filterset_class = WMaterialFilter From dc8bab86cfa97304a3169464b46c4624e1d70d28 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 13:40:46 +0800 Subject: [PATCH 22/43] =?UTF-8?q?feat:=20puorder=E5=A2=9E=E5=8A=A0material?= =?UTF-8?q?s=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pum/migrations/0003_puorder_materials.py | 19 +++++++++++++++++++ apps/pum/models.py | 2 ++ apps/pum/serializers.py | 4 +++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 apps/pum/migrations/0003_puorder_materials.py diff --git a/apps/pum/migrations/0003_puorder_materials.py b/apps/pum/migrations/0003_puorder_materials.py new file mode 100644 index 00000000..52ece2f2 --- /dev/null +++ b/apps/pum/migrations/0003_puorder_materials.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.12 on 2023-12-01 05:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0025_auto_20231120_1139'), + ('pum', '0002_alter_puorderitem_material'), + ] + + operations = [ + migrations.AddField( + model_name='puorder', + name='materials', + field=models.ManyToManyField(blank=True, related_name='pu_order_materials', through='pum.PuOrderItem', to='mtm.Material', verbose_name='多个物料'), + ), + ] diff --git a/apps/pum/models.py b/apps/pum/models.py index 9eae5ccf..ec009c5c 100644 --- a/apps/pum/models.py +++ b/apps/pum/models.py @@ -58,6 +58,8 @@ class PuOrder(CommonBModel): Supplier, verbose_name='供应商', on_delete=models.CASCADE) delivery_date = models.DateField('截止到货日期', null=True, blank=True) submit_time = models.DateTimeField('提交时间', null=True, blank=True) + materials = models.ManyToManyField( + Material, verbose_name='多个物料', blank=True, through='pum.puorderitem', related_name='pu_order_materials') class PuOrderItem(BaseModel): diff --git a/apps/pum/serializers.py b/apps/pum/serializers.py index 57b5fa93..e6e62a3a 100644 --- a/apps/pum/serializers.py +++ b/apps/pum/serializers.py @@ -4,7 +4,7 @@ from apps.utils.constants import EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS_BASE, EXCLU from rest_framework.exceptions import ValidationError from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem -from apps.mtm.serializers import MaterialSerializer +from apps.mtm.serializers import MaterialSerializer, MaterialSimpleSerializer class SupplierSerializer(CustomModelSerializer): @@ -83,6 +83,8 @@ class PuOrderSerializer(CustomModelSerializer): source='create_by.name', read_only=True) update_by_name = serializers.CharField( source='update_by.name', read_only=True) + materials_ = MaterialSimpleSerializer( + source='materials', many=True, read_only=True) class Meta: model = PuOrder From 9d847c8d87255c6d83c746654a7aaeee279c33bf Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 13:51:40 +0800 Subject: [PATCH 23/43] =?UTF-8?q?feat:=20=E9=87=87=E8=B4=AD=E8=AE=A1?= =?UTF-8?q?=E5=88=92=E5=92=8C=E8=AE=A2=E5=8D=95=E9=83=BD=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pum/migrations/0004_auto_20231201_1350.py | 26 +++++++++++++++++++ apps/pum/models.py | 4 +++ apps/pum/views.py | 6 +++-- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 apps/pum/migrations/0004_auto_20231201_1350.py diff --git a/apps/pum/migrations/0004_auto_20231201_1350.py b/apps/pum/migrations/0004_auto_20231201_1350.py new file mode 100644 index 00000000..dad3a593 --- /dev/null +++ b/apps/pum/migrations/0004_auto_20231201_1350.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.12 on 2023-12-01 05:50 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('pum', '0003_puorder_materials'), + ] + + operations = [ + migrations.AddField( + model_name='puorder', + name='submit_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='submit_user_puorder', to=settings.AUTH_USER_MODEL, verbose_name='提交人'), + ), + migrations.AddField( + model_name='puplan', + name='submit_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='submit_user_puplan', to=settings.AUTH_USER_MODEL, verbose_name='提交人'), + ), + ] diff --git a/apps/pum/models.py b/apps/pum/models.py index ec009c5c..7d6886e7 100644 --- a/apps/pum/models.py +++ b/apps/pum/models.py @@ -35,6 +35,8 @@ class PuPlan(CommonBModel): number = models.CharField('编号', max_length=20) name = models.CharField('名称', max_length=50, null=True, blank=True) submit_time = models.DateTimeField('提交时间', null=True, blank=True) + submit_user = models.ForeignKey( + 'system.user', verbose_name='提交人', related_name='submit_user_puplan', on_delete=models.CASCADE, null=True, blank=True) class PuOrder(CommonBModel): @@ -58,6 +60,8 @@ class PuOrder(CommonBModel): Supplier, verbose_name='供应商', on_delete=models.CASCADE) delivery_date = models.DateField('截止到货日期', null=True, blank=True) submit_time = models.DateTimeField('提交时间', null=True, blank=True) + submit_user = models.ForeignKey( + 'system.user', verbose_name='提交人', related_name='submit_user_puorder', on_delete=models.CASCADE, null=True, blank=True) materials = models.ManyToManyField( Material, verbose_name='多个物料', blank=True, through='pum.puorderitem', related_name='pu_order_materials') diff --git a/apps/pum/views.py b/apps/pum/views.py index fb479e69..4eaec077 100644 --- a/apps/pum/views.py +++ b/apps/pum/views.py @@ -46,7 +46,7 @@ class PuPlanViewSet(CustomModelViewSet): raise ParseError('该计划存在明细不可删除') return super().perform_destroy(instance) - @action(methods=['post'], detail=True, perms_map={'post': 'pu_plan.update'}, serializer_class=serializers.Serializer) + @action(methods=['post'], detail=True, perms_map={'post': 'pu_plan.submit'}, serializer_class=serializers.Serializer) def submit(self, request, *args, **kwargs): """提交采购计划 @@ -59,6 +59,7 @@ class PuPlanViewSet(CustomModelViewSet): if puplan.state != PuPlan.PUPLAN_CREATE: raise ParseError('采购计划状态异常') puplan.submit_time = timezone.now() + puplan.submit_user = user puplan.state = PuPlan.PUPLAN_SUBMITED puplan.save() return Response() @@ -106,7 +107,7 @@ class PuOrderViewSet(CustomModelViewSet): raise ParseError('采购订单非创建中不可删除') instance.delete(soft=False) - @action(methods=['post'], detail=True, perms_map={'post': 'pu_order.update'}, serializer_class=serializers.Serializer) + @action(methods=['post'], detail=True, perms_map={'post': 'pu_order.submit'}, serializer_class=serializers.Serializer) @transaction.atomic def submit(self, request, *args, **kwargs): """提交采购订单 @@ -122,6 +123,7 @@ class PuOrderViewSet(CustomModelViewSet): if puorder.state != PuOrder.PUORDER_CREATE: raise ParseError('采购计划状态异常') puorder.submit_time = timezone.now() + puorder.submit_user = user puorder.state = PuOrder.PUORDER_SUBMITED puorder.save() PumService.change_puplan_state_when_puorder_sumbit(puorder) From e3d37c6dfaf30a56557bb102f809c60dddf02bc0 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 14:16:06 +0800 Subject: [PATCH 24/43] =?UTF-8?q?feat:=20wm=E5=A2=9E=E5=8A=A0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/filters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index 3db2843b..5806e838 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -35,6 +35,7 @@ class WMaterialFilter(filters.FilterSet): model = WMaterial fields = { "material": ["exact", "in"], + "material__process": ["exact", "in"], "belong_dept": ["exact"], "belong_dept__name": ["exact"], "batch": ["exact"], From e3c0273e0dd2a36a7da1db9cead462511ac20e8a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 15:25:39 +0800 Subject: [PATCH 25/43] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0material?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/filters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/mtm/filters.py b/apps/mtm/filters.py index 8f718a4c..39b9749a 100644 --- a/apps/mtm/filters.py +++ b/apps/mtm/filters.py @@ -15,6 +15,7 @@ class MaterialFilter(filters.FilterSet): "is_hidden": ["exact"], "is_assemb": ["exact"], "need_route": ["exact"], + "process": ["exact", "in", "isnull"], "orderitem_material__order": ['exact'], "pu_orderitem_material__pu_order": ["exact"], "route_material_out__mgroup": ["exact"] From ac323781ebb9208f4347300862fe301ce04dfb22 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 1 Dec 2023 15:51:32 +0800 Subject: [PATCH 26/43] =?UTF-8?q?feat=20=E5=A2=9E=E5=8A=A0wm=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/filters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index 5806e838..b1818d93 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -35,6 +35,7 @@ class WMaterialFilter(filters.FilterSet): model = WMaterial fields = { "material": ["exact", "in"], + "material__type": ["exact", "in"], "material__process": ["exact", "in"], "belong_dept": ["exact"], "belong_dept__name": ["exact"], From 7bd8d0dd1f7f9d92274e1cc6f8dfe8bef1e94d9b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 4 Dec 2023 08:37:35 +0800 Subject: [PATCH 27/43] =?UTF-8?q?fix:=20base=20permission=E5=8E=BB?= =?UTF-8?q?=E9=99=A4=E6=95=B0=E6=8D=AE=E5=BA=93=E7=BA=A6=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0003_alter_permission_parent.py | 19 ++++++++ apps/system/models.py | 47 ++++++++++++------- 2 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 apps/system/migrations/0003_alter_permission_parent.py diff --git a/apps/system/migrations/0003_alter_permission_parent.py b/apps/system/migrations/0003_alter_permission_parent.py new file mode 100644 index 00000000..ca646f27 --- /dev/null +++ b/apps/system/migrations/0003_alter_permission_parent.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.12 on 2023-12-04 00:37 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0002_myschedule'), + ] + + operations = [ + migrations.AlterField( + model_name='permission', + name='parent', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.permission', verbose_name='父'), + ), + ] diff --git a/apps/system/models.py b/apps/system/models.py index e7e34e6e..155d2936 100755 --- a/apps/system/models.py +++ b/apps/system/models.py @@ -26,10 +26,11 @@ class Permission(BaseModel): (PERM_TYPE_BUTTON, '按钮') ) name = models.CharField('名称', max_length=30) - type = models.PositiveSmallIntegerField('类型', choices=menu_type_choices, default=30) + type = models.PositiveSmallIntegerField( + '类型', choices=menu_type_choices, default=30) sort = models.PositiveSmallIntegerField('排序标记', default=1) parent = models.ForeignKey('self', null=True, blank=True, - on_delete=models.SET_NULL, verbose_name='父') + on_delete=models.SET_NULL, verbose_name='父', db_constraint=False) codes = models.JSONField('权限标识', default=list, null=True, blank=True) def __str__(self): @@ -67,7 +68,8 @@ class Role(CommonADModel): """ name = models.CharField('名称', max_length=32) code = models.CharField('角色标识', max_length=32, null=True, blank=True) - perms = models.ManyToManyField(Permission, blank=True, verbose_name='功能权限', related_name='role_perms') + perms = models.ManyToManyField( + Permission, blank=True, verbose_name='功能权限', related_name='role_perms') description = models.CharField('描述', max_length=50, blank=True, null=True) class Meta: @@ -106,8 +108,10 @@ class PostRole(BaseModel): """ data_range = models.PositiveSmallIntegerField('数据权限范围', choices=DataFilter.choices, default=DataFilter.THISLEVEL_AND_BELOW) - post = models.ForeignKey(Post, verbose_name='关联岗位', on_delete=models.CASCADE) - role = models.ForeignKey(Role, verbose_name='关联角色', on_delete=models.CASCADE) + post = models.ForeignKey(Post, verbose_name='关联岗位', + on_delete=models.CASCADE) + role = models.ForeignKey(Role, verbose_name='关联角色', + on_delete=models.CASCADE) class SoftDeletableUserManager(SoftDeletableManagerMixin, UserManager): @@ -127,16 +131,21 @@ class User(AbstractUser, CommonBModel): 'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管') post = models.ForeignKey(Post, verbose_name='主要岗位', on_delete=models.SET_NULL, null=True, blank=True) - posts = models.ManyToManyField(Post, through='system.userpost', related_name='user_posts') + posts = models.ManyToManyField( + Post, through='system.userpost', related_name='user_posts') depts = models.ManyToManyField(Dept, through='system.userpost') roles = models.ManyToManyField(Role, verbose_name='关联角色') # 关联账号 secret = models.CharField('密钥', max_length=100, null=True, blank=True) - wx_openid = models.CharField('微信公众号OpenId', max_length=100, null=True, blank=True) - wx_nickname = models.CharField('微信昵称', max_length=100, null=True, blank=True) - wx_headimg = models.CharField('微信头像', max_length=100, null=True, blank=True) - wxmp_openid = models.CharField('微信小程序OpenId', max_length=100, null=True, blank=True) + wx_openid = models.CharField( + '微信公众号OpenId', max_length=100, null=True, blank=True) + wx_nickname = models.CharField( + '微信昵称', max_length=100, null=True, blank=True) + wx_headimg = models.CharField( + '微信头像', max_length=100, null=True, blank=True) + wxmp_openid = models.CharField( + '微信小程序OpenId', max_length=100, null=True, blank=True) objects = SoftDeletableUserManager() @@ -154,9 +163,12 @@ class UserPost(BaseModel): 用户岗位关系表 """ name = models.CharField('名称', max_length=20, null=True, blank=True) - user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='up_user') - post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='up_post') - dept = models.ForeignKey(Dept, on_delete=models.CASCADE, related_name='up_dept') + user = models.ForeignKey( + User, on_delete=models.CASCADE, related_name='up_user') + post = models.ForeignKey( + Post, on_delete=models.CASCADE, related_name='up_post') + dept = models.ForeignKey( + Dept, on_delete=models.CASCADE, related_name='up_dept') sort = models.PositiveSmallIntegerField('排序', default=1) class Meta: @@ -229,7 +241,8 @@ class File(CommonAModel): (FILE_TYPE_OTHER, '其它') ) mime = models.CharField('文件格式', max_length=120, null=True, blank=True) - type = models.CharField('文件类型', max_length=50, choices=type_choices, default='文档') + type = models.CharField('文件类型', max_length=50, + choices=type_choices, default='文档') path = models.CharField('地址', max_length=200, null=True, blank=True) class Meta: @@ -250,5 +263,7 @@ class MySchedule(CommonAModel): ) name = models.CharField('名称', max_length=200) type = models.PositiveSmallIntegerField('周期类型', default=10) - interval = models.ForeignKey(IntervalSchedule, on_delete=models.PROTECT, null=True, blank=True) - crontab = models.ForeignKey(CrontabSchedule, on_delete=models.PROTECT, null=True, blank=True) \ No newline at end of file + interval = models.ForeignKey( + IntervalSchedule, on_delete=models.PROTECT, null=True, blank=True) + crontab = models.ForeignKey( + CrontabSchedule, on_delete=models.PROTECT, null=True, blank=True) From 1a0978785310ab53cae142adc57a173459a539e9 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 4 Dec 2023 17:08:04 +0800 Subject: [PATCH 28/43] =?UTF-8?q?feat:=20base=20redis=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=A0=E5=85=A5conf.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/settings.py b/server/settings.py index ecdb0f76..4f033385 100755 --- a/server/settings.py +++ b/server/settings.py @@ -282,7 +282,7 @@ AUTHENTICATION_BACKENDS = ( CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": "redis://127.0.0.1:6379/2", + "LOCATION": conf.REDIS_LOCATION, "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } @@ -290,7 +290,7 @@ CACHES = { } # celery配置,celery正常运行必须安装redis -CELERY_BROKER_URL = "redis://127.0.0.1:6379/3" # 任务存储 +CELERY_BROKER_URL = conf.CELERY_BROKER_URL # 任务存储 CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行100个任务就会被销毁,可防止内存泄露 CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区 CELERY_ENABLE_UTC = True # 启动时区设置 From b744ac459106e78e916f346ebb746ba30a9f652e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 5 Dec 2023 08:51:07 +0800 Subject: [PATCH 29/43] =?UTF-8?q?feat:=20base=20=E5=81=9A=E5=88=B0celery?= =?UTF-8?q?=E5=9C=A8=E9=A1=B9=E7=9B=AE=E9=97=B4=E5=AE=8C=E5=85=A8=E9=9A=94?= =?UTF-8?q?=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/celery.py | 4 ++-- server/settings.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/server/celery.py b/server/celery.py index 59449c0d..747a08bb 100755 --- a/server/celery.py +++ b/server/celery.py @@ -1,11 +1,11 @@ import os - +from . import conf from celery import Celery # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings') -app = Celery('ehs') +app = Celery(conf.BASE_PROJECT_CODE) # Using a string here means the worker doesn't have to serialize # the configuration object to child processes. diff --git a/server/settings.py b/server/settings.py index 4f033385..c0929740 100755 --- a/server/settings.py +++ b/server/settings.py @@ -282,7 +282,7 @@ AUTHENTICATION_BACKENDS = ( CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": conf.REDIS_LOCATION, + "LOCATION": conf.CACHE_LOCATION, "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } @@ -291,6 +291,7 @@ CACHES = { # celery配置,celery正常运行必须安装redis CELERY_BROKER_URL = conf.CELERY_BROKER_URL # 任务存储 +CELERY_TASK_DEFAULT_QUEUE = conf.CELERY_TASK_DEFAULT_QUEUE # 任务队列 CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行100个任务就会被销毁,可防止内存泄露 CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区 CELERY_ENABLE_UTC = True # 启动时区设置 From 1ef6826776998270fc4284fa154e33a0c1ff0505 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 5 Dec 2023 08:54:30 +0800 Subject: [PATCH 30/43] =?UTF-8?q?feat:=20base=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/settings.py b/server/settings.py index c0929740..0aed35ec 100755 --- a/server/settings.py +++ b/server/settings.py @@ -70,7 +70,7 @@ DEBUG = conf.DEBUG ALLOWED_HOSTS = ['*'] SYS_NAME = 'XT_EHS' -SYS_VERSION = '2.2.2' +SYS_VERSION = '2.3.0' # Application definition From 95f67b654370396d11b480ac2a8d196009e34ac5 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 5 Dec 2023 13:02:14 +0800 Subject: [PATCH 31/43] =?UTF-8?q?feat:=20is=5Fhidden=E7=9A=84=E7=89=A9?= =?UTF-8?q?=E6=96=99=E4=B9=9F=E9=9C=80=E8=A6=81=E8=BF=9B=E8=A1=8C=E8=BD=A6?= =?UTF-8?q?=E9=97=B4=E5=BA=93=E5=AD=98=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 5c561f4d..a3b26f63 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -149,7 +149,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): belong_dept = mlog.mgroup.belong_dept material_out = mlog.material_out material_in = mlog.material_in - if material_in and material_in.is_hidden is False: # 需要进行车间库存管理 + if material_in: # 需要进行车间库存管理 # 需要判断领用数是否合理 material_has_qs = WMaterial.objects.filter( batch=mlog.batch, material=material_in, belong_dept=belong_dept) @@ -165,7 +165,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): else: material_has.count = material_has.count - mlog.count_use material_has.save() - if material_out and material_out.is_hidden is False: # 需要入车间库存 + if material_out: # 需要入车间库存 # 有多个产物的情况 if material_out.brothers and Mlogb.objects.filter(mlog=mlog).exists(): for item in Mlogb.objects.filter(mlog=mlog): From 33ea769ad4eb9f2137870984d4f56b8cb61e0dc7 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 5 Dec 2023 17:25:09 +0800 Subject: [PATCH 32/43] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=B1=BB=E5=9E=8B=20mass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/migrations/0017_auto_20231205_1724.py | 23 +++++++++++++++++++ apps/pm/models.py | 9 ++++++++ apps/pm/services.py | 2 ++ 3 files changed, 34 insertions(+) create mode 100644 apps/pm/migrations/0017_auto_20231205_1724.py diff --git a/apps/pm/migrations/0017_auto_20231205_1724.py b/apps/pm/migrations/0017_auto_20231205_1724.py new file mode 100644 index 00000000..6cd1a9ca --- /dev/null +++ b/apps/pm/migrations/0017_auto_20231205_1724.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.12 on 2023-12-05 09:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0016_auto_20231130_1628'), + ] + + operations = [ + migrations.AddField( + model_name='mtask', + name='type', + field=models.CharField(default='mass', help_text="(('mass', '量产'), ('pilot', '中试'))", max_length=10, verbose_name='任务类型'), + ), + migrations.AddField( + model_name='utask', + name='type', + field=models.CharField(default='mass', help_text="(('mass', '量产'), ('pilot', '中试'))", max_length=10, verbose_name='任务类型'), + ), + ] diff --git a/apps/pm/models.py b/apps/pm/models.py index b3022d7c..1973ff3d 100644 --- a/apps/pm/models.py +++ b/apps/pm/models.py @@ -4,6 +4,11 @@ from apps.mtm.models import Material, Mgroup # Create your models here. +TASK_TYPE = ( + ('mass', '量产'), + ('pilot', '中试') +) + class Utask(CommonBDModel): """ @@ -23,6 +28,8 @@ class Utask(CommonBDModel): (UTASK_STOP, '已停止'), (UTASK_DONE, '已提交') ) + type = models.CharField('任务类型', max_length=10, + help_text=str(TASK_TYPE), default='mass') state = models.PositiveIntegerField( '状态', choices=UTASK_STATES, default=UTASK_CREATED, help_text=str(UTASK_STATES)) number = models.CharField('编号', max_length=50, unique=True) @@ -55,6 +62,8 @@ class Mtask(CommonADModel): (MTASK_STOP, '已停止'), (MTASK_DONE, '已提交') ) + type = models.CharField('任务类型', max_length=10, + help_text=str(TASK_TYPE), default='mass') state = models.PositiveIntegerField( '状态', choices=MTASK_STATES, default=MTASK_CREATED, help_text=str(MTASK_STATES)) number = models.CharField('编号', max_length=50, unique=True) diff --git a/apps/pm/services.py b/apps/pm/services.py index fce4ff6a..7f73e07c 100644 --- a/apps/pm/services.py +++ b/apps/pm/services.py @@ -71,6 +71,7 @@ class PmService: for i in range(rela_days): task_date = start_date + timedelta(days=i) Mtask.objects.create(**{ + 'type': utask.type, 'number': f'{number}_{i+1}', 'material_out': utask.material, 'material_in': utask.material_in, @@ -124,6 +125,7 @@ class PmService: task_date = start_date + timedelta(days=i) Mtask.objects.create(**{ 'number': f'{number}_r{ind+1}_{i+1}', + 'type': utask.type, 'material_out': halfgood, 'material_in': material_in, 'mgroup': mgroup, From 5dab6b0815c99167059e2f5cd393d6c3084c1220 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 7 Dec 2023 09:37:12 +0800 Subject: [PATCH 33/43] =?UTF-8?q?feat:=20base=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BA=86get=5Fmodel=5Finfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/utils/models.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/utils/models.py b/apps/utils/models.py index a23f447a..3e724bab 100755 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -1,6 +1,7 @@ import time import django.utils.timezone as timezone from django.db import models +from django.db.models import Model from django.db.models.query import QuerySet from apps.utils.snowflake import idWorker from django.db import IntegrityError @@ -184,8 +185,17 @@ class CommonBDModel(BaseModel): abstract = True -# class Smslog(BaseModel): -# """ -# 短信发送记录表 -# """ -# phone = models.CharField('号码') +def get_model_info(cls_or_instance): + """ + 返回类似 system.dept 的字符 + """ + if isinstance(cls_or_instance, Model): + # 是一个模型实例 + app_label = cls_or_instance._meta.app_label + model_name = cls_or_instance._meta.model_name + else: + # 假定是一个模型类 + app_label = cls_or_instance._meta.app_label + model_name = cls_or_instance._meta.model_name + + return f'{app_label}.{model_name}' From d9ddefe5dbbd48eb6162039dce9fa84aa4168013 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 7 Dec 2023 09:37:54 +0800 Subject: [PATCH 34/43] =?UTF-8?q?feat:=20base=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BA=86=E5=AF=B9=E6=AF=94=E5=AD=97=E5=85=B8=E5=8F=8A=E5=85=B6?= =?UTF-8?q?=E5=B5=8C=E5=A5=97=E5=86=85=E5=AE=B9=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/utils/tools.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/utils/tools.py b/apps/utils/tools.py index 18dc6661..7033a83d 100755 --- a/apps/utils/tools.py +++ b/apps/utils/tools.py @@ -9,10 +9,11 @@ import requests from io import BytesIO from rest_framework.serializers import ValidationError + def tran64(s): missing_padding = len(s) % 4 if missing_padding != 0: - s = s+'='* (4 - missing_padding) + s = s+'=' * (4 - missing_padding) return s @@ -202,4 +203,37 @@ def check_phone_e(phone): re_phone = r'^1\d{10}$' if not re.match(re_phone, phone): raise ValidationError('手机号格式错误') - return phone \ No newline at end of file + return phone + + +def compare_dicts(dict1, dict2, ignore_order=False): + if ignore_order: + for key in sorted(dict1.keys()): + if key not in dict2 or not compare_values(dict1[key], dict2[key], ignore_order): + return False + return True + else: + return dict1 == dict2 + + +def compare_lists_of_dicts(list1, list2, ignore_order=False): + """比较两个列表,这里的列表包含字典(对象)""" + if ignore_order: + # 转换列表中的字典为元组列表,然后排序进行比较 + sorted_list1 = sorted((tuple(sorted(d.items())) for d in list1)) + sorted_list2 = sorted((tuple(sorted(d.items())) for d in list2)) + return sorted_list1 == sorted_list2 + else: + # 按顺序比较列表中的字典 + return all(compare_dicts(obj1, obj2) for obj1, obj2 in zip(list1, list2)) + + +def compare_values(val1, val2, ignore_order=False): + """通用比较函数,也可以处理字典和列表。""" + if isinstance(val1, list) and isinstance(val2, list): + # 假设这里我们关心列表中对象的顺序 + return compare_lists_of_dicts(val1, val2, ignore_order) + elif isinstance(val1, dict) and isinstance(val2, dict): + return compare_dicts(val1, val2, ignore_order) + else: + return val1 == val2 From ba34b2692845ad7d0da70a44c896532cc54fb159 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 7 Dec 2023 09:38:24 +0800 Subject: [PATCH 35/43] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AE=A1?= =?UTF-8?q?=E8=AE=A1=E6=97=A5=E5=BF=97auditlog=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/monitor/migrations/0004_auditlog.py | 31 ++++++++++++ apps/monitor/models.py | 16 +++++- apps/monitor/serializers.py | 12 ++++- apps/monitor/services.py | 63 +++++++++++++++++++++++- apps/monitor/urls.py | 7 ++- apps/monitor/views.py | 17 ++++++- 6 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 apps/monitor/migrations/0004_auditlog.py diff --git a/apps/monitor/migrations/0004_auditlog.py b/apps/monitor/migrations/0004_auditlog.py new file mode 100644 index 00000000..41402798 --- /dev/null +++ b/apps/monitor/migrations/0004_auditlog.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.12 on 2023-12-07 01:35 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('monitor', '0003_alter_drfrequestlog_view_method'), + ] + + operations = [ + migrations.CreateModel( + name='AuditLog', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('action', models.CharField(max_length=20, verbose_name='动作')), + ('model_name', models.CharField(max_length=20, verbose_name='模型名')), + ('instance_id', models.CharField(editable=False, max_length=20, verbose_name='记录ID')), + ('change_reason', models.CharField(default='', max_length=50, verbose_name='变更原因')), + ('change_time', models.DateTimeField(verbose_name='变更时间')), + ('val_new', models.JSONField(default=dict, verbose_name='变更后完整数据')), + ('difference', models.JSONField(default=list, verbose_name='变更情况')), + ('change_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='操作人')), + ], + ), + ] diff --git a/apps/monitor/models.py b/apps/monitor/models.py index d20c77dc..4bf3b475 100755 --- a/apps/monitor/models.py +++ b/apps/monitor/models.py @@ -4,6 +4,19 @@ from django.db import models from apps.utils.models import BaseModel +class AuditLog(models.Model): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + action = models.CharField('动作', max_length=20) + model_name = models.CharField('模型名', max_length=20) + instance_id = models.CharField('记录ID', max_length=20, editable=False) + change_reason = models.CharField('变更原因', default='', max_length=50) + change_user = models.ForeignKey( + 'system.user', on_delete=models.SET_NULL, verbose_name='操作人', null=True, blank=True) + change_time = models.DateTimeField('变更时间') + val_new = models.JSONField('变更后完整数据', default=dict) + difference = models.JSONField('变更情况', default=list) + + class DrfRequestLog(BaseModel): """Logs Django rest framework API requests""" @@ -42,7 +55,8 @@ class DrfRequestLog(BaseModel): response = models.TextField(null=True, blank=True) errors = models.TextField(null=True, blank=True) agent = models.TextField(null=True, blank=True) - status_code = models.PositiveIntegerField(null=True, blank=True, db_index=True) + status_code = models.PositiveIntegerField( + null=True, blank=True, db_index=True) class Meta: verbose_name = "DRF请求日志" diff --git a/apps/monitor/serializers.py b/apps/monitor/serializers.py index 4a79c5aa..c2303c0d 100644 --- a/apps/monitor/serializers.py +++ b/apps/monitor/serializers.py @@ -1,4 +1,14 @@ from rest_framework import serializers +from apps.utils.serializers import CustomModelSerializer +from apps.monitor.models import AuditLog + class DbbackupDeleteSerializer(serializers.Serializer): - filepaths = serializers.ListField(child=serializers.CharField(), label="文件地址列表") \ No newline at end of file + filepaths = serializers.ListField( + child=serializers.CharField(), label="文件地址列表") + + +class AuditLogSerializer(CustomModelSerializer): + class Meta: + model = AuditLog + fields = '__all__' diff --git a/apps/monitor/services.py b/apps/monitor/services.py index 3c0a1dad..d1c83ff1 100644 --- a/apps/monitor/services.py +++ b/apps/monitor/services.py @@ -1,4 +1,63 @@ import psutil +from apps.monitor.models import AuditLog +from apps.system.models import User +from datetime import datetime +from apps.utils.tools import compare_values +from apps.utils.models import get_model_info + + +def delete_auditlog(model, instance_id): + """ + 删除其对应的审计记录 + """ + model_name = get_model_info(model) + AuditLog.objects.filter(model_name=model_name, + instance_id=instance_id).delete() + + +def create_auditlog(action: str, instance, val_new: dict, val_old: dict = None, change_reason: str = '', delete_time: datetime = None, delete_user: User = None): + """ + 生成审计日志 + action: create/update/delete/其他action + """ + app_label_model_name = get_model_info(instance) + if val_old is None: + val_old = {} + difference = [] + has_changed = False + if action == 'create': + has_changed = True + change_user = instance.create_by + change_time = instance.create_time + elif action == 'delete': + has_changed = True + change_user = delete_user if delete_user else instance.update_by + change_time = delete_time if delete_time else instance.update_time + else: + change_user = instance.update_by + change_time = instance.update_time + for k, v in val_new.items(): + if k not in ['create_by', 'update_by', 'create_time', 'update_time', 'id']: + if k not in val_old: + difference.append( + {'field': k, 'action': 'create', 'val_old': None, 'val_new': v}) + elif not compare_values(val_new.get(k), val_old.get(k), ignore_order=True): + difference.append( + {'field': k, 'action': 'update', 'val_old': val_old[k], 'val_new': v}) + if difference: + has_changed = True + if has_changed: + AuditLog.objects.create( + action=action, + model_name=app_label_model_name, + instance_id=instance.id, + val_new=val_new, + difference=difference, + change_reason=change_reason, + change_user=change_user, + change_time=change_time + ) + class ServerService: @classmethod @@ -17,7 +76,7 @@ class ServerService: ret['count'] = psutil.cpu_count(logical=False) ret['percent'] = psutil.cpu_percent(interval=1) return ret - + @classmethod def get_disk_dict(cls): ret = {} @@ -29,4 +88,4 @@ class ServerService: @classmethod def get_full(cls): - return {'cpu': cls.get_cpu_dict(), 'memory': cls.get_memory_dict(), 'disk': cls.get_disk_dict()} \ No newline at end of file + return {'cpu': cls.get_cpu_dict(), 'memory': cls.get_memory_dict(), 'disk': cls.get_disk_dict()} diff --git a/apps/monitor/urls.py b/apps/monitor/urls.py index f960a32c..66c88138 100755 --- a/apps/monitor/urls.py +++ b/apps/monitor/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from .views import DrfRequestLogViewSet, ServerInfoView, LogView, LogDetailView, index, room, video, DbBackupView +from .views import DrfRequestLogViewSet, ServerInfoView, LogView, LogDetailView, index, room, video, DbBackupView, AuditlogViewSet API_BASE_URL = 'api/monitor/' HTML_BASE_URL = 'monitor/' @@ -13,5 +13,8 @@ urlpatterns = [ path(API_BASE_URL + 'log//', LogDetailView.as_view()), path(API_BASE_URL + 'dbbackup/', DbBackupView.as_view()), path(API_BASE_URL + 'server/', ServerInfoView.as_view()), - path(API_BASE_URL + 'request_log/', DrfRequestLogViewSet.as_view({'get': 'list'}), name='requestlog_view') + path(API_BASE_URL + 'request_log/', + DrfRequestLogViewSet.as_view({'get': 'list'}), name='requestlog_view'), + path(API_BASE_URL + 'auditlog/', + AuditlogViewSet.as_view({'get': 'list'}), name='auditlog_view') ] diff --git a/apps/monitor/views.py b/apps/monitor/views.py index da476795..a840fe64 100755 --- a/apps/monitor/views.py +++ b/apps/monitor/views.py @@ -7,13 +7,13 @@ from rest_framework.permissions import IsAuthenticated from django.conf import settings import os from rest_framework import serializers -from apps.monitor.serializers import DbbackupDeleteSerializer +from apps.monitor.serializers import DbbackupDeleteSerializer, AuditLogSerializer from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from rest_framework.exceptions import NotFound from rest_framework.mixins import ListModelMixin from apps.monitor.filters import DrfLogFilterSet -from apps.monitor.models import DrfRequestLog +from apps.monitor.models import DrfRequestLog, AuditLog from apps.monitor.errors import LOG_NOT_FONED from apps.monitor.services import ServerService @@ -188,3 +188,16 @@ class DrfRequestLogViewSet(ListModelMixin, CustomGenericViewSet): ordering = ['-requested_at'] filterset_class = DrfLogFilterSet search_fields = ['path', 'view'] + + +class AuditlogViewSet(ListModelMixin, CustomGenericViewSet): + """审计日志 + + 审计日志 + """ + perms_map = {'get': '*'} + queryset = AuditLog.objects.all() + list_serializer_class = AuditLogSerializer + ordering = ['-change_time'] + filterset_fields = ['change_user'] + search_fields = ['model_name', 'action'] From 2d8169849fd92c6df7bb5dcbf4ca9f902314078c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 7 Dec 2023 09:39:52 +0800 Subject: [PATCH 36/43] =?UTF-8?q?feat:=20=E5=B0=86mlog=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AE=A1=E8=AE=A1=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index b13d51e0..321e3792 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -19,6 +19,7 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer, GenHandoverSerializer, GenHandoverWmSerializer, MlogAnaSerializer, AttLogSerializer, OtherLogSerializer) from .services import mlog_submit, update_mtask, handover_submit +from apps.monitor.services import create_auditlog, delete_auditlog # Create your views here. @@ -135,10 +136,18 @@ class MlogViewSet(CustomModelViewSet): prefetch_related_fields = ['handle_users', 'material_outs', 'b_mlog'] filterset_class = MlogFilter + @transaction.atomic + def perform_create(self, serializer): + ins = serializer.save() + data = MlogSerializer(ins).data + create_auditlog('create', ins, data) + + @transaction.atomic def perform_destroy(self, instance): if instance.submit_time is not None: raise ParseError('日志已提交不可变动') - return super().perform_destroy(instance) + delete_auditlog(instance, instance.id) + instance.delete() @action(methods=['post'], detail=True, perms_map={'post': 'mlog.submit'}, serializer_class=Serializer) @transaction.atomic @@ -148,10 +157,13 @@ class MlogViewSet(CustomModelViewSet): 日志提交 """ ins: Mlog = self.get_object() + vdata_old = MlogSerializer(ins).data if ins.submit_time is None: mlog_submit(ins, self.request.user, None) if ins.mtask: update_mtask(ins.mtask) + vdata_new = MlogSerializer(ins).data + create_auditlog('submit', ins, vdata_new, vdata_old) return Response() @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MlogRelatedSerializer) From 179782c73bb440b6bd8a22af8d1c0c7b727c160e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 7 Dec 2023 09:40:13 +0800 Subject: [PATCH 37/43] =?UTF-8?q?feat:=20auditlog=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=AD=9B=E9=80=89=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/monitor/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/monitor/views.py b/apps/monitor/views.py index a840fe64..1ed2a2fa 100755 --- a/apps/monitor/views.py +++ b/apps/monitor/views.py @@ -199,5 +199,5 @@ class AuditlogViewSet(ListModelMixin, CustomGenericViewSet): queryset = AuditLog.objects.all() list_serializer_class = AuditLogSerializer ordering = ['-change_time'] - filterset_fields = ['change_user'] + filterset_fields = ['change_user', 'model_name', 'action', 'instance_id'] search_fields = ['model_name', 'action'] From ea63c29a69e82ae0602099cb07d4d22b9db6e638 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 7 Dec 2023 10:55:06 +0800 Subject: [PATCH 38/43] =?UTF-8?q?feat:=20mlog=E6=9C=89mtask=E6=97=B6?= =?UTF-8?q?=E5=9B=BA=E5=AE=9Ahandle=5Fdate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index a79ad203..375739d4 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -223,6 +223,7 @@ class MlogSerializer(CustomModelSerializer): validated_data['material_in'] = mtask.material_in material_out = mtask.material_out validated_data['material_out'] = material_out + validated_data['handle_date'] = mtask.start_date # if not WMaterial.objects.filter(batch=batch).exists(): # raise ValidationError('批次号不存在') else: From 768a07a39a722cc331a31e5ac8a3d0b00114d0e8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 13 Dec 2023 16:08:16 +0800 Subject: [PATCH 39/43] =?UTF-8?q?feat:=20mio=E5=A2=9E=E5=8A=A0=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/inm/views.py b/apps/inm/views.py index 3be9d42f..d0633b2a 100644 --- a/apps/inm/views.py +++ b/apps/inm/views.py @@ -124,7 +124,12 @@ class MIOViewSet(CustomModelViewSet): 'submit_user', 'supplier', 'order', 'customer', 'pu_order'] serializer_class = MIOListSerializer retrieve_serializer_class = MIODetailSerializer - filterset_fields = ['state', 'type', 'pu_order', 'order'] + filterset_fields = { + 'state': ["exact", "in"], + "type": ["exact", "in"], + "pu_order": ["exact"], + "order": ["exact"] + } search_fields = ['number'] data_filter = True From 6b6ff7cd3c76bb371932c08f47d01a3ff021b4ca Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 14 Dec 2023 10:36:47 +0800 Subject: [PATCH 40/43] =?UTF-8?q?feat:=20mlog=E6=9B=B4=E6=96=B0=E6=97=B6?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 321e3792..4dbe0a50 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -149,6 +149,14 @@ class MlogViewSet(CustomModelViewSet): delete_auditlog(instance, instance.id) instance.delete() + @transaction.atomic + def perform_update(self, serializer): + ins = serializer.instance + val_old = MlogSerializer(instance=ins).data + serializer.save() + val_new = MlogSerializer(instance=ins).data + create_auditlog('update', ins, val_new, val_old) + @action(methods=['post'], detail=True, perms_map={'post': 'mlog.submit'}, serializer_class=Serializer) @transaction.atomic def submit(self, request): From 4916ae5cffba363733da51ba70b5626848d1a8f9 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 14 Dec 2023 17:14:29 +0800 Subject: [PATCH 41/43] =?UTF-8?q?feat:=20audit=5Flog=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0change=5Fuser=5Fname?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/monitor/serializers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/monitor/serializers.py b/apps/monitor/serializers.py index c2303c0d..20f3ba53 100644 --- a/apps/monitor/serializers.py +++ b/apps/monitor/serializers.py @@ -9,6 +9,9 @@ class DbbackupDeleteSerializer(serializers.Serializer): class AuditLogSerializer(CustomModelSerializer): + change_user_name = serializers.CharField( + source='change_user.name', read_only=True) + class Meta: model = AuditLog fields = '__all__' From 128dc2a7e3dee63839d8a13ee7f8cd385e4ff74d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 15 Dec 2023 09:05:08 +0800 Subject: [PATCH 42/43] =?UTF-8?q?feat:=20utask=20mtask=E7=8A=B6=E6=80=81su?= =?UTF-8?q?bmit=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/filters.py | 24 ++++++++++++++---------- apps/pm/models.py | 8 ++++---- apps/pm/services.py | 2 +- apps/wpm/services.py | 4 ++-- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/pm/filters.py b/apps/pm/filters.py index 8ce6e260..9a0bd81a 100644 --- a/apps/pm/filters.py +++ b/apps/pm/filters.py @@ -38,7 +38,7 @@ class UtaskFilter(filters.FilterSet): class MtaskFilter(filters.FilterSet): - tag = filters.CharFilter(method='filter_tag') + tag = filters.CharFilter(method='filter_tag', label='done, not_done') class Meta: model = Mtask @@ -60,13 +60,17 @@ class MtaskFilter(filters.FilterSet): } def filter_tag(self, queryset, name, value): - now = timezone.now() - day7_after = now + timedelta(days=7) - if value == 'near_done': - queryset = queryset.filter(count_ok__lt=F('count'), - end_date__lte=day7_after.date(), - end_date__gte=now.date()) - elif value == 'out_done': - queryset = queryset.filter(count_ok__lt=F('count'), - end_date__lt=now.date()) + # now = timezone.now() + # day7_after = now + timedelta(days=7) + # if value == 'near_done': + # queryset = queryset.filter(count_ok__lt=F('count'), + # end_date__lte=day7_after.date(), + # end_date__gte=now.date()) + # elif value == 'out_done': + # queryset = queryset.filter(count_ok__lt=F('count'), + # end_date__lt=now.date()) + if value == 'done': + queryset = queryset.filter(count_ok__gte=F('count')) + elif value == 'not_done': + queryset = queryset.filter(count_ok__lt=F('count')) return queryset diff --git a/apps/pm/models.py b/apps/pm/models.py index 1973ff3d..b518284a 100644 --- a/apps/pm/models.py +++ b/apps/pm/models.py @@ -19,14 +19,14 @@ class Utask(CommonBDModel): UTASK_ASSGINED = 20 UTASK_WORKING = 30 UTASK_STOP = 34 - UTASK_DONE = 40 + UTASK_SUBMIT = 40 UTASK_STATES = ( (UTASK_CREATED, '创建中'), (UTASK_DECOMPOSE, '已分解'), (UTASK_ASSGINED, '已下达'), (UTASK_WORKING, '生产中'), (UTASK_STOP, '已停止'), - (UTASK_DONE, '已提交') + (UTASK_SUBMIT, '已提交') ) type = models.CharField('任务类型', max_length=10, help_text=str(TASK_TYPE), default='mass') @@ -55,12 +55,12 @@ class Mtask(CommonADModel): MTASK_CREATED = 10 MTASK_ASSGINED = 20 MTASK_STOP = 34 - MTASK_DONE = 40 + MTASK_SUBMIT = 40 MTASK_STATES = ( (MTASK_CREATED, '创建中'), (MTASK_ASSGINED, '已下达'), (MTASK_STOP, '已停止'), - (MTASK_DONE, '已提交') + (MTASK_SUBMIT, '已提交') ) type = models.CharField('任务类型', max_length=10, help_text=str(TASK_TYPE), default='mass') diff --git a/apps/pm/services.py b/apps/pm/services.py index 7f73e07c..16a6af8e 100644 --- a/apps/pm/services.py +++ b/apps/pm/services.py @@ -267,7 +267,7 @@ class PmService: for mlog in mlogs: mlog_submit(mlog, user, now) update_mtask(mtask) - mtask.state = Mtask.MTASK_DONE + mtask.state = Mtask.MTASK_SUBMIT mtask.submit_time = now mtask.submit_user = user mtask.save() diff --git a/apps/wpm/services.py b/apps/wpm/services.py index a3b26f63..b5c4f462 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -202,8 +202,8 @@ def update_mtask(mtask: Mtask): utask.count_notok = res2['sum_count_notok'] if res2['sum_count_notok'] else 0 if utask.count_ok > 0 and utask.state == Utask.UTASK_ASSGINED: utask.state = Utask.UTASK_WORKING - if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_DONE).count() == 0: - utask.state = Utask.UTASK_DONE + if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_SUBMIT).count() == 0: + utask.state = Utask.UTASK_SUBMIT utask.save() From eadf36c1d199ff7f97393950b07f79a4a0f5eba8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 15 Dec 2023 19:39:17 +0800 Subject: [PATCH 43/43] =?UTF-8?q?fix:=20mioitem=E4=BF=AE=E6=94=B9=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...11_rename_is_bgtest_ok_mioitem_is_testok.py | 18 ++++++++++++++++++ apps/inm/models.py | 2 +- apps/inm/serializers.py | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 apps/inm/migrations/0011_rename_is_bgtest_ok_mioitem_is_testok.py diff --git a/apps/inm/migrations/0011_rename_is_bgtest_ok_mioitem_is_testok.py b/apps/inm/migrations/0011_rename_is_bgtest_ok_mioitem_is_testok.py new file mode 100644 index 00000000..4f461d3e --- /dev/null +++ b/apps/inm/migrations/0011_rename_is_bgtest_ok_mioitem_is_testok.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2023-12-15 11:38 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('inm', '0010_auto_20231116_1904'), + ] + + operations = [ + migrations.RenameField( + model_name='mioitem', + old_name='is_bgtest_ok', + new_name='is_testok', + ), + ] diff --git a/apps/inm/models.py b/apps/inm/models.py index 0c5863f3..c82ad6e0 100644 --- a/apps/inm/models.py +++ b/apps/inm/models.py @@ -121,7 +121,7 @@ class MIOItem(BaseModel): count_n_jsqx = models.PositiveIntegerField('结石气线', default=0) count_n_qt = models.PositiveIntegerField('其他', default=0) - is_bgtest_ok = models.BooleanField('配套件是否合格', default=True) + is_testok = models.BooleanField('配套件是否合格', default=True) class MIOItemA(BaseModel): diff --git a/apps/inm/serializers.py b/apps/inm/serializers.py index c2777890..6d35ae64 100644 --- a/apps/inm/serializers.py +++ b/apps/inm/serializers.py @@ -94,7 +94,7 @@ class MIOItemCreateSerializer(CustomModelSerializer): class Meta: model = MIOItem fields = ['mio', 'warehouse', 'material', - 'batch', 'count', 'assemb', 'is_bgtest_ok'] + 'batch', 'count', 'assemb', 'is_testok'] def create(self, validated_data): mio = validated_data['mio']