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

This commit is contained in:
shilixia 2021-11-03 11:27:23 +08:00
commit d5336df9fc
59 changed files with 619 additions and 388 deletions

View File

@ -2,8 +2,8 @@
ENV = 'development'
# base api
#VUE_APP_BASE_API = 'http://127.0.0.1:8000/api'
VUE_APP_BASE_API = 'http://47.95.0.242:2222/api'
VUE_APP_BASE_API = 'http://127.0.0.1:8000/api'
#VUE_APP_BASE_API = 'http://47.95.0.242:2222/api'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,

View File

@ -67,13 +67,13 @@ export default {
if (hasToken) {
this.$store.dispatch("user/getCount", {});
}
this.timer = window.setInterval(() => {
/*this.timer = window.setInterval(() => {
setTimeout(() => {
if (hasToken) {
this.$store.dispatch("user/getCount", {});
}
},0)
},5000)
},5000)*/
},
methods: {
handleClickOutside() {

View File

@ -62,7 +62,7 @@ div:focus {
// main-container global css
.app-container {
padding: 10px;
padding: 2px;
}
.el-table--medium td,   .el-table--medium th {

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增设备</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="equipmentList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增设备</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="equipmentList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增校准或检定</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="equipmentrecordList.results"

View File

@ -25,8 +25,8 @@
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<div style="margin-top: 10px">
<el-card style="margin-top: 2px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增物料</el-button
>
@ -153,7 +153,7 @@
</div>
<div>
<el-tooltip class="item" effect="dark" content="添加条件" placement="top">
<el-button @click="addConditions" style='cursor:pointer;width:95%;color:#fe000c;border:1px dashed #fe000c;height:40px;padding:0px;margin-top:10px;margin-left:20px;font-size:26px'>
<el-button @click="addConditions" style='cursor:pointer;width:95%;color:#fe000c;border:1px dashed #fe000c;height:40px;padding:0px;margin-top: 2px;margin-left:20px;font-size:26px'>
+
</el-button>
</el-tooltip>

View File

@ -25,7 +25,7 @@
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"

View File

@ -25,7 +25,7 @@
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"

View File

@ -25,7 +25,7 @@
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增仓库</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="warehouseList.results"

View File

@ -1,130 +1,72 @@
<template>
<div class="app-container">
<el-row :gutter="12">
<el-col :span="8">
<el-card>
<div slot="header" class="clearfix">
<span>CPU</span>
</div>
<el-descriptions :column="1" border>
<el-descriptions-item>
<template slot="label"> 逻辑核心数 </template>
{{ cpuData.count }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 物理核心数 </template>
{{ cpuData.lcount }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 当前使用率 </template>
{{ cpuData.percent }}%
</el-descriptions-item>
</el-descriptions>
</el-card>
</el-col>
<el-col :span="8">
<el-card>
<div slot="header" class="clearfix">
<span>内存</span>
</div>
<el-descriptions :column="1" border>
<el-descriptions-item>
<template slot="label"> 总内存 </template>
{{ memoryData.total }}GB
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 已用内存 </template>
{{ memoryData.used }}GB
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 当前使用率 </template>
{{ memoryData.percent }}%
</el-descriptions-item>
</el-descriptions>
</el-card>
</el-col>
<el-col :span="8">
<el-card>
<div slot="header" class="clearfix">
<span>硬盘</span>
</div>
<el-descriptions :column="1" border>
<el-descriptions-item>
<template slot="label"> 总大小 </template>
{{ diskData.total }}GB
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 已用内存 </template>
{{ diskData.used }}GB
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"> 当前使用率 </template>
{{ diskData.percent }}%
</el-descriptions-item>
</el-descriptions>
</el-card>
</el-col>
</el-row>
<div class="box-card">
<el-row :gutter="12">
<el-col :span="8">
<el-card shadow="always">
<div slot="header" class="clearfix">
<span>CPU</span>
</div>
<el-row class="row">
<el-col :span="8">
属性
</el-col>
<el-col :span="8">
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
逻辑核心数
</el-col>
<el-col :span="8">
{{cpuData.count}}
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
物理核心数
</el-col>
<el-col :span="8">
{{cpuData.lcount}}
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
当前使用率
</el-col>
<el-col :span="8">
{{cpuData.percent}}%
</el-col>
</el-row>
</el-card>
</el-col>
<el-col :span="8">
<el-card shadow="always">
<div slot="header" class="clearfix">
<span>内存</span>
</div>
<el-row class="row">
<el-col :span="8">
属性
</el-col>
<el-col :span="8">
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
使用率
</el-col>
<el-col :span="8">
{{memoryData.percent}}%
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
总内存
</el-col>
<el-col :span="8">
{{memoryData.total}}
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
已用内存
</el-col>
<el-col :span="8">
{{memoryData.used}}
</el-col>
</el-row>
</el-card>
</el-col>
<el-col :span="8">
<el-card shadow="always">
<div slot="header" class="clearfix">
<span>硬盘</span>
</div>
<el-row class="row">
<el-col :span="8">
属性
</el-col>
<el-col :span="8">
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
已用百分比
</el-col>
<el-col :span="8">
{{diskData.percent}}%
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
总大小
</el-col>
<el-col :span="8">
{{diskData.total}}
</el-col>
</el-row>
<el-row class="rowlist">
<el-col :span="8">
已用大小
</el-col>
<el-col :span="8">
{{diskData.used}}
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</div>
<el-card class="box-card">
<el-card style="margin-top: 6px">
<div slot="header" class="clearfix">
<span>日志列表</span>
</div>
@ -141,45 +83,33 @@
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索
>搜索
</el-button>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>重置
>重置
</el-button>
</div>
<el-table
:data="tableData"
style="width: 100%;height:400px"
style="width: 100%"
height="100"
v-el-height-adaptive-table="{ bottomOffset: 30 }"
>
<el-table-column
prop="name"
label="日志名称"
>
</el-table-column>
<el-table-column
prop="size"
label="日志大小"
>
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="100"
>
<el-table-column prop="name" label="日志名称"> </el-table-column>
<el-table-column prop="size" label="日志大小"> </el-table-column>
<el-table-column fixed="right" label="操作" width="100">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">查看详情</el-button>
<el-button @click="handleClick(scope.row)" type="text" size="small"
>查看详情</el-button
>
</template>
</el-table-column>
</el-table>
<el-dialog
:visible.sync="dialogVisible"
width="80%"
title="日志详情"
>
<el-dialog :visible.sync="dialogVisible" width="80%" title="日志详情">
<div v-html="logdec" class="dialogDiv"></div>
</el-dialog>
</el-card>
@ -188,121 +118,60 @@
<script>
import {getlogList, getLog, getServerList} from "@/api/moritor";
import { getlogList, getLog, getServerList } from "@/api/moritor";
const defaultCMA = {}
export default {
components: {},
data() {
return {
tableData: [],
cpuData: [],
diskData: [],
memoryData: [],
dialogVisible: false,
logdec: "",
text: "",
listQuery: {},
};
const defaultCMA = {};
export default {
components: {},
data() {
return {
tableData: [],
cpuData: [],
diskData: [],
memoryData: [],
dialogVisible: false,
logdec: "",
text: "",
listQuery: {},
};
},
computed: {},
watch: {},
created() {
this.getlogList();
this.getServerList();
},
methods: {
getlogList() {
getlogList(this.listQuery).then((response) => {
if (response.data) {
this.tableData = response.data;
}
});
},
computed: {},
watch: {},
created() {
handleFilter() {
this.getlogList();
this.getServerList();
},
methods: {
getlogList() {
getlogList(this.listQuery).then((response) => {
if (response.data) {
this.tableData = response.data;
}
});
},
handleFilter() {
this.getlogList();
},
resetFilter() {
this.getlogList();
},
getServerList() {
getServerList().then((response) => {
if (response.data) {
this.cpuData = response.data.cpu;
this.diskData = response.data.disk;
this.memoryData = response.data.memory;
}
});
},
handleClick(row) {
this.dialogVisible = true;
getLog(row.name).then((response) => {
if (response.data) {
this.logdec = response.data.replace(/\n/gm, "<br/>")
}
});
},
resetFilter() {
this.getlogList();
},
};
</script>
<style>
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.2);
background-color: #fefefe;
border-radius: 7px;
}
::-webkit-scrollbar-thumb{
border-radius: 7px;
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.2);
background-color: #f5f5f5;
}
.dialogDiv{
height: 70vh;
overflow-y: scroll;
}
.text {
font-size: 14px;
}
.item {
margin-bottom: 18px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.box-card {
width: 90%;
margin: 0 auto;
margin-top: 30px;
}
.row {
border-bottom: 1px solid #dfe6ec;
color: #909399;
font-weight: 500;
padding: 10px;
}
.rowlist {
border-bottom: 1px solid #dfe6ec;
color: #606266;
font-weight: 500;
padding: 10px;
}
</style>
getServerList() {
getServerList().then((response) => {
if (response.data) {
this.cpuData = response.data.cpu;
this.diskData = response.data.disk;
this.memoryData = response.data.memory;
}
});
},
handleClick(row) {
this.dialogVisible = true;
getLog(row.name).then((response) => {
if (response.data) {
this.logdec = response.data.replace(/\n/gm, "<br/>");
}
});
},
},
};
</script>

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增物料</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="materialList.results"

View File

@ -2,13 +2,13 @@
<div class="app-container">
<el-card>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增工序</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="processList.results"

View File

@ -21,7 +21,7 @@
<el-row :gutter="24">
<el-col :span="6" >
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增</el-button>
<el-table

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增供应商</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="vendorList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增标准</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="standardList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增项目</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="testitemList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增客户</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="contractList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增客户</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="customerList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增订单</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="orderList.results"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增客户</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="contractList.results"

View File

@ -16,7 +16,7 @@
highlight-current
:expand-on-click-node="false"
:filter-node-method="filterNode"
style="margin-top:10px;"
style="margin-top: 2px;"
@node-click="handleDictTypeClick"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
@ -52,7 +52,7 @@
v-show="listQuery.type"
v-loading="listLoading"
:data="dictList"
style="width: 100%;margin-top:10px;"
style="width: 100%;margin-top: 2px;"
highlight-current-row
row-key="id"
height="100"

View File

@ -41,7 +41,7 @@
<el-table
v-loading="listLoading"
:data="fileList.results"
style="width: 100%;margin-top:10px;"
style="width: 100%;margin-top: 2px;"
highlight-current-row
row-key="id"
height="100"

View File

@ -25,7 +25,7 @@
!search || data.name.toLowerCase().includes(search.toLowerCase())
)
"
style="width: 100%; margin-top: 10px"
style="width: 100%; margin-top: 2px"
highlight-current-row
row-key="id"
height="100"

View File

@ -24,7 +24,7 @@
!search || data.name.toLowerCase().includes(search.toLowerCase())
)
"
style="width: 100%; margin-top: 10px"
style="width: 100%; margin-top: 2px"
highlight-current-row
row-key="id"
height="100"

View File

@ -25,7 +25,7 @@
!search || data.name.toLowerCase().includes(search.toLowerCase())
)
"
style="width: 100%; margin-top: 10px"
style="width: 100%; margin-top: 2px"
highlight-current-row
row-key="id"
height="100"

View File

@ -20,7 +20,7 @@
<el-table
v-loading="listLoading"
:data="tableData"
style="width: 100%; margin-top: 10px"
style="width: 100%; margin-top: 2px"
highlight-current-row
row-key="id"
height="100"

View File

@ -53,7 +53,7 @@
<el-table
v-loading="listLoading"
:data="dataList.results"
style="width: 100%; margin-top: 10px"
style="width: 100%; margin-top: 2px"
highlight-current-row
row-key="id"
height="100"

View File

@ -2,13 +2,13 @@
<div class="app-container">
<el-card>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
:data="customfieldList"

View File

@ -24,11 +24,11 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate">新增</el-button>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="workflowList.results"

View File

@ -1,12 +1,12 @@
<template>
<div class="app-container">
<el-card>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate">新增
</el-button>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
:data="wfstateList"
style="width: 100%"
@ -166,7 +166,7 @@
</el-form-item>
<el-form-item label="字段状态">
<el-button @click="addWordStatusChange">添加修改</el-button>
<el-row v-for="(item,$index) in statusChange" :key="item+$index" style="margin-top: 10px">
<el-row v-for="(item,$index) in statusChange" :key="item+$index" style="margin-top: 2px">
<el-col :span="11">
<el-select style="width: 100%" v-model="item.name" placeholder="请选择字段">
<el-option v-for="item in customfieldList" :key="item.id" :label="item.field_name"

View File

@ -23,7 +23,7 @@
@click="handleFilter"
>搜索</el-button>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate">新增</el-button>
</div>
</el-card>

View File

@ -2,13 +2,13 @@
<div class="app-container">
<el-card>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
:data="wftransitionList"
style="width: 100%"

View File

@ -24,13 +24,13 @@
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<div style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增项目</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="testitemList.results"

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.6 on 2021-11-02 01:35
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0002_auto_20211029_1336'),
('inm', '0007_auto_20211028_1331'),
]
operations = [
migrations.AddField(
model_name='iproduct',
name='wproduct',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联的动态产品'),
),
migrations.AlterField(
model_name='materialbatch',
name='batch',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='批次号'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.6 on 2021-11-02 03:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inm', '0008_auto_20211102_0935'),
]
operations = [
migrations.AddField(
model_name='fifo',
name='is_audited',
field=models.BooleanField(default=False, verbose_name='是否审核'),
),
migrations.AddField(
model_name='fifodetail',
name='is_tested',
field=models.BooleanField(default=False, verbose_name='是否检测'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.6 on 2021-11-02 08:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inm', '0009_auto_20211102_1113'),
]
operations = [
migrations.AddField(
model_name='fifodetail',
name='is_testok',
field=models.BooleanField(default=False, verbose_name='是否检测合格'),
),
migrations.AlterField(
model_name='fifodetail',
name='is_tested',
field=models.BooleanField(default=False, verbose_name='是否已检测'),
),
]

View File

@ -41,7 +41,7 @@ class MaterialBatch(BaseModel):
material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息')
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
count = models.IntegerField('存量', default=0)
batch = models.CharField('批次号', max_length=100, null=True, blank=True, unique=True)
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
expiration_date = models.DateField('有效期', null=True, blank=True)
class Meta:
verbose_name = '库存表'
@ -60,6 +60,7 @@ class FIFO(CommonAModel):
(4, '生产入库')
)
type = models.IntegerField('出入库类型', default=1)
is_audited = models.BooleanField('是否审核', default=False)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库')
operator = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.DO_NOTHING, null=True, blank=True)
@ -71,6 +72,8 @@ class FIFODetail(BaseModel):
"""
出入库详细记录
"""
is_tested = models.BooleanField('是否已检测', default=False)
is_testok = models.BooleanField('是否检测合格', default=False)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
count = models.IntegerField('数量', default=0)
batch = models.CharField('批次号', max_length=100, null=True, blank=True)

View File

@ -83,9 +83,10 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
for i in details:
# 校验批次
try:
obj = MaterialBatch.objects.get(batch=i['batch'])
if obj.warehouse != validated_data['warehouse']:
raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch']))
if i['batch']:
obj = MaterialBatch.objects.get(batch=i['batch'], material=i['material'])
if obj.warehouse != validated_data['warehouse']:
raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch']))
except:
pass

View File

@ -1,35 +1,38 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from apps.inm.models import FIFODetail, Inventory, MaterialBatch
from apps.inm.models import Inventory, MaterialBatch, FIFO, FIFODetail
@receiver(post_save, sender=FIFODetail)
def update_by_fifodetail(sender, instance, created, **kwargs):
if created:
fifo = instance.fifo
material = instance.material
warehouse = fifo.warehouse
if fifo.type in [3]: # 采购入库
# 更新相关表
def update_inm(instance:FIFO, type:int=1):
"""
更新库存(正反)
"""
warehouse = instance.warehouse
if instance.type in [3]: # 采购入库
# 更新相关表
for i in FIFODetail.objects.filter(fifo=instance):
material = i.material
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
defaults={'material':material, 'warehouse':warehouse, 'count':0})
o1.count = o1.count + instance.count
o1.count = o1.count + i.count
o1.save()
o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=instance.batch,\
defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':instance.batch})
o2.count = o2.count + instance.count
o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch,\
defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':i.batch})
o2.count = o2.count + i.count
o2.save()
material.count = material.count + instance.count
material.count = material.count + i.count
material.save()
elif fifo.type in [1]: # 生产领料
# 更新相关表
elif instance.type in [1]: # 生产领料
# 更新相关表
for i in FIFODetail.objects.filter(fifo=instance):
material = i.material
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
o1.count = o1.count - instance.count
o1.count = o1.count - i.count
o1.save()
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=instance.batch)
o2.count = o2.count - instance.count
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
o2.count = o2.count - i.count
o2.save()
material.count = material.count - instance.count
material.count = material.count - i.count
material.save()

View File

@ -1,11 +1,13 @@
from django.shortcuts import render
from rest_framework import serializers
from rest_framework.exceptions import APIException
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.filters import MbFilterSet
from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse,Inventory
from apps.inm.serializers import FIFODetailSerializer, FIFOInPurSerializer, FIFOListSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
from apps.inm.signals import update_inm
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
from rest_framework.response import Response
@ -72,7 +74,7 @@ class FIFODetailViewSet(ListModelMixin, GenericViewSet):
search_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
class FIFOViewSet(ListModelMixin, GenericViewSet):
"""
出入库记录
@ -80,7 +82,10 @@ class FIFOViewSet(ListModelMixin, GenericViewSet):
perms_map = {'*': '*'}
queryset = FIFO.objects.select_related('warehouse', 'operator')
serializer_class = FIFOListSerializer
filterset_fields = ['warehouse', 'type']
filterset_fields = '__all__'
ordering_fields = '__all__'
search_fields = ['warehouse__name', 'warehouse__number']
ordering = ['-pk']
def get_serializer_class(self):
if self.action == 'list':
@ -96,4 +101,18 @@ class FIFOViewSet(ListModelMixin, GenericViewSet):
serializer.is_valid(raise_exception=True)
serializer.save(create_by=request.user)
return Response()
@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 FIFODetail.objects.filter(fifo=obj):
if not i.is_testok:
raise APIException('未检验通过, 不可审核')
obj.is_audited = True
obj.save()
update_inm(obj) # 更新库存
return Response()

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-11-02 08:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0026_auto_20211101_1522'),
]
operations = [
migrations.AlterField(
model_name='recordformfield',
name='need_judge',
field=models.BooleanField(default=False, verbose_name='需要判定项目'),
),
]

View File

@ -0,0 +1,40 @@
# Generated by Django 3.2.6 on 2021-11-02 09:07
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('mtm', '0027_alter_recordformfield_need_judge'),
]
operations = [
migrations.CreateModel(
name='SubprodctionMaterial',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('is_main', models.BooleanField(default=False, verbose_name='是否主产出')),
('count', models.FloatField(default=0, verbose_name='消耗量/产出量')),
('type', models.IntegerField(default=1, verbose_name='物料应用类型')),
('sort', models.IntegerField(default=1, verbose_name='排序号')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subprodctionmaterial_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subplan_material', to='mtm.material', verbose_name='物料')),
('subproduction', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.subproduction', verbose_name='关联生产分解')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subprodctionmaterial_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.DeleteModel(
name='SubplanMaterial',
),
]

View File

@ -88,6 +88,7 @@ class RecordForm(CommonAModel):
type = models.IntegerField('表格类型', choices=type_choices, default=1)
step = models.ForeignKey(Step, verbose_name='关联子工序', on_delete=models.CASCADE, null=True, blank=True)
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE, null=True, blank=True)
class Meta:
verbose_name = '记录表格'
verbose_name_plural = verbose_name
@ -130,7 +131,7 @@ class RecordFormField(CommonAModel):
field_choice = models.JSONField('radio、checkbox、select的选项', default=dict, blank=True, null=True,
help_text='radio,checkbox,select,multiselect类型可供选择的选项格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
sort = models.IntegerField('排序号', default=1)
need_judge = models.BooleanField('需要判定', default=False)
need_judge = models.BooleanField('需要判定项目', default=False)
high_limit = models.FloatField('上限值', null=True, blank=True)
high_rule = models.IntegerField('上限规则', choices=high_rule_choices, null=True, blank=True)
low_limit = models.FloatField('下限值', null=True, blank=True)
@ -159,7 +160,7 @@ class SubProduction(CommonAModel):
verbose_name = '产品生产工序'
verbose_name_plural = verbose_name
class SubplanMaterial(CommonAModel):
class SubprodctionMaterial(CommonAModel):
"""
输入/输出物料/工具工装
"""
@ -170,7 +171,7 @@ class SubplanMaterial(CommonAModel):
)
material = models.ForeignKey(Material, verbose_name='物料', on_delete=models.CASCADE, related_name='subplan_material')
is_main = models.BooleanField('是否主产出', default=False) # 以该产品完成度计算进度
count = models.FloatField('消耗量/产出量', default=1)
count = models.FloatField('消耗量/产出量', default=0)
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
type = models.IntegerField('物料应用类型', default=1)
sort = models.IntegerField('排序号', default=1)

View File

@ -1,7 +1,7 @@
from apps.em.serializers import EquipmentSimpleSerializer
from rest_framework import serializers
from rest_framework.exceptions import ParseError, ValidationError
from .models import Material, Process, RecordForm, RecordFormField, Step, SubplanMaterial, TechDoc, UsedStep, SubProduction
from .models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
from apps.system.serializers import FileSimpleSerializer, OrganizationSimpleSerializer
@ -69,53 +69,53 @@ class SubProductionSerializer(serializers.ModelSerializer):
class OtherMaterialSerializer(serializers.ModelSerializer):
class Meta:
model = SubplanMaterial
model = SubprodctionMaterial
fields = ['sort', 'material', 'subproduction']
def create(self, validated_data):
if SubplanMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=3).exists():
if SubprodctionMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=3).exists():
raise ValidationError('该物料已存在')
validated_data['type']=3
return super().create(validated_data)
class SubplanMaterialListSerializer(serializers.ModelSerializer):
class SubprodctionMaterialListSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
class Meta:
model = SubplanMaterial
model = SubprodctionMaterial
fields = '__all__'
class InputMaterialSerializer(serializers.ModelSerializer):
class Meta:
model = SubplanMaterial
model = SubprodctionMaterial
fields = ['count', 'sort', 'material', 'subproduction']
def create(self, validated_data):
if SubplanMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=1).exists():
if SubprodctionMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=1).exists():
raise ValidationError('该物料已存在')
validated_data['type']=1
return super().create(validated_data)
class InputMaterialUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = SubplanMaterial
model = SubprodctionMaterial
fields = ['count', 'sort']
class OutputMaterialSerializer(serializers.ModelSerializer):
class Meta:
model = SubplanMaterial
model = SubprodctionMaterial
fields = ['count', 'sort', 'material', 'subproduction', 'is_main']
def create(self, validated_data):
if SubplanMaterial.objects.filter(subproduction=validated_data['subproduction'], is_deleted=False, is_main=True, type=2).exists():
if SubprodctionMaterial.objects.filter(subproduction=validated_data['subproduction'], is_deleted=False, is_main=True, type=2).exists():
raise ValidationError('主产出只能有1个')
if SubplanMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=2).exists():
if SubprodctionMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=2).exists():
raise ValidationError('该物料已存在')
validated_data['type']=2
return super().create(validated_data)
class OutputMaterialUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = SubplanMaterial
model = SubprodctionMaterial
fields = ['count', 'sort', 'is_main']
@ -151,6 +151,11 @@ class UsedStepListSerializer(serializers.ModelSerializer):
queryset = queryset.select_related('step')
return queryset
class RecordFormSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = RecordForm
fields = ['id', 'name']
class RecordFormSerializer(serializers.ModelSerializer):
step_ = StepSimpleSerializer(source='step', read_only=True)
material_ = MaterialSimpleSerializer(source='material', read_only=True)
@ -182,6 +187,26 @@ class RecordFormFieldSerializer(serializers.ModelSerializer):
model = RecordFormField
fields = '__all__'
class RecordFormDetailSerializer(serializers.ModelSerializer):
step_ = StepSimpleSerializer(source='step', read_only=True)
material_ = MaterialSimpleSerializer(source='material', read_only=True)
form_fields = serializers.SerializerMethodField()
class Meta:
model = RecordForm
fields = '__all__'
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('step', 'material')
return queryset
def get_form_fields(self, obj):
serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False), many=True)
return serializer.data
class RecordFormFieldCreateSerializer(serializers.ModelSerializer):
class Meta:
model = RecordFormField

View File

@ -2,8 +2,8 @@ from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubplanMaterial, TechDoc, UsedStep, SubProduction
from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubplanMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer
from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormDetailSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubprodctionMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
from rest_framework.response import Response
@ -85,14 +85,14 @@ class InputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
输入物料-增删改查
"""
perms_map = {'*':'*'}
queryset = SubplanMaterial.objects.select_related('material').filter(type=1)
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=1)
serializer_class = InputMaterialSerializer
filterset_fields = ['subproduction']
ordering = ['sort', '-create_time']
def get_serializer_class(self):
if self.action == 'list':
return SubplanMaterialListSerializer
return SubprodctionMaterialListSerializer
elif self.action == 'update':
return InputMaterialUpdateSerializer
return InputMaterialSerializer
@ -102,14 +102,14 @@ class OutputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
输出物料-增删改查
"""
perms_map = {'*':'*'}
queryset = SubplanMaterial.objects.select_related('material').filter(type=2)
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=2)
serializer_class = OutputMaterialSerializer
filterset_fields = ['subproduction']
ordering = ['sort', '-create_time']
def get_serializer_class(self):
if self.action == 'list':
return SubplanMaterialListSerializer
return SubprodctionMaterialListSerializer
elif self.action == 'update':
return OutputMaterialUpdateSerializer
return OutputMaterialSerializer
@ -119,14 +119,14 @@ class OtherMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, DestroyModel
其他物料-增删改查
"""
perms_map = {'*':'*'}
queryset = SubplanMaterial.objects.select_related('material').filter(type=3)
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=3)
serializer_class = OutputMaterialSerializer
filterset_fields = ['subproduction']
ordering = ['sort', '-create_time']
def get_serializer_class(self):
if self.action == 'list':
return SubplanMaterialListSerializer
return SubprodctionMaterialListSerializer
return OtherMaterialSerializer
class UsedStepViewSet(OptimizationMixin, CreateModelMixin, DestroyModelMixin, ListModelMixin, UpdateModelMixin, GenericViewSet):
@ -153,12 +153,15 @@ class RecordFormViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet
queryset = RecordForm.objects.all()
filterset_fields = ['step', 'type', 'material']
search_fields = ['name']
ordering='id'
def get_serializer_class(self):
if self.action =='create':
return RecordFormCreateSerializer
elif self.action == 'update':
return RecordFormUpdateSerializer
elif self.action == 'retrieve':
return RecordFormDetailSerializer
return RecordFormSerializer
@action(methods=['get'], detail=True, perms_map={'get':'*'}, pagination_class=None, serializer_class=RecordFormFieldSerializer)
@ -170,6 +173,8 @@ class RecordFormViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet
serializer = self.serializer_class(instance=RecordFormField.objects.filter(form=instance, is_deleted=False), many=True)
return Response(serializer.data)
class RecordFormFieldViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
"""

View File

@ -5,7 +5,7 @@ from apps.em.models import Equipment
from apps.em.serializers import EquipmentSerializer
from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Step, SubProduction, UsedStep
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin
@ -87,7 +87,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
start_date=production_plan.start_date, end_date=production_plan.end_date,
workshop=i.process.workshop, process=i.process, create_by=request.user,
steps = list(steps))
for m in SubProduction.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
SubProductionProgress.objects.create(material=m.material, type=m.type, count=m.count*production_plan.count, subproduction_plan=instance)
production_plan.is_planed=True
production_plan.save()
@ -187,8 +187,9 @@ class ResourceViewSet(GenericViewSet):
res_d_list = []
res = []
for i in rdata:
materials = InputMaterial.objects.filter(subproduction__product__id=i['id'],
subproduction__is_deleted=False, is_deleted=False, material__type__in=[3,4]).order_by('material__number')\
# 计算输入物料
materials = SubprodctionMaterial.objects.filter(subproduction__product__id=i['id'],
subproduction__is_deleted=False, is_deleted=False, material__type__in=[3,4], type=1).order_by('material__number')\
.values('material__id', 'material__name', 'material__number', 'material__type', 'count', 'material__count')
l_m = list(materials)
for m in l_m:

View File

@ -0,0 +1,17 @@
# Generated by Django 3.2.6 on 2021-11-02 08:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('pum', '0002_vendor_material'),
]
operations = [
migrations.RemoveField(
model_name='vendor',
name='material',
),
]

View File

@ -18,7 +18,6 @@ class Vendor(CommonAModel):
contact_phone = models.CharField('联系电话', max_length=11, unique=True)
address = models.CharField('地址', max_length=200, null=True, blank=True)
description = models.CharField('描述', max_length=200, blank=True, null=True)
material = models.CharField('供应的物料', max_length=200, blank=True, null=True)
class Meta:
verbose_name = '供应商信息'
verbose_name_plural = verbose_name

View File

@ -0,0 +1,37 @@
# Generated by Django 3.2.6 on 2021-11-02 08:31
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('inm', '0010_auto_20211102_1631'),
('mtm', '0027_alter_recordformfield_need_judge'),
('qm', '0002_alter_analysisitem_rules'),
]
operations = [
migrations.CreateModel(
name='TestRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('record_data', models.JSONField(blank=True, default=dict, verbose_name='记录数据')),
('is_testok', models.BooleanField(default=True, verbose_name='是否合格')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('fifo_detail', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='inm.fifodetail', verbose_name='关联的出入库批次')),
('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.recordform', verbose_name='所用表格')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
]

View File

@ -38,4 +38,15 @@ class AnalysisItem(CommonAModel):
rules =models.JSONField('判定规则', default=list)
class Meta:
verbose_name = '检验分析项'
verbose_name = '检验分析项'
class TestRecord(CommonAModel):
"""
检验记录
"""
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
record_data = models.JSONField('记录数据', default=dict, blank=True)
is_testok = models.BooleanField('是否合格', default=True)
fifo_detail = models.ForeignKey('inm.fifodetail', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True)

View File

@ -1,6 +1,8 @@
from rest_framework import serializers
from apps.mtm.models import RecordForm, RecordFormField
from apps.mtm.serializers import RecordFormFieldSerializer, RecordFormSimpleSerializer
from apps.system.serializers import FileSimpleSerializer
from .models import Standard, TestItem
from .models import Standard, TestItem, TestRecord
class StandardCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
@ -31,3 +33,41 @@ class TestItemSerializer(serializers.ModelSerializer):
class AnalysisItemSerializer(serializers.ModelSerializer):
pass
class TestRecordCreateSerializer(serializers.ModelSerializer):
class Meta:
model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'fifo_detail']
def create(self, validated_data):
if 'is_testok' not in validated_data:
raise serializers.ValidationError('未填写检测结论')
return super().create(validated_data)
class TestRecordListSerializer(serializers.ModelSerializer):
class Meta:
model = TestRecord
fields = '__all__'
class TestRecordDetailSerializer(serializers.ModelSerializer):
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
record_data_ = serializers.SerializerMethodField()
class Meta:
model = TestRecord
fields = '__all__'
@staticmethod
def setup_eager_loading(queryset):
queryset = queryset.select_related('form','fifo_detail')
return queryset
def get_record_data_(self, obj):
record_data = obj.record_data
all_fields = RecordFormField.objects.filter(form=obj.form, is_deletd=False).order_by('sort')
all_fields_l = RecordFormFieldSerializer(instance=all_fields, many=True).data
for i in all_fields_l:
key = i['field_key']
i['field_value'] = record_data.get(key, None)
return all_fields_l

View File

@ -1,4 +1,4 @@
from apps.qm.views import StandardViewSet, TestItemViewSet
from apps.qm.views import StandardViewSet, TestItemViewSet, TestRecordViewSet
from django.db.models import base
from rest_framework import urlpatterns
from django.urls import path, include
@ -7,6 +7,7 @@ from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('standard', StandardViewSet, basename='standard')
router.register('testitem', TestItemViewSet, basename='testitem')
router.register('testrecord', TestRecordViewSet, basename='testrecord')
urlpatterns = [
path('', include(router.urls)),
]

View File

@ -1,5 +1,5 @@
from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer
from apps.qm.models import Standard, TestItem
from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer, TestRecordCreateSerializer, TestRecordDetailSerializer, TestRecordListSerializer
from apps.qm.models import Standard, TestItem, TestRecord
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from apps.system.mixins import CreateUpdateModelAMixin
@ -37,3 +37,29 @@ class TestItemViewSet(CreateUpdateModelAMixin, ModelViewSet):
if self.action in ['create', 'update']:
return TestItemCreateUpdateSerializer
return TestItemSerializer
class TestRecordViewSet(ModelViewSet):
"""
检测记录
"""
perms_map = {'*': '*'}
queryset = TestRecord.objects.select_related('fifo_detail', 'form').all()
serializer_class = TestRecordListSerializer
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'create':
return TestRecordCreateSerializer
elif self.action == 'list':
return TestRecordListSerializer
elif self.action == 'retrieve':
return TestRecordDetailSerializer
return super().get_serializer_class()
def perform_create(self, serializer):
obj = serializer.save(create_by = self.request.user)
# 如果检测合格
if obj.fifo_detail:
obj.fifo_detail.is_testok = True if obj.is_testok else False
obj.fifo_detail.is_tested = True
obj.fifo_detail.save()

View File

@ -0,0 +1,26 @@
# Generated by Django 3.2.6 on 2021-11-02 01:35
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pm', '0009_auto_20211029_1017'),
('wpm', '0002_auto_20211029_1336'),
]
operations = [
migrations.AddField(
model_name='wproduct',
name='production_plan',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='pm.productionplan', verbose_name='关联主生产计划'),
preserve_default=False,
),
migrations.AlterField(
model_name='wproduct',
name='subproduction_plan',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='当前子生产计划'),
),
]

View File

@ -1,6 +1,7 @@
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse
from apps.inm.signals import update_inm
from apps.mtm.models import Material
from apps.mtm.serializers import MaterialSimpleSerializer
@ -37,28 +38,33 @@ class PickSerializer(serializers.Serializer):
validated_data['operator'] = operator
validated_data['type'] = 1
validated_data['inout_date'] = timezone.now()
fifo = FIFO.objects.create(validated_data)
fifo = FIFO.objects.create(**validated_data)
for i in picks:
# 更新出库详情
i['fifo'] = fifo
i['count'] = i.pop('pick_count')
FIFODetail.objects.create(**i)
# 更新车间物料
wm = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
process=validated_data['process'],defaults={
wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
process=sp.process,defaults={
'material':i['material'],
'batch':i['batch'],
'process':validated_data['process'],
'workshop':validated_data['workshop'],
'process':sp.process,
'workshop':sp.workshop,
'count':0
})
wm.count = wm.count + i['pick_count']
wm.count = wm.count + i['count']
wm.save()
# 更新子计划进度
# 更新子计划物料情况
spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1)
spp.count_real = spp.count_real + i['pick_count']
spp.count_real = spp.count_real + i['count']
spp.save()
sp.is_picked=True
sp.save()
# 更新库存
fifo.is_audited = True
fifo.save()
update_inm(fifo)
return fifo
class WMaterialListSerializer(serializers.ModelSerializer):
@ -67,5 +73,5 @@ class WMaterialListSerializer(serializers.ModelSerializer):
"""
material_ = MaterialSimpleSerializer(source='material', read_only=True)
class Meta:
model = Material
model = WMaterial
fields = '__all__'

View File

@ -31,4 +31,10 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
serializer= PickSerializer(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
serializer.save()
return Response()
return Response()
class DoFormInit(CreateAPIView):
"""
生产操作表单创建
"""
perms_map={'*':'*'}

View File

@ -0,0 +1,6 @@
from rest_framework.viewsets import GenericViewSet
class MyGenericViewSet(GenericViewSet):
filterset_fields = '__all__'
ordering_fields = '__all__'
ordering = ['-pk']