From 9504b527cb34e68c9cd132ee78324bb19c4cd6b2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 27 Sep 2023 15:41:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E8=BD=A6=E9=97=B4?= =?UTF-8?q?=E5=BA=93=E5=AD=98=E5=B9=B6=E5=AE=8C=E6=88=90=E7=94=9F=E4=BA=A7?= =?UTF-8?q?=E9=A2=86=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inm/migrations/0003_auto_20230927_1516.py | 26 +++++++++ apps/inm/models.py | 37 ++++++++----- apps/inm/serializers.py | 49 +++++++++++++---- apps/inm/services.py | 20 ++++--- apps/inm/views.py | 26 ++++++--- apps/mtm/models.py | 2 +- apps/utils/viewsets.py | 14 ++--- apps/wpm/migrations/0011_wmaterial.py | 37 +++++++++++++ apps/wpm/models.py | 14 ++++- apps/wpm/serializers.py | 25 +++++++-- apps/wpm/services.py | 40 +++++++++++--- apps/wpm/urls.py | 6 +-- apps/wpm/views.py | 53 +++++++++++++------ 13 files changed, 275 insertions(+), 74 deletions(-) create mode 100644 apps/inm/migrations/0003_auto_20230927_1516.py create mode 100644 apps/wpm/migrations/0011_wmaterial.py diff --git a/apps/inm/migrations/0003_auto_20230927_1516.py b/apps/inm/migrations/0003_auto_20230927_1516.py new file mode 100644 index 00000000..5080d834 --- /dev/null +++ b/apps/inm/migrations/0003_auto_20230927_1516.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.12 on 2023-09-27 07:16 + +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), + ('inm', '0002_mio_mioitem'), + ] + + operations = [ + migrations.AddField( + model_name='mio', + name='pick_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='领料人'), + ), + migrations.AlterField( + model_name='mioitem', + name='batch', + field=models.CharField(max_length=50, verbose_name='批次号'), + ), + ] diff --git a/apps/inm/models.py b/apps/inm/models.py index 52108b4d..49b30ef0 100644 --- a/apps/inm/models.py +++ b/apps/inm/models.py @@ -3,8 +3,10 @@ from apps.utils.models import BaseModel, CommonBModel, CommonBDModel from apps.pum.models import Supplier, PuOrder from apps.sam.models import Customer, Order from apps.mtm.models import Material +from apps.system.models import User # Create your models here. + class WareHouse(CommonBModel): """ 仓库信息 @@ -31,7 +33,7 @@ class MIO(CommonBDModel): """ 出入库记录 """ - MIO_TYPE_DO_OUT = 'do_out' + MIO_TYPE_DO_OUT = 'do_out' MIO_TYPE_SALE_OUT = 'sale_out' MIO_TYPE_PUR_IN = 'pur_in' MIO_TYPE_DO_IN = 'do_in' @@ -53,24 +55,35 @@ class MIO(CommonBDModel): (MIO_SUBMITED, '已提交') ) number = models.CharField('编号', max_length=20) - state = models.PositiveSmallIntegerField('状态', choices=MIO_STATES, default=10, help_text=str(MIO_CREATE)) - type = models.CharField('出入库类型', max_length=10, default=MIO_TYPE_DO_OUT, choices=MIO_TYPES, help_text=str(MIO_TYPES)) + state = models.PositiveSmallIntegerField( + '状态', choices=MIO_STATES, default=10, help_text=str(MIO_CREATE)) + type = models.CharField('出入库类型', max_length=10, default=MIO_TYPE_DO_OUT, + choices=MIO_TYPES, help_text=str(MIO_TYPES)) inout_date = models.DateField('出入库日期', null=True, blank=True) - supplier = models.ForeignKey(Supplier, verbose_name='供应商', on_delete=models.CASCADE, null=True, blank=True) - customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE, null=True, blank=True) - pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单', on_delete=models.CASCADE, null=True, blank=True) - order = models.ForeignKey(Order, verbose_name='关联订单', on_delete=models.CASCADE, null=True, blank=True) + supplier = models.ForeignKey( + Supplier, verbose_name='供应商', on_delete=models.CASCADE, null=True, blank=True) + customer = models.ForeignKey( + Customer, verbose_name='客户', on_delete=models.CASCADE, null=True, blank=True) + pu_order = models.ForeignKey( + PuOrder, verbose_name='关联采购订单', on_delete=models.CASCADE, null=True, blank=True) + order = models.ForeignKey( + Order, verbose_name='关联订单', on_delete=models.CASCADE, null=True, blank=True) note = models.CharField('备注', max_length=1000, default='') expiration_date = models.DateField('有效期', null=True, blank=True) submit_time = models.DateTimeField('提交时间', null=True, blank=True) + pick_user = models.ForeignKey( + User, verbose_name='领料人', on_delete=models.CASCADE, null=True, blank=True) class MIOItem(BaseModel): """ 出入库明细 """ - mio = models.ForeignKey(MIO, verbose_name='关联出入库', on_delete=models.CASCADE) - warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库') - material = models.ForeignKey(Material, verbose_name='物料', on_delete=models.CASCADE) - batch = models.CharField('批次号', max_length=20) - count = models.PositiveIntegerField('数量', default=0) \ No newline at end of file + mio = models.ForeignKey(MIO, verbose_name='关联出入库', + on_delete=models.CASCADE) + warehouse = models.ForeignKey( + WareHouse, on_delete=models.CASCADE, verbose_name='仓库') + material = models.ForeignKey( + Material, verbose_name='物料', on_delete=models.CASCADE) + batch = models.CharField('批次号', max_length=50) + count = models.PositiveIntegerField('数量', default=0) diff --git a/apps/inm/serializers.py b/apps/inm/serializers.py index 6f3c3e22..0d893ba5 100644 --- a/apps/inm/serializers.py +++ b/apps/inm/serializers.py @@ -1,10 +1,13 @@ from rest_framework import serializers -from apps.utils.serializers import CustomModelSerializer -from apps.inm.models import WareHouse, MaterialBatch, MIO, MIOItem -from apps.utils.constants import EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS_BASE -from apps.pum.models import PuOrder from rest_framework.exceptions import ValidationError + from apps.mtm.serializers import MaterialSerializer +from apps.pum.models import PuOrder +from apps.system.models import Dept, User +from apps.utils.constants import EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS_DEPT +from apps.utils.serializers import CustomModelSerializer + +from .models import MIO, MaterialBatch, MIOItem, WareHouse class WareHourseSerializer(CustomModelSerializer): @@ -15,8 +18,11 @@ class WareHourseSerializer(CustomModelSerializer): class MaterialBatchSerializer(CustomModelSerializer): - warehouse_name = serializers.CharField(source='warehouse.name', read_only=True) - material_name = serializers.CharField(source='material.name', read_only=True) + warehouse_name = serializers.CharField( + source='warehouse.name', read_only=True) + material_name = serializers.CharField( + source='material.name', read_only=True) + class Meta: model = MaterialBatch fields = '__all__' @@ -24,12 +30,14 @@ class MaterialBatchSerializer(CustomModelSerializer): class MIOSerializer(CustomModelSerializer): - create_by_name = serializers.CharField(source='create_by.name', read_only=True) + create_by_name = serializers.CharField( + source='create_by.name', read_only=True) + class Meta: model = MIO fields = '__all__' read_only_fields = EXCLUDE_FIELDS_DEPT + ['state', 'submit_time'] - + def validate(self, attrs): if 'pu_order' in attrs and attrs['pu_order']: attrs['supplier'] = attrs['pu_order'].supplier @@ -46,15 +54,16 @@ class MIOSerializer(CustomModelSerializer): else: raise ValidationError('该采购订单不可选') return super().create(validated_data) - + def update(self, instance, validated_data): validated_data.pop('type') return super().update(instance, validated_data) - + class MIOItemSerializer(CustomModelSerializer): warehouse_name = serializers.CharField(source='warehouse', read_only=True) material_ = MaterialSerializer(source='material', read_only=True) + class Meta: model = MIOItem fields = '__all__' @@ -64,3 +73,23 @@ class MIOItemSerializer(CustomModelSerializer): if mio.state != MIO.MIO_CREATE: raise ValidationError('出入库记录非创建中不可新增') return super().create(validated_data) + + +class PickSerializer(CustomModelSerializer): + belong_dept = serializers.PrimaryKeyRelatedField( + label="领料车间", queryset=Dept.objects.all(), required=True) + pick_user = serializers.PrimaryKeyRelatedField( + label="领料人", queryset=User.objects.all(), required=True) + + class Meta: + model = MIO + fields = ['number', 'note', 'pick_user', 'belong_dept'] + + def create(self, validated_data): + validated_data['type'] = MIO.MIO_TYPE_DO_OUT + return super().create(validated_data) + + def update(self, instance, validated_data): + if instance.state != MIO.MIO_CREATE: + raise ValidationError('记录非创建中') + return super().update(instance, validated_data) diff --git a/apps/inm/services.py b/apps/inm/services.py index 6e32a836..fd71a460 100644 --- a/apps/inm/services.py +++ b/apps/inm/services.py @@ -4,33 +4,36 @@ from django.db.models.aggregates import Sum class InmService: - + @classmethod def update_inm(cls, instance: MIO): """ 更新库存, 暂不支持反向操作 """ - if instance.type in [MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_DO_IN, MIO.MIO_TYPE_OTHER_IN]: # 采购入库, 生产入库, 其他入库 + if instance.type in [MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_DO_IN, MIO.MIO_TYPE_OTHER_IN]: # 采购入库, 生产入库, 其他入库 cls.update_mb(instance) if instance.type == MIO.MIO_TYPE_PUR_IN: # 需要更新订单 from apps.pum.services import PumService PumService.mio_purin(instance) - elif instance.type in [MIO.MIO_TYPE_DO_OUT, MIO.MIO_TYPE_SALE_OUT, MIO.MIO_TYPE_OTHER_OUT]: # 生产领料 销售出库 + elif instance.type in [MIO.MIO_TYPE_DO_OUT, MIO.MIO_TYPE_SALE_OUT, MIO.MIO_TYPE_OTHER_OUT]: # 生产领料 销售出库 cls.update_mb(instance, -1) if instance.type == MIO.MIO_TYPE_SALE_OUT: from apps.sam.services import SamService SamService.mio_saleout(instance) + elif instance.type == MIO.MIO_TYPE_DO_OUT: + from apps.wpm.services import pick + pick(instance) @classmethod - def update_mb(cls, instance: MIO, in_or_out: int =1): + def update_mb(cls, instance: MIO, in_or_out: int = 1): """ 更新物料批次 """ for i in MIOItem.objects.filter(mio=instance): material = i.material warehouse = i.warehouse - mb, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch,\ - defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':i.batch}) + mb, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch, + defaults={'material': material, 'warehouse': warehouse, 'count': 0, 'batch': i.batch}) if in_or_out == 1: mb.count = mb.count + i.count if mb.expiration_date is None: @@ -43,5 +46,6 @@ class InmService: mb.save() else: raise ValidationError('不支持的操作') - material.count = MaterialBatch.objects.filter(material=material).aggregate(total=Sum('count')).get('total', 0) - material.save() \ No newline at end of file + material.count = MaterialBatch.objects.filter( + material=material).aggregate(total=Sum('count')).get('total', 0) + material.save() diff --git a/apps/inm/views.py b/apps/inm/views.py index 66475ac0..58f8a2f6 100644 --- a/apps/inm/views.py +++ b/apps/inm/views.py @@ -8,7 +8,8 @@ from django.utils import timezone from rest_framework.response import Response from apps.inm.models import WareHouse, MaterialBatch, MIO, MIOItem -from apps.inm.serializers import (MaterialBatchSerializer, WareHourseSerializer, MIOSerializer, MIOItemSerializer) +from apps.inm.serializers import ( + MaterialBatchSerializer, WareHourseSerializer, MIOSerializer, MIOItemSerializer, PickSerializer) from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.inm.services import InmService from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin @@ -60,7 +61,19 @@ class MIOViewSet(ListModelMixin, DestroyModelMixin, CustomGenericViewSet): if instance.state != MIO.MIO_CREATE: raise ParseError('非创建中不可删除') return super().perform_destroy(instance) - + + @action(methods=['post'], detail=False, perms_map={'post': 'mio.pick'}, serializer_class=PickSerializer) + @transaction.atomic + def pick(self, request, *args, **kwargs): + """生产领料 + + 生产领料 + """ + sr = PickSerializer(data=request.data) + sr.is_valid(raise_exception=True) + sr.save() + return Response() + @action(methods=['post'], detail=True, perms_map={'post': 'mio.update'}, serializer_class=serializers.Serializer) @transaction.atomic def submit(self, request, *args, **kwargs): @@ -70,16 +83,17 @@ class MIOViewSet(ListModelMixin, DestroyModelMixin, CustomGenericViewSet): """ ins = self.get_object() user = request.user - if ins.create_by != user: + if ins.state != MIO.MIO_TYPE_DO_OUT and ins.create_by != user: raise PermissionDenied('非创建人不可提交') if ins.state != MIO.MIO_CREATE: - raise ParseError('订单非创建中') + raise ParseError('记录状态异常') ins.submit_time = timezone.now() ins.state = MIO.MIO_SUBMITED ins.save() InmService.update_inm(ins) return Response() + class MIOItemViewSet(ListModelMixin, BulkCreateModelMixin, BulkDestroyModelMixin, CustomGenericViewSet): """ list: 出入库明细 @@ -91,8 +105,8 @@ class MIOItemViewSet(ListModelMixin, BulkCreateModelMixin, BulkDestroyModelMixin select_related_fields = ['warehouse', 'mio', 'material'] filterset_fields = ['warehouse', 'mio', 'material'] ordering = ['create_time'] - + def perform_destroy(self, instance): if instance.state != MIO.MIO_CREATE: raise ParseError('出入库记录非创建中不可删除') - return super().perform_destroy(instance) \ No newline at end of file + return super().perform_destroy(instance) diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 989fe9e3..b7772fe8 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -62,7 +62,7 @@ class Material(CommonAModel): ordering = ['sort', '-create_time'] def __str__(self): - return self.name + return f'{self.specification}-{self.name}' class Shift(CommonAModel): diff --git a/apps/utils/viewsets.py b/apps/utils/viewsets.py index 88ef6490..87d7e156 100755 --- a/apps/utils/viewsets.py +++ b/apps/utils/viewsets.py @@ -26,12 +26,11 @@ class CustomGenericViewSet(MyLoggingMixin, GenericViewSet): """ 增强的GenericViewSet """ - perms_map = {} # 权限标识 + perms_map = {'get': '*'} # 权限标识 throttle_classes = [UserRateThrottle] logging_methods = ['POST', 'PUT', 'PATCH', 'DELETE'] ordering_fields = '__all__' ordering = '-create_time' - filterset_fields = [] create_serializer_class = None update_serializer_class = None partial_update_serializer_class = None @@ -44,15 +43,18 @@ class CustomGenericViewSet(MyLoggingMixin, GenericViewSet): data_filter_field = 'belong_dept' hash_k = None cache_seconds = 5 # 接口缓存时间默认5秒 + filterset_fields = select_related_fields def finalize_response(self, request, response, *args, **kwargs): if self.hash_k and self.cache_seconds: - cache.set(self.hash_k, response.data, timeout=self.cache_seconds) # 将结果存入缓存,设置超时时间 + cache.set(self.hash_k, response.data, + timeout=self.cache_seconds) # 将结果存入缓存,设置超时时间 return super().finalize_response(request, response, *args, **kwargs) - + def initial(self, request, *args, **kwargs): super().initial(request, *args, **kwargs) - cache_seconds = getattr(self, f"{self.action}_cache_seconds", getattr(self, 'cache_seconds', 0)) + cache_seconds = getattr( + self, f"{self.action}_cache_seconds", getattr(self, 'cache_seconds', 0)) if cache_seconds: self.cache_seconds = cache_seconds rdata = {} @@ -164,6 +166,7 @@ class CustomModelViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, ListModelMi """ 增强的ModelViewSet """ + def __init__(self, **kwargs) -> None: super().__init__(**kwargs) # 增加默认权限标识 @@ -210,4 +213,3 @@ class CustomModelViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, ListModelMi return self.get_paginated_response(serializer.data) serializer = self.get_serializer(new_qs, many=True) return Response(serializer.data) - diff --git a/apps/wpm/migrations/0011_wmaterial.py b/apps/wpm/migrations/0011_wmaterial.py new file mode 100644 index 00000000..d709b618 --- /dev/null +++ b/apps/wpm/migrations/0011_wmaterial.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.12 on 2023-09-27 07:16 + +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 = [ + ('mtm', '0014_alter_process_options'), + ('system', '0002_myschedule'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('wpm', '0010_auto_20230808_1413'), + ] + + operations = [ + migrations.CreateModel( + name='WMaterial', + 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='删除标记')), + ('batch', models.CharField(max_length=50, verbose_name='批次号')), + ('count', models.PositiveIntegerField(default=0, verbose_name='当前数量')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wmaterial_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='wmaterial_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wmaterial_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 7c1bdcfe..9a06834c 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -1,6 +1,6 @@ from django.db import models -from apps.utils.models import CommonADModel -from apps.mtm.models import Mgroup, Team, Shift +from apps.utils.models import CommonADModel, CommonBDModel +from apps.mtm.models import Mgroup, Team, Shift, Material from django.utils.timezone import localtime # Create your models here. @@ -63,3 +63,13 @@ class SfLogExp(CommonADModel): handler = models.CharField('处理人', default='', max_length=100) is_current_down = models.BooleanField('是否本班停机', default=False) duration = models.FloatField('停机时长(h)', null=True, blank=True) + + +class WMaterial(CommonBDModel): + """ + belong_dept是所在车间 + """ + material = models.ForeignKey( + Material, verbose_name='物料', on_delete=models.CASCADE) + batch = models.CharField('批次号', max_length=50) + count = models.PositiveIntegerField('当前数量', default=0) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 319a94b0..5ccaa8dd 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -2,12 +2,15 @@ from apps.utils.constants import EXCLUDE_FIELDS from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers -from apps.wpm.models import SfLog, StLog, SfLogExp +from .models import SfLog, StLog, SfLogExp, WMaterial from apps.system.models import Dictionary from apps.wpm.tasks import cal_enstat_when_pcoal_heat_change, cal_enstat_when_team_change +from apps.mtm.serializers import MaterialSerializer + class StLogSerializer(CustomModelSerializer): mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) + class Meta: model = StLog fields = '__all__' @@ -18,10 +21,12 @@ class SfLogSerializer(CustomModelSerializer): team_name = serializers.CharField(source='team.name', read_only=True) shift_name = serializers.CharField(source='shift.name', read_only=True) leader_name = serializers.CharField(source='leader.name', read_only=True) + class Meta: model = SfLog fields = '__all__' - read_only_fields = EXCLUDE_FIELDS + ['mgroup', 'start_time', 'end_time', 'belong_dept'] + read_only_fields = EXCLUDE_FIELDS + \ + ['mgroup', 'start_time', 'end_time', 'belong_dept'] extra_kwargs = { 'team': {'required': True}, 'leader': {'required': True} @@ -48,11 +53,23 @@ class SfLogSerializer(CustomModelSerializer): class SflogExpSerializer(CustomModelSerializer): mgroup = serializers.CharField(source='sflog.mgroup.id', read_only=True) - mgroup_name = serializers.CharField(source='sflog.mgroup.name', read_only=True) + mgroup_name = serializers.CharField( + source='sflog.mgroup.name', read_only=True) stlog_ = StLogSerializer(source='stlog', read_only=True) happen_time = serializers.DateTimeField(required=True, label='发生时间') cate = serializers.CharField(required=True, label='原因类别') + class Meta: model = SfLogExp fields = '__all__' - read_only_fields = EXCLUDE_FIELDS + ['stlog', 'is_current_down'] \ No newline at end of file + read_only_fields = EXCLUDE_FIELDS + ['stlog', 'is_current_down'] + + +class WMaterialSerializer(CustomModelSerializer): + material_ = MaterialSerializer(source='material', read_only=True) + belong_dept_name = serializers.CharField( + source='belong_dept.name', read_only=True) + + class Meta: + model = WMaterial + fields = '__all__' diff --git a/apps/wpm/services.py b/apps/wpm/services.py index aa03b931..604a9caa 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -1,9 +1,14 @@ -from apps.wpm.models import SfLog, SfLogExp -from apps.mtm.models import Shift, Mgroup import datetime -from django.utils.timezone import localtime -from django.db.models import Sum + from django.core.cache import cache +from django.db.models import Sum +from django.utils.timezone import localtime + +from apps.inm.models import MIO, MIOItem +from apps.mtm.models import Mgroup, Shift + +from .models import SfLog, SfLogExp, WMaterial + def make_sflogs(mgroup: Mgroup, start_date: datetime.date, end_date: datetime.date): for shift in Shift.objects.all(): @@ -24,6 +29,7 @@ def make_sflogs(mgroup: Mgroup, start_date: datetime.date, end_date: datetime.da }) current_date = current_date + datetime.timedelta(days=1) + def get_pcoal_heat(year_s: int, month_s: int, day_s: int): """ 获取煤粉热值 @@ -36,11 +42,33 @@ def get_pcoal_heat(year_s: int, month_s: int, day_s: int): else: try: qs = SfLog.objects.get(end_time__year=year_s, end_time__month=month_s, end_time__day=day_s, - mgroup__name='回转窑', shift__name='白班') + mgroup__name='回转窑', shift__name='白班') if qs.pcoal_heat is None: qs.pcoal_heat = 0 qs.save() cache.set(f'pgoal_val_{year_s}_{month_s}_{day_s}', qs.pcoal_heat) return qs.pcoal_heat - except: + except Exception: return 0 + + +def pick(mio: MIO): + """ + 生产领料到车间 + """ + belong_dept = mio.belong_dept + pick_user = mio.pick_user + mioitems = MIOItem.objects.filter(mio=mio) + for item in mioitems: + wm, new_create = WMaterial.objects.get_or_create(batch=item.batch, material=item.material, + belong_dept=belong_dept, defaults={ + "batch": item.batch, + "material": item.material, + "count": item.count, + "create_by": pick_user, + "belong_dept": belong_dept + }) + if not new_create: + wm.count = wm.count + item.count + wm.update_by = pick_user + wm.save() diff --git a/apps/wpm/urls.py b/apps/wpm/urls.py index 9b2b4277..f82126da 100644 --- a/apps/wpm/urls.py +++ b/apps/wpm/urls.py @@ -1,7 +1,7 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.wpm.views import SfLogViewSet, StLogViewSet, SfLogExpViewSet +from apps.wpm.views import SfLogViewSet, StLogViewSet, SfLogExpViewSet, WMaterialViewSet API_BASE_URL = 'api/wpm/' @@ -11,7 +11,7 @@ router = DefaultRouter() router.register('sflog', SfLogViewSet, basename='sflog') router.register('stlog', StLogViewSet, basename='stlog') router.register('sflogexp', SfLogExpViewSet, basename='sflogexp') - +router.register('wmaterial', WMaterialViewSet, basename='wmaterial') urlpatterns = [ path(API_BASE_URL, include(router.urls)), -] \ No newline at end of file +] diff --git a/apps/wpm/views.py b/apps/wpm/views.py index bae2de22..cecd2931 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -1,18 +1,20 @@ -from django.shortcuts import render -from rest_framework.mixins import ListModelMixin, UpdateModelMixin -from rest_framework.decorators import action from django.db import transaction -from rest_framework.response import Response +from django.shortcuts import render +from rest_framework.decorators import action from rest_framework.exceptions import ParseError -from rest_framework.mixins import DestroyModelMixin, UpdateModelMixin, ListModelMixin +from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin +from rest_framework.response import Response -from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet -from apps.wpm.models import SfLog, StLog, SfLogExp -from apps.wpm.serializers import SfLogSerializer, StLogSerializer, SflogExpSerializer -from apps.wpm.filters import SfLogFilter, SfLogExpFilter from apps.mtm.models import Material +from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet + +from .filters import SfLogExpFilter, SfLogFilter +from .models import SfLog, SfLogExp, StLog, WMaterial +from .serializers import SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer # Create your views here. + + class StLogViewSet(ListModelMixin, CustomGenericViewSet): """ list:停机记录 @@ -51,16 +53,21 @@ class SfLogViewSet(UpdateModelMixin, ListModelMixin, DestroyModelMixin, CustomGe from apps.qm.models import QuaStat, TestItem from apps.qm.serializers import QuaStatSerializer obj = self.get_object() - test_materials = Material.objects.filter(id__in=obj.mgroup.test_materials).order_by('sort', '-create_time') + test_materials = Material.objects.filter( + id__in=obj.mgroup.test_materials).order_by('sort', '-create_time') for material in test_materials: - testitems = TestItem.objects.filter(id__in=material.testitems).order_by('sort', '-create_time') + testitems = TestItem.objects.filter( + id__in=material.testitems).order_by('sort', '-create_time') for testitem in testitems: - params = {'material': material, 'testitem': testitem, 'sflog': obj} - QuaStat.objects.get_or_create(**params, defaults={**params, **{'create_by': request.user, 'belong_dept': obj.mgroup.belong_dept}}) - qs = QuaStat.objects.filter(sflog=obj).order_by('material__sort', 'material__create_time', 'testitem__sort', 'testitem__create_time') + params = {'material': material, + 'testitem': testitem, 'sflog': obj} + QuaStat.objects.get_or_create( + **params, defaults={**params, **{'create_by': request.user, 'belong_dept': obj.mgroup.belong_dept}}) + qs = QuaStat.objects.filter(sflog=obj).order_by( + 'material__sort', 'material__create_time', 'testitem__sort', 'testitem__create_time') sr = QuaStatSerializer(instance=qs, many=True) return Response(sr.data) - + class SfLogExpViewSet(CustomModelViewSet): """ @@ -71,4 +78,18 @@ class SfLogExpViewSet(CustomModelViewSet): queryset = SfLogExp.objects.all() serializer_class = SflogExpSerializer select_related_fields = ['sflog', 'sflog__mgroup', 'stlog'] - filterset_class = SfLogExpFilter \ No newline at end of file + filterset_class = SfLogExpFilter + + +class WMaterialViewSet(ListModelMixin, CustomGenericViewSet): + """ + list: 车间库存 + + 车间库存 + """ + queryset = WMaterial.objects.all() + serializer_class = WMaterialSerializer + select_related_fields = ['material', 'belong_dept'] + search_fields = ['material__name', + 'material__number', 'material__specification'] + filterset_fields = ['material', 'belong_dept']