diff --git a/apps/mtm/migrations/0025_auto_20231120_1139.py b/apps/mtm/migrations/0025_auto_20231120_1139.py new file mode 100644 index 00000000..067c5df7 --- /dev/null +++ b/apps/mtm/migrations/0025_auto_20231120_1139.py @@ -0,0 +1,49 @@ +# Generated by Django 3.2.12 on 2023-11-20 03:39 + +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), + ('system', '0002_myschedule'), + ('mtm', '0024_auto_20231116_1416'), + ] + + operations = [ + migrations.AddField( + model_name='mgroup', + name='shift_rule', + field=models.CharField(default='默认', max_length=10, verbose_name='班次规则'), + ), + migrations.AddField( + model_name='shift', + name='belong_dept', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='shift_belong_dept', to='system.dept', verbose_name='所属部门'), + ), + migrations.AddField( + model_name='shift', + name='rule', + field=models.CharField(default='默认', max_length=10, verbose_name='所属规则'), + ), + migrations.CreateModel( + name='TeamMember', + 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='删除标记')), + ('mgroup', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.mgroup', verbose_name='所在工段')), + ('post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.post', verbose_name='岗位')), + ('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.team', verbose_name='关联班组')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='成员')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 4ba0ff58..8836d176 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -75,10 +75,11 @@ class Material(CommonAModel): return f'{self.name}-{self.model}-{self.specification}' -class Shift(CommonAModel): +class Shift(CommonBModel): """班次 """ name = models.CharField('名称', max_length=50) + rule = models.CharField('所属规则', max_length=10, default='默认') start_time_o = models.TimeField('开始时间') end_time_o = models.TimeField('结束时间') @@ -87,7 +88,7 @@ class Shift(CommonAModel): class Team(CommonBModel): - """班组 + """班组, belong_dept为所属车间 """ name = models.CharField('名称', max_length=50) leader = models.ForeignKey( @@ -101,6 +102,7 @@ class Mgroup(CommonBModel): name = models.CharField('名称', max_length=50) cate = models.CharField( '分类', max_length=50, default='section', help_text='section/other') # section是工段 + shift_rule = models.CharField('班次规则', max_length=10, default='默认') process = models.ForeignKey( Process, verbose_name='工序', on_delete=models.SET_NULL, null=True, blank=True) product = models.ForeignKey( @@ -118,6 +120,17 @@ class Mgroup(CommonBModel): ordering = ['sort', '-create_time'] +class TeamMember(BaseModel): + team = models.ForeignKey(Team, verbose_name='关联班组', + on_delete=models.CASCADE) + user = models.ForeignKey( + 'system.user', verbose_name='成员', on_delete=models.CASCADE) + mgroup = models.ForeignKey( + Mgroup, verbose_name='所在工段', on_delete=models.CASCADE) + post = models.ForeignKey('system.post', verbose_name='岗位', + on_delete=models.SET_NULL, null=True, blank=True) + + class Goal(CommonADModel): """目标 """ diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index ba47b93b..bc5d476f 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -1,9 +1,9 @@ from apps.utils.serializers import CustomModelSerializer -from apps.mtm.models import Shift, Material, Mgroup, Team, Goal, Process, Route -from apps.utils.constants import EXCLUDE_FIELDS +from apps.mtm.models import Shift, Material, Mgroup, Team, Goal, Process, Route, TeamMember +from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS_DEPT from rest_framework import serializers -from rest_framework.exceptions import ValidationError -from apps.system.models import Dept +from rest_framework.exceptions import ValidationError, ParseError +from apps.system.models import Dept, UserPost from django.db import transaction @@ -44,6 +44,29 @@ class MgroupSerializer(CustomModelSerializer): read_only_fields = EXCLUDE_FIELDS +class TeamMemberSerializer(CustomModelSerializer): + user_name = serializers.CharField(source='user.name', read_only=True) + mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) + post_name = serializers.CharField(source='post.name', read_only=True) + + class Meta: + model = Team + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS_BASE + + def validate(self, attrs): + user = attrs['user'] + post = attrs.get('post', None) + if post is None: + userpost = UserPost.objects.filter( + dept=attrs['mgroup'].belong_dept, user=user).first() + if userpost: + attrs['post'] = userpost.post + else: + raise ParseError(f'{user.name}未配置岗位') + return super().validate(attrs) + + class TeamSerializer(CustomModelSerializer): belong_dept = serializers.PrimaryKeyRelatedField( label="所属部门", queryset=Dept.objects.all(), required=True) diff --git a/apps/mtm/urls.py b/apps/mtm/urls.py index e6e2402c..844e1636 100644 --- a/apps/mtm/urls.py +++ b/apps/mtm/urls.py @@ -1,7 +1,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) +from apps.mtm.views import (MgroupViewSet, ShiftViewSet, TeamViewSet, MaterialViewSet, + GoalViewSet, ProcessViewSet, RouteViewSet, TeamMemberViewSet) API_BASE_URL = 'api/mtm/' HTML_BASE_URL = 'mtm/' @@ -14,6 +15,7 @@ router.register('shift', ShiftViewSet, basename='shift') router.register('goal', GoalViewSet, basename='goal') router.register('process', ProcessViewSet, basename='process') router.register('route', RouteViewSet, basename='route') +router.register('teammember', TeamMemberViewSet, basename='teammember') urlpatterns = [ path(API_BASE_URL, include(router.urls)), -] \ No newline at end of file +] diff --git a/apps/mtm/views.py b/apps/mtm/views.py index d97df4b1..4e16b577 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -5,12 +5,13 @@ 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 +from apps.mtm.models import Goal, Material, Mgroup, Shift, Team, Process, Route, TeamMember from apps.mtm.serializers import (GoalSerializer, MaterialSerializer, MgroupGoalYearSerializer, MgroupSerializer, - ShiftSerializer, TeamSerializer, ProcessSerializer, RouteSerializer) + ShiftSerializer, TeamSerializer, ProcessSerializer, RouteSerializer, TeamMemberSerializer) from apps.mtm.services import get_mgroup_goals from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet +from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin # Create your views here. @@ -68,6 +69,19 @@ class TeamViewSet(CustomModelViewSet): search_fields = ['name'] +class TeamMemberViewSet(ListModelMixin, BulkCreateModelMixin, BulkDestroyModelMixin, CustomGenericViewSet): + """ + list: 班组成员 + + 班组成员 + """ + perms_map = {'get': '*', 'post': 'team.update', 'delete': 'team.delete'} + queryset = TeamMember.objects.all() + serializer_class = TeamMemberSerializer + select_related_fields = ['mgroup', 'post', 'team', 'user'] + filterset_fields = ['mgroup', 'post', 'team'] + + class GoalViewSet(CustomModelViewSet): """ list: 目标