From 4cadeac2d4d19e20c65daaab8a09806424d29c17 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 15 Mar 2022 10:45:20 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E7=94=9F=E4=BA=A7=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/services.py | 6 +++++- hb_server/apps/srm/serializers.py | 3 +++ hb_server/apps/srm/services.py | 25 +++++++++++++++++++++++++ hb_server/apps/srm/urls.py | 3 ++- hb_server/apps/srm/views.py | 16 +++++++++++++++- hb_server/apps/wpm/services.py | 17 +++++++++++++++++ 6 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 hb_server/apps/srm/services.py diff --git a/hb_server/apps/inm/services.py b/hb_server/apps/inm/services.py index 159f148..0d44820 100644 --- a/hb_server/apps/inm/services.py +++ b/hb_server/apps/inm/services.py @@ -6,6 +6,8 @@ from apps.sam.models import SalePack, SaleProduct from django.db.models import Count from django.db.models.aggregates import Sum import logging + +from apps.wpm.services import WpmService logger = logging.getLogger('log') class InmService: @@ -133,8 +135,10 @@ class InmService: # 更新动态产品表情况 from apps.wpm.models import WProduct - WProduct.objects.filter(id__in=ips.values_list('wproduct', flat=True)).update( + wps = WProduct.objects.filter(id__in=ips.values_list('wproduct', flat=True)) + wps.update( act_state=WProduct.WPR_ACT_STATE_SELLED) + WpmService.add_wproducts_flow_log(instances=wps, change_str='selled') # 变更销售记录实际发货数 sale.count_real = ips.count() diff --git a/hb_server/apps/srm/serializers.py b/hb_server/apps/srm/serializers.py index 2a4e11f..283d360 100644 --- a/hb_server/apps/srm/serializers.py +++ b/hb_server/apps/srm/serializers.py @@ -25,6 +25,9 @@ class ProcessYieldSerializer(serializers.Serializer): datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True) datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True) +class ProductCountSerializer(serializers.Serializer): + datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True) + datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True) class AtWorkCountSerializer(serializers.Serializer): year = serializers.IntegerField(label='年') diff --git a/hb_server/apps/srm/services.py b/hb_server/apps/srm/services.py new file mode 100644 index 0000000..de57324 --- /dev/null +++ b/hb_server/apps/srm/services.py @@ -0,0 +1,25 @@ +from apps.mtm.models import Material +from apps.wpm.models import WProduct, WproductFlow + + +class SrmServices: + """ + 数据统计分析 + """ + @classmethod + def get_wp_product_count(cls, datetime_start, datetime_end): + """ + 根据生产情况统计相关数量 + """ + objs = WproductFlow.objects.filter(is_lastlog=True, material__type=Material.MA_TYPE_GOOD) + if datetime_start: + objs = objs.filter(create_time__gte=datetime_start) + if datetime_end: + objs = WproductFlow.objects.filter(create_time__lte=datetime_end) + count = objs.count() + count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM, + WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).count() + count_notok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).count() + count_selled = objs.filter(act_state=WProduct.WPR_ACT_STATE_SELLED).count() + count_mtestok = objs.filter(is_mtestok=True).count() + return dict(count=count,count_ok=count_ok, count_notok=count_notok, count_selled=count_selled, count_mtestok=count_mtestok) \ No newline at end of file diff --git a/hb_server/apps/srm/urls.py b/hb_server/apps/srm/urls.py index 2b53153..2437fbe 100644 --- a/hb_server/apps/srm/urls.py +++ b/hb_server/apps/srm/urls.py @@ -3,11 +3,12 @@ from rest_framework import urlpatterns from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.srm.views import AtWorkCountView, GanttPlan, ProcessYieldView +from apps.srm.views import AtWorkCountView, GanttPlan, ProcessYieldView, ProductCountView router = DefaultRouter() urlpatterns = [ path('gantt/plan/', GanttPlan.as_view()), + path('product/count/', ProductCountView.as_view()), path('process/yield/', ProcessYieldView.as_view()), path('at_work/', AtWorkCountView.as_view()), path('', include(router.urls)), diff --git a/hb_server/apps/srm/views.py b/hb_server/apps/srm/views.py index ead2e2e..28d0da3 100644 --- a/hb_server/apps/srm/views.py +++ b/hb_server/apps/srm/views.py @@ -9,7 +9,8 @@ from rest_framework.response import Response from apps.hrm.models import ClockRecord from apps.mtm.models import Process, Step from apps.pm.models import ProductionPlan, SubProductionPlan -from apps.srm.serializers import AtWorkCountSerializer, PlanGanttSerializer, ProcessYieldSerializer +from apps.srm.serializers import AtWorkCountSerializer, PlanGanttSerializer, ProcessYieldSerializer, ProductCountSerializer +from apps.srm.services import SrmServices from apps.wpm.models import WProduct, WproductFlow from django.db.models import Count, F # Create your views here. @@ -23,6 +24,19 @@ class GanttPlan(ListAPIView): queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process') ordering = ['-id'] +class ProductCountView(CreateAPIView): + """ + 产品数量统计 + """ + perms_map = {'post':'*'} + serializer_class = ProductCountSerializer + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data + res = SrmServices.get_wp_product_count(datetime_start= vdata.get('datetime_start', None), datetime_end= vdata.get('datetime_end', None)) + return Response(res) + class ProcessYieldView(CreateAPIView): """ 工序成品率统计 diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py index 36db321..74af318 100644 --- a/hb_server/apps/wpm/services.py +++ b/hb_server/apps/wpm/services.py @@ -167,6 +167,23 @@ class WpmService(object): ins.change_str = change_str ins.save() + @classmethod + def add_wproducts_flow_log(cls, instances, change_str=''): + """ + 批量创建产品变动日志 + """ + WproductFlow.objects.filter(wproduct__in=instances).update(is_lastlog=False) + wfw = [] + for i in instances: + ins = WproductFlow() + ins.wproduct = i + for f in WproductFlow.__meta.fields: + if f.name not in ['id', 'wproduct', 'is_lastlog']: + setattr(ins, f.name, getattr(i, f.name, None)) + ins.change_str = change_str + wfw.append(ins) + WproductFlow.objects.bulk_create(wfw) + @classmethod def update_cutting_list_with_operation(cls, op:Operation): """ From 80956f41c223a03ca1bbe18e5bc63afedce0a998 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 15 Mar 2022 11:13:17 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E6=95=B0=E9=87=8Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/srm/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hb_server/apps/srm/services.py b/hb_server/apps/srm/services.py index de57324..2c3400b 100644 --- a/hb_server/apps/srm/services.py +++ b/hb_server/apps/srm/services.py @@ -15,7 +15,7 @@ class SrmServices: if datetime_start: objs = objs.filter(create_time__gte=datetime_start) if datetime_end: - objs = WproductFlow.objects.filter(create_time__lte=datetime_end) + objs = objs.filter(create_time__lte=datetime_end) count = objs.count() count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM, WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).count() From 1d0de666b8409de164cfdebcdccb0bb90a41e88f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 15 Mar 2022 15:03:24 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=95=B0=E9=87=8F?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=EF=BC=8C=E7=94=9F=E4=BA=A7=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/develop/views.py | 4 ++ .../migrations/0013_alter_equipment_state.py | 18 +++++++ .../inm/migrations/0034_alter_fifo_sale.py | 20 +++++++ hb_server/apps/srm/serializers.py | 14 ++++- hb_server/apps/srm/services.py | 53 +++++++++++++++++-- hb_server/apps/srm/urls.py | 5 +- hb_server/apps/srm/views.py | 50 +++++++++++++++-- .../wpm/migrations/0054_auto_20220315_1500.py | 28 ++++++++++ hb_server/apps/wpm/models.py | 2 + hb_server/apps/wpm/views.py | 3 +- 10 files changed, 186 insertions(+), 11 deletions(-) create mode 100644 hb_server/apps/em/migrations/0013_alter_equipment_state.py create mode 100644 hb_server/apps/inm/migrations/0034_alter_fifo_sale.py create mode 100644 hb_server/apps/wpm/migrations/0054_auto_20220315_1500.py diff --git a/hb_server/apps/develop/views.py b/hb_server/apps/develop/views.py index ec43e41..f46227b 100644 --- a/hb_server/apps/develop/views.py +++ b/hb_server/apps/develop/views.py @@ -121,6 +121,10 @@ class UpdateFIFONumber(APIView): i.save() return Response() +class CorrectWproductState(APIView): + permission_classes = [IsAdminUser] + def post(self, request): + pass class ReloadServer(APIView): diff --git a/hb_server/apps/em/migrations/0013_alter_equipment_state.py b/hb_server/apps/em/migrations/0013_alter_equipment_state.py new file mode 100644 index 0000000..da0e59b --- /dev/null +++ b/hb_server/apps/em/migrations/0013_alter_equipment_state.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2022-03-15 07:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('em', '0012_auto_20220120_1048'), + ] + + operations = [ + migrations.AlterField( + model_name='equipment', + name='state', + field=models.PositiveIntegerField(choices=[(10, '完好'), (20, '限用'), (30, '在修'), (40, '禁用'), (50, '报废')], default=0, verbose_name='设备状态'), + ), + ] diff --git a/hb_server/apps/inm/migrations/0034_alter_fifo_sale.py b/hb_server/apps/inm/migrations/0034_alter_fifo_sale.py new file mode 100644 index 0000000..4bd942d --- /dev/null +++ b/hb_server/apps/inm/migrations/0034_alter_fifo_sale.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.9 on 2022-03-15 07:00 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('sam', '0016_sale_iproducts'), + ('inm', '0033_fifoitem_expiration_date'), + ] + + operations = [ + migrations.AlterField( + model_name='fifo', + name='sale', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fifo_sale', to='sam.sale', verbose_name='关联销售记录'), + ), + ] diff --git a/hb_server/apps/srm/serializers.py b/hb_server/apps/srm/serializers.py index 283d360..ab5e1a4 100644 --- a/hb_server/apps/srm/serializers.py +++ b/hb_server/apps/srm/serializers.py @@ -1,6 +1,8 @@ +from email.policy import default from rest_framework import serializers from apps.pm.models import ProductionPlan, SubProductionPlan from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer +from apps.system.models import Organization class SubplanGanttSerializer(serializers.ModelSerializer): process_ = ProcessSimpleSerializer(source='process', read_only=True) @@ -25,10 +27,20 @@ class ProcessYieldSerializer(serializers.Serializer): datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True) datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True) -class ProductCountSerializer(serializers.Serializer): +class SrmCountSerializer(serializers.Serializer): datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True) datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True) +class ProductCountSerializer(serializers.Serializer): + tag_choices=( + (1, '统计成品'), + (2, '统计全部') + ) + datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True) + datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True) + tag = serializers.ChoiceField(choices=tag_choices, label='统计范围1成品2全部', default=1) + dept = serializers.PrimaryKeyRelatedField(queryset=Organization.objects.all(), label="车间", required=False) + class AtWorkCountSerializer(serializers.Serializer): year = serializers.IntegerField(label='年') month = serializers.IntegerField(label='月') \ No newline at end of file diff --git a/hb_server/apps/srm/services.py b/hb_server/apps/srm/services.py index 2c3400b..e6edf02 100644 --- a/hb_server/apps/srm/services.py +++ b/hb_server/apps/srm/services.py @@ -1,25 +1,68 @@ from apps.mtm.models import Material +from apps.pm.models import ProductionPlan +from apps.sam.models import Order from apps.wpm.models import WProduct, WproductFlow - +from django.db.models import F class SrmServices: """ 数据统计分析 """ @classmethod - def get_wp_product_count(cls, datetime_start, datetime_end): + def get_product_count(cls, datetime_start=None, datetime_end=None, tag=1, dept=None): """ 根据生产情况统计相关数量 """ - objs = WproductFlow.objects.filter(is_lastlog=True, material__type=Material.MA_TYPE_GOOD) + if tag == 1: + objs = WproductFlow.objects.filter(is_lastlog=True, material__type=Material.MA_TYPE_GOOD) + else: + objs = WproductFlow.objects.filter(is_lastlog=True) if datetime_start: objs = objs.filter(create_time__gte=datetime_start) if datetime_end: objs = objs.filter(create_time__lte=datetime_end) + if dept: + objs = objs.filter(subproduction_plan__workshop=dept) count = objs.count() count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM, WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).count() - count_notok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).count() + # count_notok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).count() + count_notok = ( + objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).exclude(step__process__id=1) + | objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP], + step__process__id=1).exclude(number=None) + ).count() count_selled = objs.filter(act_state=WProduct.WPR_ACT_STATE_SELLED).count() count_mtestok = objs.filter(is_mtestok=True).count() - return dict(count=count,count_ok=count_ok, count_notok=count_notok, count_selled=count_selled, count_mtestok=count_mtestok) \ No newline at end of file + return dict(count=count,count_ok=count_ok, count_notok=count_notok, count_selled=count_selled, count_mtestok=count_mtestok) + + @classmethod + def get_plan_count(cls, datetime_start=None, datetime_end=None): + """ + 任务数量 + """ + objs = ProductionPlan.objects.all() + if datetime_start: + objs = objs.filter(end_date__gte=datetime_start) + if datetime_end: + objs = objs.filter(end_date__lte=datetime_end) + count = objs.count() + count_use = objs.exclude(state__in=[ProductionPlan.PLAN_STATE_PAUSE, ProductionPlan.PLAN_STATE_STOP]).count() + count_completed = objs.filter(state__in=[ProductionPlan.PLAN_STATE_DONE, ProductionPlan.PLAN_MTEST_DONE]).count() + return dict(count=count, count_use=count_use, count_completed=count_completed) + + + @classmethod + def get_order_count(cls, datetime_start=None, datetime_end=None): + """ + 订单数量 + """ + objs = Order.objects.all() + if datetime_start: + objs = objs.filter(delivery_date__gte=datetime_start) + if datetime_end: + objs = objs.filter(delivery_date__lte=datetime_end) + count = objs.count() + count_delivered = objs.filter(delivered_count__gte=F('count')).count() + return dict(count=count, count_delivered=count_delivered) + \ No newline at end of file diff --git a/hb_server/apps/srm/urls.py b/hb_server/apps/srm/urls.py index 2437fbe..2829723 100644 --- a/hb_server/apps/srm/urls.py +++ b/hb_server/apps/srm/urls.py @@ -3,13 +3,16 @@ from rest_framework import urlpatterns from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.srm.views import AtWorkCountView, GanttPlan, ProcessYieldView, ProductCountView +from apps.srm.views import AtWorkCountView, GanttPlan, OrderCountView, PlanCountView, ProcessNowView, ProcessYieldView, ProductCountView router = DefaultRouter() urlpatterns = [ path('gantt/plan/', GanttPlan.as_view()), path('product/count/', ProductCountView.as_view()), + path('plan/count/', PlanCountView.as_view()), + path('order/count/', OrderCountView.as_view()), path('process/yield/', ProcessYieldView.as_view()), + path('process/now/', ProcessNowView.as_view()), path('at_work/', AtWorkCountView.as_view()), path('', include(router.urls)), ] diff --git a/hb_server/apps/srm/views.py b/hb_server/apps/srm/views.py index 28d0da3..158489f 100644 --- a/hb_server/apps/srm/views.py +++ b/hb_server/apps/srm/views.py @@ -1,6 +1,7 @@ from datetime import date, timedelta from django.shortcuts import render +from idna import valid_contextj from numpy import number from rest_framework import serializers from rest_framework.generics import ListAPIView, CreateAPIView @@ -9,10 +10,10 @@ from rest_framework.response import Response from apps.hrm.models import ClockRecord from apps.mtm.models import Process, Step from apps.pm.models import ProductionPlan, SubProductionPlan -from apps.srm.serializers import AtWorkCountSerializer, PlanGanttSerializer, ProcessYieldSerializer, ProductCountSerializer +from apps.srm.serializers import AtWorkCountSerializer, PlanGanttSerializer, ProcessYieldSerializer, ProductCountSerializer, SrmCountSerializer from apps.srm.services import SrmServices from apps.wpm.models import WProduct, WproductFlow -from django.db.models import Count, F +from django.db.models import Count, F, Sum # Create your views here. class GanttPlan(ListAPIView): @@ -34,9 +35,52 @@ class ProductCountView(CreateAPIView): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data - res = SrmServices.get_wp_product_count(datetime_start= vdata.get('datetime_start', None), datetime_end= vdata.get('datetime_end', None)) + res = SrmServices.get_product_count(**vdata) return Response(res) + +class PlanCountView(CreateAPIView): + """ + 计划数量统计 + """ + perms_map = {'post':'*'} + serializer_class = SrmCountSerializer + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data + res = SrmServices.get_plan_count(**vdata) + return Response(res) + +class OrderCountView(CreateAPIView): + """ + 订单数量统计 + """ + perms_map = {'post':'*'} + serializer_class = SrmCountSerializer + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data + res = SrmServices.get_order_count(**vdata) + return Response(res) + +class ProcessNowView(CreateAPIView): + """ + 工序当前进度 + """ + perms_map = {'post':'*'} + serializers_class = serializers.Serializer + + def create(self, request, *args, **kwargs): + objs = SubProductionPlan.objects.filter(production_plan__state__in =[ProductionPlan.PLAN_STATE_WORKING, + ProductionPlan.PLAN_STATE_ASSGINED]).order_by('process__number').values('process', + 'process__name').annotate(count_ok=Sum('count_ok'), + count=Sum('count'), count_real=Sum('count_real'), count_notok=Sum('count_notok')) + return Response(objs) + class ProcessYieldView(CreateAPIView): """ 工序成品率统计 diff --git a/hb_server/apps/wpm/migrations/0054_auto_20220315_1500.py b/hb_server/apps/wpm/migrations/0054_auto_20220315_1500.py new file mode 100644 index 0000000..3b4a060 --- /dev/null +++ b/hb_server/apps/wpm/migrations/0054_auto_20220315_1500.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.9 on 2022-03-15 07:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0053_auto_20220129_1512'), + ] + + operations = [ + migrations.AlterField( + model_name='operationequip', + name='state', + field=models.PositiveSmallIntegerField(choices=[(10, '完好'), (20, '限用'), (30, '在修'), (40, '禁用'), (50, '报废')], default=10, verbose_name='当前设备状态'), + ), + migrations.AlterField( + model_name='wproduct', + name='act_state', + field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '已入库'), (50, '不合格'), (60, '待成品检验'), (70, '已报废'), (80, '已售出'), (90, '已使用')], default=0, verbose_name='进行状态'), + ), + migrations.AlterField( + model_name='wproductflow', + name='act_state', + field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '已入库'), (50, '不合格'), (60, '待成品检验'), (70, '已报废'), (80, '已售出'), (90, '已使用')], default=0, verbose_name='进行状态'), + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index f75908f..b408f18 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -43,6 +43,7 @@ class WProduct(CommonAModel): WPR_ACT_STATE_TOFINALTEST = 60 WPR_ACT_STATE_SCRAP = 70 WPR_ACT_STATE_SELLED = 80 + WPR_ACT_STATE_USED = 90 act_state_choices = ( (WPR_ACT_STATE_TORETEST, '待复检'), (WPR_ACT_STATE_DOWAIT, '操作准备中'), @@ -55,6 +56,7 @@ class WProduct(CommonAModel): (WPR_ACT_STATE_TOFINALTEST, '待成品检验'), (WPR_ACT_STATE_SCRAP, '已报废'), (WPR_ACT_STATE_SELLED, '已售出'), + (WPR_ACT_STATE_USED, '已使用'), ) SCRAP_REASON_QIPAO = 10 SCRAP_REASON_PODIAN = 20 diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 430dc78..b8234d0 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -781,8 +781,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd WpmService.add_wproduct_flow_log(wproduct, 'wproduct_create') # 隐藏原半成品 wps = WProduct.objects.filter(ow_wproduct__operation=op) - wps.update(is_hidden=True, child=wproduct, + wps.update(act_state=WProduct.WPR_ACT_STATE_USED, child=wproduct, is_hidden=True, update_by=request.user, update_time=timezone.now()) + WpmService.add_wproducts_flow_log(wps, change_str='wproduct_create') else: raise exceptions.APIException('产出物料未填写或填写错误') op.is_submited = True From e7fdc7984a7ad994df0534cda6ec525e08c5bb96 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 15 Mar 2022 16:50:37 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0count=5Fdoing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/cms/__init__.py | 0 hb_server/apps/cms/admin.py | 3 +++ hb_server/apps/cms/apps.py | 5 +++++ hb_server/apps/cms/migrations/__init__.py | 0 hb_server/apps/cms/models.py | 3 +++ hb_server/apps/cms/tests.py | 3 +++ hb_server/apps/cms/views.py | 3 +++ hb_server/apps/develop/views.py | 6 ++++-- hb_server/apps/srm/services.py | 10 ++++++++-- 9 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 hb_server/apps/cms/__init__.py create mode 100644 hb_server/apps/cms/admin.py create mode 100644 hb_server/apps/cms/apps.py create mode 100644 hb_server/apps/cms/migrations/__init__.py create mode 100644 hb_server/apps/cms/models.py create mode 100644 hb_server/apps/cms/tests.py create mode 100644 hb_server/apps/cms/views.py diff --git a/hb_server/apps/cms/__init__.py b/hb_server/apps/cms/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hb_server/apps/cms/admin.py b/hb_server/apps/cms/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/hb_server/apps/cms/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/hb_server/apps/cms/apps.py b/hb_server/apps/cms/apps.py new file mode 100644 index 0000000..7ef3fea --- /dev/null +++ b/hb_server/apps/cms/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CmsConfig(AppConfig): + name = 'cms' diff --git a/hb_server/apps/cms/migrations/__init__.py b/hb_server/apps/cms/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hb_server/apps/cms/models.py b/hb_server/apps/cms/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/hb_server/apps/cms/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/hb_server/apps/cms/tests.py b/hb_server/apps/cms/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/hb_server/apps/cms/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/hb_server/apps/cms/views.py b/hb_server/apps/cms/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/hb_server/apps/cms/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/hb_server/apps/develop/views.py b/hb_server/apps/develop/views.py index f46227b..4013959 100644 --- a/hb_server/apps/develop/views.py +++ b/hb_server/apps/develop/views.py @@ -121,10 +121,12 @@ class UpdateFIFONumber(APIView): i.save() return Response() -class CorrectWproductState(APIView): +class CorrectWproduct(APIView): permission_classes = [IsAdminUser] def post(self, request): - pass + """ + """ + # WProduct.objects.filter(is_hidden=True).update(act_state=WProduct.WPR_ACT_STATE_USED) class ReloadServer(APIView): diff --git a/hb_server/apps/srm/services.py b/hb_server/apps/srm/services.py index e6edf02..d9ae057 100644 --- a/hb_server/apps/srm/services.py +++ b/hb_server/apps/srm/services.py @@ -3,7 +3,7 @@ from apps.pm.models import ProductionPlan from apps.sam.models import Order from apps.wpm.models import WProduct, WproductFlow from django.db.models import F - +from apps.wpm.serializers import WProductDetailSerializer class SrmServices: """ 数据统计分析 @@ -34,7 +34,13 @@ class SrmServices: ).count() count_selled = objs.filter(act_state=WProduct.WPR_ACT_STATE_SELLED).count() count_mtestok = objs.filter(is_mtestok=True).count() - return dict(count=count,count_ok=count_ok, count_notok=count_notok, count_selled=count_selled, count_mtestok=count_mtestok) + count_mtestnotok = objs.filter(is_mtestok=False).count() + count_doing = objs.filter(act_state__in=[ + WProduct.WPR_ACT_STATE_TOTEST, WProduct.WPR_ACT_STATE_TOCOMBTEST, WProduct.WPR_ACT_STATE_TOFINALTEST, + WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_DOWAIT, WProduct.WPR_ACT_STATE_DOING + ], subproduction_plan__product=F('material')).count() + return dict(count=count,count_ok=count_ok, count_notok=count_notok, + count_selled=count_selled, count_mtestok=count_mtestok, count_mtestnotok=count_mtestnotok, count_doing=count_doing) @classmethod def get_plan_count(cls, datetime_start=None, datetime_end=None): From b4795ab9f263eed98581a7b80262db917f27a60b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 16 Mar 2022 10:28:39 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0cms=20article?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/cms/apps.py | 3 +- hb_server/apps/cms/migrations/0001_initial.py | 37 +++++++++++++++++++ hb_server/apps/cms/models.py | 11 +++++- hb_server/apps/cms/serializers.py | 21 +++++++++++ hb_server/apps/cms/urls.py | 10 +++++ hb_server/apps/cms/views.py | 23 ++++++++++++ hb_server/apps/hrm/urls.py | 2 +- hb_server/apps/srm/views.py | 2 +- hb_server/server/settings.py | 3 +- hb_server/server/urls.py | 1 + 10 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 hb_server/apps/cms/migrations/0001_initial.py create mode 100644 hb_server/apps/cms/serializers.py create mode 100644 hb_server/apps/cms/urls.py diff --git a/hb_server/apps/cms/apps.py b/hb_server/apps/cms/apps.py index 7ef3fea..d20462e 100644 --- a/hb_server/apps/cms/apps.py +++ b/hb_server/apps/cms/apps.py @@ -2,4 +2,5 @@ from django.apps import AppConfig class CmsConfig(AppConfig): - name = 'cms' + name = 'apps.cms' + verbose_name = '内容管理' diff --git a/hb_server/apps/cms/migrations/0001_initial.py b/hb_server/apps/cms/migrations/0001_initial.py new file mode 100644 index 0000000..bbfa1ac --- /dev/null +++ b/hb_server/apps/cms/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.9 on 2022-03-16 02:25 + +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 = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Article', + fields=[ + ('id', models.BigAutoField(auto_created=True, 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='删除标记')), + ('title', models.CharField(max_length=100, verbose_name='标题')), + ('content', models.TextField(verbose_name='内容')), + ('author', models.CharField(blank=True, max_length=100, null=True, verbose_name='作者')), + ('is_top', models.BooleanField(default=False, verbose_name='是否置顶')), + ('is_published', models.BooleanField(default=False, verbose_name='是否发布')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='article_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/hb_server/apps/cms/models.py b/hb_server/apps/cms/models.py index 71a8362..86964fe 100644 --- a/hb_server/apps/cms/models.py +++ b/hb_server/apps/cms/models.py @@ -1,3 +1,12 @@ from django.db import models - +from apps.system.models import CommonAModel # Create your models here. +class Article(CommonAModel): + """ + 文章 + """ + title = models.CharField('标题', max_length=100) + content = models.TextField('内容') + author = models.CharField('作者', max_length=100, null=True, blank=True) + is_top = models.BooleanField('是否置顶', default=False) + is_published = models.BooleanField('是否发布', default=False) diff --git a/hb_server/apps/cms/serializers.py b/hb_server/apps/cms/serializers.py new file mode 100644 index 0000000..f8a6b8e --- /dev/null +++ b/hb_server/apps/cms/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers +from apps.cms.models import Article +from apps.system.serializers import UserSimpleSerializer + +class ArticleListSerializer(serializers.ModelSerializer): + create_by_ = UserSimpleSerializer(source='create_by', read_only=True) + class Meta: + model = Article + exclude = ['content'] + +class ArticleCreateUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = Article + fields = ['title', 'content', 'author', 'is_published', 'is_top'] + + +class ArticleDetailSerializer(serializers.ModelSerializer): + create_by_ = UserSimpleSerializer(source='create_by', read_only=True) + class Meta: + model = Article + fields = '__all__' \ No newline at end of file diff --git a/hb_server/apps/cms/urls.py b/hb_server/apps/cms/urls.py new file mode 100644 index 0000000..df95a52 --- /dev/null +++ b/hb_server/apps/cms/urls.py @@ -0,0 +1,10 @@ +from rest_framework.routers import DefaultRouter +from django.urls import path, include +from apps.cms.views import ArticleViewSet + +router = DefaultRouter() +router.register('article', ArticleViewSet, basename='article') + +urlpatterns = [ + path('', include(router.urls)), +] \ No newline at end of file diff --git a/hb_server/apps/cms/views.py b/hb_server/apps/cms/views.py index 91ea44a..0d918e9 100644 --- a/hb_server/apps/cms/views.py +++ b/hb_server/apps/cms/views.py @@ -1,3 +1,26 @@ from django.shortcuts import render +from rest_framework.viewsets import ModelViewSet +from apps.cms.models import Article +from apps.cms.serializers import ArticleCreateUpdateSerializer, ArticleDetailSerializer, ArticleListSerializer +from apps.system.mixins import CreateUpdateModelAMixin # Create your views here. + +class ArticleViewSet(CreateUpdateModelAMixin, ModelViewSet): + """ + 文章增删改查 + """ + perms_map = {'get': '*', 'post': 'article_create' + , 'put':'article_update', 'delete':'article_delete'} + queryset = Article.objects.select_related('create_by') + filterset_fields = ['is_top', 'is_published'] + serializer_class = ArticleListSerializer + search_fields = ['title', 'author'] + ordering = ['is_published', 'is_top', 'update_time'] + + def get_serializer_class(self): + if self.action in ['create', 'update']: + return ArticleCreateUpdateSerializer + elif self.action in ['retrieve']: + return ArticleDetailSerializer + return super().get_serializer_class() \ No newline at end of file diff --git a/hb_server/apps/hrm/urls.py b/hb_server/apps/hrm/urls.py index 9db9637..b0ced0c 100644 --- a/hb_server/apps/hrm/urls.py +++ b/hb_server/apps/hrm/urls.py @@ -1,4 +1,4 @@ -from django.db.models import base + from rest_framework import urlpatterns from apps.hrm.views import ClockRecordViewSet, EmployeeViewSet, FaceLogin, NotWorkRemarkViewSet from django.urls import path, include diff --git a/hb_server/apps/srm/views.py b/hb_server/apps/srm/views.py index 158489f..631380b 100644 --- a/hb_server/apps/srm/views.py +++ b/hb_server/apps/srm/views.py @@ -72,7 +72,7 @@ class ProcessNowView(CreateAPIView): 工序当前进度 """ perms_map = {'post':'*'} - serializers_class = serializers.Serializer + serializer_class = serializers.Serializer def create(self, request, *args, **kwargs): objs = SubProductionPlan.objects.filter(production_plan__state__in =[ProductionPlan.PLAN_STATE_WORKING, diff --git a/hb_server/server/settings.py b/hb_server/server/settings.py index d0fdffa..32a09e1 100644 --- a/hb_server/server/settings.py +++ b/hb_server/server/settings.py @@ -60,7 +60,8 @@ INSTALLED_APPS = [ 'apps.pm', 'apps.wpm', 'apps.srm', - 'apps.develop' + 'apps.develop', + 'apps.cms' ] X_FRAME_OPTIONS = 'SAMEORIGIN' diff --git a/hb_server/server/urls.py b/hb_server/server/urls.py index 50bc49f..2e95b54 100644 --- a/hb_server/server/urls.py +++ b/hb_server/server/urls.py @@ -72,6 +72,7 @@ urlpatterns = [ path('api/wpm/', include('apps.wpm.urls')), path('api/srm/', include('apps.srm.urls')), path('api/develop/', include('apps.develop.urls')), + path('api/cms/', include('apps.cms.urls')), # 工具 path('api/utils/signature/', GenSignature.as_view()), From d3f999d2c8b8929c9c84af7fc58079f943ece5ac Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 16 Mar 2022 16:11:45 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E5=85=B6=E4=BB=96=E5=87=BA=E5=BA=93?= =?UTF-8?q?=E4=B8=8D=E5=8F=AF=E6=93=8D=E4=BD=9C=E6=88=90=E5=93=81=E6=88=96?= =?UTF-8?q?=E5=8D=8A=E6=88=90=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/serializers.py | 3 +++ hb_server/apps/inm/views.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/hb_server/apps/inm/serializers.py b/hb_server/apps/inm/serializers.py index 357084d..c5df25b 100644 --- a/hb_server/apps/inm/serializers.py +++ b/hb_server/apps/inm/serializers.py @@ -2,6 +2,7 @@ from rest_framework import exceptions from rest_framework import serializers from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse, Inventory +from apps.mtm.models import Material from apps.pum.models import PuOrder, Vendor from apps.qm.models import TestRecord, TestRecordItem from apps.sam.serializers import OrderSimpleSerializer @@ -173,6 +174,8 @@ class FIFOOutOtherSerializer(serializers.ModelSerializer): obj.save() for i in details: mb = i.pop('material_batch') + if mb.material.type in [Material.MA_TYPE_GOOD, Material.MA_TYPE_HALFGOOD]: + raise ValidationError('不可直接出成品或半成品') i['material'] = mb.material i['batch'] = mb.batch i['warehouse'] = mb.warehouse diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index fcc454f..c528834 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -163,6 +163,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): return super().destroy(request, *args, **kwargs) @action(methods=['post'], detail=False, perms_map={'post': 'fifo_in_pur'}, serializer_class=FIFOInPurSerializer) + @transaction.atomic() def in_pur(self, request, pk=None): """ 采购入库 @@ -174,6 +175,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): @action(methods=['post'], detail=False, perms_map={'post': 'fifo_in_other'}, serializer_class=FIFOInOtherSerializer) + @transaction.atomic() def in_other(self, request, pk=None): """ 其他入库 @@ -185,6 +187,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): @action(methods=['post'], detail=False, perms_map={'post': 'fifo_out_other'}, serializer_class=FIFOOutOtherSerializer) + @transaction.atomic() def out_other(self, request, pk=None): """ 其他出库 From 8859c13edf5ce29d979eb3d498b5f1772ca7bbd3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 16 Mar 2022 16:34:59 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0to=5Forder=5Fneed=5Fmte?= =?UTF-8?q?st=E5=AD=97=E6=AE=B5=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/filters.py | 3 ++- hb_server/apps/wpm/filters.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/inm/filters.py b/hb_server/apps/inm/filters.py index 377cb4d..1c44ab5 100644 --- a/hb_server/apps/inm/filters.py +++ b/hb_server/apps/inm/filters.py @@ -23,10 +23,11 @@ class MbFilterSet(DynamicFieldsFilterMixin, filters.FilterSet): class IProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet): order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order") to_order = filters.NumberFilter(field_name="wproduct__to_order") + to_order_need_mtest = filters.BooleanFilter(field_name="wproduct__to_order__need_mtest") need_to_order = filters.BooleanFilter(field_name="wproduct__need_to_order") update_time_start = filters.DateFilter(field_name="update_time", lookup_expr='gte') update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte') class Meta: model = IProduct fields = ['material', 'warehouse', 'batch', 'order', 'material__type', 'update_time_start', 'update_time_end', - 'to_order', 'need_to_order', 'state'] + 'to_order', 'need_to_order', 'state', 'to_order_need_mtest'] diff --git a/hb_server/apps/wpm/filters.py b/hb_server/apps/wpm/filters.py index 2798e98..2ef5b25 100644 --- a/hb_server/apps/wpm/filters.py +++ b/hb_server/apps/wpm/filters.py @@ -33,6 +33,7 @@ class WProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet): tag = filters.CharFilter(method='filter_tag') production_plan = filters.NumberFilter( field_name='subproduction_plan__production_plan') + to_order_need_mtest = filters.BooleanFilter(field_name="to_order__need_mtest") def filter_fields(self, queryset, name, value): return queryset @@ -41,7 +42,7 @@ class WProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet): class Meta: model = WProduct fields = ['step', 'subproduction_plan', 'material', - 'step__process', 'act_state', 'material__type', 'need_to_order'] + 'step__process', 'act_state', 'material__type', 'need_to_order', 'to_order_need_mtest'] def filter_tag(self, queryset, name, value): if value == 'no_scrap': From f8fab968215ae531c2addf701f0f8f739dad247a Mon Sep 17 00:00:00 2001 From: shilixia <2309368887@qq.com> Date: Wed, 16 Mar 2022 16:38:24 +0800 Subject: [PATCH 08/12] junjian --- hb_client/src/views/inm/product.vue | 2 +- hb_client/src/views/qm/product.vue | 68 +++-------------------------- 2 files changed, 6 insertions(+), 64 deletions(-) diff --git a/hb_client/src/views/inm/product.vue b/hb_client/src/views/inm/product.vue index 7391079..871eaec 100644 --- a/hb_client/src/views/inm/product.vue +++ b/hb_client/src/views/inm/product.vue @@ -35,7 +35,7 @@