Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop

This commit is contained in:
shijing 2022-03-17 10:52:37 +08:00
commit e6b6144a72
32 changed files with 411 additions and 75 deletions

View File

@ -35,7 +35,7 @@
<el-table-column label="订单"> <el-table-column label="订单">
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if="scope.row.to_order_">{{scope.row.to_order_.number}}</span> <span v-if="scope.row.to_order_">{{scope.row.to_order_.number}}</span>
<el-tag v-else-if="scope.row.to_order_ == null && scope.row.need_to_order == true"> <el-tag v-else-if="scope.row.to_order_ == null">
需要确定订单 需要确定订单
</el-tag> </el-tag>
<span v-else></span> <span v-else></span>

View File

@ -1,49 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card> <el-card>
<el-tabs v-model="activeName" type="card">
<el-tab-pane label="待军检" name="first">
<el-button
v-if="checkPermission(['wp_need_to_order'])"
type="primary"
icon="el-icon-plus"
@click="handleorder"
>
申请
</el-button>
<el-table
ref="multipleTable"
:data="iproductData.results"
border
fit
stripe
highlight-current-row
max-height="700"
height="100"
v-el-height-adaptive-table="{bottomOffset: 42}"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column type="index" width="50"/>
<el-table-column label="成品编号" prop="number">
</el-table-column>
<el-table-column label="成品批次" prop="batch">
</el-table-column>
<el-table-column label="成品名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column>
<el-table-column label="所在仓库">
<template slot-scope="scope">{{ scope.row.warehouse_.name }}</template>
</el-table-column>
</el-table>
<pagination
v-show="iproductData.count > 0"
:total="iproductData.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-tab-pane>
<el-tab-pane label="军检列表" name="second">
<el-table <el-table
:data="iproductData2.results" :data="iproductData2.results"
border border
@ -117,8 +75,7 @@
:limit.sync="listQuery2.page_size" :limit.sync="listQuery2.page_size"
@pagination="getList2" @pagination="getList2"
/> />
</el-tab-pane>
</el-tabs>
<el-dialog <el-dialog
:visible.sync="dialogVisible" :visible.sync="dialogVisible"
:close-on-click-modal="false" :close-on-click-modal="false"
@ -158,13 +115,7 @@
components: {Pagination}, components: {Pagination},
data() { data() {
return { return {
iproductData: {
count: 0,
},
listQuery: {
page: 1,
page_size: 20,
},
iproductData2: { iproductData2: {
count: 0, count: 0,
}, },
@ -181,24 +132,15 @@
}; };
}, },
created() { created() {
this.getList();
this.getList2(); this.getList2();
}, },
methods: { methods: {
checkPermission, checkPermission,
getList() {
this.listQuery.material__type = 1;
this.listQuery.need_to_order = false;
getiproductList(this.listQuery).then((response) => {
if (response.data) {
this.iproductData = response.data;
}
});
},
getList2() { getList2() {
this.listQuery2.material__type = 1; this.listQuery2.material__type = 1;
this.listQuery2.to_order_need_mtest = true;
getiproductList(this.listQuery2).then((response) => { getiproductList(this.listQuery2).then((response) => {
if (response.data) { if (response.data) {
this.iproductData2 = response.data; this.iproductData2 = response.data;

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class CmsConfig(AppConfig):
name = 'apps.cms'
verbose_name = '内容管理'

View File

@ -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,
},
),
]

View File

@ -0,0 +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)

View File

@ -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__'

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -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)),
]

View File

@ -0,0 +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()

View File

@ -121,6 +121,12 @@ class UpdateFIFONumber(APIView):
i.save() i.save()
return Response() return Response()
class CorrectWproduct(APIView):
permission_classes = [IsAdminUser]
def post(self, request):
"""
"""
# WProduct.objects.filter(is_hidden=True).update(act_state=WProduct.WPR_ACT_STATE_USED)
class ReloadServer(APIView): class ReloadServer(APIView):

View File

@ -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='设备状态'),
),
]

View File

@ -1,4 +1,4 @@
from django.db.models import base
from rest_framework import urlpatterns from rest_framework import urlpatterns
from apps.hrm.views import ClockRecordViewSet, EmployeeViewSet, FaceLogin, NotWorkRemarkViewSet from apps.hrm.views import ClockRecordViewSet, EmployeeViewSet, FaceLogin, NotWorkRemarkViewSet
from django.urls import path, include from django.urls import path, include

View File

@ -23,10 +23,11 @@ class MbFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
class IProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet): class IProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order") order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
to_order = filters.NumberFilter(field_name="wproduct__to_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") 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_start = filters.DateFilter(field_name="update_time", lookup_expr='gte')
update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte') update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte')
class Meta: class Meta:
model = IProduct model = IProduct
fields = ['material', 'warehouse', 'batch', 'order', 'material__type', 'update_time_start', 'update_time_end', 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']

View File

@ -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='关联销售记录'),
),
]

View File

@ -2,6 +2,7 @@ from rest_framework import exceptions
from rest_framework import serializers from rest_framework import serializers
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse, Inventory 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.pum.models import PuOrder, Vendor
from apps.qm.models import TestRecord, TestRecordItem from apps.qm.models import TestRecord, TestRecordItem
from apps.sam.serializers import OrderSimpleSerializer from apps.sam.serializers import OrderSimpleSerializer
@ -173,6 +174,8 @@ class FIFOOutOtherSerializer(serializers.ModelSerializer):
obj.save() obj.save()
for i in details: for i in details:
mb = i.pop('material_batch') 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['material'] = mb.material
i['batch'] = mb.batch i['batch'] = mb.batch
i['warehouse'] = mb.warehouse i['warehouse'] = mb.warehouse

View File

@ -6,6 +6,8 @@ from apps.sam.models import SalePack, SaleProduct
from django.db.models import Count from django.db.models import Count
from django.db.models.aggregates import Sum from django.db.models.aggregates import Sum
import logging import logging
from apps.wpm.services import WpmService
logger = logging.getLogger('log') logger = logging.getLogger('log')
class InmService: class InmService:
@ -133,8 +135,10 @@ class InmService:
# 更新动态产品表情况 # 更新动态产品表情况
from apps.wpm.models import WProduct 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) act_state=WProduct.WPR_ACT_STATE_SELLED)
WpmService.add_wproducts_flow_log(instances=wps, change_str='selled')
# 变更销售记录实际发货数 # 变更销售记录实际发货数
sale.count_real = ips.count() sale.count_real = ips.count()

View File

@ -163,6 +163,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
return super().destroy(request, *args, **kwargs) return super().destroy(request, *args, **kwargs)
@action(methods=['post'], detail=False, perms_map={'post': 'fifo_in_pur'}, serializer_class=FIFOInPurSerializer) @action(methods=['post'], detail=False, perms_map={'post': 'fifo_in_pur'}, serializer_class=FIFOInPurSerializer)
@transaction.atomic()
def in_pur(self, request, pk=None): 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'}, @action(methods=['post'], detail=False, perms_map={'post': 'fifo_in_other'},
serializer_class=FIFOInOtherSerializer) serializer_class=FIFOInOtherSerializer)
@transaction.atomic()
def in_other(self, request, pk=None): 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'}, @action(methods=['post'], detail=False, perms_map={'post': 'fifo_out_other'},
serializer_class=FIFOOutOtherSerializer) serializer_class=FIFOOutOtherSerializer)
@transaction.atomic()
def out_other(self, request, pk=None): def out_other(self, request, pk=None):
""" """
其他出库 其他出库

View File

@ -1,6 +1,8 @@
from email.policy import default
from rest_framework import serializers from rest_framework import serializers
from apps.pm.models import ProductionPlan, SubProductionPlan from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer
from apps.system.models import Organization
class SubplanGanttSerializer(serializers.ModelSerializer): class SubplanGanttSerializer(serializers.ModelSerializer):
process_ = ProcessSimpleSerializer(source='process', read_only=True) process_ = ProcessSimpleSerializer(source='process', read_only=True)
@ -25,6 +27,19 @@ class ProcessYieldSerializer(serializers.Serializer):
datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True) datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True)
datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True) datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True)
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): class AtWorkCountSerializer(serializers.Serializer):
year = serializers.IntegerField(label='') year = serializers.IntegerField(label='')

View File

@ -0,0 +1,74 @@
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
from apps.wpm.serializers import WProductDetailSerializer
class SrmServices:
"""
数据统计分析
"""
@classmethod
def get_product_count(cls, datetime_start=None, datetime_end=None, tag=1, dept=None):
"""
根据生产情况统计相关数量
"""
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]).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()
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):
"""
任务数量
"""
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)

View File

@ -3,12 +3,16 @@ from rest_framework import urlpatterns
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from apps.srm.views import AtWorkCountView, GanttPlan, ProcessYieldView from apps.srm.views import AtWorkCountView, GanttPlan, OrderCountView, PlanCountView, ProcessNowView, ProcessYieldView, ProductCountView
router = DefaultRouter() router = DefaultRouter()
urlpatterns = [ urlpatterns = [
path('gantt/plan/', GanttPlan.as_view()), 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/yield/', ProcessYieldView.as_view()),
path('process/now/', ProcessNowView.as_view()),
path('at_work/', AtWorkCountView.as_view()), path('at_work/', AtWorkCountView.as_view()),
path('', include(router.urls)), path('', include(router.urls)),
] ]

View File

@ -1,6 +1,7 @@
from datetime import date, timedelta from datetime import date, timedelta
from django.shortcuts import render from django.shortcuts import render
from idna import valid_contextj
from numpy import number from numpy import number
from rest_framework import serializers from rest_framework import serializers
from rest_framework.generics import ListAPIView, CreateAPIView from rest_framework.generics import ListAPIView, CreateAPIView
@ -9,9 +10,10 @@ from rest_framework.response import Response
from apps.hrm.models import ClockRecord from apps.hrm.models import ClockRecord
from apps.mtm.models import Process, Step from apps.mtm.models import Process, Step
from apps.pm.models import ProductionPlan, SubProductionPlan from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.srm.serializers import AtWorkCountSerializer, PlanGanttSerializer, ProcessYieldSerializer from apps.srm.serializers import AtWorkCountSerializer, PlanGanttSerializer, ProcessYieldSerializer, ProductCountSerializer, SrmCountSerializer
from apps.srm.services import SrmServices
from apps.wpm.models import WProduct, WproductFlow 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. # Create your views here.
class GanttPlan(ListAPIView): class GanttPlan(ListAPIView):
@ -23,6 +25,62 @@ class GanttPlan(ListAPIView):
queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process') queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process')
ordering = ['-id'] 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_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':'*'}
serializer_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): class ProcessYieldView(CreateAPIView):
""" """
工序成品率统计 工序成品率统计

View File

@ -33,6 +33,7 @@ class WProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
tag = filters.CharFilter(method='filter_tag') tag = filters.CharFilter(method='filter_tag')
production_plan = filters.NumberFilter( production_plan = filters.NumberFilter(
field_name='subproduction_plan__production_plan') 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): def filter_fields(self, queryset, name, value):
return queryset return queryset
@ -41,7 +42,7 @@ class WProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
class Meta: class Meta:
model = WProduct model = WProduct
fields = ['step', 'subproduction_plan', 'material', 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): def filter_tag(self, queryset, name, value):
if value == 'no_scrap': if value == 'no_scrap':

View File

@ -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='进行状态'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.9 on 2022-03-17 00:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0054_auto_20220315_1500'),
]
operations = [
migrations.AlterField(
model_name='wproductflow',
name='child',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_child', to='wpm.wproduct'),
),
]

View File

@ -43,6 +43,7 @@ class WProduct(CommonAModel):
WPR_ACT_STATE_TOFINALTEST = 60 WPR_ACT_STATE_TOFINALTEST = 60
WPR_ACT_STATE_SCRAP = 70 WPR_ACT_STATE_SCRAP = 70
WPR_ACT_STATE_SELLED = 80 WPR_ACT_STATE_SELLED = 80
WPR_ACT_STATE_USED = 90
act_state_choices = ( act_state_choices = (
(WPR_ACT_STATE_TORETEST, '待复检'), (WPR_ACT_STATE_TORETEST, '待复检'),
(WPR_ACT_STATE_DOWAIT, '操作准备中'), (WPR_ACT_STATE_DOWAIT, '操作准备中'),
@ -55,6 +56,7 @@ class WProduct(CommonAModel):
(WPR_ACT_STATE_TOFINALTEST, '待成品检验'), (WPR_ACT_STATE_TOFINALTEST, '待成品检验'),
(WPR_ACT_STATE_SCRAP, '已报废'), (WPR_ACT_STATE_SCRAP, '已报废'),
(WPR_ACT_STATE_SELLED, '已售出'), (WPR_ACT_STATE_SELLED, '已售出'),
(WPR_ACT_STATE_USED, '已使用'),
) )
SCRAP_REASON_QIPAO = 10 SCRAP_REASON_QIPAO = 10
SCRAP_REASON_PODIAN = 20 SCRAP_REASON_PODIAN = 20
@ -98,7 +100,7 @@ class WProduct(CommonAModel):
act_state = models.IntegerField( act_state = models.IntegerField(
'进行状态', default=0, choices=act_state_choices) '进行状态', default=0, choices=act_state_choices)
is_hidden = models.BooleanField('是否隐藏', default=False) is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True, child = models.ForeignKey('wpm.wproduct', blank=True, null=True,
on_delete=models.CASCADE, related_name='wp_child') on_delete=models.CASCADE, related_name='wp_child')
remark = models.CharField('备注', max_length=200, null=True, blank=True) remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
@ -174,7 +176,7 @@ class WproductFlow(CommonAModel):
act_state = models.IntegerField( act_state = models.IntegerField(
'进行状态', default=0, choices=WProduct.act_state_choices) '进行状态', default=0, choices=WProduct.act_state_choices)
is_hidden = models.BooleanField('是否隐藏', default=False) is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True, child = models.ForeignKey('wpm.wproduct', blank=True, null=True,
on_delete=models.CASCADE, related_name='wpf_child') on_delete=models.CASCADE, related_name='wpf_child')
remark = models.CharField('备注', max_length=200, null=True, blank=True) remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey( subproduction_plan = models.ForeignKey(

View File

@ -167,6 +167,23 @@ class WpmService(object):
ins.change_str = change_str ins.change_str = change_str
ins.save() 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 @classmethod
def update_cutting_list_with_operation(cls, op:Operation): def update_cutting_list_with_operation(cls, op:Operation):
""" """

View File

@ -781,8 +781,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
WpmService.add_wproduct_flow_log(wproduct, 'wproduct_create') WpmService.add_wproduct_flow_log(wproduct, 'wproduct_create')
# 隐藏原半成品 # 隐藏原半成品
wps = WProduct.objects.filter(ow_wproduct__operation=op) 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()) update_by=request.user, update_time=timezone.now())
WpmService.add_wproducts_flow_log(wps, change_str='wproduct_create')
else: else:
raise exceptions.APIException('产出物料未填写或填写错误') raise exceptions.APIException('产出物料未填写或填写错误')
op.is_submited = True op.is_submited = True

View File

@ -60,7 +60,8 @@ INSTALLED_APPS = [
'apps.pm', 'apps.pm',
'apps.wpm', 'apps.wpm',
'apps.srm', 'apps.srm',
'apps.develop' 'apps.develop',
'apps.cms'
] ]
X_FRAME_OPTIONS = 'SAMEORIGIN' X_FRAME_OPTIONS = 'SAMEORIGIN'

View File

@ -72,6 +72,7 @@ urlpatterns = [
path('api/wpm/', include('apps.wpm.urls')), path('api/wpm/', include('apps.wpm.urls')),
path('api/srm/', include('apps.srm.urls')), path('api/srm/', include('apps.srm.urls')),
path('api/develop/', include('apps.develop.urls')), path('api/develop/', include('apps.develop.urls')),
path('api/cms/', include('apps.cms.urls')),
# 工具 # 工具
path('api/utils/signature/', GenSignature.as_view()), path('api/utils/signature/', GenSignature.as_view()),