diff --git a/apps/pm/__init__.py b/apps/pm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/pm/admin.py b/apps/pm/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/pm/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/pm/apps.py b/apps/pm/apps.py new file mode 100644 index 00000000..33ab5967 --- /dev/null +++ b/apps/pm/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PmConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.pm' diff --git a/apps/pm/filters.py b/apps/pm/filters.py new file mode 100644 index 00000000..0e63bf68 --- /dev/null +++ b/apps/pm/filters.py @@ -0,0 +1,32 @@ +from django_filters import rest_framework as filters +from apps.pm.models import Mtask +from django.utils import timezone +from datetime import datetime, timedelta +from django.db.models import F + +class MtaskFilter(filters.FilterSet): + tag = filters.CharFilter(method='filter_tag') + class Meta: + model = Mtask + fields = { + "state": ["exact", "in"], + "start_date": ["exact", "gte", "lte"], + "end_date": ["exact", "gte", "lte"], + "process": ["exact"], + "process__cate": ["exact"], + "material": ["exact"], + "order": ["exact"], + "parent": ["exact", "isnull"] + } + + 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()) + return queryset \ No newline at end of file diff --git a/apps/pm/migrations/0001_initial.py b/apps/pm/migrations/0001_initial.py new file mode 100644 index 00000000..38572a37 --- /dev/null +++ b/apps/pm/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 3.2.12 on 2023-09-22 08:51 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('sam', '0002_auto_20230921_1018'), + ('system', '0002_myschedule'), + ('mtm', '0011_auto_20230922_1601'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Mtask', + 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.PositiveIntegerField(choices=[(10, '创建中'), (20, '已下达'), (30, '生产中'), (40, '已完成')], default=10, help_text="((10, '创建中'), (20, '已下达'), (30, '生产中'), (40, '已完成'))", verbose_name='状态')), + ('number', models.CharField(max_length=50, unique=True, verbose_name='编号')), + ('count', models.PositiveIntegerField(default=1, verbose_name='任务数')), + ('count_real', models.PositiveIntegerField(default=0, verbose_name='实际生产数')), + ('count_ok', models.PositiveIntegerField(default=0, verbose_name='合格数')), + ('count_notok', models.PositiveIntegerField(default=0, verbose_name='不合格数')), + ('start_date', models.DateField(verbose_name='计划开工日期')), + ('end_date', models.DateField(verbose_name='计划完工日期')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mtask_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mtask_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='产品')), + ('order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mtask_order', to='sam.order', verbose_name='所属订单')), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pm.mtask', verbose_name='父任务')), + ('process', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.process', verbose_name='工序')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mtask_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/pm/migrations/__init__.py b/apps/pm/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/pm/models.py b/apps/pm/models.py new file mode 100644 index 00000000..960b6027 --- /dev/null +++ b/apps/pm/models.py @@ -0,0 +1,33 @@ +from django.db import models +from apps.utils.models import CommonBModel +from apps.sam.models import Order +from apps.mtm.models import Material, Process + +# Create your models here. + +class Mtask(CommonBModel): + """ + 生产任务 + """ + MTASK_CREATED = 10 + MTASK_ASSGINED = 20 + MTASK_WORKING = 30 + MTASK_DONE = 40 + MTASK_STATES = ( + (MTASK_CREATED, '创建中'), + (MTASK_ASSGINED, '已下达'), + (MTASK_WORKING, '生产中'), + (MTASK_DONE, '已完成') + ) + state = models.PositiveIntegerField('状态', choices=MTASK_STATES, default=MTASK_CREATED, help_text=str(MTASK_STATES)) + number = models.CharField('编号', max_length=50, unique=True) + order = models.ForeignKey(Order, verbose_name='所属订单', null=True, blank=True, on_delete=models.SET_NULL, related_name='mtask_order') + process = models.ForeignKey(Process, verbose_name='工序', on_delete=models.CASCADE) + material = models.ForeignKey(Material, verbose_name='产品', on_delete=models.CASCADE) + count = models.PositiveIntegerField('任务数', default=1) + count_real = models.PositiveIntegerField('实际生产数', default=0) + count_ok = models.PositiveIntegerField('合格数', default=0) + count_notok = models.PositiveIntegerField('不合格数', default=0) + start_date = models.DateField('计划开工日期') + end_date = models.DateField('计划完工日期') + parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='父任务') \ No newline at end of file diff --git a/apps/pm/serializers.py b/apps/pm/serializers.py new file mode 100644 index 00000000..7bad5eda --- /dev/null +++ b/apps/pm/serializers.py @@ -0,0 +1,9 @@ +from apps.utils.serializers import CustomModelSerializer +from apps.pm.models import Mtask +from apps.mtm.serializers import MaterialSerializer + +class MtaskSerializer(CustomModelSerializer): + material_ = MaterialSerializer(source='material', read_only=True) + class Meta: + model = Mtask + fields = '__all__' \ No newline at end of file diff --git a/apps/pm/services.py b/apps/pm/services.py new file mode 100644 index 00000000..fd827998 --- /dev/null +++ b/apps/pm/services.py @@ -0,0 +1,2 @@ +class PmService: + pass \ No newline at end of file diff --git a/apps/pm/tests.py b/apps/pm/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/pm/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/pm/urls.py b/apps/pm/urls.py new file mode 100644 index 00000000..725faae1 --- /dev/null +++ b/apps/pm/urls.py @@ -0,0 +1,12 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from apps.pm.views import (MtaskViewSet) + +API_BASE_URL = 'api/pm/' +HTML_BASE_URL = 'pm/' + +router = DefaultRouter() +router.register('mtask', MtaskViewSet, basename='mtask') +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] \ No newline at end of file diff --git a/apps/pm/views.py b/apps/pm/views.py new file mode 100644 index 00000000..5aeefb2f --- /dev/null +++ b/apps/pm/views.py @@ -0,0 +1,15 @@ +from django.shortcuts import render +from apps.utils.viewsets import CustomModelViewSet +from apps.pm.models import Mtask +from apps.pm.serializers import MtaskSerializer +from apps.pm.filters import MtaskFilter +# Create your views here. + +class MtaskViewSet(CustomModelViewSet): + queryset = Mtask.objects.all() + serializer_class = MtaskSerializer + filterset_class = MtaskFilter + select_related_fields = ['material', 'process', 'order'] + ordering_fields = ['start_date', 'process__sort'] + ordering = ['process__sort', '-start_date', '-create_time'] + diff --git a/server/settings.py b/server/settings.py index e91e7381..05550801 100755 --- a/server/settings.py +++ b/server/settings.py @@ -107,7 +107,8 @@ INSTALLED_APPS = [ 'apps.fim', 'apps.inm', 'apps.sam', - 'apps.pum' + 'apps.pum', + 'apps.pm' ] MIDDLEWARE = [ diff --git a/server/urls.py b/server/urls.py index 49861982..3fe2146d 100755 --- a/server/urls.py +++ b/server/urls.py @@ -64,6 +64,7 @@ urlpatterns = [ path('', include('apps.inm.urls')), path('', include('apps.sam.urls')), path('', include('apps.pum.urls')), + path('', include('apps.pm.urls')),