bugfix
This commit is contained in:
commit
a98de8720a
|
@ -348,7 +348,7 @@ export const asyncRoutes = [
|
|||
component: Layout,
|
||||
redirect: '/qm/product',
|
||||
name: 'qm',
|
||||
meta: { title: '质量管理', icon: 'example', perms: ['equipment_set'] },
|
||||
meta: { title: '检验管理', icon: 'example', perms: ['equipment_set'] },
|
||||
children: [
|
||||
{
|
||||
path: 'product',
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
width="90%"
|
||||
:title="dialogType === 'edit' ? '编辑出/如库记录' : '新增出/如库记录'"
|
||||
>
|
||||
<el-form
|
||||
|
@ -110,20 +111,11 @@
|
|||
: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">
|
||||
<el-row>
|
||||
<el-col :span="6" style="margin-right: 10px">
|
||||
<el-col :span="5" style="margin-right: 10px">
|
||||
<el-form-item
|
||||
class="warehouse"
|
||||
label="仓库:"
|
||||
|
@ -141,7 +133,7 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6" style="margin-right: 10px">
|
||||
<el-col :span="5" style="margin-right: 10px">
|
||||
<el-form-item
|
||||
class="material"
|
||||
label="物料:"
|
||||
|
@ -159,7 +151,7 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6" style="margin-right: 10px">
|
||||
<el-col :span="5" style="margin-right: 10px">
|
||||
<el-form-item
|
||||
class="count"
|
||||
label="数量"
|
||||
|
@ -171,7 +163,7 @@
|
|||
></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6" style="margin-right: 10px">
|
||||
<el-col :span="5" style="margin-right: 10px">
|
||||
<el-form-item
|
||||
class="batch"
|
||||
label="批次"
|
||||
|
|
|
@ -35,14 +35,14 @@
|
|||
<el-table-column label="入库数量">
|
||||
<template slot-scope="scope">{{ scope.row.count }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否检查">
|
||||
<el-table-column label="是否需要复验">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.is_tested == false">未检查</el-tag>
|
||||
<el-tag v-else>已检查</el-tag>
|
||||
<el-tag v-if="scope.row.need_test == false">否</el-tag>
|
||||
<el-tag v-else>是</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="检查是否合格">
|
||||
<template slot-scope="scope" v-if="scope.row.is_tested == true">
|
||||
<el-table-column label="复验是否合格">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.is_testok == false">不合格</el-tag>
|
||||
<el-tag v-else>合格</el-tag>
|
||||
</template>
|
||||
|
@ -51,10 +51,16 @@
|
|||
<el-table-column align="center" label="操作" width="220px">
|
||||
<template slot-scope="scope">
|
||||
<el-link
|
||||
v-if="scope.row.is_tested == false"
|
||||
|
||||
type="primary"
|
||||
@click="handleMaterial(scope)"
|
||||
>检查</el-link
|
||||
>复验</el-link
|
||||
>
|
||||
<el-link
|
||||
|
||||
type="primary"
|
||||
@click="handlefile(scope)"
|
||||
>上传</el-link
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -262,6 +268,11 @@ export default {
|
|||
}
|
||||
this.listLoading = false;
|
||||
});
|
||||
},
|
||||
//上传物料文件
|
||||
handlefile(scope)
|
||||
{
|
||||
|
||||
},
|
||||
handleMaterial(scope) {
|
||||
//调该物料对应的检查表
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
|
||||
|
||||
</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-table
|
||||
|
|
|
@ -350,6 +350,7 @@
|
|||
this.dialogVisible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs["Form"].resetFields();
|
||||
this.value1="";
|
||||
});
|
||||
|
||||
},
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
</el-table>
|
||||
|
||||
<!--检验记录-->
|
||||
<el-dialog title="检验记录" :close-on-click-modal="false" :visible.sync="limitedCheckRecord">
|
||||
<el-dialog title="检验记录" :visible.sync="limitedCheckRecord">
|
||||
<el-table
|
||||
:data="recordList"
|
||||
border
|
||||
|
@ -89,28 +89,42 @@
|
|||
|
||||
<el-table-column align="center" label="操作">
|
||||
<template slot-scope="scope">
|
||||
|
||||
<el-link
|
||||
v-if="!scope.row.is_submited"
|
||||
@click="handleInspectionRecord(scope)"
|
||||
>检验
|
||||
</el-link>
|
||||
<el-link
|
||||
v-else
|
||||
|
||||
@click="handleRecordDetail(scope)"
|
||||
>查看
|
||||
</el-link>
|
||||
<el-link
|
||||
@click="delTestRecord(scope)"
|
||||
>删除
|
||||
</el-link>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="putin">确 定</el-button>
|
||||
|
||||
</div>
|
||||
</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>
|
||||
|
||||
|
||||
|
@ -123,12 +137,14 @@
|
|||
import { getProductionplan,getsubproductionplanList } from "@/api/pm";
|
||||
import { getwproductList,getrecordList} from "@/api/wpm";
|
||||
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
|
||||
|
||||
const defaultrecordform = {enabled:false};
|
||||
export default {
|
||||
components: { Pagination },
|
||||
components: { Pagination,customForm },
|
||||
data() {
|
||||
return {
|
||||
productionplan:{
|
||||
|
@ -136,6 +152,7 @@ export default {
|
|||
},
|
||||
activeName:"1",
|
||||
wproduct:[],
|
||||
recordList:[],
|
||||
limitedCheckRecord:false,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
|
@ -162,6 +179,30 @@ export default {
|
|||
},
|
||||
process_json: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: {},
|
||||
|
@ -217,10 +258,56 @@ export default {
|
|||
this.limitedCheckRecord=true;
|
||||
getrecordList({wproduct: scope.row.id,page:0}).then(res => {
|
||||
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>
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
<template slot-scope="scope">{{ scope.row.count_real }}</template>
|
||||
</el-table-column>
|
||||
<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 label="物料名称">
|
||||
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
|
||||
|
@ -200,7 +200,7 @@
|
|||
<template slot-scope="scope">{{ scope.row.count_real }}</template>
|
||||
</el-table-column>
|
||||
<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 label="物料名称">
|
||||
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
|
||||
|
@ -309,7 +309,8 @@ export default {
|
|||
{
|
||||
this.xhwl.push(item);
|
||||
}
|
||||
else{
|
||||
else if(item.type==2)
|
||||
{
|
||||
this.ccwl.push(item);
|
||||
}
|
||||
|
||||
|
|
|
@ -134,18 +134,18 @@
|
|||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {getfifodetailList} from "@/api/inm";
|
||||
import checkPermission from "@/utils/permission";
|
||||
import {mtest, getwproductList} from "@/api/wpm";
|
||||
import customForm from '@/components/customForm/index';
|
||||
import {getrecordformList, getrffieldList} from "@/api/mtm";
|
||||
import {getTestRecord, getTestRecordItem} from "@/api/qm";
|
||||
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||
export default {
|
||||
components: {Pagination, customForm},
|
||||
data() {
|
||||
return {
|
||||
wproductList: {
|
||||
import { getfifodetailList } from "@/api/inm";
|
||||
import checkPermission from "@/utils/permission";
|
||||
import { mtest,getwproductList } from "@/api/wpm";
|
||||
import { getrecordformList, getrffieldList} from "@/api/mtm";
|
||||
import {getTestRecord,getTestRecordItem} from "@/api/qm";
|
||||
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data() {
|
||||
return {
|
||||
wproductList: {
|
||||
count: 0,
|
||||
},
|
||||
listQuery: {
|
||||
|
|
|
@ -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_.specification}}</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-card style="margin-bottom: 20px">
|
||||
<div slot="header" class="clearfix">
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
<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="不合格品数量">不合格数没有</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="玻璃所在子工序">{{process}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
|
||||
</el-descriptions>
|
||||
|
|
|
@ -50,8 +50,8 @@
|
|||
|
||||
</el-table-column>
|
||||
<el-table-column label="产品数量">
|
||||
<template slot-scope="scope" v-if="scope.row.wproduct_">
|
||||
{{ scope.row.wproduct_.length }}
|
||||
<template slot-scope="scope" >
|
||||
{{ scope.row.count_work }}
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -136,7 +136,7 @@ export default {
|
|||
|
||||
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() {
|
||||
|
|
|
@ -132,6 +132,23 @@
|
|||
</el-table-column>
|
||||
<el-table-column prop="equip_.name" label="设备名称">
|
||||
</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">
|
||||
<template slot-scope="scope">
|
||||
<el-link
|
||||
|
@ -463,9 +480,9 @@
|
|||
</el-table-column>
|
||||
<el-table-column type="index" width="50" />
|
||||
|
||||
<el-table-column label="生产计划编号">
|
||||
<el-table-column label="子计划编号">
|
||||
<template slot-scope="scope">{{
|
||||
scope.row.subproduction_plan
|
||||
scope.row.subproduction_plan_.number
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物料名称">
|
||||
|
@ -604,6 +621,12 @@ export default {
|
|||
listQuery: {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
},
|
||||
state_:{
|
||||
0:'完好',
|
||||
1:'限用',
|
||||
2:'在修',
|
||||
3:'禁用',
|
||||
},
|
||||
scrap: [
|
||||
{ lable: "使用", value: true },
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
.vscode/
|
||||
.vs/
|
||||
.idea/
|
||||
venv/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
|
|
@ -2,11 +2,13 @@ from django.db.models import base
|
|||
from rest_framework import urlpatterns
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateLastTestResult
|
||||
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateFIFOItem, UpdateLastTestResult
|
||||
|
||||
urlpatterns = [
|
||||
path('cleandata/', CleanDataView.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())
|
||||
]
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ from rest_framework.decorators import permission_classes
|
|||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
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.pm.models import ProductionPlan
|
||||
from apps.sam.models import Order
|
||||
|
@ -62,3 +62,21 @@ class UpdateLastTestResult(APIView):
|
|||
i.last_test_result = tr.is_testok
|
||||
i.save()
|
||||
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()
|
||||
|
|
|
@ -27,7 +27,7 @@ class EquipmentSerializer(ModelSerializer):
|
|||
class EquipmentSimpleSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Equipment
|
||||
fields = ['id', 'number', 'name']
|
||||
fields = ['id', 'number', 'name', 'state']
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.contrib.auth.models import AbstractUser
|
|||
from django.db.models.base import Model
|
||||
import django.utils.timezone as timezone
|
||||
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 simple_history.models import HistoricalRecords
|
||||
|
||||
|
@ -36,3 +36,8 @@ class Employee(CommonAModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Attendance(CommonADModel):
|
||||
"""
|
||||
出勤记录
|
||||
"""
|
||||
|
|
@ -3,22 +3,25 @@ from django_filters import rest_framework as filters
|
|||
from apps.mtm.models import Material
|
||||
from .models import IProduct, MaterialBatch
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
class MbFilterSet(filters.FilterSet):
|
||||
material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all())
|
||||
tag = filters.CharFilter(method="filter_tag")
|
||||
|
||||
class Meta:
|
||||
model = MaterialBatch
|
||||
fields = ['material', 'warehouse']
|
||||
|
||||
def filter_tag(self, queryset, name, value):
|
||||
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
|
||||
|
||||
|
||||
class IProductFilterSet(filters.FilterSet):
|
||||
|
||||
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
|
||||
|
||||
class Meta:
|
||||
model = IProduct
|
||||
fields = ['material', 'warehouse', 'batch', 'order', 'material__type']
|
|
@ -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='出入库日期'),
|
||||
),
|
||||
]
|
|
@ -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='是否复验合格'),
|
||||
),
|
||||
]
|
|
@ -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='上传材料'),
|
||||
),
|
||||
]
|
|
@ -17,6 +17,7 @@ class WareHouse(CommonAModel):
|
|||
number = models.CharField('仓库编号', max_length=20, unique=True)
|
||||
name = models.CharField('仓库名称', max_length=20, unique=True)
|
||||
place = models.CharField('具体地点', max_length=50)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '仓库信息'
|
||||
verbose_name_plural = verbose_name
|
||||
|
@ -24,37 +25,44 @@ class WareHouse(CommonAModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
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)
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
warehouse = models.ForeignKey(
|
||||
WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '库存表'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class MaterialBatch(BaseModel):
|
||||
"""
|
||||
物料批次
|
||||
"""
|
||||
material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息')
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
material = models.ForeignKey(
|
||||
Material, on_delete=models.CASCADE, verbose_name='物料信息')
|
||||
warehouse = models.ForeignKey(
|
||||
WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
count = models.PositiveIntegerField('存量', default=0)
|
||||
batch = models.CharField('批次号', max_length=100, default='')
|
||||
expiration_date = models.DateField('有效期', null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '库存表'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
|
||||
class FIFO(CommonADModel):
|
||||
"""
|
||||
出入库记录
|
||||
"""
|
||||
FIFO_TYPE_DO_OUT = 1 # 生产领料
|
||||
FIFO_TYPE_DO_OUT = 1 # 生产领料
|
||||
FIFO_TYPE_SALE_OUT = 2
|
||||
FIFO_TYPE_PUR_IN = 3
|
||||
FIFO_TYPE_DO_IN = 4
|
||||
|
@ -66,8 +74,9 @@ class FIFO(CommonADModel):
|
|||
)
|
||||
type = models.IntegerField('出入库类型', default=1)
|
||||
is_audited = models.BooleanField('是否审核', default=False)
|
||||
auditor = models.ForeignKey(User, verbose_name='审核人', on_delete=models.CASCADE, null=True, blank=True)
|
||||
inout_date = models.DateField('出入库日期')
|
||||
auditor = models.ForeignKey(
|
||||
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='')
|
||||
|
||||
|
||||
|
@ -75,38 +84,46 @@ class FIFOItem(BaseModel):
|
|||
"""
|
||||
出入库详细条目
|
||||
"""
|
||||
is_tested = models.BooleanField('是否已检验', default=False)
|
||||
is_testok = models.BooleanField('是否检验合格', default=False)
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库')
|
||||
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||
need_test = models.BooleanField('是否需要复验', default=False)
|
||||
is_testok = models.BooleanField('是否复验合格', null=True, blank=True)
|
||||
warehouse = models.ForeignKey(
|
||||
WareHouse, on_delete=models.CASCADE, verbose_name='仓库')
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||
count = models.PositiveIntegerField('数量', default=0)
|
||||
batch = models.CharField('批次号', max_length=100, default='')
|
||||
fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE)
|
||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True)
|
||||
fifo = models.ForeignKey(FIFO, verbose_name='关联出入库',
|
||||
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):
|
||||
"""
|
||||
具体产品条目
|
||||
"""
|
||||
number = models.CharField('物品编号', unique=True, max_length=50)
|
||||
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||
warehouse = models.ForeignKey(
|
||||
WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
batch = models.CharField('所属批次号', max_length=100, default='')
|
||||
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)
|
||||
|
||||
|
||||
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,
|
||||
related_name='fifoitem_wproduct')
|
||||
related_name='fifoitem_wproduct')
|
||||
number = models.CharField('物品编号', max_length=50)
|
||||
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||
iproduct = models.ForeignKey(IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL)
|
||||
|
||||
|
||||
|
||||
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||
iproduct = models.ForeignKey(
|
||||
IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL)
|
||||
|
|
|
@ -1,48 +1,59 @@
|
|||
from rest_framework import exceptions
|
||||
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.system.serializers import UserSimpleSerializer
|
||||
from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer
|
||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||
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:
|
||||
model = WareHouse
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class WareHouseCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = WareHouse
|
||||
fields = ['name', 'number', 'place']
|
||||
|
||||
|
||||
class WareHouseSimpleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = WareHouse
|
||||
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)
|
||||
|
||||
class Meta:
|
||||
model = Inventory
|
||||
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)
|
||||
|
||||
class Meta:
|
||||
model = MaterialBatch
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
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)
|
||||
is_mtested = serializers.BooleanField(source='wproduct.is_mtested', 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)
|
||||
|
||||
class Meta:
|
||||
model = IProduct
|
||||
fields = '__all__'
|
||||
|
@ -51,28 +62,35 @@ class IProductListSerializer(serializers.ModelSerializer):
|
|||
class FIFOListSerializer(serializers.ModelSerializer):
|
||||
auditor_ = UserSimpleSerializer(source='auditor', read_only=True)
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model=FIFO
|
||||
model = FIFO
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class FIFOItemSerializer(serializers.ModelSerializer):
|
||||
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:
|
||||
model= FIFOItem
|
||||
model = FIFOItem
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class IProductInPurSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = IProduct
|
||||
fields = ['number']
|
||||
|
||||
|
||||
class FIFODetailInPurSerializer(serializers.ModelSerializer):
|
||||
details = IProductInPurSerializer(many=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = FIFOItem
|
||||
fields = ['material', 'count', 'batch', 'details', 'warehouse']
|
||||
|
||||
|
||||
class MaterialBatchQuerySerializer(serializers.Serializer):
|
||||
warehouse = 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)
|
||||
|
||||
class Meta:
|
||||
model = FIFO
|
||||
fields = ['details', 'inout_date']
|
||||
fields = ['details']
|
||||
|
||||
def create(self, validated_data):
|
||||
details = validated_data.pop('details')
|
||||
if len(details)>0:
|
||||
if len(details) > 0:
|
||||
pass
|
||||
else:
|
||||
raise serializers.ValidationError('没有入库内容')
|
||||
|
@ -137,17 +156,33 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
|||
return obj
|
||||
|
||||
|
||||
|
||||
class InmTestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = TestRecordItem
|
||||
fields = ['form_field', 'field_value', 'is_testok']
|
||||
|
||||
|
||||
class InmTestRecordCreateSerializer(serializers.ModelSerializer):
|
||||
record_data = InmTestRecordItemCreateSerializer(many=True)
|
||||
fifo_item = serializers.PrimaryKeyRelatedField(queryset=FIFOItem.objects.all(), required=True)
|
||||
is_testok = serializers.BooleanField()
|
||||
|
||||
class Meta:
|
||||
model = TestRecord
|
||||
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)
|
|
@ -1,3 +1,10 @@
|
|||
from django.urls import reverse
|
||||
from django.test import TestCase
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
from rest_framework import status
|
||||
# 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)
|
|
@ -1,25 +1,26 @@
|
|||
from django.shortcuts import render
|
||||
from rest_framework import serializers
|
||||
from rest_framework import exceptions
|
||||
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 apps.inm.filters import IProductFilterSet, MbFilterSet
|
||||
|
||||
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.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse, Inventory
|
||||
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.mtm.models import Material
|
||||
from apps.pm.services import PmService
|
||||
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.response import Response
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.wpm.services import WpmServies
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
||||
class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||
"""
|
||||
仓库-增删改查
|
||||
|
@ -32,26 +33,30 @@ class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
|||
ordering_fields = ['create_time']
|
||||
ordering = ['-create_time']
|
||||
|
||||
def get_serializer_class(self):
|
||||
def get_serializer_class(self):
|
||||
if self.action in ['create', 'update']:
|
||||
return WareHouseCreateUpdateSerializer
|
||||
return WareHouseSerializer
|
||||
|
||||
|
||||
class InventoryViewSet(ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
仓库物料表
|
||||
"""
|
||||
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
|
||||
filterset_fields = ['material', 'warehouse']
|
||||
search_fields = []
|
||||
ordering_fields = ['create_time']
|
||||
ordering = ['-create_time']
|
||||
|
||||
|
||||
class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
|
||||
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
|
||||
# filterset_fields = ['material', 'warehouse']
|
||||
filterset_class = MbFilterSet
|
||||
|
@ -59,7 +64,7 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
|
|||
ordering_fields = ['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):
|
||||
"""
|
||||
复杂查询
|
||||
|
@ -67,27 +72,35 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
|
|||
data = request.data
|
||||
serializer = MaterialBatchQuerySerializer(data=data)
|
||||
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)
|
||||
|
||||
class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
||||
|
||||
class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
|
||||
"""
|
||||
出入库记录详情表
|
||||
"""
|
||||
perms_map = {'*': '*'}
|
||||
queryset = FIFOItem.objects.select_related('material', 'fifo').all()
|
||||
queryset = FIFOItem.objects.select_related('material', 'fifo').prefetch_related('files').all()
|
||||
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 = []
|
||||
ordering_fields = ['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):
|
||||
if instance.fifo.is_audited:
|
||||
raise APIException('该出入库记录已通过审核, 无法删除')
|
||||
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):
|
||||
"""
|
||||
检验
|
||||
|
@ -99,9 +112,9 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
if 'is_testok' not in vdata:
|
||||
raise APIException('未填写检验结论')
|
||||
with transaction.atomic():
|
||||
obj = serializer.save(create_by = self.request.user)
|
||||
obj = serializer.save(create_by=self.request.user)
|
||||
tris = []
|
||||
for m in record_data: # 保存记录详情
|
||||
for m in record_data: # 保存记录详情
|
||||
m['field_value'] = m['field_value']
|
||||
m['is_testok'] = m['is_testok'] if 'is_testok' in m else True
|
||||
m['test_record'] = obj
|
||||
|
@ -111,10 +124,10 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
# 如果检验合格
|
||||
if obj.fifo_item:
|
||||
obj.fifo_item.is_testok = True if obj.is_testok else False
|
||||
obj.fifo_item.is_tested = True
|
||||
obj.fifo_item.save()
|
||||
return Response()
|
||||
|
||||
|
||||
class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
||||
"""
|
||||
出入库记录
|
||||
|
@ -138,7 +151,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
raise exceptions.APIException('该记录已审核,不可删除')
|
||||
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):
|
||||
"""
|
||||
采购入库
|
||||
|
@ -148,13 +161,13 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
serializer.save(create_by=request.user)
|
||||
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):
|
||||
"""
|
||||
审核通过
|
||||
"""
|
||||
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:
|
||||
raise APIException('未检验通过, 不可审核')
|
||||
if obj.is_audited:
|
||||
|
@ -162,8 +175,9 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
with transaction.atomic():
|
||||
obj.is_audited = True
|
||||
obj.auditor = request.user
|
||||
obj.inout_date = timezone.now() # 也是审核日期
|
||||
obj.save()
|
||||
update_inm(obj) # 更新库存
|
||||
update_inm(obj) # 更新库存
|
||||
return Response()
|
||||
|
||||
|
||||
|
@ -172,7 +186,8 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
|
|||
半成品库存表
|
||||
"""
|
||||
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
|
||||
filterset_class = IProductFilterSet
|
||||
search_fields = []
|
||||
|
|
|
@ -59,6 +59,7 @@ class TestRecordItemSerializer(serializers.ModelSerializer):
|
|||
parent = serializers.PrimaryKeyRelatedField(source='form_field.parent', 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)
|
||||
draw_template = serializers.CharField(source='form_field.draw_template', read_only=True)
|
||||
class Meta:
|
||||
model = TestRecordItem
|
||||
fields = '__all__'
|
||||
|
|
|
@ -150,8 +150,7 @@ class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, C
|
|||
warehouse = WareHouse.objects.get(id=i['warehouse'])
|
||||
material = Material.objects.get(id=i['material'])
|
||||
fifoitem = FIFOItem()
|
||||
fifoitem.is_tested = True
|
||||
fifoitem.is_testok = True
|
||||
fifoitem.need_test = False
|
||||
fifoitem.warehouse = warehouse
|
||||
fifoitem.material = material
|
||||
fifoitem.count = i['total']
|
||||
|
|
|
@ -4,39 +4,50 @@ from apps.mtm.models import Material, Step
|
|||
from apps.wpm.services import WpmServies
|
||||
from .models import Operation, OperationMaterial, OperationRecord, WMaterial, WProduct
|
||||
|
||||
|
||||
class WMaterialFilterSet(filters.FilterSet):
|
||||
|
||||
operation = filters.NumberFilter(method='filter_operation')
|
||||
|
||||
class Meta:
|
||||
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):
|
||||
operation = Operation.objects.get(pk=value)
|
||||
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
|
||||
step = operation.step
|
||||
if wproducts.exists():
|
||||
subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts)
|
||||
subplans = WpmServies.get_subplans_queryset_from_wproducts(
|
||||
wproducts)
|
||||
else:
|
||||
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
|
||||
|
||||
|
||||
class WProductFilterSet(filters.FilterSet):
|
||||
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:
|
||||
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):
|
||||
if value == 'no_scrap':
|
||||
queryset = queryset.exclude(act_state=WProduct.WPR_ACT_STATE_SCRAP)
|
||||
return queryset
|
||||
|
||||
|
||||
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:
|
||||
model = OperationMaterial
|
||||
fields = ['operation', 'subproduction_plan', 'material']
|
||||
|
@ -44,6 +55,7 @@ class CuttingFilterSet(filters.FilterSet):
|
|||
|
||||
class OperationRecordFilterSet(filters.FilterSet):
|
||||
wproduct = filters.NumberFilter(method='filter_wproduct')
|
||||
|
||||
class Meta:
|
||||
model = OperationRecord
|
||||
fields = ['operation', 'form']
|
||||
|
|
|
@ -13,15 +13,20 @@ from utils.model import SoftModel, BaseModel
|
|||
from simple_history.models import HistoricalRecords
|
||||
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial
|
||||
from apps.em.models import Equipment
|
||||
|
||||
|
||||
class WMaterial(BaseModel):
|
||||
"""
|
||||
车间生产物料
|
||||
"""
|
||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE)
|
||||
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
|
||||
subproduction_plan = models.ForeignKey(
|
||||
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)
|
||||
count = models.PositiveIntegerField('当前数量', default=0)
|
||||
|
||||
|
||||
class WProduct(CommonAModel):
|
||||
"""
|
||||
动态半成品/成品表
|
||||
|
@ -37,7 +42,7 @@ class WProduct(CommonAModel):
|
|||
WPR_ACT_STATE_TOFINALTEST = 60
|
||||
WPR_ACT_STATE_SCRAP = 70
|
||||
WPR_ACT_STATE_SELLED = 80
|
||||
act_state_choices=(
|
||||
act_state_choices = (
|
||||
(WPR_ACT_STATE_TORETEST, '待复检'),
|
||||
(WPR_ACT_STATE_DOWAIT, '操作准备中'),
|
||||
(WPR_ACT_STATE_DOING, '操作进行中'),
|
||||
|
@ -80,29 +85,39 @@ class WProduct(CommonAModel):
|
|||
(NG_BACK_FROM, '退回供方'),
|
||||
(NG_RECALL, '召回')
|
||||
)
|
||||
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
|
||||
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
||||
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)
|
||||
number = models.CharField(
|
||||
'物品编号', unique=True, null=True, blank=True, max_length=50)
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
ng_sign = models.PositiveSmallIntegerField('不合格标记', choices=ng_choices, null=True, blank=True)
|
||||
scrap_reason = models.IntegerField(
|
||||
'报废原因', 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='当前操作',
|
||||
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')
|
||||
coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作',
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_coperation')
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_coperation')
|
||||
test = models.ForeignKey('qm.testrecord', verbose_name='当前检验',
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_test')
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_test')
|
||||
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
|
||||
|
||||
is_mtested = models.BooleanField('是否军检', default=False)
|
||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||
|
@ -123,42 +138,60 @@ class WprouctTicket(CommonAModel):
|
|||
"""
|
||||
|
||||
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
|
||||
wproduct = models.ForeignKey(WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
|
||||
material = models.ForeignKey(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)
|
||||
wproduct = models.ForeignKey(
|
||||
WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
|
||||
material = models.ForeignKey(
|
||||
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):
|
||||
"""
|
||||
动态产品表日志
|
||||
"""
|
||||
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)
|
||||
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
||||
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, 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)
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
||||
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
ng_sign = models.PositiveSmallIntegerField('不合格标记', choices= WProduct.ng_choices, null=True, blank=True)
|
||||
scrap_reason = models.IntegerField(
|
||||
'报废原因', 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='当前操作',
|
||||
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='创建所关联操作',
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_coperation')
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_coperation')
|
||||
test = models.ForeignKey('qm.testrecord', verbose_name='当前检验',
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
is_mtested = models.BooleanField('是否军检', default=False)
|
||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||
|
@ -179,65 +212,88 @@ class Pick(CommonADModel):
|
|||
(PICK_FROM_WAREHOUSE, '仓库领取'),
|
||||
(PICK_FROM_WPRODUCT, '半成品领取'),
|
||||
)
|
||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE)
|
||||
type = models.PositiveSmallIntegerField(choices=type_choice, default=PICK_FROM_WAREHOUSE)
|
||||
fifo = models.ForeignKey(FIFO, verbose_name='关联的出入库记录', on_delete=models.CASCADE, null=True, blank=True)
|
||||
subproduction_plan = models.ForeignKey(
|
||||
SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE)
|
||||
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):
|
||||
"""
|
||||
领取半成品时详情
|
||||
"""
|
||||
pick = models.ForeignKey(Pick, verbose_name='关联领料', on_delete=models.CASCADE)
|
||||
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='pw_wproduct')
|
||||
pick = models.ForeignKey(Pick, verbose_name='关联领料',
|
||||
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)
|
||||
material = models.ForeignKey(Material, verbose_name='领取时的物料状态', on_delete=models.CASCADE)
|
||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='领取时所属子生产计划', on_delete=models.CASCADE)
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='领取时的物料状态', on_delete=models.CASCADE)
|
||||
subproduction_plan = models.ForeignKey(
|
||||
SubProductionPlan, verbose_name='领取时所属子生产计划', on_delete=models.CASCADE)
|
||||
|
||||
|
||||
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)
|
||||
is_submited = models.BooleanField('是否提交', default=False)
|
||||
|
||||
|
||||
class OperationWproduct(BaseModel):
|
||||
"""
|
||||
生产操作半成品关联表
|
||||
"""
|
||||
operation = models.ForeignKey(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')
|
||||
operation = models.ForeignKey(
|
||||
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)
|
||||
material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
|
||||
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)
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
|
||||
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)
|
||||
|
||||
class Meta:
|
||||
unique_together = (
|
||||
('operation','wproduct')
|
||||
('operation', 'wproduct')
|
||||
)
|
||||
|
||||
|
||||
class OperationMaterial(BaseModel):
|
||||
"""
|
||||
生产操作物料消耗产出表
|
||||
"""
|
||||
type = models.IntegerField('类型', default=0, choices=SubprodctionMaterial.type_choices)
|
||||
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='om_operation')
|
||||
type = models.IntegerField(
|
||||
'类型', 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,
|
||||
null=True, blank=True, related_name='om_material')
|
||||
null=True, blank=True, related_name='om_material')
|
||||
count = models.PositiveSmallIntegerField('消耗或产出数量', null=True, blank=True)
|
||||
|
||||
wmaterial = models.ForeignKey(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)
|
||||
wmaterial = models.ForeignKey(
|
||||
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)
|
||||
use_scrap = models.BooleanField('是否使用的边角料', default=False)
|
||||
|
||||
#以下为冷加工下料清单所用字段
|
||||
# 以下为冷加工下料清单所用字段
|
||||
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)
|
||||
count_cut = models.PositiveIntegerField('切裁片数', default=0)
|
||||
count_real = models.PositiveIntegerField('生产片数', default=0)
|
||||
|
@ -249,26 +305,35 @@ class OperationMaterial(BaseModel):
|
|||
|
||||
class Meta:
|
||||
unique_together = (
|
||||
('operation','material', 'batch')
|
||||
('operation', 'material', 'batch')
|
||||
)
|
||||
|
||||
|
||||
class OperationRecord(BaseModel):
|
||||
"""
|
||||
记录表格
|
||||
"""
|
||||
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE, related_name='or_form')
|
||||
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='or_operation')
|
||||
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格',
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
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):
|
||||
operation = models.ForeignKey(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')
|
||||
operation = models.ForeignKey(
|
||||
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)
|
|
@ -69,7 +69,6 @@ class PickSerializer(serializers.Serializer):
|
|||
if isLowLevel:
|
||||
iproducts = i.pop('iproducts')
|
||||
i['fifo'] = fifo
|
||||
i['is_testok'] = True # 默认检验合格
|
||||
i['subproduction_plan'] = sp
|
||||
fifoitem = FIFOItem.objects.create(**i)
|
||||
# 创建再下一个层级
|
||||
|
@ -418,12 +417,12 @@ class WplanPutInSerializer(serializers.Serializer):
|
|||
|
||||
class WproductPutInSerializer(serializers.Serializer):
|
||||
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):
|
||||
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
|
||||
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):
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -173,6 +173,7 @@ REST_FRAMEWORK = {
|
|||
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
|
||||
'UNAUTHENTICATED_USER': None,
|
||||
'UNAUTHENTICATED_TOKEN': None,
|
||||
'TEST_REQUEST_DEFAULT_FORMAT': 'json'
|
||||
}
|
||||
# simplejwt配置
|
||||
SIMPLE_JWT = {
|
||||
|
|
Loading…
Reference in New Issue