Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
e6b6144a72
|
@ -35,7 +35,7 @@
|
|||
<el-table-column label="订单">
|
||||
<template slot-scope="scope">
|
||||
<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>
|
||||
<span v-else></span>
|
||||
|
|
|
@ -1,49 +1,7 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<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
|
||||
:data="iproductData2.results"
|
||||
border
|
||||
|
@ -117,8 +75,7 @@
|
|||
:limit.sync="listQuery2.page_size"
|
||||
@pagination="getList2"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
|
@ -158,13 +115,7 @@
|
|||
components: {Pagination},
|
||||
data() {
|
||||
return {
|
||||
iproductData: {
|
||||
count: 0,
|
||||
},
|
||||
listQuery: {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
},
|
||||
|
||||
iproductData2: {
|
||||
count: 0,
|
||||
},
|
||||
|
@ -181,24 +132,15 @@
|
|||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.getList2();
|
||||
},
|
||||
|
||||
methods: {
|
||||
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() {
|
||||
this.listQuery2.material__type = 1;
|
||||
this.listQuery2.to_order_need_mtest = true;
|
||||
getiproductList(this.listQuery2).then((response) => {
|
||||
if (response.data) {
|
||||
this.iproductData2 = response.data;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CmsConfig(AppConfig):
|
||||
name = 'apps.cms'
|
||||
verbose_name = '内容管理'
|
|
@ -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,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -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)
|
|
@ -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__'
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -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)),
|
||||
]
|
|
@ -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()
|
|
@ -121,6 +121,12 @@ class UpdateFIFONumber(APIView):
|
|||
i.save()
|
||||
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):
|
||||
|
|
|
@ -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='设备状态'),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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='关联销售记录'),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
其他出库
|
||||
|
|
|
@ -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,6 +27,19 @@ 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 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='年')
|
||||
|
|
|
@ -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)
|
||||
|
|
@ -3,12 +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
|
||||
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)),
|
||||
]
|
||||
|
|
|
@ -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,9 +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
|
||||
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):
|
||||
|
@ -23,6 +25,62 @@ 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_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):
|
||||
"""
|
||||
工序成品率统计
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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='进行状态'),
|
||||
),
|
||||
]
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
|
@ -98,7 +100,7 @@ class WProduct(CommonAModel):
|
|||
act_state = models.IntegerField(
|
||||
'进行状态', default=0, choices=act_state_choices)
|
||||
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')
|
||||
remark = models.CharField('备注', max_length=200, null=True, blank=True)
|
||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
|
||||
|
@ -174,7 +176,7 @@ class WproductFlow(CommonAModel):
|
|||
act_state = models.IntegerField(
|
||||
'进行状态', default=0, choices=WProduct.act_state_choices)
|
||||
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')
|
||||
remark = models.CharField('备注', max_length=200, null=True, blank=True)
|
||||
subproduction_plan = models.ForeignKey(
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -60,7 +60,8 @@ INSTALLED_APPS = [
|
|||
'apps.pm',
|
||||
'apps.wpm',
|
||||
'apps.srm',
|
||||
'apps.develop'
|
||||
'apps.develop',
|
||||
'apps.cms'
|
||||
]
|
||||
|
||||
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
||||
|
|
|
@ -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()),
|
||||
|
|
Loading…
Reference in New Issue