diff --git a/apps/mtm/admin.py b/apps/mtm/admin.py index 66dc4a89..4cc50f4c 100644 --- a/apps/mtm/admin.py +++ b/apps/mtm/admin.py @@ -5,7 +5,7 @@ from apps.mtm.models import Material, Shift, Mgroup, Process @admin.register(Process) class ProcessAdmin(admin.ModelAdmin): - list_display = ('id', 'name', 'cate', 'sort') + list_display = ('id', 'name', 'cate', 'sort', 'into_wm_mgroup') @admin.register(Material) diff --git a/apps/mtm/migrations/0032_auto_20240702_1409.py b/apps/mtm/migrations/0032_auto_20240702_1409.py new file mode 100644 index 00000000..3f21a3c2 --- /dev/null +++ b/apps/mtm/migrations/0032_auto_20240702_1409.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.12 on 2024-07-02 06:09 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('wf', '0002_alter_state_filter_dept'), + ('mtm', '0031_process_into_wm_mgroup'), + ] + + operations = [ + migrations.CreateModel( + name='RoutePack', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('state', models.PositiveSmallIntegerField(choices=[(10, '创建中'), (20, '审批中'), (30, '已确认')], default=10, verbose_name='状态')), + ('name', models.CharField(max_length=100, verbose_name='名称')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='routepack_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='产品')), + ('ticket', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='routepack_ticket', to='wf.ticket', verbose_name='关联工单')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='routepack_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='route', + name='routepack', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.routepack', verbose_name='关联路线包'), + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 377b2bec..a372d337 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -166,10 +166,30 @@ class Goal(CommonADModel): unique_together = ("mgroup", "year", "goal_cate") +class RoutePack(CommonADModel): + """ + 加工工艺 + """ + RP_S_CREATE = 10 + RP_S_AUDIT = 20 + RP_S_CONFIRM = 30 + RP_STATE = ( + (RP_S_CREATE, '创建中'), + (RP_S_AUDIT, '审批中'), + (RP_S_CONFIRM, '已确认'), + ) + state = models.PositiveSmallIntegerField('状态', default=10, choices=RP_STATE) + name = models.CharField('名称', max_length=100) + material = models.ForeignKey( + Material, verbose_name='产品', on_delete=models.CASCADE) + ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', + on_delete=models.SET_NULL, related_name='routepack_ticket', null=True, blank=True, db_constraint=False) + class Route(CommonADModel): """ 加工路线 """ + routepack = models.ForeignKey(RoutePack, verbose_name='关联路线包', on_delete=models.CASCADE, null=True, blank=True) material = models.ForeignKey( Material, verbose_name='关联产品', on_delete=models.CASCADE, null=True, blank=True) process = models.ForeignKey( diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index 4389b899..77d58044 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -1,5 +1,5 @@ from apps.utils.serializers import CustomModelSerializer -from apps.mtm.models import Shift, Material, Mgroup, Team, Goal, Process, Route, TeamMember +from apps.mtm.models import Shift, Material, Mgroup, Team, Goal, Process, Route, TeamMember, RoutePack from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS_DEPT from rest_framework import serializers from rest_framework.exceptions import ValidationError, ParseError @@ -128,6 +128,20 @@ class ProcessSerializer(CustomModelSerializer): read_only_fields = EXCLUDE_FIELDS +class RoutePackSerializer(CustomModelSerializer): + material_name = serializers.StringRelatedField( + source='material', read_only=True) + class Meta: + model = RoutePack + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + ['state'] + + def update(self, instance, validated_data): + if validated_data['material'] != instance.material: + raise ParseError('不可变更产品') + return super().update(instance, validated_data) + + class RouteSerializer(CustomModelSerializer): material_ = MaterialSerializer(source='material', read_only=True) process_name = serializers.CharField(source='process.name', read_only=True) diff --git a/apps/mtm/urls.py b/apps/mtm/urls.py index 844e1636..0e879705 100644 --- a/apps/mtm/urls.py +++ b/apps/mtm/urls.py @@ -2,7 +2,8 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter from apps.mtm.views import (MgroupViewSet, ShiftViewSet, TeamViewSet, MaterialViewSet, - GoalViewSet, ProcessViewSet, RouteViewSet, TeamMemberViewSet) + GoalViewSet, ProcessViewSet, RouteViewSet, TeamMemberViewSet, + RoutePackViewSet) API_BASE_URL = 'api/mtm/' HTML_BASE_URL = 'mtm/' @@ -14,6 +15,7 @@ router.register('material', MaterialViewSet, basename='material') router.register('shift', ShiftViewSet, basename='shift') router.register('goal', GoalViewSet, basename='goal') router.register('process', ProcessViewSet, basename='process') +router.register('routepack', RoutePackViewSet, basename='routepack') router.register('route', RouteViewSet, basename='route') router.register('teammember', TeamMemberViewSet, basename='teammember') urlpatterns = [ diff --git a/apps/mtm/views.py b/apps/mtm/views.py index 4133f8fe..8f9e67d5 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -6,10 +6,11 @@ from rest_framework.response import Response from rest_framework.exceptions import ParseError from apps.mtm.filters import GoalFilter, MaterialFilter, RouteFilter -from apps.mtm.models import Goal, Material, Mgroup, Shift, Team, Process, Route, TeamMember +from apps.mtm.models import Goal, Material, Mgroup, Shift, Team, Process, Route, TeamMember, RoutePack from apps.mtm.serializers import (GoalSerializer, MaterialSerializer, MgroupGoalYearSerializer, MgroupSerializer, - ShiftSerializer, TeamSerializer, ProcessSerializer, RouteSerializer, TeamMemberSerializer) + ShiftSerializer, TeamSerializer, ProcessSerializer, + RouteSerializer, TeamMemberSerializer, RoutePackSerializer) from apps.mtm.services import get_mgroup_goals, daoru_material from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin @@ -173,6 +174,31 @@ class ProcessViewSet(CustomModelViewSet): return super().perform_destroy(instance) + +class RoutePackViewSet(CustomModelViewSet): + """ + list: 工艺路线包 + + 工艺路线包 + """ + queryset = RoutePack.objects.all() + serializer_class = RoutePackSerializer + search_fields = ['name'] + select_related_fields = ['material'] + filterset_fields = ['material'] + + def update(self, request, *args, **kwargs): + obj: RoutePack = self.get_object() + if obj.state != RoutePack.RP_S_CREATE: + raise ParseError('该状态下不可编辑') + return super().update(request, *args, **kwargs) + + def destroy(self, request, *args, **kwargs): + obj: RoutePack = self.get_object() + if obj.state != RoutePack.RP_S_CREATE: + raise ParseError('该状态下不可删除') + return super().destroy(request, *args, **kwargs) + class RouteViewSet(CustomModelViewSet): queryset = Route.objects.all() serializer_class = RouteSerializer