This commit is contained in:
shijing 2022-01-17 10:30:24 +08:00
commit a98de8720a
32 changed files with 874 additions and 501 deletions

View File

@ -348,7 +348,7 @@ export const asyncRoutes = [
component: Layout, component: Layout,
redirect: '/qm/product', redirect: '/qm/product',
name: 'qm', name: 'qm',
meta: { title: '质量管理', icon: 'example', perms: ['equipment_set'] }, meta: { title: '检验管理', icon: 'example', perms: ['equipment_set'] },
children: [ children: [
{ {
path: 'product', path: 'product',

View File

@ -100,6 +100,7 @@
<el-dialog <el-dialog
:visible.sync="dialogVisible" :visible.sync="dialogVisible"
:close-on-click-modal="false" :close-on-click-modal="false"
width="90%"
:title="dialogType === 'edit' ? '编辑出/如库记录' : '新增出/如库记录'" :title="dialogType === 'edit' ? '编辑出/如库记录' : '新增出/如库记录'"
> >
<el-form <el-form
@ -110,20 +111,11 @@
:rules="rule1" :rules="rule1"
> >
<el-form-item label="入库时间" prop="inout_date">
<el-date-picker
v-model="inventory.inout_date"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
>
</el-date-picker>
</el-form-item>
<div v-for="(item, index) in inventory.details" :key="index"> <div v-for="(item, index) in inventory.details" :key="index">
<el-row> <el-row>
<el-col :span="6" style="margin-right: 10px"> <el-col :span="5" style="margin-right: 10px">
<el-form-item <el-form-item
class="warehouse" class="warehouse"
label="仓库:" label="仓库:"
@ -141,7 +133,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6" style="margin-right: 10px"> <el-col :span="5" style="margin-right: 10px">
<el-form-item <el-form-item
class="material" class="material"
label="物料:" label="物料:"
@ -159,7 +151,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6" style="margin-right: 10px"> <el-col :span="5" style="margin-right: 10px">
<el-form-item <el-form-item
class="count" class="count"
label="数量" label="数量"
@ -171,7 +163,7 @@
></el-input-number> ></el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6" style="margin-right: 10px"> <el-col :span="5" style="margin-right: 10px">
<el-form-item <el-form-item
class="batch" class="batch"
label="批次" label="批次"

View File

@ -35,14 +35,14 @@
<el-table-column label="入库数量"> <el-table-column label="入库数量">
<template slot-scope="scope">{{ scope.row.count }}</template> <template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column> </el-table-column>
<el-table-column label="是否检查"> <el-table-column label="是否需要复验">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="scope.row.is_tested == false">未检查</el-tag> <el-tag v-if="scope.row.need_test == false"></el-tag>
<el-tag v-else>已检查</el-tag> <el-tag v-else></el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="检查是否合格"> <el-table-column label="复验是否合格">
<template slot-scope="scope" v-if="scope.row.is_tested == true"> <template slot-scope="scope">
<el-tag v-if="scope.row.is_testok == false">不合格</el-tag> <el-tag v-if="scope.row.is_testok == false">不合格</el-tag>
<el-tag v-else>合格</el-tag> <el-tag v-else>合格</el-tag>
</template> </template>
@ -51,10 +51,16 @@
<el-table-column align="center" label="操作" width="220px"> <el-table-column align="center" label="操作" width="220px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="scope.row.is_tested == false"
type="primary" type="primary"
@click="handleMaterial(scope)" @click="handleMaterial(scope)"
>检查</el-link >复验</el-link
>
<el-link
type="primary"
@click="handlefile(scope)"
>上传</el-link
> >
</template> </template>
</el-table-column> </el-table-column>
@ -262,6 +268,11 @@ export default {
} }
this.listLoading = false; this.listLoading = false;
}); });
},
//上传物料文件
handlefile(scope)
{
}, },
handleMaterial(scope) { handleMaterial(scope) {
//调该物料对应的检查表 //调该物料对应的检查表

View File

@ -12,7 +12,10 @@
</el-card> </el-card>
<el-tabs v-model="activeName" type="card" >
<el-tabs v-model="activeName" type="card">
<el-tab-pane label="供应商" name="5" v-if="this.type==3||this.type==4">
</el-tab-pane>
<el-tab-pane label="批次" name="3"> <el-tab-pane label="批次" name="3">
<el-table <el-table

View File

@ -350,6 +350,7 @@
this.dialogVisible = true; this.dialogVisible = true;
this.$nextTick(() => { this.$nextTick(() => {
this.$refs["Form"].resetFields(); this.$refs["Form"].resetFields();
this.value1="";
}); });
}, },

View File

@ -75,7 +75,7 @@
</el-table> </el-table>
<!--检验记录--> <!--检验记录-->
<el-dialog title="检验记录" :close-on-click-modal="false" :visible.sync="limitedCheckRecord"> <el-dialog title="检验记录" :visible.sync="limitedCheckRecord">
<el-table <el-table
:data="recordList" :data="recordList"
border border
@ -89,28 +89,42 @@
<el-table-column align="center" label="操作"> <el-table-column align="center" label="操作">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="!scope.row.is_submited"
@click="handleInspectionRecord(scope)"
>检验
</el-link>
<el-link
v-else
@click="handleRecordDetail(scope)" @click="handleRecordDetail(scope)"
>查看 >查看
</el-link> </el-link>
<el-link
@click="delTestRecord(scope)"
>删除
</el-link>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false"> </el-button> <el-button @click="dialogFormVisible = false"> </el-button>
<el-button type="primary" @click="putin"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
<!--非检查表显示-->
<el-dialog
width="60%"
:title="formName"
:visible.sync="recordVisible"
:close-on-click-modal="false"
@close="recordCancel"
>
<customForm
v-if="recordVisible"
:results="fieldList"
:hasPicture="hasPicture"
:formID="recordform"
:wproduct="wproduct"
:recordId="recordId"
:isDisabled="isDisabled"
@recordSubmit="recordSubmit"
@recordSave="recordSave"
@recordCancel="recordCancel"
/>
</el-dialog>
</el-card> </el-card>
@ -123,12 +137,14 @@
import { getProductionplan,getsubproductionplanList } from "@/api/pm"; import { getProductionplan,getsubproductionplanList } from "@/api/pm";
import { getwproductList,getrecordList} from "@/api/wpm"; import { getwproductList,getrecordList} from "@/api/wpm";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import customForm from '@/components/customForm/index'
import {getrffieldList} from "@/api/mtm";
import {getTestRecord} from "@/api/qm"; import { getTestRecord ,getTestRecordItem} from "@/api/qm";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultrecordform = {enabled:false};
export default { export default {
components: { Pagination }, components: { Pagination,customForm },
data() { data() {
return { return {
productionplan:{ productionplan:{
@ -136,6 +152,7 @@ export default {
}, },
activeName:"1", activeName:"1",
wproduct:[], wproduct:[],
recordList:[],
limitedCheckRecord:false, limitedCheckRecord:false,
listQuery: { listQuery: {
page: 1, page: 1,
@ -162,6 +179,30 @@ export default {
}, },
process_json:null, process_json:null,
productionplanID:null, productionplanID:null,
dialogVisibleForm: false,
tableForm:{
name:'',
},
recordform: defaultrecordform,
dialogType: "new",
dialogVisible: false,
dialogType1: "new",
dialogVisible1: false,
tableForm: defaultrecordform,
checkForm: {
hhh: '',
},
recordVisible: false,
customfieldList: [],
recordform: null,
recordId: null,
fifo_detail: "",
formName: "项目检查表",
hasPicture: false,
fieldList: [],
}; };
}, },
computed: {}, computed: {},
@ -217,10 +258,56 @@ export default {
this.limitedCheckRecord=true; this.limitedCheckRecord=true;
getrecordList({wproduct: scope.row.id,page:0}).then(res => { getrecordList({wproduct: scope.row.id,page:0}).then(res => {
if (res.code == 200) { if (res.code == 200) {
that.recordList = res.data.results; this.recordList = res.data;
} }
}) })
},
//点击记录里的查看
handleRecordDetail(scope) {
let that = this;
that.recordVisible = false;
that.recordId = scope.row.id;
that.recordform = scope.row.form;
that.formName = scope.row.form_.name;
getrffieldList({ form: this.recordform, page: 1, page_size: 100 }).then(
(response) => {
if (response.data) {
that.hasPicture = false;
let fieldList = response.data.results;
that.fieldList = [...fieldList];
let arr = fieldList.filter((item) => {
return item.field_type === "draw";
});
if (arr.length > 0) {
that.hasPicture = true;
} }
getTestRecordItem(scope.row.id).then((res) => {
let arr = [];
let fieldList = res.data.record_data;
for (let i = 0; i < that.fieldList.length; i++) {
let obj = that.fieldList[i];
obj.is_testok = null;
for (let j = 0; j < fieldList.length; j++) {
if (that.fieldList[i].field_key === fieldList[j].field_key) {
obj.id = fieldList[j].id;
obj.is_testok = fieldList[j].is_testok;
obj.field_value = fieldList[j].field_value;
}
}
arr.push(obj);
}
that.fieldList = arr;
that.$nextTick(() => {
that.isDisabled = true;
that.recordVisible = true;
});
});
}
}
);
},
}, },
}; };
</script> </script>

View File

@ -165,7 +165,7 @@
<template slot-scope="scope">{{ scope.row.count_real }}</template> <template slot-scope="scope">{{ scope.row.count_real }}</template>
</el-table-column> </el-table-column>
<el-table-column label="生产计划编号"> <el-table-column label="生产计划编号">
<template slot-scope="scope">{{ scope.row.subproduction_plan }}</template> <template slot-scope="scope">{{ scope.row.subproduction_plan_.number }}</template>
</el-table-column> </el-table-column>
<el-table-column label="物料名称"> <el-table-column label="物料名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template> <template slot-scope="scope">{{ scope.row.material_.name }}</template>
@ -200,7 +200,7 @@
<template slot-scope="scope">{{ scope.row.count_real }}</template> <template slot-scope="scope">{{ scope.row.count_real }}</template>
</el-table-column> </el-table-column>
<el-table-column label="生产计划编号"> <el-table-column label="生产计划编号">
<template slot-scope="scope">{{ scope.row.subproduction_plan }}</template> <template slot-scope="scope">{{ scope.row.subproduction_plan_.number }}</template>
</el-table-column> </el-table-column>
<el-table-column label="物料名称"> <el-table-column label="物料名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template> <template slot-scope="scope">{{ scope.row.material_.name }}</template>
@ -309,7 +309,8 @@ export default {
{ {
this.xhwl.push(item); this.xhwl.push(item);
} }
else{ else if(item.type==2)
{
this.ccwl.push(item); this.ccwl.push(item);
} }

View File

@ -134,15 +134,15 @@
</div> </div>
</template> </template>
<script> <script>
import {getfifodetailList} from "@/api/inm"; import { getfifodetailList } from "@/api/inm";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import {mtest, getwproductList} from "@/api/wpm"; import { mtest,getwproductList } from "@/api/wpm";
import customForm from '@/components/customForm/index'; import { getrecordformList, getrffieldList} from "@/api/mtm";
import {getrecordformList, getrffieldList} from "@/api/mtm"; import {getTestRecord,getTestRecordItem} from "@/api/qm";
import {getTestRecord, getTestRecordItem} from "@/api/qm"; import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default { export default {
components: {Pagination, customForm}, components: { Pagination },
data() { data() {
return { return {
wproductList: { wproductList: {

View File

@ -6,7 +6,7 @@
<el-descriptions-item label="产品名称" v-if="productionplan.product_">{{productionplan.product_.name}}</el-descriptions-item> <el-descriptions-item label="产品名称" v-if="productionplan.product_">{{productionplan.product_.name}}</el-descriptions-item>
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}</el-descriptions-item> <el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}</el-descriptions-item>
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item> <el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
<el-descriptions-item label="不合格品数量">不合格数没有</el-descriptions-item> <el-descriptions-item label="不合格品数量">{{productionplan.count_notok}}</el-descriptions-item>
</el-descriptions> </el-descriptions>
<el-card style="margin-bottom: 20px"> <el-card style="margin-bottom: 20px">
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">

View File

@ -8,9 +8,10 @@
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}} <el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item> <el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
<el-descriptions-item label="不合格品数量">不合格数没有</el-descriptions-item> <el-descriptions-item label="不合格品数量">{{productionplan.count_notok}}</el-descriptions-item>
<el-descriptions-item label="玻璃编号">{{wproductnumber}}</el-descriptions-item> <el-descriptions-item label="玻璃编号">{{wproductnumber}}</el-descriptions-item>
<el-descriptions-item label="玻璃所在子工序">{{process}}</el-descriptions-item> <el-descriptions-item label="玻璃所在子工序">{{process}}</el-descriptions-item>
</el-descriptions>
</el-descriptions> </el-descriptions>

View File

@ -50,8 +50,8 @@
</el-table-column> </el-table-column>
<el-table-column label="产品数量"> <el-table-column label="产品数量">
<template slot-scope="scope" v-if="scope.row.wproduct_"> <template slot-scope="scope" >
{{ scope.row.wproduct_.length }} {{ scope.row.count_work }}
</template> </template>
</el-table-column> </el-table-column>
@ -136,7 +136,7 @@ export default {
handleoperation(scope) handleoperation(scope)
{ {
this.$router.push({name: "operationdo", params: { id: scope.row.id,submited:scope.row.is_submited }, }) this.$router.push({name: "operationdo", params: { id: scope.row.id}, })
}, },
//大工序工序渲染 //大工序工序渲染
getProcessList() { getProcessList() {

View File

@ -132,6 +132,23 @@
</el-table-column> </el-table-column>
<el-table-column prop="equip_.name" label="设备名称"> <el-table-column prop="equip_.name" label="设备名称">
</el-table-column> </el-table-column>
<el-table-column label="设备状态">
<template slot-scope="scope">
<el-tag v-if="scope.row.state===0" type="success">
{{ state_[scope.row.equip_.state] }}
</el-tag>
<el-tag v-else-if="scope.row.state===1" type="warning">
{{ state_[scope.row.equip_.state] }}
</el-tag>
<el-tag v-else-if="scope.row.state===2" >
{{ state_[scope.row.equip_.state] }}
</el-tag>
<el-tag v-else type="danger">
{{ state_[scope.row.equip_.state] }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="100px"> <el-table-column align="center" label="操作" width="100px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
@ -463,9 +480,9 @@
</el-table-column> </el-table-column>
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="生产计划编号"> <el-table-column label="计划编号">
<template slot-scope="scope">{{ <template slot-scope="scope">{{
scope.row.subproduction_plan scope.row.subproduction_plan_.number
}}</template> }}</template>
</el-table-column> </el-table-column>
<el-table-column label="物料名称"> <el-table-column label="物料名称">
@ -604,6 +621,12 @@ export default {
listQuery: { listQuery: {
page: 1, page: 1,
page_size: 20, page_size: 20,
},
state_:{
0:'完好',
1:'限用',
2:'在修',
3:'禁用',
}, },
scrap: [ scrap: [
{ lable: "使用", value: true }, { lable: "使用", value: true },

View File

@ -1,5 +1,6 @@
.vscode/ .vscode/
.vs/ .vs/
.idea/
venv/ venv/
__pycache__/ __pycache__/
*.pyc *.pyc

View File

@ -2,11 +2,13 @@ from django.db.models import base
from rest_framework import urlpatterns 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.develop.views import CleanDataView, UpdateCuttingView, UpdateLastTestResult from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateFIFOItem, UpdateLastTestResult
urlpatterns = [ urlpatterns = [
path('cleandata/', CleanDataView.as_view()), path('cleandata/', CleanDataView.as_view()),
path('update_cutting/', UpdateCuttingView.as_view()), path('update_cutting/', UpdateCuttingView.as_view()),
path('update_last_result/', UpdateLastTestResult.as_view()) path('update_last_result/', UpdateLastTestResult.as_view()),
path('update_last_result/', UpdateLastTestResult.as_view()),
path('update_fifoitem/', UpdateFIFOItem.as_view())
] ]

View File

@ -4,7 +4,7 @@ from rest_framework.decorators import permission_classes
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response from rest_framework.response import Response
from apps.inm.models import FIFO, Inventory, MaterialBatch from apps.inm.models import FIFO, FIFOItem, Inventory, MaterialBatch
from apps.mtm.models import Material from apps.mtm.models import Material
from apps.pm.models import ProductionPlan from apps.pm.models import ProductionPlan
from apps.sam.models import Order from apps.sam.models import Order
@ -62,3 +62,21 @@ class UpdateLastTestResult(APIView):
i.last_test_result = tr.is_testok i.last_test_result = tr.is_testok
i.save() i.save()
return Response() return Response()
class UpdateFIFOItem(APIView):
permission_classes = [IsAdminUser]
@transaction.atomic
def post(self, request, format=None):
"""
更新出入库结果
"""
for i in FIFOItem.objects.all():
if i.fifo.type == FIFO.FIFO_TYPE_PUR_IN:
if i.is_testok:
i.need_test = True
i.save()
else:
i.is_testok = None
i.save()
return Response()

View File

@ -27,7 +27,7 @@ class EquipmentSerializer(ModelSerializer):
class EquipmentSimpleSerializer(ModelSerializer): class EquipmentSimpleSerializer(ModelSerializer):
class Meta: class Meta:
model = Equipment model = Equipment
fields = ['id', 'number', 'name'] fields = ['id', 'number', 'name', 'state']

View File

@ -3,7 +3,7 @@ from django.contrib.auth.models import AbstractUser
from django.db.models.base import Model from django.db.models.base import Model
import django.utils.timezone as timezone import django.utils.timezone as timezone
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File,Position from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File,Position
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
@ -36,3 +36,8 @@ class Employee(CommonAModel):
def __str__(self): def __str__(self):
return self.name return self.name
class Attendance(CommonADModel):
"""
出勤记录
"""

View File

@ -3,22 +3,25 @@ from django_filters import rest_framework as filters
from apps.mtm.models import Material from apps.mtm.models import Material
from .models import IProduct, MaterialBatch from .models import IProduct, MaterialBatch
from django.utils import timezone from django.utils import timezone
class MbFilterSet(filters.FilterSet): class MbFilterSet(filters.FilterSet):
material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all()) material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all())
tag = filters.CharFilter(method="filter_tag") tag = filters.CharFilter(method="filter_tag")
class Meta: class Meta:
model = MaterialBatch model = MaterialBatch
fields = ['material', 'warehouse'] fields = ['material', 'warehouse']
def filter_tag(self, queryset, name, value): def filter_tag(self, queryset, name, value):
if value == 'expired': if value == 'expired':
queryset = queryset.exclude(expiration_date=None).filter(expiration_date__lte = timezone.now()) queryset = queryset.exclude(expiration_date=None).filter(expiration_date__lte=timezone.now())
return queryset return queryset
class IProductFilterSet(filters.FilterSet): class IProductFilterSet(filters.FilterSet):
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order") order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
class Meta: class Meta:
model = IProduct model = IProduct
fields = ['material', 'warehouse', 'batch', 'order', 'material__type'] fields = ['material', 'warehouse', 'batch', 'order', 'material__type']

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-01-14 07:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inm', '0025_auto_20220113_0932'),
]
operations = [
migrations.AlterField(
model_name='fifo',
name='inout_date',
field=models.DateField(blank=True, null=True, verbose_name='出入库日期'),
),
]

View File

@ -0,0 +1,33 @@
# Generated by Django 3.2.9 on 2022-01-14 07:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0003_auto_20210812_0909'),
('inm', '0026_alter_fifo_inout_date'),
]
operations = [
migrations.RemoveField(
model_name='fifoitem',
name='is_tested',
),
migrations.AddField(
model_name='fifoitem',
name='files',
field=models.ManyToManyField(to='system.File', verbose_name='上传材料'),
),
migrations.AddField(
model_name='fifoitem',
name='need_test',
field=models.BooleanField(default=False, verbose_name='是否需要复验'),
),
migrations.AlterField(
model_name='fifoitem',
name='is_testok',
field=models.BooleanField(blank=True, null=True, verbose_name='是否复验合格'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.9 on 2022-01-14 08:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0003_auto_20210812_0909'),
('inm', '0027_auto_20220114_1551'),
]
operations = [
migrations.AlterField(
model_name='fifoitem',
name='files',
field=models.ManyToManyField(blank=True, to='system.File', verbose_name='上传材料'),
),
]

View File

@ -17,6 +17,7 @@ class WareHouse(CommonAModel):
number = models.CharField('仓库编号', max_length=20, unique=True) number = models.CharField('仓库编号', max_length=20, unique=True)
name = models.CharField('仓库名称', max_length=20, unique=True) name = models.CharField('仓库名称', max_length=20, unique=True)
place = models.CharField('具体地点', max_length=50) place = models.CharField('具体地点', max_length=50)
class Meta: class Meta:
verbose_name = '仓库信息' verbose_name = '仓库信息'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name
@ -24,32 +25,39 @@ class WareHouse(CommonAModel):
def __str__(self): def __str__(self):
return self.name return self.name
class Inventory(BaseModel): class Inventory(BaseModel):
""" """
库存物料 库存物料
""" """
material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息') material = models.ForeignKey(
Material, on_delete=models.CASCADE, verbose_name='物料信息')
count = models.PositiveIntegerField('仓库物料存量', default=0) count = models.PositiveIntegerField('仓库物料存量', default=0)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库') warehouse = models.ForeignKey(
WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
class Meta: class Meta:
verbose_name = '库存表' verbose_name = '库存表'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name
class MaterialBatch(BaseModel): class MaterialBatch(BaseModel):
""" """
物料批次 物料批次
""" """
material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息') material = models.ForeignKey(
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库') Material, on_delete=models.CASCADE, verbose_name='物料信息')
warehouse = models.ForeignKey(
WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
count = models.PositiveIntegerField('存量', default=0) count = models.PositiveIntegerField('存量', default=0)
batch = models.CharField('批次号', max_length=100, default='') batch = models.CharField('批次号', max_length=100, default='')
expiration_date = models.DateField('有效期', null=True, blank=True) expiration_date = models.DateField('有效期', null=True, blank=True)
class Meta: class Meta:
verbose_name = '库存表' verbose_name = '库存表'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name
class FIFO(CommonADModel): class FIFO(CommonADModel):
""" """
出入库记录 出入库记录
@ -66,8 +74,9 @@ class FIFO(CommonADModel):
) )
type = models.IntegerField('出入库类型', default=1) type = models.IntegerField('出入库类型', default=1)
is_audited = models.BooleanField('是否审核', default=False) is_audited = models.BooleanField('是否审核', default=False)
auditor = models.ForeignKey(User, verbose_name='审核人', on_delete=models.CASCADE, null=True, blank=True) auditor = models.ForeignKey(
inout_date = models.DateField('出入库日期') User, verbose_name='审核人', on_delete=models.CASCADE, null=True, blank=True)
inout_date = models.DateField('出入库日期', null=True, blank=True)
remark = models.CharField('备注', max_length=1000, default='') remark = models.CharField('备注', max_length=1000, default='')
@ -75,38 +84,46 @@ class FIFOItem(BaseModel):
""" """
出入库详细条目 出入库详细条目
""" """
is_tested = models.BooleanField('是否已检验', default=False) need_test = models.BooleanField('是否需要复验', default=False)
is_testok = models.BooleanField('是否检验合格', default=False) is_testok = models.BooleanField('是否复验合格', null=True, blank=True)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库') warehouse = models.ForeignKey(
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE) WareHouse, on_delete=models.CASCADE, verbose_name='仓库')
material = models.ForeignKey(
Material, verbose_name='物料类型', on_delete=models.CASCADE)
count = models.PositiveIntegerField('数量', default=0) count = models.PositiveIntegerField('数量', default=0)
batch = models.CharField('批次号', max_length=100, default='') batch = models.CharField('批次号', max_length=100, default='')
fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE) fifo = models.ForeignKey(FIFO, verbose_name='关联出入库',
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(
SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True)
files = models.ManyToManyField(File, verbose_name='上传材料', blank=True)
class IProduct(BaseModel): class IProduct(BaseModel):
""" """
具体产品条目 具体产品条目
""" """
number = models.CharField('物品编号', unique=True, max_length=50) number = models.CharField('物品编号', unique=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE) material = models.ForeignKey(
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库') Material, verbose_name='物料类型', on_delete=models.CASCADE)
warehouse = models.ForeignKey(
WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, default='') batch = models.CharField('所属批次号', max_length=100, default='')
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False,
null=True, blank=True, related_name='iproduct_wproduct') null=True, blank=True, related_name='iproduct_wproduct')
is_saled = models.BooleanField('是否售出', default=False) is_saled = models.BooleanField('是否售出', default=False)
class FIFOItemProduct(BaseModel): class FIFOItemProduct(BaseModel):
""" """
出入库产品 出入库产品
""" """
fifoitem = models.ForeignKey(FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE) fifoitem = models.ForeignKey(
FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True, wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True,
related_name='fifoitem_wproduct') related_name='fifoitem_wproduct')
number = models.CharField('物品编号', max_length=50) number = models.CharField('物品编号', max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE) material = models.ForeignKey(
iproduct = models.ForeignKey(IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL) Material, verbose_name='物料类型', on_delete=models.CASCADE)
iproduct = models.ForeignKey(
IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL)

View File

@ -1,48 +1,59 @@
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.qm.models import TestRecord, TestRecordItem from apps.qm.models import TestRecord, TestRecordItem
from apps.system.serializers import UserSimpleSerializer from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer
from apps.mtm.serializers import MaterialSimpleSerializer from apps.mtm.serializers import MaterialSimpleSerializer
from django.db import transaction from django.db import transaction
class WareHouseSerializer(serializers. ModelSerializer):
create_by_=UserSimpleSerializer('create_by', read_only=True) class WareHouseSerializer(serializers.ModelSerializer):
create_by_ = UserSimpleSerializer('create_by', read_only=True)
class Meta: class Meta:
model = WareHouse model = WareHouse
fields = '__all__' fields = '__all__'
class WareHouseCreateUpdateSerializer(serializers.ModelSerializer): class WareHouseCreateUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = WareHouse model = WareHouse
fields = ['name', 'number', 'place'] fields = ['name', 'number', 'place']
class WareHouseSimpleSerializer(serializers.ModelSerializer): class WareHouseSimpleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = WareHouse model = WareHouse
fields = ['name', 'number', 'place'] fields = ['name', 'number', 'place']
class InventorySerializer(serializers. ModelSerializer):
material_= MaterialSimpleSerializer(source='material', read_only=True) class InventorySerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True) warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
class Meta: class Meta:
model = Inventory model = Inventory
fields = '__all__' fields = '__all__'
class MaterialBatchSerializer(serializers. ModelSerializer):
material_= MaterialSimpleSerializer(source='material', read_only=True) class MaterialBatchSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True) warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
class Meta: class Meta:
model = MaterialBatch model = MaterialBatch
fields = '__all__' fields = '__all__'
class IProductListSerializer(serializers.ModelSerializer): class IProductListSerializer(serializers.ModelSerializer):
material_= MaterialSimpleSerializer(source='material', read_only=True) material_ = MaterialSimpleSerializer(source='material', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True) warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
is_mtested = serializers.BooleanField(source='wproduct.is_mtested', read_only=True) is_mtested = serializers.BooleanField(source='wproduct.is_mtested', read_only=True)
is_mtestok = serializers.BooleanField(source='wproduct.is_mtestok', read_only=True) is_mtestok = serializers.BooleanField(source='wproduct.is_mtestok', read_only=True)
remark_mtest = serializers.CharField(source='wproduct.remark_mtest', read_only=True) remark_mtest = serializers.CharField(source='wproduct.remark_mtest', read_only=True)
class Meta: class Meta:
model = IProduct model = IProduct
fields = '__all__' fields = '__all__'
@ -51,28 +62,35 @@ class IProductListSerializer(serializers.ModelSerializer):
class FIFOListSerializer(serializers.ModelSerializer): class FIFOListSerializer(serializers.ModelSerializer):
auditor_ = UserSimpleSerializer(source='auditor', read_only=True) auditor_ = UserSimpleSerializer(source='auditor', read_only=True)
create_by_ = UserSimpleSerializer(source='create_by', read_only=True) create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
class Meta: class Meta:
model=FIFO model = FIFO
fields = '__all__' fields = '__all__'
class FIFOItemSerializer(serializers.ModelSerializer): class FIFOItemSerializer(serializers.ModelSerializer):
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True) warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
material_= MaterialSimpleSerializer(source='material', read_only=True) material_ = MaterialSimpleSerializer(source='material', read_only=True)
files_ = FileSimpleSerializer(source='files', many=True, read_only=True)
class Meta: class Meta:
model= FIFOItem model = FIFOItem
fields = '__all__' fields = '__all__'
class IProductInPurSerializer(serializers.ModelSerializer): class IProductInPurSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = IProduct model = IProduct
fields = ['number'] fields = ['number']
class FIFODetailInPurSerializer(serializers.ModelSerializer): class FIFODetailInPurSerializer(serializers.ModelSerializer):
details = IProductInPurSerializer(many=True, required=False) details = IProductInPurSerializer(many=True, required=False)
class Meta: class Meta:
model = FIFOItem model = FIFOItem
fields = ['material', 'count', 'batch', 'details', 'warehouse'] fields = ['material', 'count', 'batch', 'details', 'warehouse']
class MaterialBatchQuerySerializer(serializers.Serializer): class MaterialBatchQuerySerializer(serializers.Serializer):
warehouse = serializers.IntegerField(label="仓库ID", required=False) warehouse = serializers.IntegerField(label="仓库ID", required=False)
materials = serializers.ListField(child=serializers.IntegerField(label="物料ID"), required=False) materials = serializers.ListField(child=serializers.IntegerField(label="物料ID"), required=False)
@ -83,13 +101,14 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
采购入库序列化 采购入库序列化
""" """
details = FIFODetailInPurSerializer(many=True) details = FIFODetailInPurSerializer(many=True)
class Meta: class Meta:
model = FIFO model = FIFO
fields = ['details', 'inout_date'] fields = ['details']
def create(self, validated_data): def create(self, validated_data):
details = validated_data.pop('details') details = validated_data.pop('details')
if len(details)>0: if len(details) > 0:
pass pass
else: else:
raise serializers.ValidationError('没有入库内容') raise serializers.ValidationError('没有入库内容')
@ -137,17 +156,33 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
return obj return obj
class InmTestRecordItemCreateSerializer(serializers.ModelSerializer): class InmTestRecordItemCreateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = TestRecordItem model = TestRecordItem
fields = ['form_field', 'field_value', 'is_testok'] fields = ['form_field', 'field_value', 'is_testok']
class InmTestRecordCreateSerializer(serializers.ModelSerializer): class InmTestRecordCreateSerializer(serializers.ModelSerializer):
record_data = InmTestRecordItemCreateSerializer(many=True) record_data = InmTestRecordItemCreateSerializer(many=True)
fifo_item = serializers.PrimaryKeyRelatedField(queryset=FIFOItem.objects.all(), required=True) fifo_item = serializers.PrimaryKeyRelatedField(queryset=FIFOItem.objects.all(), required=True)
is_testok = serializers.BooleanField() is_testok = serializers.BooleanField()
class Meta: class Meta:
model = TestRecord model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'fifo_item'] fields = ['form', 'record_data', 'is_testok', 'fifo_item']
class FIFOItemUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = FIFOItem
fields = ['need_test', 'files']
def validate(self, attrs):
ins = self.instance
fifo = ins.fifo
if fifo.is_audited:
raise exceptions.APIException('该记录已审核')
if ins.is_testok is not None:
attrs.pop('need_test')
return super().validate(attrs)

View File

@ -1,3 +1,10 @@
from django.urls import reverse
from django.test import TestCase from django.test import TestCase
from rest_framework.test import APITestCase
from rest_framework import status
# Create your tests here. # Create your tests here.
class WareHouseTests(APITestCase):
def test_list_warehouse(self):
url = reverse('warehouse-list')
resp = self.client.get(url)
self.assertEqual(resp.status_code, status.HTTP_200_OK)

View File

@ -1,25 +1,26 @@
from django.shortcuts import render
from rest_framework import serializers from rest_framework import serializers
from rest_framework import exceptions from rest_framework import exceptions
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.filters import IProductFilterSet, MbFilterSet from apps.inm.filters import IProductFilterSet, MbFilterSet
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse, Inventory
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOItemUpdateSerializer, FIFOListSerializer, IProductListSerializer, \
InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, \
WareHouseCreateUpdateSerializer, InventorySerializer
from apps.inm.signals import update_inm from apps.inm.signals import update_inm
from apps.mtm.models import Material
from apps.pm.services import PmService
from apps.qm.models import TestRecordItem from apps.qm.models import TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from django.db import transaction from django.db import transaction
from django.utils import timezone
from apps.wpm.services import WpmServies
# Create your views here. # Create your views here.
class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet): class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
""" """
仓库-增删改查 仓库-增删改查
@ -37,21 +38,25 @@ class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
return WareHouseCreateUpdateSerializer return WareHouseCreateUpdateSerializer
return WareHouseSerializer return WareHouseSerializer
class InventoryViewSet(ListModelMixin, GenericViewSet): class InventoryViewSet(ListModelMixin, GenericViewSet):
""" """
仓库物料表 仓库物料表
""" """
perms_map = {'*': '*'} perms_map = {'*': '*'}
queryset = Inventory.objects.select_related('material', 'warehouse').filter(count__gt=0).all() queryset = Inventory.objects.select_related(
'material', 'warehouse').filter(count__gt=0).all()
serializer_class = InventorySerializer serializer_class = InventorySerializer
filterset_fields = ['material', 'warehouse'] filterset_fields = ['material', 'warehouse']
search_fields = [] search_fields = []
ordering_fields = ['create_time'] ordering_fields = ['create_time']
ordering = ['-create_time'] ordering = ['-create_time']
class MaterialBatchViewSet(ListModelMixin, GenericViewSet): class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
perms_map = {'*': '*'} perms_map = {'*': '*'}
queryset = MaterialBatch.objects.select_related('material', 'warehouse').filter(count__gt=0).all() queryset = MaterialBatch.objects.select_related(
'material', 'warehouse').filter(count__gt=0).all()
serializer_class = MaterialBatchSerializer serializer_class = MaterialBatchSerializer
# filterset_fields = ['material', 'warehouse'] # filterset_fields = ['material', 'warehouse']
filterset_class = MbFilterSet filterset_class = MbFilterSet
@ -59,7 +64,7 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
ordering_fields = ['create_time'] ordering_fields = ['create_time']
ordering = ['-create_time'] ordering = ['-create_time']
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=MaterialBatchQuerySerializer) @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MaterialBatchQuerySerializer)
def query(self, request, pk=None): def query(self, request, pk=None):
""" """
复杂查询 复杂查询
@ -67,27 +72,35 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
data = request.data data = request.data
serializer = MaterialBatchQuerySerializer(data=data) serializer = MaterialBatchQuerySerializer(data=data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
queryset = self.queryset.filter(warehouse__id=data['warehouse'], material__id__in=data['materials']) queryset = self.queryset.filter(
warehouse__id=data['warehouse'], material__id__in=data['materials'])
return Response(MaterialBatchSerializer(instance=queryset, many=True).data) return Response(MaterialBatchSerializer(instance=queryset, many=True).data)
class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
""" """
出入库记录详情表 出入库记录详情表
""" """
perms_map = {'*': '*'} perms_map = {'*': '*'}
queryset = FIFOItem.objects.select_related('material', 'fifo').all() queryset = FIFOItem.objects.select_related('material', 'fifo').prefetch_related('files').all()
serializer_class = FIFOItemSerializer serializer_class = FIFOItemSerializer
filterset_fields = ['material', 'fifo', 'fifo__type', 'is_tested', 'is_testok'] filterset_fields = ['material', 'fifo',
'fifo__type', 'need_test', 'is_testok']
search_fields = [] search_fields = []
ordering_fields = ['create_time'] ordering_fields = ['create_time']
ordering = ['-create_time'] ordering = ['-create_time']
def get_serializer_class(self):
if self.action == 'update':
return FIFOItemUpdateSerializer
return super().get_serializer_class()
def perform_destroy(self, instance): def perform_destroy(self, instance):
if instance.fifo.is_audited: if instance.fifo.is_audited:
raise APIException('该出入库记录已通过审核, 无法删除') raise APIException('该出入库记录已通过审核, 无法删除')
return super().perform_destroy(instance) return super().perform_destroy(instance)
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=InmTestRecordCreateSerializer) @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=InmTestRecordCreateSerializer)
def test(self, request, pk=None): def test(self, request, pk=None):
""" """
检验 检验
@ -99,7 +112,7 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
if 'is_testok' not in vdata: if 'is_testok' not in vdata:
raise APIException('未填写检验结论') raise APIException('未填写检验结论')
with transaction.atomic(): with transaction.atomic():
obj = serializer.save(create_by = self.request.user) obj = serializer.save(create_by=self.request.user)
tris = [] tris = []
for m in record_data: # 保存记录详情 for m in record_data: # 保存记录详情
m['field_value'] = m['field_value'] m['field_value'] = m['field_value']
@ -111,10 +124,10 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
# 如果检验合格 # 如果检验合格
if obj.fifo_item: if obj.fifo_item:
obj.fifo_item.is_testok = True if obj.is_testok else False obj.fifo_item.is_testok = True if obj.is_testok else False
obj.fifo_item.is_tested = True
obj.fifo_item.save() obj.fifo_item.save()
return Response() return Response()
class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
""" """
出入库记录 出入库记录
@ -138,7 +151,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
raise exceptions.APIException('该记录已审核,不可删除') raise exceptions.APIException('该记录已审核,不可删除')
return super().destroy(request, *args, **kwargs) return super().destroy(request, *args, **kwargs)
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=FIFOInPurSerializer) @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=FIFOInPurSerializer)
def in_pur(self, request, pk=None): def in_pur(self, request, pk=None):
""" """
采购入库 采购入库
@ -148,13 +161,13 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
serializer.save(create_by=request.user) serializer.save(create_by=request.user)
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) @action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=serializers.Serializer)
def audit(self, request, pk=None): def audit(self, request, pk=None):
""" """
审核通过 审核通过
""" """
obj = self.get_object() obj = self.get_object()
for i in FIFOItem.objects.filter(fifo=obj): for i in FIFOItem.objects.filter(fifo=obj, need_test=True):
if not i.is_testok: if not i.is_testok:
raise APIException('未检验通过, 不可审核') raise APIException('未检验通过, 不可审核')
if obj.is_audited: if obj.is_audited:
@ -162,6 +175,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
with transaction.atomic(): with transaction.atomic():
obj.is_audited = True obj.is_audited = True
obj.auditor = request.user obj.auditor = request.user
obj.inout_date = timezone.now() # 也是审核日期
obj.save() obj.save()
update_inm(obj) # 更新库存 update_inm(obj) # 更新库存
return Response() return Response()
@ -172,7 +186,8 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
半成品库存表 半成品库存表
""" """
perms_map = {'*': '*'} perms_map = {'*': '*'}
queryset = IProduct.objects.select_related('material', 'warehouse', 'wproduct__subproduction_plan__production_plan__order') queryset = IProduct.objects.select_related(
'material', 'warehouse', 'wproduct__subproduction_plan__production_plan__order')
serializer_class = IProductListSerializer serializer_class = IProductListSerializer
filterset_class = IProductFilterSet filterset_class = IProductFilterSet
search_fields = [] search_fields = []

View File

@ -59,6 +59,7 @@ class TestRecordItemSerializer(serializers.ModelSerializer):
parent = serializers.PrimaryKeyRelatedField(source='form_field.parent', read_only=True) parent = serializers.PrimaryKeyRelatedField(source='form_field.parent', read_only=True)
help_text = serializers.CharField(source='form_field.help_text', read_only=True) help_text = serializers.CharField(source='form_field.help_text', read_only=True)
sort = serializers.IntegerField(source='form_field.sort', read_only=True) sort = serializers.IntegerField(source='form_field.sort', read_only=True)
draw_template = serializers.CharField(source='form_field.draw_template', read_only=True)
class Meta: class Meta:
model = TestRecordItem model = TestRecordItem
fields = '__all__' fields = '__all__'

View File

@ -150,8 +150,7 @@ class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, C
warehouse = WareHouse.objects.get(id=i['warehouse']) warehouse = WareHouse.objects.get(id=i['warehouse'])
material = Material.objects.get(id=i['material']) material = Material.objects.get(id=i['material'])
fifoitem = FIFOItem() fifoitem = FIFOItem()
fifoitem.is_tested = True fifoitem.need_test = False
fifoitem.is_testok = True
fifoitem.warehouse = warehouse fifoitem.warehouse = warehouse
fifoitem.material = material fifoitem.material = material
fifoitem.count = i['total'] fifoitem.count = i['total']

View File

@ -4,39 +4,50 @@ from apps.mtm.models import Material, Step
from apps.wpm.services import WpmServies from apps.wpm.services import WpmServies
from .models import Operation, OperationMaterial, OperationRecord, WMaterial, WProduct from .models import Operation, OperationMaterial, OperationRecord, WMaterial, WProduct
class WMaterialFilterSet(filters.FilterSet): class WMaterialFilterSet(filters.FilterSet):
operation = filters.NumberFilter(method='filter_operation') operation = filters.NumberFilter(method='filter_operation')
class Meta: class Meta:
model = WMaterial model = WMaterial
fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop', 'operation'] fields = ['material', 'subproduction_plan', 'subproduction_plan__process',
'subproduction_plan__workshop', 'operation']
def filter_operation(self, queryset, name, value): def filter_operation(self, queryset, name, value):
operation = Operation.objects.get(pk=value) operation = Operation.objects.get(pk=value)
wproducts = WProduct.objects.filter(ow_wproduct__operation=value) wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
step = operation.step step = operation.step
if wproducts.exists(): if wproducts.exists():
subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts) subplans = WpmServies.get_subplans_queryset_from_wproducts(
wproducts)
else: else:
subplans = WpmServies.get_subplans_queyset_from_step(step) subplans = WpmServies.get_subplans_queyset_from_step(step)
queryset = queryset.filter(subproduction_plan__in=subplans).exclude(material__type=Material.MA_TYPE_HALFGOOD) queryset = queryset.filter(subproduction_plan__in=subplans).exclude(
material__type=Material.MA_TYPE_HALFGOOD)
return queryset return queryset
class WProductFilterSet(filters.FilterSet): class WProductFilterSet(filters.FilterSet):
tag = filters.CharFilter(method='filter_tag') tag = filters.CharFilter(method='filter_tag')
production_plan = filters.NumberFilter(field_name='subproduction_plan__production_plan') production_plan = filters.NumberFilter(
field_name='subproduction_plan__production_plan')
class Meta: class Meta:
model = WProduct model = WProduct
fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state', 'material__type'] fields = ['step', 'subproduction_plan', 'material',
'step__process', 'act_state', 'material__type']
def filter_tag(self, queryset, name, value): def filter_tag(self, queryset, name, value):
if value == 'no_scrap': if value == 'no_scrap':
queryset = queryset.exclude(act_state=WProduct.WPR_ACT_STATE_SCRAP) queryset = queryset.exclude(act_state=WProduct.WPR_ACT_STATE_SCRAP)
return queryset return queryset
class CuttingFilterSet(filters.FilterSet): class CuttingFilterSet(filters.FilterSet):
production_plan = filters.NumberFilter(field_name='subproduction_plan__production_plan') production_plan = filters.NumberFilter(
field_name='subproduction_plan__production_plan')
class Meta: class Meta:
model = OperationMaterial model = OperationMaterial
fields = ['operation', 'subproduction_plan', 'material'] fields = ['operation', 'subproduction_plan', 'material']
@ -44,6 +55,7 @@ class CuttingFilterSet(filters.FilterSet):
class OperationRecordFilterSet(filters.FilterSet): class OperationRecordFilterSet(filters.FilterSet):
wproduct = filters.NumberFilter(method='filter_wproduct') wproduct = filters.NumberFilter(method='filter_wproduct')
class Meta: class Meta:
model = OperationRecord model = OperationRecord
fields = ['operation', 'form'] fields = ['operation', 'form']

View File

@ -13,15 +13,20 @@ from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial
from apps.em.models import Equipment from apps.em.models import Equipment
class WMaterial(BaseModel): class WMaterial(BaseModel):
""" """
车间生产物料 车间生产物料
""" """
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE) SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE)
material = models.ForeignKey(
Material, verbose_name='关联物料', on_delete=models.CASCADE)
batch = models.CharField('批次号', max_length=100, null=True, blank=True) batch = models.CharField('批次号', max_length=100, null=True, blank=True)
count = models.PositiveIntegerField('当前数量', default=0) count = models.PositiveIntegerField('当前数量', default=0)
class WProduct(CommonAModel): class WProduct(CommonAModel):
""" """
动态半成品/成品表 动态半成品/成品表
@ -37,7 +42,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
act_state_choices=( act_state_choices = (
(WPR_ACT_STATE_TORETEST, '待复检'), (WPR_ACT_STATE_TORETEST, '待复检'),
(WPR_ACT_STATE_DOWAIT, '操作准备中'), (WPR_ACT_STATE_DOWAIT, '操作准备中'),
(WPR_ACT_STATE_DOING, '操作进行中'), (WPR_ACT_STATE_DOING, '操作进行中'),
@ -80,20 +85,30 @@ class WProduct(CommonAModel):
(NG_BACK_FROM, '退回供方'), (NG_BACK_FROM, '退回供方'),
(NG_RECALL, '召回') (NG_RECALL, '召回')
) )
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50) number = models.CharField(
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE) '物品编号', unique=True, null=True, blank=True, max_length=50)
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_step') material = models.ForeignKey(
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='w_step') Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices) pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
on_delete=models.CASCADE, related_name='w_pre_step')
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
related_name='w_step')
act_state = models.IntegerField(
'进行状态', 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, on_delete=models.CASCADE, related_name='wproduct_child') child = models.ForeignKey('self', blank=True, null=True,
on_delete=models.CASCADE, related_name='wproduct_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, related_name='wproduct_subplan') subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
related_name='wproduct_subplan')
scrap_reason = models.IntegerField('报废原因', choices=scrap_reason_choices, null=True, blank=True) scrap_reason = models.IntegerField(
ng_sign = models.PositiveSmallIntegerField('不合格标记', choices=ng_choices, null=True, blank=True) '报废原因', choices=scrap_reason_choices, null=True, blank=True)
ng_sign = models.PositiveSmallIntegerField(
'不合格标记', choices=ng_choices, null=True, blank=True)
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) warehouse = models.ForeignKey(
WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作', operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation') on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
@ -123,34 +138,52 @@ class WprouctTicket(CommonAModel):
""" """
number = models.CharField('物品编号', null=True, blank=True, max_length=50) number = models.CharField('物品编号', null=True, blank=True, max_length=50)
wproduct = models.ForeignKey(WProduct, verbose_name='关联产品', on_delete=models.CASCADE) wproduct = models.ForeignKey(
material = models.ForeignKey(Material, verbose_name='所在物料状态', on_delete=models.CASCADE) WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
step = models.ForeignKey(Step, verbose_name='所在步骤/发现步骤', on_delete=models.CASCADE) material = models.ForeignKey(
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE) Material, verbose_name='所在物料状态', on_delete=models.CASCADE)
step = models.ForeignKey(
Step, verbose_name='所在步骤/发现步骤', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(
SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE)
resp_process = models.ForeignKey(
Process, verbose_name='责任工序', on_delete=models.CASCADE, null=True, blank=True)
ticket = models.ForeignKey(
'wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='wt_ticket')
decision = models.PositiveSmallIntegerField(
'最终决定', choices=WProduct.ng_choices, null=True, blank=True)
resp_process = models.ForeignKey(Process, verbose_name='责任工序', on_delete=models.CASCADE, null=True, blank=True)
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='wt_ticket')
decision = models.PositiveSmallIntegerField('最终决定', choices=WProduct.ng_choices, null=True, blank=True)
class WproductFlow(CommonAModel): class WproductFlow(CommonAModel):
""" """
动态产品表日志 动态产品表日志
""" """
wproduct = models.ForeignKey(WProduct, on_delete=models.CASCADE, verbose_name='关联产品', null=True, blank=True) wproduct = models.ForeignKey(
WProduct, on_delete=models.CASCADE, verbose_name='关联产品', null=True, blank=True)
number = models.CharField('物品编号', null=True, blank=True, max_length=50) number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE) material = models.ForeignKey(
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='wl_pre_step') Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='wl_step') pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
act_state = models.IntegerField('进行状态', default=0, choices=WProduct.act_state_choices) on_delete=models.CASCADE, related_name='wl_pre_step')
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
related_name='wl_step')
act_state = models.IntegerField(
'进行状态', 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, on_delete=models.CASCADE, related_name='wproduct_child') child = models.ForeignKey('self', blank=True, null=True,
on_delete=models.CASCADE, related_name='wproduct_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)
scrap_reason = models.IntegerField('报废原因', choices= WProduct.scrap_reason_choices, null=True, blank=True) scrap_reason = models.IntegerField(
ng_sign = models.PositiveSmallIntegerField('不合格标记', choices= WProduct.ng_choices, null=True, blank=True) '报废原因', choices=WProduct.scrap_reason_choices, null=True, blank=True)
ng_sign = models.PositiveSmallIntegerField(
'不合格标记', choices=WProduct.ng_choices, null=True, blank=True)
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) warehouse = models.ForeignKey(
WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作', operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_operation') on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_operation')
coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作', coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作',
@ -179,63 +212,86 @@ class Pick(CommonADModel):
(PICK_FROM_WAREHOUSE, '仓库领取'), (PICK_FROM_WAREHOUSE, '仓库领取'),
(PICK_FROM_WPRODUCT, '半成品领取'), (PICK_FROM_WPRODUCT, '半成品领取'),
) )
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(
type = models.PositiveSmallIntegerField(choices=type_choice, default=PICK_FROM_WAREHOUSE) SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE)
fifo = models.ForeignKey(FIFO, verbose_name='关联的出入库记录', on_delete=models.CASCADE, null=True, blank=True) type = models.PositiveSmallIntegerField(
choices=type_choice, default=PICK_FROM_WAREHOUSE)
fifo = models.ForeignKey(
FIFO, verbose_name='关联的出入库记录', on_delete=models.CASCADE, null=True, blank=True)
class PickWproduct(BaseModel): class PickWproduct(BaseModel):
""" """
领取半成品时详情 领取半成品时详情
""" """
pick = models.ForeignKey(Pick, verbose_name='关联领料', on_delete=models.CASCADE) pick = models.ForeignKey(Pick, verbose_name='关联领料',
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='pw_wproduct') on_delete=models.CASCADE)
wproduct = models.ForeignKey(
WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='pw_wproduct')
number = models.CharField('物品编号', null=True, blank=True, max_length=50) number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='领取时的物料状态', on_delete=models.CASCADE) material = models.ForeignKey(
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='领取时所属子生产计划', on_delete=models.CASCADE) Material, verbose_name='领取时的物料状态', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(
SubProductionPlan, verbose_name='领取时所属子生产计划', on_delete=models.CASCADE)
class Operation(CommonADModel): class Operation(CommonADModel):
""" """
生产操作 生产操作
""" """
step = models.ForeignKey(Step, verbose_name='操作步骤', on_delete=models.CASCADE, null=True, blank=True) step = models.ForeignKey(Step, verbose_name='操作步骤',
on_delete=models.CASCADE, null=True, blank=True)
remark = models.CharField('操作备注', max_length=200, null=True, blank=True) remark = models.CharField('操作备注', max_length=200, null=True, blank=True)
is_submited = models.BooleanField('是否提交', default=False) is_submited = models.BooleanField('是否提交', default=False)
class OperationWproduct(BaseModel): class OperationWproduct(BaseModel):
""" """
生产操作半成品关联表 生产操作半成品关联表
""" """
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='ow_operation') operation = models.ForeignKey(
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct') Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='ow_operation')
wproduct = models.ForeignKey(
WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct')
number = models.CharField('物品编号', null=True, blank=True, max_length=50) number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE) material = models.ForeignKey(
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='ow_subplan') Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
ng_sign = models.PositiveSmallIntegerField('当时的不合格标记', choices= WProduct.ng_choices, null=True, blank=True) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
related_name='ow_subplan')
ng_sign = models.PositiveSmallIntegerField(
'当时的不合格标记', choices=WProduct.ng_choices, null=True, blank=True)
place = models.CharField('摆放位置', null=True, blank=True, max_length=200) place = models.CharField('摆放位置', null=True, blank=True, max_length=200)
class Meta: class Meta:
unique_together = ( unique_together = (
('operation','wproduct') ('operation', 'wproduct')
) )
class OperationMaterial(BaseModel): class OperationMaterial(BaseModel):
""" """
生产操作物料消耗产出表 生产操作物料消耗产出表
""" """
type = models.IntegerField('类型', default=0, choices=SubprodctionMaterial.type_choices) type = models.IntegerField(
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='om_operation') '类型', default=0, choices=SubprodctionMaterial.type_choices)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE,
related_name='om_operation')
material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE,
null=True, blank=True, related_name='om_material') null=True, blank=True, related_name='om_material')
count = models.PositiveSmallIntegerField('消耗或产出数量', null=True, blank=True) count = models.PositiveSmallIntegerField('消耗或产出数量', null=True, blank=True)
wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True) wmaterial = models.ForeignKey(
subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE, null=True, blank=True) WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE,
null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE, null=True, blank=True) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE,
null=True, blank=True)
batch = models.CharField('批次号', max_length=100, null=True, blank=True) batch = models.CharField('批次号', max_length=100, null=True, blank=True)
use_scrap = models.BooleanField('是否使用的边角料', default=False) use_scrap = models.BooleanField('是否使用的边角料', default=False)
#以下为冷加工下料清单所用字段 # 以下为冷加工下料清单所用字段
from_material = models.ForeignKey(Material, verbose_name='源物料', on_delete=models.CASCADE, from_material = models.ForeignKey(Material, verbose_name='源物料', on_delete=models.CASCADE,
null=True, blank=True, related_name='om_fmaterial') null=True, blank=True, related_name='om_fmaterial')
from_batch = models.CharField('源批次', max_length=100, null=True, blank=True) from_batch = models.CharField('源批次', max_length=100, null=True, blank=True)
@ -249,26 +305,35 @@ class OperationMaterial(BaseModel):
class Meta: class Meta:
unique_together = ( unique_together = (
('operation','material', 'batch') ('operation', 'material', 'batch')
) )
class OperationRecord(BaseModel): class OperationRecord(BaseModel):
""" """
记录表格 记录表格
""" """
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE, related_name='or_form') form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格',
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='or_operation') on_delete=models.CASCADE, related_name='or_form')
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE,
related_name='or_operation')
is_filled = models.BooleanField('是否填写', default=True) is_filled = models.BooleanField('是否填写', default=True)
class OperationRecordItem(BaseModel): class OperationRecordItem(BaseModel):
""" """
记录表格字段值 记录表格字段值
""" """
form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE, related_name='ori_form_field') form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE,
related_name='ori_form_field')
field_value = models.JSONField('录入值', null=True, blank=True) field_value = models.JSONField('录入值', null=True, blank=True)
operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE, related_name='item_operation_record') operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE,
related_name='item_operation_record')
class OperationEquip(BaseModel): class OperationEquip(BaseModel):
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation') operation = models.ForeignKey(
equip = models.ForeignKey(Equipment, verbose_name='生产设备', on_delete=models.CASCADE, related_name='oe_equip') Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation')
equip = models.ForeignKey(Equipment, verbose_name='生产设备',
on_delete=models.CASCADE, related_name='oe_equip')
remark = models.TextField('备注', null=True, blank=True) remark = models.TextField('备注', null=True, blank=True)

View File

@ -69,7 +69,6 @@ class PickSerializer(serializers.Serializer):
if isLowLevel: if isLowLevel:
iproducts = i.pop('iproducts') iproducts = i.pop('iproducts')
i['fifo'] = fifo i['fifo'] = fifo
i['is_testok'] = True # 默认检验合格
i['subproduction_plan'] = sp i['subproduction_plan'] = sp
fifoitem = FIFOItem.objects.create(**i) fifoitem = FIFOItem.objects.create(**i)
# 创建再下一个层级 # 创建再下一个层级
@ -418,12 +417,12 @@ class WplanPutInSerializer(serializers.Serializer):
class WproductPutInSerializer(serializers.Serializer): class WproductPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False) remark = serializers.CharField(label="入库备注", required=False, allow_blank=True)
class WproductPutInsSerializer(serializers.Serializer): class WproductPutInsSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID', many=True) wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID', many=True)
remark = serializers.CharField(label="入库备注", required =False, allow_null=True) remark = serializers.CharField(label="入库备注", required=False, allow_blank=True)
class OperationEquipListSerializer(serializers.Serializer): class OperationEquipListSerializer(serializers.Serializer):

View File

@ -1,66 +1,77 @@
from django.db.models.expressions import F
from django.shortcuts import render
from rest_framework.generics import CreateAPIView, GenericAPIView from rest_framework.generics import CreateAPIView, GenericAPIView
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, \
from rest_framework.utils import serializer_helpers ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.viewsets import GenericViewSet
from rest_framework.views import APIView from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
from apps.inm.signals import update_inm from apps.inm.signals import update_inm
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc
from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.models import SubProductionPlan, SubProductionProgress
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionProgressSerializer
from apps.qm.models import TestRecord, TestRecordItem from apps.qm.models import TestRecord, TestRecordItem
from apps.qm.serializers import TestRecordDetailSerializer from apps.qm.serializers import TestRecordDetailSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from apps.wf.models import Workflow from apps.wf.models import Workflow
from apps.wf.serializers import WorkflowSimpleSerializer
from apps.wpm.filters import CuttingFilterSet, OperationRecordFilterSet, WMaterialFilterSet, WProductFilterSet from apps.wpm.filters import CuttingFilterSet, OperationRecordFilterSet, WMaterialFilterSet, WProductFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem, WprouctTicket from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, \
OperationMaterial, OperationRecord, OperationRecordItem, WprouctTicket
from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerializer, OperationEquipUpdateSerializer, \
OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, \
OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, \
OperationRecordDetailSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, \
OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, \
OperationListSerializer, OperationWproductUpdateSerializer, PickHalfsSerializer, \
PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, \
WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, \
WpmTestFormInitSerializer, WproductMtestSerializer, WproductPutInSerializer, \
WproductPutInsSerializer, WproductTicketListSerializer
from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordDetailSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, OperationWproductUpdateSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestFormInitSerializer, WpmTestRecordCreateSerializer, WproductMtestSerializer, WproductPutInSerializer, WproductPutInsSerializer, WproductTicketListSerializer
from rest_framework.response import Response from rest_framework.response import Response
from django.db import transaction from django.db import transaction
from rest_framework import exceptions, serializers from rest_framework import exceptions, serializers
from apps.wpm.services import WpmServies from apps.wpm.services import WpmServies
from django.utils import timezone from django.utils import timezone
from utils.tools import ranstr
from rest_framework import status from rest_framework import status
from django.db.models import Count from django.db.models import Count
# Create your views here. # Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet): class WPlanViewSet(ListModelMixin, GenericViewSet):
""" """
车间生产计划 车间生产计划
""" """
perms_map = {'*': '*'} perms_map = {'*': '*'}
queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'product').exclude(state=0) queryset = SubProductionPlan.objects.select_related(
'process', 'workshop', 'subproduction', 'product').exclude(state=0)
search_fields = [] search_fields = []
serializer_class = SubProductionPlanListSerializer serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state', 'product', 'workshop'] filterset_fields = ['production_plan',
'process', 'state', 'product', 'workshop']
ordering_fields = [] ordering_fields = []
ordering = ['-update_time'] ordering = ['-update_time']
@action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfsSerializer) @action(methods=['post', 'get'], detail=True, perms_map={'post': '*', 'get': '*'}, serializer_class=PickHalfsSerializer)
@transaction.atomic @transaction.atomic
def pick_half(self, request, pk=None): def pick_half(self, request, pk=None):
""" """
领半成品 领半成品
""" """
sp = self.get_object() sp = self.get_object()
if request.method=='GET': if request.method == 'GET':
""" """
领半成品 领半成品
""" """
spps = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN, spps = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN,
material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material') material__type=Material.MA_TYPE_HALFGOOD,
subproduction_plan=sp).select_related('material')
return Response(SubProductionProgressSerializer(instance=spps, many=True).data) return Response(SubProductionProgressSerializer(instance=spps, many=True).data)
elif request.method=='POST': elif request.method == 'POST':
serializer= PickHalfsSerializer(data=request.data) serializer = PickHalfsSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data vdata = serializer.validated_data
first_step = Step.objects.get(pk=sp.steps[0]['id']) first_step = Step.objects.get(pk=sp.steps[0]['id'])
@ -71,13 +82,14 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
pick.create_by = request.user pick.create_by = request.user
pick.save() pick.save()
for i in vdata: for i in vdata:
if 'wproducts' in i and len(i['wproducts'])>0: if 'wproducts' in i and len(i['wproducts']) > 0:
spp = i['id'] spp = i['id']
spp.count_pick = spp.count_pick + len(i['wproducts']) spp.count_pick = spp.count_pick + len(i['wproducts'])
# if spp.count_pick > spp.count: # if spp.count_pick > spp.count:
# raise exceptions.APIException('超过计划数') # raise exceptions.APIException('超过计划数')
spp.save() spp.save()
wps = WProduct.objects.filter(pk__in=[x.id for x in i['wproducts']], act_state=WProduct.WPR_ACT_STATE_OK) wps = WProduct.objects.filter(
pk__in=[x.id for x in i['wproducts']], act_state=WProduct.WPR_ACT_STATE_OK)
wps.update(step=first_step, wps.update(step=first_step,
act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None, act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None,
subproduction_plan=sp, update_by=request.user, update_time=timezone.now()) subproduction_plan=sp, update_by=request.user, update_time=timezone.now())
@ -91,9 +103,10 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
m.update_by = request.user m.update_by = request.user
m.update_time = timezone.now() m.update_time = timezone.now()
m.save() m.save()
WpmServies.add_wproduct_flow_log(instance=m, change_str='pick_half') WpmServies.add_wproduct_flow_log(
instance=m, change_str='pick_half')
pw = PickWproduct() pw = PickWproduct()
pw.pick =pick pw.pick = pick
pw.wproduct = m pw.wproduct = m
pw.number = m.number pw.number = m.number
pw.material = m.material pw.material = m.material
@ -105,91 +118,35 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
return Response() return Response()
# @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WplanPutInSerializer)
# @transaction.atomic
# def putin(self, request, pk=None):
# """
# 半成品入库
# """
# serializer= WplanPutInSerializer(data=request.data)
# serializer.is_valid(raise_exception=True)
# vdata = serializer.validated_data
# subplan = self.get_object()
# material = subplan.product
# batch = subplan.number
# warehouse = vdata['warehouse']
# wproducts = WProduct.objects.filter(subproduction_plan=subplan,
# act_state=WProduct.WPR_ACT_STATE_OK, material=material, is_deleted=False)
# if wproducts.exists():
# # 创建入库记录
# remark = vdata.get('remark', '')
# fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
# is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark)
# # 创建入库明细
# fifoitem = FIFOItem()
# fifoitem.is_tested = True
# fifoitem.is_testok = True
# fifoitem.warehouse = warehouse
# fifoitem.material = material
# fifoitem.count = wproducts.count()
# fifoitem.batch = batch
# fifoitem.fifo = fifo
# fifoitem.subproduction_plan = subplan
# fifoitem.save()
# # 创建入库明细半成品
# ips = []
# for i in wproducts:
# ip = {}
# ip['fifoitem'] = fifoitem
# ip['wproduct'] = i
# ip['number'] = i.number
# ip['material'] = material
# ips.append(FIFOItemProduct(**ip))
# FIFOItemProduct.objects.bulk_create(ips)
# # 创建IProduct
# ips2 = []
# for i in wproducts:
# ip = {}
# ip['warehouse'] = warehouse
# ip['batch'] = batch
# ip['wproduct'] = i
# ip['number'] = i.number
# ip['material'] = material
# ips2.append(IProduct(**ip))
# IProduct.objects.bulk_create(ips2)
# # 更新库存并修改半成品进行状态
# update_inm(fifo)
# wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now())
# return Response()
class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet): class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
""" """
车间物料表 车间物料表
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = WMaterial.objects.select_related('material', 'subproduction_plan').filter(count__gt=0) queryset = WMaterial.objects.select_related(
'material', 'subproduction_plan').filter(count__gt=0)
serializer_class = WMaterialListSerializer serializer_class = WMaterialListSerializer
filterset_class = WMaterialFilterSet filterset_class = WMaterialFilterSet
ordering_fields = ['material__number'] ordering_fields = ['material__number']
ordering = ['material__number'] ordering = ['material__number']
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PickSerializer) @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=PickSerializer)
def pick(self, request, pk=None): def pick(self, request, pk=None):
""" """
领料 领料
""" """
serializer= PickSerializer(data=request.data, context={'request': request}) serializer = PickSerializer(
data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
serializer.save() serializer.save()
return Response() return Response()
class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
""" """
半成品 半成品
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = WProduct.objects.select_related('step', 'material', queryset = WProduct.objects.select_related('step', 'material',
'subproduction_plan', 'warehouse').prefetch_related('wproduct_child') 'subproduction_plan', 'warehouse').prefetch_related('wproduct_child')
serializer_class = WProductListSerializer serializer_class = WProductListSerializer
@ -209,7 +166,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
queryset = queryset.filter(is_hidden=False) queryset = queryset.filter(is_hidden=False)
return queryset return queryset
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestFormInitSerializer) @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WpmTestFormInitSerializer)
@transaction.atomic @transaction.atomic
def test_init(self, request, pk=None): def test_init(self, request, pk=None):
""" """
@ -225,11 +182,12 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
# 根据情况创建一条检验记录 # 根据情况创建一条检验记录
if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST, if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST,
WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST, WProduct.WPR_ACT_STATE_TOCOMBTEST]: WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST,
WProduct.WPR_ACT_STATE_TOCOMBTEST]:
raise exceptions.APIException('该产品当前状态不可检验') raise exceptions.APIException('该产品当前状态不可检验')
savedict = dict( savedict = dict(
create_by = self.request.user, create_by=self.request.user,
wproduct=wproduct, wproduct=wproduct,
material=wproduct.material, material=wproduct.material,
number=wproduct.number, number=wproduct.number,
@ -263,32 +221,33 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
tri.save() tri.save()
return Response(TestRecordDetailSerializer(instance=tr).data) return Response(TestRecordDetailSerializer(instance=tr).data)
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer) @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductPutInsSerializer)
@transaction.atomic @transaction.atomic
def putins(self, request, pk=None): def putins(self, request, pk=None):
""" """
半成品批量入库 半成品批量入库
""" """
serializer= WproductPutInsSerializer(data=request.data) serializer = WproductPutInsSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data vdata = serializer.validated_data
wproducts = WProduct.objects.filter(pk__in=[x.id for x in vdata['wproducts']]) wproducts = WProduct.objects.filter(
pk__in=[x.id for x in vdata['wproducts']])
warehouse = vdata['warehouse'] warehouse = vdata['warehouse']
for i in wproducts: for i in wproducts:
if i.act_state is not WProduct.WPR_ACT_STATE_OK: if i.act_state is not WProduct.WPR_ACT_STATE_OK:
raise exceptions.APIException('存在不可入库半成品') raise exceptions.APIException('存在不可入库半成品')
# 聚合一下 # 聚合一下
wproducts_a = wproducts.values('subproduction_plan', 'material', 'subproduction_plan__number').annotate(total=Count('id')) wproducts_a = wproducts.values(
'subproduction_plan', 'material', 'subproduction_plan__number').annotate(total=Count('id'))
# 创建入库记录 # 创建入库记录
remark = vdata.get('remark', '') remark = vdata.get('remark', '')
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) is_audited=True, auditor=request.user, inout_date=timezone.now(),
create_by=request.user, remark=remark)
# 创建入库明细 # 创建入库明细
for i in wproducts_a: for i in wproducts_a:
spi = SubProductionPlan.objects.get(pk=i['subproduction_plan']) spi = SubProductionPlan.objects.get(pk=i['subproduction_plan'])
fifoitem = FIFOItem() fifoitem = FIFOItem()
fifoitem.is_tested = True
fifoitem.is_testok = True
fifoitem.warehouse = warehouse fifoitem.warehouse = warehouse
fifoitem.material = Material.objects.get(pk=i['material']) fifoitem.material = Material.objects.get(pk=i['material'])
fifoitem.count = i['total'] fifoitem.count = i['total']
@ -297,7 +256,8 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
fifoitem.subproduction_plan = spi fifoitem.subproduction_plan = spi
fifoitem.save() fifoitem.save()
wproducts_items = wproducts.filter(subproduction_plan=i['subproduction_plan'], material=i['material']) wproducts_items = wproducts.filter(
subproduction_plan=i['subproduction_plan'], material=i['material'])
ips = [] ips = []
for i in wproducts_items: for i in wproducts_items:
# 创建入库明细半成品 # 创建入库明细半成品
@ -319,13 +279,13 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
WpmServies.add_wproduct_flow_log(i, 'putins') WpmServies.add_wproduct_flow_log(i, 'putins')
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer) @action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=WproductPutInSerializer)
@transaction.atomic @transaction.atomic
def putin(self, request, pk=None): def putin(self, request, pk=None):
""" """
半成品入库 半成品入库
""" """
serializer= WproductPutInSerializer(data=request.data) serializer = WproductPutInSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data vdata = serializer.validated_data
wproduct = self.get_object() wproduct = self.get_object()
@ -337,11 +297,10 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
# 创建入库记录 # 创建入库记录
remark = vdata.get('remark', '') remark = vdata.get('remark', '')
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) is_audited=True, auditor=request.user, inout_date=timezone.now(),
create_by=request.user, remark=remark)
# 创建入库明细 # 创建入库明细
fifoitem = FIFOItem() fifoitem = FIFOItem()
fifoitem.is_tested = True
fifoitem.is_testok = True
fifoitem.warehouse = warehouse fifoitem.warehouse = warehouse
fifoitem.material = material fifoitem.material = material
fifoitem.count = 1 # 单个半成品入库 fifoitem.count = 1 # 单个半成品入库
@ -361,13 +320,13 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
FIFOItemProduct.objects.bulk_create(ips) FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态 # 更新库存并修改半成品进行状态
update_inm(fifo) update_inm(fifo)
wproduct.act_state=WProduct.WPR_ACT_STATE_INM wproduct.act_state = WProduct.WPR_ACT_STATE_INM
wproduct.warehouse=warehouse wproduct.warehouse = warehouse
wproduct.save() wproduct.save()
WpmServies.add_wproduct_flow_log(wproduct, 'putin') WpmServies.add_wproduct_flow_log(wproduct, 'putin')
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=ScrapSerializer) @action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=ScrapSerializer)
def scrap(self, request, pk=None): def scrap(self, request, pk=None):
""" """
报废操作 报废操作
@ -391,7 +350,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
obj.update_time = timezone.now() obj.update_time = timezone.now()
obj.save() obj.save()
WpmServies.add_wproduct_flow_log(obj, 'scrap') WpmServies.add_wproduct_flow_log(obj, 'scrap')
if obj.step.process.id == 1: #如果是冷加工 if obj.step.process.id == 1: # 如果是冷加工
WpmServies.update_cutting_list_with_operation(obj.coperation) WpmServies.update_cutting_list_with_operation(obj.coperation)
return Response() return Response()
@ -403,34 +362,36 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
# wfs = Workflow.objects.filter(key__startswith= 'wp_') # wfs = Workflow.objects.filter(key__startswith= 'wp_')
# return WorkflowSimpleSerializer(instance=wfs, many=True).data # return WorkflowSimpleSerializer(instance=wfs, many=True).data
@action(methods=['get'], detail=True, perms_map={'get':'*'}) @action(methods=['get'], detail=True, perms_map={'get': '*'})
def wf_bhg(self, request, pk=None): def wf_bhg(self, request, pk=None):
""" """
发起不合格审理单 发起不合格审理单
""" """
obj = self.get_object() obj = self.get_object()
if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK or obj.ng_sign is not None\ if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK or obj.ng_sign is not None \
or obj.ticket is not None: or obj.ticket is not None:
raise exceptions.APIException('该产品不可发起不合格审理') raise exceptions.APIException('该产品不可发起不合格审理')
workflow = Workflow.objects.filter(name='不合格品审理单', is_deleted=False).first() workflow = Workflow.objects.filter(
name='不合格品审理单', is_deleted=False).first()
if workflow: if workflow:
test_record = TestRecord.objects.filter(wproduct=obj, is_deleted=False, is_testok=False).order_by('-id').first() test_record = TestRecord.objects.filter(
wproduct=obj, is_deleted=False, is_testok=False).order_by('-id').first()
exist_data = { exist_data = {
'wproduct':obj.id, 'wproduct': obj.id,
'wproduct_number':obj.number, 'wproduct_number': obj.number,
'wproduct_name':obj.material.name, 'wproduct_name': obj.material.name,
'wproduct_specification':obj.material.specification, 'wproduct_specification': obj.material.specification,
'finder':request.user.id, 'finder': request.user.id,
'find_process':obj.step.process.id, 'find_process': obj.step.process.id,
'tester':test_record.create_by.id 'tester': test_record.create_by.id
} }
ret = {'workflow':workflow.id} ret = {'workflow': workflow.id}
ret['exist_data'] = exist_data ret['exist_data'] = exist_data
return Response(ret) return Response(ret)
else: else:
raise exceptions.APIException('未找到对应审批流程') raise exceptions.APIException('未找到对应审批流程')
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductMtestSerializer) @action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=WproductMtestSerializer)
@transaction.atomic @transaction.atomic
def mtest(self, request, pk=None): def mtest(self, request, pk=None):
""" """
@ -446,7 +407,8 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
is_mtestok = request.data.get('is_mtestok') is_mtestok = request.data.get('is_mtestok')
obj.is_mtestok = is_mtestok obj.is_mtestok = is_mtestok
if is_mtestok: if is_mtestok:
WpmServies.update_plan_state_by_mtestok(obj.subproduction_plan.production_plan) WpmServies.update_plan_state_by_mtestok(
obj.subproduction_plan.production_plan)
obj.save() obj.save()
change_str = 'mtest_notok' change_str = 'mtest_notok'
if is_mtestok: if is_mtestok:
@ -454,7 +416,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
WpmServies.add_wproduct_flow_log(instance=obj, change_str=change_str) WpmServies.add_wproduct_flow_log(instance=obj, change_str=change_str)
return Response() return Response()
@action(methods=['get'], detail=True, perms_map={'get':'*'}) @action(methods=['get'], detail=True, perms_map={'get': '*'})
def card(self, request, pk=None): def card(self, request, pk=None):
""" """
流程卡 流程卡
@ -469,35 +431,40 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
ret.append(line1) ret.append(line1)
steps_list_full_1 = card_data['parents'][0]['step_list_full'] steps_list_full_1 = card_data['parents'][0]['step_list_full']
for index, item in enumerate(steps_list_full_1): for index, item in enumerate(steps_list_full_1):
linex = [str(index+1), item['step_name']] linex = [str(index + 1), item['step_name']]
for i in card_data['parents']: for i in card_data['parents']:
linex.append(i['step_list_full'][index]['actions']) linex.append(i['step_list_full'][index]['actions'])
ret.append(linex) ret.append(linex)
ret.append(['序号', '工序', card_data['number']]) ret.append(['序号', '工序', card_data['number']])
step_list_full = card_data['step_list_full'] step_list_full = card_data['step_list_full']
for index, item in enumerate(step_list_full): for index, item in enumerate(step_list_full):
ret.append([str(index+1), item['step_name'], item['actions']]) ret.append([str(index + 1), item['step_name'], item['actions']])
return Response(ret) return Response(ret)
class WproductTicketViewSet(ListModelMixin, GenericViewSet): class WproductTicketViewSet(ListModelMixin, GenericViewSet):
""" """
玻璃审批工单 玻璃审批工单
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = WprouctTicket.objects.select_related('step', 'material', 'subproduction_plan', queryset = WprouctTicket.objects.select_related('step', 'material', 'subproduction_plan',
'resp_process', 'subproduction_plan__production_plan__order', 'subproduction_plan__production_plan') 'resp_process', 'subproduction_plan__production_plan__order',
'subproduction_plan__production_plan')
serializer_class = WproductTicketListSerializer serializer_class = WproductTicketListSerializer
filterset_fields = ['step', 'material', 'subproduction_plan', 'resp_process'] filterset_fields = ['step', 'material',
'subproduction_plan', 'resp_process']
ordering_fields = ['id'] ordering_fields = ['id']
ordering = ['-id'] ordering = ['-id']
class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet): class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin,
GenericViewSet):
""" """
生产操作记录 生产操作记录
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = Operation.objects.select_related('step').prefetch_related('ow_operation', 'oe_operation', 'or_operation').all() queryset = Operation.objects.select_related('step').prefetch_related(
'ow_operation', 'oe_operation', 'or_operation').all()
serializer_class = OperationListSerializer serializer_class = OperationListSerializer
filterset_fields = ['step', 'step__process', 'is_submited'] filterset_fields = ['step', 'step__process', 'is_submited']
ordering_fields = ['id'] ordering_fields = ['id']
@ -537,9 +504,10 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
@transaction.atomic @transaction.atomic
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
data = request.data data = request.data
serializer = OperationCreateSerializer(data=data, context={'request':self.request}) serializer = OperationCreateSerializer(
data=data, context={'request': self.request})
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data #校验之后的数据 vdata = serializer.validated_data # 校验之后的数据
step = vdata['step'] step = vdata['step']
op = Operation() op = Operation()
op.step = step op.step = step
@ -550,9 +518,10 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 创建操作所用半成品关联记录 # 创建操作所用半成品关联记录
if 'wproducts' in vdata: if 'wproducts' in vdata:
owps = [] owps = []
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts']) splans = WpmServies.get_subplans_queryset_from_wproducts(
vdata['wproducts'])
for wpd in vdata['wproducts']: for wpd in vdata['wproducts']:
wpd.operation= op wpd.operation = op
wpd.act_state = WProduct.WPR_ACT_STATE_DOING wpd.act_state = WProduct.WPR_ACT_STATE_DOING
wpd.update_by = request.user wpd.update_by = request.user
wpd.save() wpd.save()
@ -567,9 +536,11 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
owps.append(OperationWproduct(**owp)) owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps) OperationWproduct.objects.bulk_create(owps)
else: else:
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts']) splans = WpmServies.get_subplans_queryset_from_wproducts(
vdata['wproducts'])
# 查询需要填写的自定义表格 # 查询需要填写的自定义表格
forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO, enabled=True) forms = RecordForm.objects.filter(
step=step, type=RecordForm.RF_TYPE_DO, enabled=True)
for i in forms: for i in forms:
opr = OperationRecord() opr = OperationRecord()
opr.operation = op opr.operation = op
@ -591,7 +562,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
ope.save() ope.save()
# 查询所需的工具工装 # 查询所需的工具工装
for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL, for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
subproduction__subplan_subprod__in = splans, is_deleted=False).distinct(): subproduction__subplan_subprod__in=splans,
is_deleted=False).distinct():
opm = OperationMaterial() opm = OperationMaterial()
opm.operation = op opm.operation = op
opm.material = i.material opm.material = i.material
@ -599,7 +571,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
opm.save() opm.save()
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) @action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=serializers.Serializer)
@transaction.atomic @transaction.atomic
def submit(self, request, pk=None): def submit(self, request, pk=None):
""" """
@ -616,7 +588,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 校验消耗产出是否正确填写 # 校验消耗产出是否正确填写
if op.step.type == Step.STEP_TYPE_DIV: if op.step.type == Step.STEP_TYPE_DIV:
sps_omi_l = omis.values_list('subproduction_plan', flat=True) sps_omi_l = omis.values_list('subproduction_plan', flat=True)
sps_omo_l = omos.filter(use_scrap=False).values_list('subproduction_plan', flat=True) sps_omo_l = omos.filter(use_scrap=False).values_list(
'subproduction_plan', flat=True)
if set(list(sps_omi_l)) != set(list(sps_omo_l)): if set(list(sps_omi_l)) != set(list(sps_omo_l)):
raise exceptions.APIException('消耗与产出不一致') raise exceptions.APIException('消耗与产出不一致')
@ -629,7 +602,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
for i in omis: for i in omis:
# 更新车间物料 # 更新车间物料
i_wmat = i.wmaterial i_wmat = i.wmaterial
i_wmat.count = i_wmat.count- i.count i_wmat.count = i_wmat.count - i.count
i_wmat.save() i_wmat.save()
# 更新子计划物料消耗情况 # 更新子计划物料消耗情况
spp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan, spp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan,
@ -640,7 +613,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
for i in omos: for i in omos:
if not i.subproduction_progress.is_main: if not i.subproduction_progress.is_main:
# 更新车间物料产出情况 # 更新车间物料产出情况
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i.subproduction_plan, material=i.material) ins, _ = WMaterial.objects.get_or_create(
subproduction_plan=i.subproduction_plan, material=i.material)
ins.count = ins.count + i.count ins.count = ins.count + i.count
ins.save() ins.save()
# 更新子计划物料产出情况 # 更新子计划物料产出情况
@ -659,7 +633,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
wp.step = newstep wp.step = newstep
wp.pre_step = step wp.pre_step = step
if hasNext: if hasNext:
wp.act_state= WProduct.WPR_ACT_STATE_DOWAIT wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else: else:
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material = wsp.product wp.material = wsp.product
@ -678,7 +652,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
raise exceptions.APIException('请选择物料产出') raise exceptions.APIException('请选择物料产出')
for i in omos: for i in omos:
if i.subproduction_progress.is_main: if i.subproduction_progress.is_main:
newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step) newstep, _ = WpmServies.get_next_step(
i.subproduction_plan, step)
wpr = dict(material=i.material, step=newstep, wpr = dict(material=i.material, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='', act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i.subproduction_plan, subproduction_plan=i.subproduction_plan,
@ -686,15 +661,18 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
for x in range(i.count): for x in range(i.count):
ins = WProduct.objects.create(**wpr) ins = WProduct.objects.create(**wpr)
# 添加日志 # 添加日志
WpmServies.add_wproduct_flow_log(ins, 'wproduct_create') WpmServies.add_wproduct_flow_log(
ins, 'wproduct_create')
# 更新进度 # 更新进度
WpmServies.update_subproduction_progress_main(sp=i.subproduction_plan) WpmServies.update_subproduction_progress_main(
sp=i.subproduction_plan)
elif step.type == Step.STEP_TYPE_COMB: elif step.type == Step.STEP_TYPE_COMB:
oms_w = omos.filter(subproduction_progress__is_main=True) oms_w = omos.filter(subproduction_progress__is_main=True)
if len(oms_w) == 1: if len(oms_w) == 1:
oms_w = oms_w[0] oms_w = oms_w[0]
# 校验单片数量是否正确, 暂时未写 # 校验单片数量是否正确, 暂时未写
newstep, hasNext = WpmServies.get_next_step(oms_w.subproduction_plan, step) newstep, hasNext = WpmServies.get_next_step(
oms_w.subproduction_plan, step)
wproduct = WProduct() wproduct = WProduct()
wproduct.material = oms_w.material wproduct.material = oms_w.material
wproduct.step = newstep wproduct.step = newstep
@ -704,32 +682,34 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
else: else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
# 更新子计划进度 # 更新子计划进度
WpmServies.update_subproduction_progress_main(sp=oms_w.subproduction_plan) WpmServies.update_subproduction_progress_main(
sp=oms_w.subproduction_plan)
wproduct.create_by = request.user wproduct.create_by = request.user
wproduct.coperation = op wproduct.coperation = op
wproduct.save() wproduct.save()
WpmServies.add_wproduct_flow_log(wproduct, 'wproduct_create') WpmServies.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, update_by=request.user, update_time=timezone.now()) wps.update(is_hidden=True, child=wproduct,
update_by=request.user, update_time=timezone.now())
else: else:
raise exceptions.APIException('产出物料未填写或填写错误') raise exceptions.APIException('产出物料未填写或填写错误')
op.is_submited = True op.is_submited = True
op.save() op.save()
# 如果是冷加工 # 如果是冷加工
if step.process.id==1: if step.process.id == 1:
WpmServies.update_cutting_list_with_operation(op=op) WpmServies.update_cutting_list_with_operation(op=op)
return Response() return Response()
class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet): class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
""" """
操作使用的半成品 操作使用的半成品
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = OperationWproduct.objects.select_related('subproduction_plan', 'material').all() queryset = OperationWproduct.objects.select_related(
'subproduction_plan', 'material').all()
serializer_class = OperationWproductListSerializer serializer_class = OperationWproductListSerializer
filterset_fields = ['material', 'subproduction_plan', 'operation'] filterset_fields = ['material', 'subproduction_plan', 'operation']
ordering_fields = ['id'] ordering_fields = ['id']
@ -751,12 +731,14 @@ class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMix
wp.save() wp.save()
return Response() return Response()
class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet): class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
""" """
操作使用的设备 操作使用的设备
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = OperationEquip.objects.select_related('operation', 'equip').all() queryset = OperationEquip.objects.select_related(
'operation', 'equip').all()
serializer_class = OperationEquipListSerializer serializer_class = OperationEquipListSerializer
filterset_fields = ['operation', 'equip'] filterset_fields = ['operation', 'equip']
ordering_fields = ['id'] ordering_fields = ['id']
@ -781,12 +763,14 @@ class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin,
instance.delete() instance.delete()
return Response() return Response()
class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin, GenericViewSet): class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin, GenericViewSet):
""" """
操作使用的自定义表格 操作使用的自定义表格
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = OperationRecord.objects.select_related('operation', 'form').all() queryset = OperationRecord.objects.select_related(
'operation', 'form').all()
serializer_class = OperationRecordListSerializer serializer_class = OperationRecordListSerializer
filterset_class = OperationRecordFilterSet filterset_class = OperationRecordFilterSet
ordering_fields = ['id'] ordering_fields = ['id']
@ -798,6 +782,7 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin
elif self.action == 'retrieve': elif self.action == 'retrieve':
return OperationRecordDetailSerializer return OperationRecordDetailSerializer
return super().get_serializer_class() return super().get_serializer_class()
@transaction.atomic() @transaction.atomic()
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
instance = self.get_object() instance = self.get_object()
@ -806,7 +791,6 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin
instance.delete() instance.delete()
return Response() return Response()
def update(self, request, *args, **kwargs): def update(self, request, *args, **kwargs):
serializer = OperationRecordSubmitSerializer(data=request.data) serializer = OperationRecordSubmitSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
@ -828,8 +812,9 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod
""" """
消耗物料 消耗物料
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN) queryset = OperationMaterial.objects.select_related(
'operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN)
serializer_class = OperationMaterialListSerializer serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan'] filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id'] ordering_fields = ['id']
@ -840,7 +825,8 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod
return OperationMaterialCreate1Serailizer return OperationMaterialCreate1Serailizer
return super().get_serializer_class() return super().get_serializer_class()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=OperationMaterialCreate1ListSerailizer) @action(methods=['post'], detail=False, perms_map={'post': '*'},
serializer_class=OperationMaterialCreate1ListSerailizer)
def creates(self, request, pk=None): def creates(self, request, pk=None):
""" """
批量创建消耗物料 批量创建消耗物料
@ -850,7 +836,6 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod
serializer.save() serializer.save()
return Response() return Response()
@transaction.atomic() @transaction.atomic()
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
instance = self.get_object() instance = self.get_object()
@ -859,13 +844,16 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod
instance.delete() instance.delete()
return Response() return Response()
class CuttingListViewSet(ListModelMixin, GenericViewSet): class CuttingListViewSet(ListModelMixin, GenericViewSet):
""" """
下料清单 下料清单
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = OperationMaterial.objects.select_related('operation', queryset = OperationMaterial.objects.select_related('operation',
'subproduction_plan', 'material', 'operation__create_by').filter(operation__step__id=1, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) 'subproduction_plan', 'material',
'operation__create_by').filter(operation__step__id=1,
type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
serializer_class = CuttingListSerializer serializer_class = CuttingListSerializer
filterset_class = CuttingFilterSet filterset_class = CuttingFilterSet
ordering_fields = ['id'] ordering_fields = ['id']
@ -876,8 +864,9 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo
""" """
产出物料 产出物料
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_OUT) queryset = OperationMaterial.objects.select_related(
'operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
serializer_class = OperationMaterialListSerializer serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan'] filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id'] ordering_fields = ['id']
@ -888,7 +877,8 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo
return OperationMaterialCreate2Serailizer return OperationMaterialCreate2Serailizer
return super().get_serializer_class() return super().get_serializer_class()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=OperationMaterialCreate2ListSerailizer) @action(methods=['post'], detail=False, perms_map={'post': '*'},
serializer_class=OperationMaterialCreate2ListSerailizer)
def creates(self, request, pk=None): def creates(self, request, pk=None):
""" """
批量创建产出物料 批量创建产出物料
@ -906,12 +896,14 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo
instance.delete() instance.delete()
return Response() return Response()
class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet): class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
""" """
工具工装 工具工装
""" """
perms_map={'*':'*'} perms_map = {'*': '*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL) queryset = OperationMaterial.objects.select_related(
'operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL)
serializer_class = OperationMaterialListSerializer serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan'] filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id'] ordering_fields = ['id']
@ -930,9 +922,11 @@ class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyMode
instance.delete() instance.delete()
return Response() return Response()
class DoFormInit(CreateAPIView, GenericAPIView): class DoFormInit(CreateAPIView, GenericAPIView):
perms_map={'*':'*'} perms_map = {'*': '*'}
serializer_class=OperationInitSerializer serializer_class = OperationInitSerializer
def post(self, request, format=None): def post(self, request, format=None):
""" """
调用操作表单 调用操作表单
@ -944,23 +938,27 @@ class DoFormInit(CreateAPIView, GenericAPIView):
ret = {} ret = {}
ret_0 = {} ret_0 = {}
ret_0['step'] = data['step'] ret_0['step'] = data['step']
splans =[] splans = []
ret_0['input'] = [] ret_0['input'] = []
# ret_0['subproduction_plan'] = data['subproduction_plan'] # ret_0['subproduction_plan'] = data['subproduction_plan']
if 'wproducts' in data and data['wproducts']: if 'wproducts' in data and data['wproducts']:
ret_0['wproducts'] = data['wproducts'] ret_0['wproducts'] = data['wproducts']
splans = WProduct.objects.filter(id__in=data['wproducts']).values_list('subproduction_plan', flat=True) splans = WProduct.objects.filter(id__in=data['wproducts']).values_list(
'subproduction_plan', flat=True)
# 调出所属子计划现有物料 # 调出所属子计划现有物料
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(subproduction_plan__in=splans), many=True).data ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(
subproduction_plan__in=splans), many=True).data
else: else:
if 'subproduction_plan' in vdata: if 'subproduction_plan' in vdata:
splans = [vdata['subproduction_plan']] splans = [vdata['subproduction_plan']]
else: else:
splans = SubProductionPlan.objects.filter(is_deleted=False, splans = SubProductionPlan.objects.filter(is_deleted=False,
subproduction__usedstep_subproduction__step=vdata['step'], state=3) subproduction__usedstep_subproduction__step=vdata[
'step'],
state=3)
ret_0['wproducts'] = [] ret_0['wproducts'] = []
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(subproduction_plan__in=splans), many=True).data ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(
subproduction_plan__in=splans), many=True).data
for i in ret_0['input']: for i in ret_0['input']:
i['count_input'] = 0 i['count_input'] = 0
@ -974,30 +972,34 @@ class DoFormInit(CreateAPIView, GenericAPIView):
# 此时显示所有子计划需要输出的物料 # 此时显示所有子计划需要输出的物料
o_objs = SubProductionProgress.objects.filter( o_objs = SubProductionProgress.objects.filter(
subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
ret_0['output'] = list(o_objs.values('subproduction_plan', 'material', 'material__name', 'material__number')) ret_0['output'] = list(o_objs.values(
'subproduction_plan', 'material', 'material__name', 'material__number'))
for i in ret_0['output']: for i in ret_0['output']:
i['count_output']=0 i['count_output'] = 0
ret['forms'] = [] ret['forms'] = []
ret_0['id'] = 0 ret_0['id'] = 0
ret_0['name'] = '基本信息' ret_0['name'] = '基本信息'
# 查询工具工装 # 查询工具工装
ret_0['tools'] = SubprodctionMaterialListSerializer(instance= ret_0['tools'] = SubprodctionMaterialListSerializer(
SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL, instance=SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
subproduction__subplan_subprod__in = splans), many=True).data subproduction__subplan_subprod__in=splans), many=True).data
# 查询技术文档 # 查询技术文档
ret_0['techdocs'] = TechDocListSerializer(instance = ret_0['techdocs'] = TechDocListSerializer(
TechDoc.objects.filter(subproduction__subplan_subprod__in = splans, enabled=True)\ instance=TechDoc.objects.filter(
subproduction__subplan_subprod__in=splans, enabled=True)
.distinct(), many=True).data .distinct(), many=True).data
ret['forms'].append(ret_0) ret['forms'].append(ret_0)
forms = RecordForm.objects.filter(step=vdata['step'], type=RecordForm.RF_TYPE_DO) forms = RecordForm.objects.filter(
step=vdata['step'], type=RecordForm.RF_TYPE_DO)
if forms.exists(): if forms.exists():
ret['forms'].extend(RecordFormDetailSerializer(instance=forms, many=True).data) ret['forms'].extend(RecordFormDetailSerializer(
instance=forms, many=True).data)
return Response(ret) return Response(ret)
class DoFormSubmit(CreateAPIView, GenericAPIView): class DoFormSubmit(CreateAPIView, GenericAPIView):
perms_map={'*':'*'} perms_map = {'*': '*'}
serializer_class = OperationSubmitSerializer serializer_class = OperationSubmitSerializer
@transaction.atomic @transaction.atomic
@ -1006,9 +1008,10 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
提交操作表单 提交操作表单
""" """
data = request.data data = request.data
serializer = OperationSubmitSerializer(data=data, context={'request':self.request}) serializer = OperationSubmitSerializer(
data=data, context={'request': self.request})
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data #校验之后的数据 vdata = serializer.validated_data # 校验之后的数据
# 创建一个生产操作记录 # 创建一个生产操作记录
action_obj = Operation() action_obj = Operation()
@ -1034,12 +1037,12 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
# 保存物料消耗 # 保存物料消耗
for i in vdata['input']: for i in vdata['input']:
if i['count_input']: #如果有消耗 if i['count_input']: # 如果有消耗
i_wmat = i['id'] i_wmat = i['id']
OperationMaterial.objects.create(type=1, operation=action_obj, OperationMaterial.objects.create(type=1, operation=action_obj,
wmaterial= i_wmat, count=i['count_input']) wmaterial=i_wmat, count=i['count_input'])
# 更新车间物料 # 更新车间物料
i_wmat.count = i_wmat.count- i['count_input'] i_wmat.count = i_wmat.count - i['count_input']
i_wmat.save() i_wmat.save()
# 更新子计划物料消耗情况 # 更新子计划物料消耗情况
sp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan, sp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan,
@ -1055,7 +1058,8 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
# 如果是切割 # 如果是切割
# 获取下一步子工序 # 获取下一步子工序
if vdata['step'].type == Step.STEP_TYPE_DIV: if vdata['step'].type == Step.STEP_TYPE_DIV:
newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) newstep, _ = WpmServies.get_next_step(
i['subproduction_plan'], vdata['step'])
wpr = dict(material=ma, step=newstep, wpr = dict(material=ma, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='', act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i['subproduction_plan']) subproduction_plan=i['subproduction_plan'])
@ -1064,7 +1068,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
else: else:
# 更新操作产出物料表 # 更新操作产出物料表
OperationMaterial.objects.create(type=2, operation=action_obj, OperationMaterial.objects.create(type=2, operation=action_obj,
material= ma, count=i['count_output']) material=ma, count=i['count_output'])
# 更新车间物料表 # 更新车间物料表
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i['subproduction_plan'], ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i['subproduction_plan'],
material=ma) material=ma)
@ -1082,30 +1086,32 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproducts = vdata['wproducts'] wproducts = vdata['wproducts']
if 'suproduction_plan' in vdata: if 'suproduction_plan' in vdata:
wproducts.update(is_hidden=True) # 隐藏 wproducts.update(is_hidden=True) # 隐藏
newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) newstep, hasNext = WpmServies.get_next_step(
i['subproduction_plan'], vdata['step'])
wproduct = WProduct() wproduct = WProduct()
wproduct.material = vdata['subproduction_plan'].product wproduct.material = vdata['subproduction_plan'].product
wproduct.step = newstep wproduct.step = newstep
wproduct.subproduction_plan=vdata['subproduction_plan'] wproduct.subproduction_plan = vdata['subproduction_plan']
wproduct.parent = data['wproducts'] wproduct.parent = data['wproducts']
if hasNext: if hasNext:
wproduct.act_state=WProduct.WPR_ACT_STATE_DOWAIT wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else: else:
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.save() wproduct.save()
else: else:
raise exceptions.APIException('请指定子计划') raise exceptions.APIException('请指定子计划')
else: else:
for wproduct in vdata['wproducts']: for wproduct in vdata['wproducts']:
# 获取下一步子工序 # 获取下一步子工序
newstep, hasNext = WpmServies.get_next_step(wproduct.subproduction_plan, vdata['step']) newstep, hasNext = WpmServies.get_next_step(
wproduct.subproduction_plan, vdata['step'])
wproduct.step = newstep wproduct.step = newstep
wproduct.pre_step=vdata['step'] wproduct.pre_step = vdata['step']
if hasNext: if hasNext:
wproduct.act_state=WProduct.WPR_ACT_STATE_DOWAIT wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else: else:
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.material=wproduct.subproduction_plan.product wproduct.material = wproduct.subproduction_plan.product
wproduct.save() wproduct.save()
# 保存自定义表单结果 # 保存自定义表单结果
@ -1127,5 +1133,3 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wrds.append(OperationRecordItem(**m)) wrds.append(OperationRecordItem(**m))
OperationRecordItem.objects.bulk_create(wrds) OperationRecordItem.objects.bulk_create(wrds)
return Response() return Response()

View File

@ -173,6 +173,7 @@ REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_USER': None,
'UNAUTHENTICATED_TOKEN': None, 'UNAUTHENTICATED_TOKEN': None,
'TEST_REQUEST_DEFAULT_FORMAT': 'json'
} }
# simplejwt配置 # simplejwt配置
SIMPLE_JWT = { SIMPLE_JWT = {