caihgudingdan
This commit is contained in:
commit
efdc534a02
|
@ -153,8 +153,7 @@ export const asyncRoutes = [
|
|||
meta: { title: '产品管理', icon: 'example', perms: ['mtm_productprocess'] }
|
||||
},
|
||||
]
|
||||
}
|
||||
,
|
||||
},
|
||||
{
|
||||
path: '/pm',
|
||||
component: Layout,
|
||||
|
@ -208,8 +207,7 @@ export const asyncRoutes = [
|
|||
}
|
||||
|
||||
]
|
||||
}
|
||||
,
|
||||
},
|
||||
{
|
||||
path: '/wpm',
|
||||
component: Layout,
|
||||
|
@ -339,8 +337,7 @@ export const asyncRoutes = [
|
|||
hidden: true
|
||||
}
|
||||
]
|
||||
}
|
||||
,
|
||||
},
|
||||
{
|
||||
path: '/qm',
|
||||
component: Layout,
|
||||
|
@ -407,7 +404,6 @@ export const asyncRoutes = [
|
|||
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/personnel',
|
||||
component: Layout,
|
||||
|
@ -435,8 +431,7 @@ export const asyncRoutes = [
|
|||
},
|
||||
|
||||
]
|
||||
}
|
||||
,
|
||||
},
|
||||
{
|
||||
path: '/inm',
|
||||
component: Layout,
|
||||
|
@ -492,36 +487,74 @@ export const asyncRoutes = [
|
|||
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
path: '/procurement',
|
||||
component: Layout,
|
||||
redirect: '/procurement/vendor',
|
||||
name: 'procurement',
|
||||
meta: { title: '采购管理', icon: 'example', perms: ['procurement_set'] },
|
||||
children: [
|
||||
{
|
||||
path: 'vendor',
|
||||
name: 'vendor',
|
||||
component: () => import('@/views/procurement/vendor'),
|
||||
meta: { title: '供应商', icon: 'example', perms: ['vendor_manage'] }
|
||||
},
|
||||
{
|
||||
path: 'puorder',
|
||||
name: 'puorder',
|
||||
component: () => import('@/views/procurement/puorder'),
|
||||
meta: { title: '采购订单', icon: 'example', perms: ['vendor_manage'] }
|
||||
},
|
||||
{
|
||||
path: 'puorderitem/:id',
|
||||
name: 'puorderitem',
|
||||
component: () => import('@/views/procurement/puorderitem'),
|
||||
meta: { title: '采购订单项', perms: ['vendor_manage'] },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/procurement',
|
||||
component: Layout,
|
||||
redirect: '/procurement/vendor',
|
||||
name: 'procurement',
|
||||
meta: { title: '采购管理', icon: 'example', perms: ['procurement_set'] },
|
||||
children: [
|
||||
{
|
||||
path: 'vendor',
|
||||
name: 'vendor',
|
||||
component: () => import('@/views/procurement/vendor'),
|
||||
meta: { title: '供应商', icon: 'example', perms: ['vendor_manage'] }
|
||||
},
|
||||
{
|
||||
path: 'puorder',
|
||||
name: 'puorder',
|
||||
component: () => import('@/views/procurement/puorder'),
|
||||
meta: { title: '采购订单', icon: 'example', perms: ['vendor_manage'] }
|
||||
},
|
||||
{
|
||||
path: 'puorderitem/:id',
|
||||
name: 'puorderitem',
|
||||
component: () => import('@/views/procurement/puorderitem'),
|
||||
meta: { title: '采购订单项', perms: ['vendor_manage'] },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/statistics',
|
||||
component: Layout,
|
||||
redirect: '/statistics/progressStatistics',
|
||||
name: 'statistics',
|
||||
meta: { title: '统计分析', icon: 'example', perms: ['workflow_manage'] },
|
||||
children: [
|
||||
{
|
||||
path: 'progressStatistics',
|
||||
name: 'progressStatistics',
|
||||
component: () => import('@/views/statistics/progressStatistics'),
|
||||
meta: { title: '进度统计', icon: 'example', perms: ['workflow_index'] }
|
||||
},
|
||||
{
|
||||
path: 'materialStatistics',
|
||||
name: 'materialStatistics',
|
||||
component: () => import('@/views/statistics/materialStatistics'),
|
||||
meta: { title: '物料统计', icon: 'example', perms: ['workflow_index'] }
|
||||
},
|
||||
{
|
||||
path: 'personStatistics',
|
||||
name: 'personStatistics',
|
||||
component: () => import('@/views/statistics/personStatistics'),
|
||||
meta: { title: '人员统计', icon: 'example', perms: ['workflow_index'] }
|
||||
},
|
||||
{
|
||||
path: 'costStatistics',
|
||||
name: 'costStatistics',
|
||||
component: () => import('@/views/statistics/costStatistics'),
|
||||
meta: { title: '成本统计', icon: 'example', perms: ['workflow_index'] }
|
||||
},
|
||||
{
|
||||
path: 'testStatistics',
|
||||
name: 'testStatistics',
|
||||
component: () => import('@/views/statistics/testStatistics'),
|
||||
meta: { title: '检验统计', icon: 'example', perms: ['workflow_index'] }
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/workflow',
|
||||
component: Layout,
|
||||
|
@ -707,6 +740,12 @@ export const asyncRoutes = [
|
|||
component: () => import('@/views/testModel/faceLogin'),
|
||||
meta: { title: '人脸识别登录', icon: 'example' }
|
||||
},
|
||||
{
|
||||
path: 'caram',
|
||||
name: 'caram',
|
||||
component: () => import('@/views/testModel/caram'),
|
||||
meta: { title: '相机调用', icon: 'example' }
|
||||
},
|
||||
{
|
||||
path: 'markImage',
|
||||
name: 'markImage',
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<el-input
|
||||
v-model="listQuery.search"
|
||||
placeholder="采购订单编号、供应商名称"
|
||||
placeholder="供应商名称"
|
||||
style="width: 300px"
|
||||
class="filter-item"
|
||||
@keyup.enter.native="handleFilter"
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<div :id="id" :class="className" style="width: 100%!important;" :style="{ height: height, width: width }"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "charts",
|
||||
props: {
|
||||
className: {
|
||||
type: String,
|
||||
default: 'chart'
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: 'chart'
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '2.5rem'
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
handler(options) {
|
||||
this.chart.setOption(options, true)
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initChart();
|
||||
/*window.addEventListener("resize",function () {
|
||||
this.chart = this.$echarts.init(document.getElementById(this.id));
|
||||
let myCharts=document.getElementById(this.id); // 增加这一行
|
||||
myCharts.style.width=window.innerWidth-400+ 'px'; // 再增加这一行
|
||||
this.$echarts.init(document.getElementById(this.id)).resize();
|
||||
})*/
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.chart.dispose();
|
||||
this.chart = null
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
this.chart = this.$echarts.init(document.getElementById(this.id));
|
||||
this.chart.setOption(this.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chartsName{
|
||||
width: 100%!important;
|
||||
}
|
||||
</style>
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "largeScreen"
|
||||
name: "costStatistics"
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,364 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
|
||||
<el-tab-pane label="废料统计" name="废料统计">
|
||||
<el-row :gutter="5">
|
||||
<el-col :span="3" style="height: 1px"></el-col>
|
||||
<el-col :span="5">
|
||||
<div class="chartsTitle">废料原因占比</div>
|
||||
<Echart
|
||||
:options="pieOptions"
|
||||
id="pieChart"
|
||||
height="400px"
|
||||
width="260px"
|
||||
></Echart>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<div class="chartsTitle">废料原因统计</div>
|
||||
<div id="barChart" style="width:100%;height: 400px;"></div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div style="padding: 20px;">
|
||||
<div class="chartsTitle">废料明细表</div>
|
||||
<el-table
|
||||
small
|
||||
:data="list"
|
||||
fit stripe
|
||||
size="mini"
|
||||
pager-count="3"
|
||||
style="border-top: 1px solid #f5f5f5;"
|
||||
>
|
||||
<el-table-column label="序号" type="index">
|
||||
</el-table-column>
|
||||
<el-table-column label="物料编号" prop="card">
|
||||
</el-table-column>
|
||||
<el-table-column label="物料型号" prop="sco">
|
||||
</el-table-column>
|
||||
<el-table-column label="物料名称" prop="name" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="报废原因" prop="reason">
|
||||
</el-table-column>
|
||||
<el-table-column label="报废数量" prop="num">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="采购统计" name="采购统计">
|
||||
<el-row :gutter="5" v-if="activeName==='采购统计'">
|
||||
<el-col :span="2" style="height: 1px;"></el-col>
|
||||
<el-col :span="10">
|
||||
<div class="chartsTitle">采购物料表</div>
|
||||
<charts
|
||||
:id="chartId1"
|
||||
:options="barOptions"
|
||||
:className="chartsName"
|
||||
height="400px"
|
||||
width="600px"
|
||||
>
|
||||
</charts>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<div class="chartsTitle">采购供应商表</div>
|
||||
<charts
|
||||
:id="chartId2"
|
||||
:options="barOptions"
|
||||
:className="chartsName"
|
||||
height="400px"
|
||||
width="600px"
|
||||
>
|
||||
</charts>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div style="padding: 20px">
|
||||
<div class="chartsTitle">采购明细表</div>
|
||||
<el-table
|
||||
small
|
||||
:data="list"
|
||||
fit stripe
|
||||
size="mini"
|
||||
pager-count="3"
|
||||
style="border-top: 1px solid #f5f5f5;"
|
||||
>
|
||||
<el-table-column label="序号" type="index" width="50">
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" prop="name" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="数量" prop="num" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" prop="name" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="供应商" prop="sco" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="废料来源" name="废料来源">
|
||||
<el-row>
|
||||
<el-col v-if="activeName==='废料来源'">
|
||||
<div class="chartsTitle">废料来源</div>
|
||||
<charts
|
||||
:id="chartId3"
|
||||
:options="barOptions"
|
||||
:className="chartsName"
|
||||
height="400px"
|
||||
>
|
||||
</charts>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div style="padding: 20px;">
|
||||
<div class="chartsTitle">废料来源明细表</div>
|
||||
<el-table
|
||||
small
|
||||
:data="list"
|
||||
fit stripe
|
||||
size="mini"
|
||||
pager-count="3"
|
||||
style="border-top: 1px solid #f5f5f5;"
|
||||
>
|
||||
<el-table-column label="序号" type="index">
|
||||
</el-table-column>
|
||||
<el-table-column label="编号" prop="card">
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" prop="name" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="数量" prop="num">
|
||||
</el-table-column>
|
||||
<el-table-column label="供应商" prop="sco" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import charts from './charts.vue'
|
||||
import Echart from '@/components/echart';
|
||||
export default {
|
||||
name: "materialStatistics",
|
||||
components: {
|
||||
charts,
|
||||
Echart
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chartId1:'chart1',
|
||||
chartId2:'chart2',
|
||||
chartId3:'chart3',
|
||||
barChart:null,
|
||||
barChart1:null,
|
||||
pieOptions: {},
|
||||
barOptions: {},
|
||||
activeName:'废料统计',
|
||||
chartsName:"chartsName",
|
||||
cdata: {
|
||||
xData: ["气泡", "划痕"],
|
||||
seriesData: [
|
||||
{value: 30, name: "气泡"},
|
||||
{value: 70, name: "划痕"},
|
||||
]
|
||||
},
|
||||
chartData: {
|
||||
xAxisData: ["气泡", "划痕"],
|
||||
seriesData: [30, 70],
|
||||
},
|
||||
xAxisbar:["供应商1", "供应商2", "供应商3", "供应商4", "供应商5", "供应商6", "供应商7"],
|
||||
barData: [80, 95, 96, 96, 96, 98, 99],
|
||||
list: [
|
||||
{id: 1, name: 'HIehd91', card: '3331', sco: 'REF-31',num:2,reason:"气泡"},
|
||||
{id: 2, name: 'HIehd92', card: '3332', sco: 'REF-32',num:1,reason:"划痕"},
|
||||
{id: 3, name: 'HIehd93', card: '3333', sco: 'REF-33',num:3,reason:"擦伤"},
|
||||
{id: 4, name: 'HIehd94', card: '3334', sco: 'REF-34',num:2,reason:"气泡"},
|
||||
{id: 5, name: 'HIehd95', card: '3335', sco: 'REF-35',num:1,reason:"擦伤"},
|
||||
{id: 6, name: 'HIehd96', card: '3336', sco: 'REF-36',num:2,reason:"气泡"},
|
||||
{id: 7, name: 'HIehd97', card: '3337', sco: 'REF-37',num:1,reason:"划痕"},
|
||||
],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
cdata: {
|
||||
handler(newData) {
|
||||
this.pieOptions = {
|
||||
color: [
|
||||
"#32c5e9",
|
||||
"#ffdb5c"
|
||||
],
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b} : {c} ({d}%)"
|
||||
},
|
||||
toolbox: {
|
||||
show: true
|
||||
},
|
||||
calculable: true,
|
||||
series: [
|
||||
{
|
||||
name: '废料原因',
|
||||
type: 'pie', // 设置图表类型为饼图
|
||||
radius: '65%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
|
||||
center: ['50%', '50%'], //圆心位置
|
||||
data:newData.seriesData
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
},
|
||||
methods: {
|
||||
drawChart() {
|
||||
let that = this;
|
||||
this.barChart = this.$echarts.init(document.getElementById('barChart'));
|
||||
this.barChart.setOption({
|
||||
grid: {
|
||||
top: '10%',
|
||||
left: '3%',
|
||||
right: '5%',
|
||||
bottom: '1%',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: function (params) {
|
||||
let color = params.color;//图例颜色
|
||||
let htmlStr = '<div>';
|
||||
htmlStr += params.name + '<br/>';
|
||||
htmlStr += '<span style="height:10px;width:10px;font-size:12px;border-radius:5px;margin-right:5px;font-family:Consolas;display:inline-block;background:' + color + ';"></span>';
|
||||
htmlStr += params.seriesName + ':' + params.value + '%';
|
||||
htmlStr += '</div>';
|
||||
return htmlStr;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false, //去掉X轴分割线
|
||||
},
|
||||
data: that.chartData.xAxisData,
|
||||
},
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: true,//y轴线
|
||||
},
|
||||
axisTick: {
|
||||
show: false//Y轴刻度线
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#333333'//Y轴文本颜色
|
||||
},
|
||||
splitLine: {
|
||||
show: true, //Y轴分割线
|
||||
lineStyle: {
|
||||
color: '#dddddd'//Y轴分割线颜色
|
||||
}
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
name: '成品率',
|
||||
type: 'bar',
|
||||
barWidth: 20,
|
||||
data: that.chartData.seriesData,
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'top', //在上方显示
|
||||
formatter: '{c}%',//显示百分号
|
||||
textStyle: { //数值样式
|
||||
color: 'black',//字体颜色
|
||||
fontSize: 10//字体大小
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#409EFF'
|
||||
},
|
||||
}]
|
||||
});
|
||||
},
|
||||
handleClick(tab){
|
||||
// console.log(tab);
|
||||
// debugger;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.drawChart();
|
||||
this.barOptions ={
|
||||
grid: {
|
||||
top: '10%',
|
||||
left: '3%',
|
||||
right: '5%',
|
||||
bottom: '1%',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: function (params) {
|
||||
let color = params.color;//图例颜色
|
||||
let htmlStr = '<div>';
|
||||
htmlStr += params.name + '<br/>';
|
||||
htmlStr += '<span style="height:10px;width:10px;font-size:12px;border-radius:5px;margin-right:5px;font-family:Consolas;display:inline-block;background:' + color + ';"></span>';
|
||||
htmlStr += params.seriesName + ':' + params.value + '%';
|
||||
htmlStr += '</div>';
|
||||
return htmlStr;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false, //去掉X轴分割线
|
||||
},
|
||||
data: this.xAxisbar,
|
||||
},
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: true,//y轴线
|
||||
},
|
||||
axisTick: {
|
||||
show: false//Y轴刻度线
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#333333'//Y轴文本颜色
|
||||
},
|
||||
splitLine: {
|
||||
show: true, //Y轴分割线
|
||||
lineStyle: {
|
||||
color: '#dddddd'//Y轴分割线颜色
|
||||
}
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
name: '成品率',
|
||||
type: 'bar',
|
||||
barWidth: 20,
|
||||
data: this.barData,
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'top', //在上方显示
|
||||
formatter: '{c}',//显示百分号
|
||||
textStyle: { //数值样式
|
||||
color: 'black',//字体颜色
|
||||
fontSize: 10//字体大小
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#409EFF'
|
||||
},
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chartsTitle{
|
||||
text-align: center;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
font-size: 22px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,13 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "personStatistics"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,175 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="5">
|
||||
<el-col :span="8">
|
||||
<el-card>
|
||||
<Echart
|
||||
:options="pieOptions"
|
||||
id="pieChart"
|
||||
height="400px"
|
||||
width="260px"
|
||||
></Echart>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-card>
|
||||
<charts
|
||||
:id="chartId1"
|
||||
:options="barOptions"
|
||||
:className="chartsName"
|
||||
height="400px"
|
||||
width="600px"
|
||||
>
|
||||
</charts>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-col>
|
||||
<el-card>
|
||||
<charts
|
||||
:id="chartId2"
|
||||
:options="barOptions"
|
||||
:className="chartsName"
|
||||
height="480px"
|
||||
width="100%"
|
||||
>
|
||||
</charts>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import charts from './charts.vue'
|
||||
import Echart from '@/components/echart';
|
||||
export default {
|
||||
name: "progressStatistics",
|
||||
components: {
|
||||
Echart,
|
||||
charts
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chartsName:'barChart',
|
||||
chartId1:'chart1',
|
||||
chartId2:'chart2',
|
||||
pieOptions: {},
|
||||
barOptions: {},
|
||||
cdata: {
|
||||
xData: ["交付率", "逾期率"],
|
||||
seriesData: [
|
||||
{value: 99, name: "交付率"},
|
||||
{value: 1, name: "逾期率"},
|
||||
]
|
||||
},
|
||||
xAxisbar:["冷加工", "热弯", "钢化", "镀膜", "夹层", "包边", "装框"],
|
||||
barData: [80, 95, 96, 96, 96, 98, 99],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
cdata: {
|
||||
handler(newData) {
|
||||
this.pieOptions = {
|
||||
color: [
|
||||
"#32c5e9",
|
||||
"#ffdb5c"
|
||||
],
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b} : {c} ({d}%)"
|
||||
},
|
||||
toolbox: {
|
||||
show: true
|
||||
},
|
||||
calculable: true,
|
||||
series: [
|
||||
{
|
||||
name: '访问来源',
|
||||
type: 'pie', // 设置图表类型为饼图
|
||||
radius: '65%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
|
||||
center: ['50%', '50%'], //圆心位置
|
||||
data:newData.seriesData
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted() {
|
||||
this.barOptions ={
|
||||
grid: {
|
||||
top: '10%',
|
||||
left: '3%',
|
||||
right: '5%',
|
||||
bottom: '1%',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: function (params) {
|
||||
let color = params.color;//图例颜色
|
||||
let htmlStr = '<div>';
|
||||
htmlStr += params.name + '<br/>';
|
||||
htmlStr += '<span style="height:10px;width:10px;font-size:12px;border-radius:5px;margin-right:5px;font-family:Consolas;display:inline-block;background:' + color + ';"></span>';
|
||||
htmlStr += params.seriesName + ':' + params.value + '%';
|
||||
htmlStr += '</div>';
|
||||
return htmlStr;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false, //去掉X轴分割线
|
||||
},
|
||||
data: this.xAxisbar,
|
||||
},
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: true,//y轴线
|
||||
},
|
||||
axisTick: {
|
||||
show: false//Y轴刻度线
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#333333'//Y轴文本颜色
|
||||
},
|
||||
splitLine: {
|
||||
show: true, //Y轴分割线
|
||||
lineStyle: {
|
||||
color: '#dddddd'//Y轴分割线颜色
|
||||
}
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
name: '成品率',
|
||||
type: 'bar',
|
||||
barWidth: 20,
|
||||
data: this.barData,
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'top', //在上方显示
|
||||
formatter: '{c}%',//显示百分号
|
||||
textStyle: { //数值样式
|
||||
color: 'black',//字体颜色
|
||||
fontSize: 10//字体大小
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#409EFF'
|
||||
},
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,13 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "testStatistics"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,117 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-button type="primary" @click="openVideo">打开摄像头</el-button>
|
||||
<el-button @click="closeVideo">关闭摄像头</el-button>
|
||||
<el-button type="danger" @click="screenshot">截图</el-button>
|
||||
<div>
|
||||
<video id="video" ref="video" />
|
||||
</div>
|
||||
<canvas ref="canvas" width="400" height="300" style="display:none" />
|
||||
<!-- 截图展示图片 -->
|
||||
<img ref="screenshot">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "caram",
|
||||
methods:{
|
||||
// 打开摄像头
|
||||
openVideo() {
|
||||
// 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
|
||||
console.log("navigator.mediaDevices", navigator.mediaDevices);
|
||||
if (navigator.mediaDevices === undefined) {
|
||||
navigator.mediaDevices = {};
|
||||
}
|
||||
// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
|
||||
// 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
|
||||
if (navigator.mediaDevices.getUserMedia === undefined) {
|
||||
navigator.mediaDevices.getUserMedia = constraints => {
|
||||
// 首先,如果有getUserMedia的话,就获得它
|
||||
const getUserMedia =
|
||||
navigator.getUserMedia ||
|
||||
(navigator.getUserMedia =
|
||||
navigator.mozGetUserMedia ||
|
||||
navigator.webkitGetUserMedia ||
|
||||
navigator.msGetUserMedia);
|
||||
console.log("getUserMedia", getUserMedia);
|
||||
// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
|
||||
if (!getUserMedia) {
|
||||
return Promise.reject(new Error("该浏览器暂不支持摄像头!"));
|
||||
}
|
||||
// 否则,为老的navigator.getUserMedia方法包裹一个Promise
|
||||
return new Promise((resolve, reject) => {
|
||||
getUserMedia.call(navigator, constraints, resolve, reject);
|
||||
});
|
||||
};
|
||||
}
|
||||
const constraints = {
|
||||
audio: true,
|
||||
video: {
|
||||
width: { ideal: 1280, max: 1920 },
|
||||
height: { ideal: 720, max: 1080 }
|
||||
}
|
||||
};
|
||||
console.log("window.navigator", window.navigator);
|
||||
window.navigator.mediaDevices
|
||||
.getUserMedia(constraints)
|
||||
.then(stream => {
|
||||
const video = this.$refs.video;
|
||||
// 旧的浏览器可能没有srcObject
|
||||
if ("srcObject" in video) {
|
||||
video.srcObject = stream;
|
||||
} else {
|
||||
// 防止在新的浏览器里使用它,因为它已经不再支持了
|
||||
video.src = window.URL.createObjectURL(stream);
|
||||
}
|
||||
video.onloadedmetadata = e => {
|
||||
video.play();
|
||||
};
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err.name + ": " + err.message);
|
||||
});
|
||||
},
|
||||
// 截图
|
||||
screenshot() {
|
||||
// 获取视频
|
||||
const video = this.$refs.video;
|
||||
// 获取截图的地址
|
||||
const screenshot = this.$refs.screenshot;
|
||||
// 获取canvas
|
||||
const canvas = this.$refs.canvas;
|
||||
// 渲染一个2d平面的视图
|
||||
const ctx = canvas.getContext("2d");
|
||||
// 设置canvas 视图文件地址和大小
|
||||
ctx.drawImage(video, 0, 0, 400, 300);
|
||||
// 将数据转为base64赋值给img标签的src属性
|
||||
screenshot.src = canvas.toDataURL("image/png");
|
||||
console.log("screenshot.src", screenshot.src);
|
||||
const imgData = canvas
|
||||
.toDataURL("image/png")
|
||||
.replace("image/png", "image/octet-stream");
|
||||
// 下载图片到本地
|
||||
const save_link = document.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
"a"
|
||||
);
|
||||
save_link.href = imgData;
|
||||
save_link.download = "file_" + new Date().getTime() + ".png";
|
||||
save_link.click();
|
||||
},
|
||||
// 关闭摄像头
|
||||
closeVideo() {
|
||||
console.log("srcObject", this.$refs.video.srcObject);
|
||||
const srcObject = this.$refs.video.srcObject ? this.$refs.video.srcObject.getTracks() : this.$refs.video.src.getTracks()
|
||||
srcObject.forEach(track => {
|
||||
track.stop();
|
||||
this.$refs.video.src = null;
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -2,7 +2,7 @@ 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, UpdateEquipState, UpdateFIFOItem, UpdateLastTestResult, UpdateNeedToOrder, UpdateSpg
|
||||
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateEquipState, UpdateFIFOItem, UpdateFIFONumber, UpdateLastTestResult, UpdateNeedToOrder, UpdateSpg
|
||||
|
||||
urlpatterns = [
|
||||
path('cleandata/', CleanDataView.as_view()),
|
||||
|
@ -12,6 +12,7 @@ urlpatterns = [
|
|||
path('update_fifoitem/', UpdateFIFOItem.as_view()),
|
||||
path('update_spg/', UpdateSpg.as_view()),
|
||||
path('update_equip_state/', UpdateEquipState.as_view()),
|
||||
path('update_need_to_order/', UpdateNeedToOrder.as_view())
|
||||
path('update_need_to_order/', UpdateNeedToOrder.as_view()),
|
||||
path('update_fifo_number/', UpdateFIFONumber.as_view())
|
||||
]
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from apps.pm.models import ProductionPlan, SubProductionPlan
|
|||
from apps.sam.models import Order
|
||||
from apps.wf.models import Ticket
|
||||
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow
|
||||
from apps.wpm.services import WpmServies
|
||||
from apps.wpm.services import WpmService
|
||||
from apps.em.tasks import update_equip_state_by_next_check_date
|
||||
# Create your views here.
|
||||
|
||||
|
@ -46,7 +46,7 @@ class UpdateCuttingView(APIView):
|
|||
i.coperation = op
|
||||
i.save()
|
||||
WproductFlow.objects.filter(wproduct=i).update(coperation=op)
|
||||
WpmServies.update_cutting_list_with_operation(op)
|
||||
WpmService.update_cutting_list_with_operation(op)
|
||||
return Response()
|
||||
|
||||
from apps.qm.models import TestRecord
|
||||
|
@ -90,7 +90,7 @@ class UpdateSpg(APIView):
|
|||
冷加工重新计算合格率
|
||||
"""
|
||||
for i in SubProductionPlan.objects.filter(subproduction__process__id=1):
|
||||
WpmServies.update_subproduction_progress_main(sp=i)
|
||||
WpmService.update_subproduction_progress_main(sp=i)
|
||||
return Response()
|
||||
|
||||
|
||||
|
@ -105,4 +105,16 @@ class UpdateNeedToOrder(APIView):
|
|||
permission_classes = [IsAdminUser]
|
||||
def post(self, request):
|
||||
WProduct.objects.exclude(to_order=None).update(need_to_order=True)
|
||||
return Response()
|
||||
|
||||
class UpdateFIFONumber(APIView):
|
||||
permission_classes = [IsAdminUser]
|
||||
def post(self, request):
|
||||
from utils.tools import ranstr
|
||||
for i in FIFO.objects.all():
|
||||
if i.type in [FIFO.FIFO_TYPE_DO_IN, FIFO.FIFO_TYPE_PUR_IN]:
|
||||
i.number = 'RK'+ ranstr(7)
|
||||
else:
|
||||
i.number = 'CK' + ranstr(7)
|
||||
i.save()
|
||||
return Response()
|
|
@ -2,7 +2,4 @@ from django.apps import AppConfig
|
|||
|
||||
class InmConfig(AppConfig):
|
||||
name = 'apps.inm'
|
||||
verbose_name = '库存管理'
|
||||
|
||||
def ready(self):
|
||||
import apps.inm.signals
|
||||
verbose_name = '库存管理'
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-28 01:43
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pum', '0004_puorder_puorderitem'),
|
||||
('inm', '0029_fifo_pu_order'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='fifo',
|
||||
name='number',
|
||||
field=models.CharField(default=1, max_length=100, verbose_name='记录编号'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='fifo',
|
||||
name='vendor',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pum.vendor', verbose_name='供应商'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='fifoitemproduct',
|
||||
name='fifoitem',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inm.fifoitem', verbose_name='关联出入库条目'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-28 06:32
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pum', '0004_puorder_puorderitem'),
|
||||
('inm', '0030_auto_20220128_0943'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='fifoitem',
|
||||
name='pu_order_item',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pum.puorderitem', verbose_name='关联采购订单条目'),
|
||||
),
|
||||
]
|
|
@ -2,7 +2,7 @@ from django.db import models
|
|||
from django.db.models.base import Model
|
||||
import django.utils.timezone as timezone
|
||||
from django.db.models.query import QuerySet
|
||||
from apps.pum.models import PuOrder
|
||||
from apps.pum.models import PuOrder, PuOrderItem, Vendor
|
||||
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
|
||||
from utils.model import SoftModel, BaseModel
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
@ -73,12 +73,15 @@ class FIFO(CommonADModel):
|
|||
(FIFO_TYPE_PUR_IN, '采购入库'),
|
||||
(FIFO_TYPE_DO_IN, '生产入库')
|
||||
)
|
||||
number = models.CharField('记录编号', max_length=100)
|
||||
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('出入库日期', null=True, blank=True)
|
||||
remark = models.CharField('备注', max_length=1000, default='')
|
||||
vendor = models.ForeignKey(Vendor, verbose_name='供应商',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
|
||||
null=True, blank=True, on_delete=models.CASCADE)
|
||||
|
||||
|
@ -100,6 +103,8 @@ class FIFOItem(BaseModel):
|
|||
subproduction_plan = models.ForeignKey(
|
||||
SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True)
|
||||
files = models.ManyToManyField(File, verbose_name='上传材料', blank=True)
|
||||
pu_order_item = models.ForeignKey(PuOrderItem,
|
||||
verbose_name='关联采购订单条目', null=True, blank=True, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class IProduct(BaseModel):
|
||||
|
@ -119,14 +124,17 @@ class IProduct(BaseModel):
|
|||
|
||||
class FIFOItemProduct(BaseModel):
|
||||
"""
|
||||
出入库产品
|
||||
出入库记录具体产品
|
||||
"""
|
||||
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')
|
||||
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')
|
||||
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)
|
||||
IProduct, verbose_name='关联库存产品',
|
||||
null=True, blank=True, on_delete=models.SET_NULL)
|
||||
|
|
|
@ -2,6 +2,7 @@ from rest_framework import exceptions
|
|||
from rest_framework import serializers
|
||||
|
||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse, Inventory
|
||||
from apps.pum.models import PuOrder, Vendor
|
||||
from apps.qm.models import TestRecord, TestRecordItem
|
||||
from apps.sam.serializers import OrderSimpleSerializer
|
||||
|
||||
|
@ -10,6 +11,8 @@ from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer
|
|||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||
from django.db import transaction
|
||||
from utils.mixins import DynamicFieldsSerializerMixin
|
||||
from utils.tools import ranstr
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
|
||||
|
||||
|
@ -73,6 +76,28 @@ class FIFOListSerializer(serializers.ModelSerializer):
|
|||
model = FIFO
|
||||
fields = '__all__'
|
||||
|
||||
class FIFOItemCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = FIFOItem
|
||||
fields = ['warehouse',
|
||||
'material', 'batch', 'fifo', 'files', 'pu_order_item']
|
||||
|
||||
def create(self, validated_data):
|
||||
fifo = validated_data['fifo']
|
||||
pu_order_item = validated_data.get('pu_order_item', None)
|
||||
if pu_order_item:
|
||||
if fifo.pu_order != pu_order_item.pu_order:
|
||||
raise ValidationError('项目与采购订单不一致')
|
||||
validated_data['material']=pu_order_item.material
|
||||
else:
|
||||
if fifo.pu_order is not None:
|
||||
raise ValidationError('非采购订单')
|
||||
return super().create(validated_data)
|
||||
|
||||
class FIFOItemUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = FIFOItem
|
||||
fields = ['warehouse', 'batch', 'files']
|
||||
|
||||
class FIFOItemSerializer(serializers.ModelSerializer):
|
||||
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||
|
@ -83,14 +108,14 @@ class FIFOItemSerializer(serializers.ModelSerializer):
|
|||
fields = '__all__'
|
||||
|
||||
|
||||
class IProductInPurSerializer(serializers.ModelSerializer):
|
||||
class FIFOItemProductCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = IProduct
|
||||
fields = ['number']
|
||||
|
||||
|
||||
class FIFODetailInPurSerializer(serializers.ModelSerializer):
|
||||
details = IProductInPurSerializer(many=True, required=False)
|
||||
details = FIFOItemProductCreateSerializer(many=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = FIFOItem
|
||||
|
@ -101,41 +126,26 @@ class MaterialBatchQuerySerializer(serializers.Serializer):
|
|||
warehouse = serializers.IntegerField(label="仓库ID", required=False)
|
||||
materials = serializers.ListField(child=serializers.IntegerField(label="物料ID"), required=False)
|
||||
|
||||
|
||||
class FIFOInPurSerializer(serializers.ModelSerializer):
|
||||
class FIFOInOtherSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
采购入库序列化
|
||||
其他入库序列化
|
||||
"""
|
||||
details = FIFODetailInPurSerializer(many=True)
|
||||
|
||||
details = FIFODetailInPurSerializer(many=True, required=False)
|
||||
vendor = serializers.PrimaryKeyRelatedField(label='供应商ID',
|
||||
queryset=Vendor.objects.all())
|
||||
class Meta:
|
||||
model = FIFO
|
||||
fields = ['details']
|
||||
fields = ['details', 'vendor']
|
||||
|
||||
def create(self, validated_data):
|
||||
details = validated_data.pop('details')
|
||||
if len(details) > 0:
|
||||
pass
|
||||
else:
|
||||
raise serializers.ValidationError('没有入库内容')
|
||||
|
||||
# for i in details:
|
||||
# # 校验批次
|
||||
# try:
|
||||
# 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
|
||||
|
||||
# 创建采购入库
|
||||
with transaction.atomic():
|
||||
validated_data['type'] = FIFO.FIFO_TYPE_PUR_IN
|
||||
obj = FIFO(**validated_data)
|
||||
obj.save()
|
||||
for i in details:
|
||||
if 'details' in i:
|
||||
i['number'] = 'RK' + ranstr(7)
|
||||
p_details = i.pop('details')
|
||||
if len(p_details) != i['count']:
|
||||
raise serializers.ValidationError('数目对不上')
|
||||
|
@ -148,19 +158,30 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
|||
x['fifoitem'] = fifoitem
|
||||
p_list0.append(FIFOItemProduct(**x))
|
||||
FIFOItemProduct.objects.bulk_create(p_list0)
|
||||
|
||||
p_list = []
|
||||
for x in p_details:
|
||||
x['material'] = i['material']
|
||||
x['warehouse'] = validated_data['warehouse']
|
||||
x['batch'] = i['batch']
|
||||
p_list.append(IProduct(**x))
|
||||
IProduct.objects.bulk_create(p_list)
|
||||
else:
|
||||
i['fifo'] = obj
|
||||
i['number'] = 'RK' + ranstr(7)
|
||||
FIFOItem.objects.create(**i)
|
||||
return obj
|
||||
|
||||
class FIFOInPurSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
采购入库序列化
|
||||
"""
|
||||
pu_order = serializers.PrimaryKeyRelatedField(label='采购订单ID',
|
||||
queryset = PuOrder.objects.filter(is_audited=True))
|
||||
|
||||
class Meta:
|
||||
model = FIFO
|
||||
fields = ['pu_order']
|
||||
|
||||
def create(self, validated_data):
|
||||
pu_order = validated_data['pu_order']
|
||||
validated_data['vendor'] = pu_order.vendor
|
||||
validated_data['number'] = 'RK' + ranstr(7)
|
||||
obj = FIFO.objects.create(**validated_data)
|
||||
return obj
|
||||
|
||||
|
||||
class InmTestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
from rest_framework.exceptions import ValidationError
|
||||
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
|
||||
|
||||
class InmService:
|
||||
@classmethod
|
||||
def update_inm(cls, instance:FIFO, type:int=1):
|
||||
"""
|
||||
更新库存(正反)
|
||||
"""
|
||||
if instance.type in [FIFO.FIFO_TYPE_PUR_IN, FIFO.FIFO_TYPE_DO_IN]: # 采购入库, 生产入库
|
||||
# 更新相关表
|
||||
for i in FIFOItem.objects.filter(fifo=instance):
|
||||
material = i.material
|
||||
warehouse = i.warehouse
|
||||
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
|
||||
defaults={'material':material, 'warehouse':warehouse, 'count':0})
|
||||
o1.count = o1.count + i.count
|
||||
o1.save()
|
||||
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 + i.count
|
||||
material.save()
|
||||
|
||||
# 创建IProduct
|
||||
ips2 = []
|
||||
for m in FIFOItemProduct.objects.filter(fifoitem=i):
|
||||
ip = {}
|
||||
ip['warehouse'] = warehouse
|
||||
ip['batch'] = i.batch
|
||||
wp = m.wproduct
|
||||
ip['wproduct'] = wp
|
||||
ip['number'] = m.number
|
||||
ip['material'] = m.material
|
||||
ips2.append(IProduct(**ip))
|
||||
IProduct.objects.bulk_create(ips2)
|
||||
|
||||
# 如果是采购入库更新采购订单表
|
||||
if instance.type == FIFO.FIFO_TYPE_PUR_IN:
|
||||
pur_order_item = i.pur_order_item
|
||||
delivered_count = pur_order_item.delivered_count + i.count
|
||||
if delivered_count > pur_order_item.count:
|
||||
raise ValidationError('超出采购订单所需量')
|
||||
pur_order_item.delivered_count = delivered_count
|
||||
pur_order_item.save()
|
||||
|
||||
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT, FIFO.FIFO_TYPE_SALE_OUT]: # 生产领料 销售出库
|
||||
# 更新相关表
|
||||
for i in FIFOItem.objects.filter(fifo=instance):
|
||||
material = i.material
|
||||
warehouse = i.warehouse
|
||||
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
|
||||
temp_count = o1.count - i.count
|
||||
if temp_count < 0:
|
||||
raise ValidationError('库存不足,操作失败')
|
||||
o1.count = temp_count
|
||||
o1.save()
|
||||
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
|
||||
temp_count = o2.count - i.count
|
||||
if temp_count < 0:
|
||||
raise ValidationError('库存不足,操作失败')
|
||||
o2.count = temp_count
|
||||
o2.save()
|
||||
temp_count = material.count - i.count
|
||||
if temp_count < 0:
|
||||
raise ValidationError('库存不足,操作失败')
|
||||
material.count = temp_count
|
||||
material.save()
|
||||
|
||||
# 删除IProduct
|
||||
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
|
||||
# 生产领料的情况直接从IProduct中删除
|
||||
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
|
||||
IProduct.objects.filter(number__in=numbers).delete()
|
|
@ -1,58 +0,0 @@
|
|||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
|
||||
|
||||
|
||||
def update_inm(instance:FIFO, type:int=1):
|
||||
"""
|
||||
更新库存(正反)
|
||||
"""
|
||||
if instance.type in [FIFO.FIFO_TYPE_PUR_IN, FIFO.FIFO_TYPE_DO_IN]: # 采购入库, 生产入库
|
||||
# 更新相关表
|
||||
for i in FIFOItem.objects.filter(fifo=instance):
|
||||
material = i.material
|
||||
warehouse = i.warehouse
|
||||
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
|
||||
defaults={'material':material, 'warehouse':warehouse, 'count':0})
|
||||
o1.count = o1.count + i.count
|
||||
o1.save()
|
||||
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 + i.count
|
||||
material.save()
|
||||
|
||||
# 创建IProduct
|
||||
ips2 = []
|
||||
for m in FIFOItemProduct.objects.filter(fifoitem=i):
|
||||
ip = {}
|
||||
ip['warehouse'] = warehouse
|
||||
ip['batch'] = i.batch
|
||||
wp = m.wproduct
|
||||
ip['wproduct'] = wp
|
||||
ip['number'] = m.number
|
||||
ip['material'] = m.material
|
||||
ips2.append(IProduct(**ip))
|
||||
IProduct.objects.bulk_create(ips2)
|
||||
|
||||
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT, FIFO.FIFO_TYPE_SALE_OUT]: # 生产领料 销售出库
|
||||
# 更新相关表
|
||||
for i in FIFOItem.objects.filter(fifo=instance):
|
||||
material = i.material
|
||||
warehouse = i.warehouse
|
||||
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
|
||||
o1.count = o1.count - i.count
|
||||
o1.save()
|
||||
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
|
||||
o2.count = o2.count - i.count
|
||||
o2.save()
|
||||
material.count = material.count - i.count
|
||||
material.save()
|
||||
|
||||
# 删除IProduct
|
||||
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
|
||||
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
|
||||
IProduct.objects.filter(number__in=numbers).delete()
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
from rest_framework import serializers
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin
|
||||
from rest_framework.exceptions import APIException, ValidationError
|
||||
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin, CreateModelMixin
|
||||
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, FIFOItemUpdateSerializer, FIFOListSerializer, IProductListSerializer, \
|
||||
from apps.inm.serializers import FIFOInOtherSerializer, FIFOItemCreateSerializer, FIFOItemSerializer, FIFOInPurSerializer, FIFOItemUpdateSerializer, FIFOListSerializer, IProductListSerializer, \
|
||||
InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, \
|
||||
WareHouseCreateUpdateSerializer, InventorySerializer
|
||||
from apps.inm.signals import update_inm
|
||||
from apps.inm.services import InmService
|
||||
from apps.qm.models import TestRecordItem
|
||||
from apps.system.mixins import CreateUpdateModelAMixin
|
||||
from rest_framework.decorators import action
|
||||
|
@ -77,7 +77,7 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
|
|||
return Response(MaterialBatchSerializer(instance=queryset, many=True).data)
|
||||
|
||||
|
||||
class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
|
||||
class FIFOItemViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
|
||||
"""
|
||||
出入库记录详情表
|
||||
"""
|
||||
|
@ -93,12 +93,27 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, Gener
|
|||
def get_serializer_class(self):
|
||||
if self.action == 'update':
|
||||
return FIFOItemUpdateSerializer
|
||||
elif self.action == 'create':
|
||||
return FIFOItemCreateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
if instance.fifo.is_audited:
|
||||
raise APIException('该出入库记录已通过审核, 无法删除')
|
||||
return super().perform_destroy(instance)
|
||||
def create(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.fifo.is_audited:
|
||||
raise ValidationError('该出入库记录已审核')
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.fifo.is_audited:
|
||||
raise ValidationError('该出入库记录已审核')
|
||||
return super().update(request, *args, **kwargs)
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.fifo.is_audited:
|
||||
raise ValidationError('该出入库记录已审核')
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=InmTestRecordCreateSerializer)
|
||||
def test(self, request, pk=None):
|
||||
|
@ -160,6 +175,17 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save(create_by=request.user)
|
||||
return Response()
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'},
|
||||
serializer_class=FIFOInOtherSerializer)
|
||||
def in_other(self, request, pk=None):
|
||||
"""
|
||||
其他入库
|
||||
"""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
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):
|
||||
|
@ -167,6 +193,8 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
审核通过
|
||||
"""
|
||||
obj = self.get_object()
|
||||
if not FIFOItem.objects.filter(fifo=obj).exists():
|
||||
raise ValidationError('出入库条目为空')
|
||||
for i in FIFOItem.objects.filter(fifo=obj, need_test=True):
|
||||
if not i.is_testok:
|
||||
raise APIException('未检验通过, 不可审核')
|
||||
|
@ -177,7 +205,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
obj.auditor = request.user
|
||||
obj.inout_date = timezone.now() # 也是审核日期
|
||||
obj.save()
|
||||
update_inm(obj) # 更新库存
|
||||
InmService.update_inm(obj) # 更新库存
|
||||
return Response()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-29 07:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0044_subproduction_need_combtest'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='usedstep',
|
||||
name='need_test',
|
||||
field=models.BooleanField(default=False, verbose_name='工序内检验'),
|
||||
),
|
||||
]
|
|
@ -242,6 +242,7 @@ class UsedStep(CommonADModel):
|
|||
涉及的生产子工序
|
||||
"""
|
||||
step = models.ForeignKey(Step, verbose_name='子工序', on_delete=models.CASCADE, related_name='usedstep')
|
||||
need_test = models.BooleanField('工序内检验', default=False)
|
||||
remark = models.TextField('生产备注', null=True, blank=True)
|
||||
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='usedstep_subproduction')
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from apps.mtm.models import Material, Step
|
|||
from apps.pm.models import ProductionPlan, SubProductionProgress
|
||||
from apps.wpm.models import Operation, WProduct
|
||||
from datetime import *
|
||||
from apps.wpm.services import WpmServies
|
||||
from apps.wpm.services import WpmService
|
||||
from django.db.models import F
|
||||
|
||||
from utils.mixins import DynamicFieldsFilterMixin
|
||||
|
@ -52,9 +52,9 @@ class SubproductionProgressFilterSet(filters.FilterSet):
|
|||
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
|
||||
step = operation.step
|
||||
if wproducts.exists():
|
||||
subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts)
|
||||
subplans = WpmService.get_subplans_queryset_from_wproducts(wproducts)
|
||||
else:
|
||||
subplans = WpmServies.get_subplans_queyset_from_step(step)
|
||||
subplans = WpmService.get_subplans_queyset_from_step(step)
|
||||
queryset = queryset.filter(subproduction_plan__in=subplans)
|
||||
if step.type == Step.STEP_TYPE_NOM:
|
||||
queryset = queryset.exclude(material__type__in =[Material.MA_TYPE_HALFGOOD, Material.MA_TYPE_GOOD])
|
||||
|
|
|
@ -89,7 +89,8 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
|
|||
subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number')
|
||||
for index, i in enumerate(subps):
|
||||
steps = Step.objects.filter(usedstep__subproduction=i, usedstep__subproduction__is_deleted=False,
|
||||
usedstep__is_deleted=False, is_deleted=False).values('id', 'number', 'name', 'usedstep__remark')
|
||||
usedstep__is_deleted=False, is_deleted=False
|
||||
).values('id', 'number', 'name', 'usedstep__remark', need_test=F('usedstep__need_test'))
|
||||
instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i,
|
||||
start_date=production_plan.start_date, end_date=production_plan.end_date,
|
||||
workshop=i.process.workshop, process=i.process, create_by=request.user,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.serializers import ModelSerializer, ValidationError
|
||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||
from .models import PuOrder, PuOrderItem, Vendor
|
||||
|
||||
|
||||
class VendorSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Vendor
|
||||
|
@ -19,6 +18,22 @@ class PuOrderItemSerializer(ModelSerializer):
|
|||
model = PuOrderItem
|
||||
fields = '__all__'
|
||||
|
||||
class PuOrderItemCreateSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = PuOrderItem
|
||||
fields = ['count', 'delivery_date', 'pu_order', 'material']
|
||||
|
||||
def validate(self, attrs):
|
||||
pu_order = attrs['pu_order']
|
||||
if pu_order.is_audited:
|
||||
raise ValidationError('采购订单已审核')
|
||||
return super().validate(attrs)
|
||||
|
||||
class PuOrderItemUpdateSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = PuOrderItem
|
||||
fields = ['count', 'delivery_date']
|
||||
|
||||
class PuOrderSerializer(ModelSerializer):
|
||||
vendor_ = VendorSimpleSerializer(source='vendor', read_only=True)
|
||||
items = PuOrderItemSerializer(source='item_pu_order', many=True, read_only=True)
|
||||
|
@ -28,4 +43,5 @@ class PuOrderSerializer(ModelSerializer):
|
|||
|
||||
class PuOrderCreateUpdateSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = PuOrder
|
||||
fields = ['number', 'vendor']
|
|
@ -1,11 +1,13 @@
|
|||
from django.db.models import base
|
||||
from rest_framework import urlpatterns
|
||||
from apps.pum.views import VendorViewSet
|
||||
from apps.pum.views import PuOrderItemViewSet, PuOrderViewSet, VendorViewSet
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('vendor', VendorViewSet, basename='vendor')
|
||||
router.register('pu_order', PuOrderViewSet, basename='pu_order')
|
||||
router.register('pu_order_item', PuOrderItemViewSet, basename='pu_order_item')
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
|
||||
from django.shortcuts import render
|
||||
from numpy import delete
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin
|
||||
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from apps.pum.models import PuOrder, Vendor
|
||||
from apps.pum.serializers import PuOrderCreateUpdateSerializer, PuOrderSerializer, VendorSerializer
|
||||
from apps.pum.models import PuOrder, PuOrderItem, Vendor
|
||||
from apps.pum.serializers import PuOrderCreateUpdateSerializer, PuOrderItemCreateSerializer, PuOrderItemSerializer, PuOrderItemUpdateSerializer, PuOrderSerializer, VendorSerializer
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
|
||||
|
||||
from rest_framework.exceptions import APIException, ValidationError
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework import serializers
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
# Create your views here.
|
||||
class VendorViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||
"""
|
||||
|
@ -41,7 +45,49 @@ class PuOrderViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
|||
return PuOrderCreateUpdateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.is_audited:
|
||||
raise ValidationError('该采购订单已审核')
|
||||
return super().update(request, *args, **kwargs)
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.is_audited:
|
||||
raise ValidationError('该采购订单已审核')
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post':'*'},
|
||||
serializer_class=serializers.Serializer)
|
||||
def audit(self, request, pk=None):
|
||||
obj = self.get_object()
|
||||
if obj.item_pu_order.exists() and not obj.is_audited:
|
||||
obj.is_audited = True
|
||||
obj.update_by = request.user
|
||||
obj.save()
|
||||
return Response()
|
||||
return Response('订单状态有误', status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class PuOrderItemViewSet(CreateModelMixin, DestroyModelMixin, GenericViewSet):
|
||||
pass
|
||||
class PuOrderItemViewSet(CreateModelMixin, ListModelMixin, DestroyModelMixin, GenericViewSet):
|
||||
"""
|
||||
采购订单条目
|
||||
"""
|
||||
perms_map = {'get': '*', 'post': '*',
|
||||
'put': '*', 'delete': '*'}
|
||||
queryset = PuOrderItem.objects.select_related('material').all()
|
||||
serializer_class = PuOrderItemSerializer
|
||||
filterset_fields = ['pu_order', 'material']
|
||||
ordering = ['-create_time']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'create':
|
||||
return PuOrderItemCreateSerializer
|
||||
elif self.action == 'update':
|
||||
return PuOrderItemUpdateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.pu_order.is_audited:
|
||||
raise ValidationError('所属采购已审核')
|
||||
return super().destroy(request, *args, **kwargs)
|
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-29 07:12
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('qm', '0022_auto_20211216_1401'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='testrecord',
|
||||
name='is_midtesing',
|
||||
field=models.BooleanField(default=False, verbose_name='是否子工序检验中'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='testrecorditem',
|
||||
name='create_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecorditem_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='testrecorditem',
|
||||
name='update_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecorditem_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='testrecord',
|
||||
name='type',
|
||||
field=models.PositiveSmallIntegerField(choices=[(20, '工序检验'), (30, '工序复检'), (36, '夹层检验'), (40, '成品检验')], default=20),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-29 07:24
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('qm', '0023_auto_20220129_1512'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='testrecord',
|
||||
old_name='is_midtesing',
|
||||
new_name='is_midtesting',
|
||||
),
|
||||
]
|
|
@ -47,13 +47,11 @@ class TestRecord(CommonADModel):
|
|||
"""
|
||||
检验记录
|
||||
"""
|
||||
TEST_STEP = 10
|
||||
TEST_PROCESS = 20
|
||||
TEST_PROCESS_RE = 30
|
||||
TEST_COMB = 36
|
||||
TEST_FINAL = 40
|
||||
type_choice = (
|
||||
(TEST_STEP, '子工序检验'),
|
||||
(TEST_PROCESS, '工序检验'),
|
||||
(TEST_PROCESS_RE, '工序复检'),
|
||||
(TEST_COMB, '夹层检验'),
|
||||
|
@ -70,10 +68,11 @@ class TestRecord(CommonADModel):
|
|||
fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True)
|
||||
origin_test = models.ForeignKey('self', verbose_name='原检验记录', on_delete=models.CASCADE, null=True, blank=True)
|
||||
is_submited = models.BooleanField('是否提交', default=False)
|
||||
is_midtesting = models.BooleanField('是否子工序检验中', default=False)
|
||||
remark = models.TextField('备注', default='')
|
||||
|
||||
|
||||
class TestRecordItem(BaseModel):
|
||||
class TestRecordItem(CommonADModel):
|
||||
"""
|
||||
记录表格字段值
|
||||
"""
|
||||
|
|
|
@ -124,14 +124,18 @@ class TestRecordUpdateSerializer(serializers.ModelSerializer):
|
|||
fields = ['is_testok', 'record_data']
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# 获取更新人
|
||||
update_by = self.context['request'].user
|
||||
record_data = validated_data.pop('record_data')
|
||||
for attr, value in validated_data.items():
|
||||
setattr(instance, attr, value)
|
||||
instance.save()
|
||||
instance.save(update_by=update_by)
|
||||
for i in record_data:
|
||||
tri = i['id']
|
||||
tri.field_value = i['field_value']
|
||||
tri.is_testok = i['is_testok']
|
||||
tri.is_hidden = i['is_hidden']
|
||||
tri.save()
|
||||
if i['field_value'] != tri.field_value:
|
||||
tri.field_value = i['field_value']
|
||||
tri.update_by = update_by
|
||||
tri.is_testok = i['is_testok']
|
||||
tri.is_hidden = i['is_hidden']
|
||||
tri.save()
|
||||
return instance
|
||||
|
|
|
@ -12,7 +12,7 @@ from django.db import transaction
|
|||
from rest_framework.decorators import action
|
||||
|
||||
from apps.wpm.models import WProduct
|
||||
from apps.wpm.services import WpmServies
|
||||
from apps.wpm.services import WpmService
|
||||
# Create your views here.
|
||||
class StandardViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||
"""
|
||||
|
@ -69,7 +69,7 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De
|
|||
|
||||
def update(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.is_submited:
|
||||
if obj.is_submited and obj.is_midtesting is False:
|
||||
raise exceptions.APIException('该记录已提交不可编辑')
|
||||
return super().update(request, *args, **kwargs)
|
||||
|
||||
|
@ -77,20 +77,22 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De
|
|||
obj = self.get_object()
|
||||
if obj.is_submited:
|
||||
raise exceptions.APIException('该记录已提交不可删除')
|
||||
WpmServies.add_wproduct_flow_log(obj.wproduct, 'test_delete')
|
||||
WpmService.add_wproduct_flow_log(obj.wproduct, 'test_delete')
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=TestRecordUpdateSerializer)
|
||||
def submit(self, request, pk=None):
|
||||
obj = self.get_object()
|
||||
if obj.is_submited and obj.is_midtesting is False:
|
||||
raise exceptions.APIException('该记录已提交')
|
||||
# 校验是否有未填项目
|
||||
if obj.type != TestRecord.TEST_PROCESS_RE:
|
||||
if obj.type != TestRecord.TEST_PROCESS_RE and obj.is_midtesting is False:
|
||||
if TestRecordItem.objects.filter(field_value__isnull=True, is_hidden=False, test_record=obj).exists():
|
||||
raise exceptions.APIException('存在未填写项目')
|
||||
with transaction.atomic():
|
||||
obj.is_submited=True
|
||||
obj.save()
|
||||
WpmServies.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算
|
||||
WpmService.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算
|
||||
return Response()
|
||||
|
||||
# def create(self, request, *args, **kwargs):
|
||||
|
|
|
@ -2,6 +2,7 @@ from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModel
|
|||
from rest_framework.viewsets import GenericViewSet
|
||||
from rest_framework.response import Response
|
||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
|
||||
from apps.inm.services import InmService
|
||||
from apps.mtm.models import Material
|
||||
from apps.sam.models import Sale, SaleProduct
|
||||
from apps.sam.serializers_sale import SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer
|
||||
|
@ -11,10 +12,11 @@ from rest_framework.decorators import action
|
|||
from django.utils import timezone
|
||||
|
||||
from apps.system.mixins import CreateUpdateModelAMixin
|
||||
from apps.inm.signals import update_inm
|
||||
from rest_framework import serializers
|
||||
from django.db.models import Count
|
||||
|
||||
from utils.tools import ranstr
|
||||
|
||||
class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
|
||||
"""
|
||||
销售记录
|
||||
|
@ -71,6 +73,7 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
|
|||
fifo.auditor = request.user
|
||||
fifo.inout_date = timezone.now()
|
||||
fifo.create_by = request.user
|
||||
fifo.number = 'CK' + ranstr(7)
|
||||
fifo.save()
|
||||
# 创建出库条目
|
||||
ips = IProduct.objects.filter(sale_iproduct__sale=obj)
|
||||
|
@ -104,7 +107,7 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
|
|||
WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
|
||||
act_state=WProduct.WPR_ACT_STATE_SELLED)
|
||||
# 更新库存
|
||||
update_inm(fifo)
|
||||
InmService.update_inm(fifo)
|
||||
# 变更审核状态
|
||||
obj.is_audited = True
|
||||
obj.save()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django_filters import rest_framework as filters
|
||||
from apps.mtm.models import Material, Step
|
||||
|
||||
from apps.wpm.services import WpmServies
|
||||
from apps.wpm.services import WpmService
|
||||
from utils.mixins import DynamicFieldsFilterMixin
|
||||
from .models import Operation, OperationMaterial, OperationRecord, WMaterial, WProduct
|
||||
|
||||
|
@ -20,10 +20,10 @@ class WMaterialFilterSet(filters.FilterSet):
|
|||
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
|
||||
step = operation.step
|
||||
if wproducts.exists():
|
||||
subplans = WpmServies.get_subplans_queryset_from_wproducts(
|
||||
subplans = WpmService.get_subplans_queryset_from_wproducts(
|
||||
wproducts)
|
||||
else:
|
||||
subplans = WpmServies.get_subplans_queyset_from_step(step)
|
||||
subplans = WpmService.get_subplans_queyset_from_step(step)
|
||||
queryset = queryset.filter(subproduction_plan__in=subplans).exclude(
|
||||
material__type=Material.MA_TYPE_HALFGOOD)
|
||||
return queryset
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-29 07:12
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0045_usedstep_need_test'),
|
||||
('wpm', '0052_auto_20220125_1116'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='wproduct',
|
||||
name='material_check',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_material_check', to='mtm.material', verbose_name='按物料状态检查'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='wproductflow',
|
||||
name='material_check',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_material_check', to='mtm.material', verbose_name='按物料状态检查'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproduct',
|
||||
name='child',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_child', to='wpm.wproduct'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproduct',
|
||||
name='material',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wp_material', to='mtm.material', verbose_name='所属物料状态'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproduct',
|
||||
name='pre_step',
|
||||
field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_pre_step', to='mtm.step', verbose_name='已执行到'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproduct',
|
||||
name='step',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_step', to='mtm.step', verbose_name='所在步骤'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproductflow',
|
||||
name='child',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_child', to='wpm.wproductflow'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproductflow',
|
||||
name='material',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wpf_material', to='mtm.material', verbose_name='所属物料状态'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproductflow',
|
||||
name='pre_step',
|
||||
field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_pre_step', to='mtm.step', verbose_name='已执行到'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproductflow',
|
||||
name='step',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_step', to='mtm.step', verbose_name='所在步骤'),
|
||||
),
|
||||
]
|
|
@ -1,4 +1,5 @@
|
|||
import re
|
||||
|
||||
from rest_framework import exceptions
|
||||
from django.db import models
|
||||
from django.db.models.base import Model
|
||||
|
@ -88,16 +89,20 @@ class WProduct(CommonAModel):
|
|||
number = models.CharField(
|
||||
'物品编号', unique=True, null=True, blank=True, max_length=50)
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
||||
Material, verbose_name='所属物料状态', on_delete=models.CASCADE,
|
||||
related_name='wp_material')
|
||||
material_check = models.ForeignKey(
|
||||
Material, verbose_name='按物料状态检查', on_delete=models.CASCADE,
|
||||
null=True, blank=True, related_name='wp_material_check')
|
||||
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
|
||||
on_delete=models.CASCADE, related_name='w_pre_step')
|
||||
on_delete=models.CASCADE, related_name='wp_pre_step')
|
||||
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
|
||||
related_name='w_step')
|
||||
related_name='wp_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')
|
||||
on_delete=models.CASCADE, related_name='wp_child')
|
||||
remark = models.CharField('备注', max_length=200, null=True, blank=True)
|
||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
|
||||
related_name='wproduct_subplan')
|
||||
|
@ -164,16 +169,19 @@ class WproductFlow(CommonAModel):
|
|||
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)
|
||||
Material, verbose_name='所属物料状态', on_delete=models.CASCADE, related_name='wpf_material')
|
||||
material_check = models.ForeignKey(
|
||||
Material, verbose_name='按物料状态检查', on_delete=models.CASCADE,
|
||||
null=True, blank=True, related_name='wpf_material_check')
|
||||
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
|
||||
on_delete=models.CASCADE, related_name='wl_pre_step')
|
||||
on_delete=models.CASCADE, related_name='wpf_pre_step')
|
||||
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
|
||||
related_name='wl_step')
|
||||
related_name='wpf_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')
|
||||
on_delete=models.CASCADE, related_name='wpf_child')
|
||||
remark = models.CharField('备注', max_length=200, null=True, blank=True)
|
||||
subproduction_plan = models.ForeignKey(
|
||||
SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
|
||||
|
|
|
@ -4,8 +4,8 @@ from rest_framework.serializers import ModelSerializer
|
|||
from apps.em.models import Equipment
|
||||
from apps.em.serializers import EquipmentSimpleSerializer
|
||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
|
||||
from apps.inm.signals import update_inm
|
||||
from apps.inm.serializers import WareHouseSimpleSerializer
|
||||
from apps.inm.services import InmService
|
||||
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial
|
||||
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer
|
||||
|
||||
|
@ -21,6 +21,7 @@ from apps.wpm.models import Operation, OperationEquip, OperationMaterial, Operat
|
|||
from django.db import transaction
|
||||
from apps.sam.models import Order
|
||||
from utils.mixins import DynamicFieldsSerializerMixin
|
||||
from utils.tools import ranstr
|
||||
|
||||
class PickHalfSerializer(serializers.Serializer):
|
||||
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
|
||||
|
@ -29,12 +30,14 @@ class PickHalfSerializer(serializers.Serializer):
|
|||
|
||||
class PickHalfsSerializer(serializers.ListSerializer):
|
||||
child = PickHalfSerializer()
|
||||
|
||||
class PickDetailSerializer(serializers.Serializer):
|
||||
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
||||
batch = serializers.CharField(label='物料批次', allow_blank=True)
|
||||
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
|
||||
pick_count = serializers.IntegerField(label="领料数量", required=False)
|
||||
iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',required=False, many=True)
|
||||
iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',
|
||||
required=False, many=True)
|
||||
|
||||
class PickSerializer(serializers.Serializer):
|
||||
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
||||
|
@ -58,7 +61,9 @@ class PickSerializer(serializers.Serializer):
|
|||
# 创建出库记录
|
||||
|
||||
with transaction.atomic():
|
||||
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user)
|
||||
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT,
|
||||
inout_date=timezone.now(), create_by=self.context['request'].user,
|
||||
number = 'CK' + ranstr(7))
|
||||
for i in picks:
|
||||
isLowLevel = False
|
||||
# 更新出库详情
|
||||
|
@ -123,7 +128,7 @@ class PickSerializer(serializers.Serializer):
|
|||
# 更新库存
|
||||
fifo.is_audited = True
|
||||
fifo.save()
|
||||
update_inm(fifo)
|
||||
InmService.update_inm(fifo)
|
||||
return fifo
|
||||
|
||||
class WMaterialListSerializer(serializers.ModelSerializer):
|
||||
|
|
|
@ -9,19 +9,21 @@ from apps.system.models import User
|
|||
from apps.wf.models import State, TicketFlow, Transition
|
||||
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow, WprouctTicket
|
||||
from utils.tools import ranstr
|
||||
class WpmServies(object):
|
||||
class WpmService(object):
|
||||
|
||||
@classmethod
|
||||
def get_next_step(cls, subproduction_plan:SubProductionPlan, nowstep:Step):
|
||||
"""
|
||||
获取下一步骤
|
||||
"""
|
||||
stepIds = [i['id'] for i in subproduction_plan.steps]
|
||||
steps_list = subproduction_plan.steps
|
||||
stepIds = [i['id'] for i in steps_list]
|
||||
pindex = stepIds.index(nowstep.id)
|
||||
need_test = steps_list[pindex].get('need_test', False)
|
||||
if pindex + 1 < len(stepIds):
|
||||
return Step.objects.get(pk=stepIds[pindex+1]), True
|
||||
return Step.objects.get(pk=stepIds[pindex+1]), need_test
|
||||
else:
|
||||
return nowstep, False
|
||||
return nowstep, need_test
|
||||
|
||||
@classmethod
|
||||
def get_subplans_queryset_from_wproducts(cls, wproducts:List):
|
||||
|
@ -47,9 +49,15 @@ class WpmServies(object):
|
|||
"""
|
||||
is_testok = test.is_testok
|
||||
wproduct = test.wproduct
|
||||
test_i = None
|
||||
if is_testok:
|
||||
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
|
||||
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and \
|
||||
test.is_midtesing is True:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
test_i = test
|
||||
|
||||
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: # 成品检验
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST
|
||||
|
@ -97,7 +105,7 @@ class WpmServies(object):
|
|||
|
||||
wproduct.update_by = user
|
||||
wproduct.update_time = timezone.now()
|
||||
wproduct.test = None
|
||||
wproduct.test = test_i
|
||||
wproduct.last_test_result = is_testok
|
||||
wproduct.save()
|
||||
# 添加日志
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.dispatch import receiver
|
|||
from rest_framework import exceptions
|
||||
from apps.wpm.models import WProduct, WproductFlow, WprouctTicket
|
||||
from apps.wpm.models import OperationWproduct
|
||||
from apps.wpm.services import WpmServies
|
||||
from apps.wpm.services import WpmService
|
||||
|
||||
|
||||
@receiver(post_save, sender=Ticket)
|
||||
|
@ -34,7 +34,7 @@ def handleTicket(sender, instance, created, **kwargs):
|
|||
# 工单绑定半成品
|
||||
wproduct.ticket = instance
|
||||
wproduct.save()
|
||||
WpmServies.add_wproduct_flow_log(wproduct, 'ticket_create')
|
||||
WpmService.add_wproduct_flow_log(wproduct, 'ticket_create')
|
||||
|
||||
|
||||
elif instance.act_state == Ticket.TICKET_ACT_STATE_FINISH:
|
||||
|
@ -77,7 +77,7 @@ def handleTicket(sender, instance, created, **kwargs):
|
|||
wp.save()
|
||||
|
||||
# 添加日志
|
||||
WpmServies.add_wproduct_flow_log(wp, 'ticket_finish')
|
||||
WpmService.add_wproduct_flow_log(wp, 'ticket_finish')
|
||||
# 更新子计划合格进度
|
||||
WpmServies.update_subproduction_progress_main(sp=wp.subproduction_plan)
|
||||
WpmService.update_subproduction_progress_main(sp=wp.subproduction_plan)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from rest_framework import urlpatterns
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from apps.wpm.views import CuttingListViewSet, DoFormInit, DoFormSubmit, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet, WproductTicketViewSet
|
||||
from apps.wpm.views import CuttingListViewSet, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet, WproductTicketViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
|
||||
|
@ -19,8 +19,6 @@ router.register('operation_tool', OperationMaterialToolViewSet, basename='operat
|
|||
router.register('subplan', WPlanViewSet, basename='wplan')
|
||||
router.register('cutting_list', CuttingListViewSet, basename='cutting_list')
|
||||
urlpatterns = [
|
||||
path('do/init/', DoFormInit.as_view()),
|
||||
path('do/submit/', DoFormSubmit.as_view()),
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, \
|
|||
ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct
|
||||
from apps.inm.signals import update_inm
|
||||
from apps.inm.services import InmService
|
||||
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc
|
||||
from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
|
||||
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
||||
|
@ -32,11 +32,13 @@ from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerial
|
|||
from rest_framework.response import Response
|
||||
from django.db import transaction
|
||||
from rest_framework import exceptions, serializers
|
||||
from apps.wpm.services import WpmServies
|
||||
from apps.wpm.services import WpmService
|
||||
from django.utils import timezone
|
||||
from rest_framework import status
|
||||
from django.db.models import Count
|
||||
|
||||
from utils.tools import ranstr
|
||||
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
@ -103,7 +105,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
|||
m.update_by = request.user
|
||||
m.update_time = timezone.now()
|
||||
m.save()
|
||||
WpmServies.add_wproduct_flow_log(
|
||||
WpmService.add_wproduct_flow_log(
|
||||
instance=m, change_str='pick_half')
|
||||
pw = PickWproduct()
|
||||
pw.pick = pick
|
||||
|
@ -149,7 +151,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
perms_map = {'*': '*'}
|
||||
queryset = WProduct.objects.select_related('step', 'material',
|
||||
'subproduction_plan', 'warehouse', 'subproduction_plan__production_plan__order',
|
||||
'to_order').prefetch_related('wproduct_child')
|
||||
'to_order').prefetch_related('wp_child')
|
||||
serializer_class = WProductListSerializer
|
||||
filterset_class = WProductFilterSet
|
||||
search_fields = ['number']
|
||||
|
@ -186,9 +188,8 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST,
|
||||
WProduct.WPR_ACT_STATE_TOCOMBTEST]:
|
||||
raise exceptions.APIException('该产品当前状态不可检验')
|
||||
|
||||
savedict = dict(
|
||||
create_by=self.request.user,
|
||||
create_by=request.user,
|
||||
wproduct=wproduct,
|
||||
material=wproduct.material,
|
||||
number=wproduct.number,
|
||||
|
@ -206,21 +207,26 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
savedict['type'] = TestRecord.TEST_FINAL
|
||||
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOCOMBTEST:
|
||||
savedict['type'] = TestRecord.TEST_COMB
|
||||
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and\
|
||||
wproduct.step != wproduct.pre_step: # 如果是工序内检验
|
||||
savedict['is_midtesting'] = True
|
||||
tr = TestRecord.objects.create(**savedict)
|
||||
# 更新wproduct
|
||||
wproduct.test = tr
|
||||
wproduct.update_by = request.user
|
||||
wproduct.update_time = timezone.now()
|
||||
wproduct.save()
|
||||
WpmServies.add_wproduct_flow_log(wproduct, 'test_init')
|
||||
WpmService.add_wproduct_flow_log(wproduct, 'test_init')
|
||||
# 创建检验条目
|
||||
for i in RecordFormField.objects.filter(form=form, is_deleted=False):
|
||||
tri = TestRecordItem()
|
||||
tri.test_record = tr
|
||||
tri.form_field = i
|
||||
tri.is_hidden = i.is_hidden
|
||||
tri.create_by = request.user
|
||||
tri.save()
|
||||
return Response(TestRecordDetailSerializer(instance=tr).data)
|
||||
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductPutInsSerializer)
|
||||
@transaction.atomic
|
||||
|
@ -242,9 +248,10 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
'subproduction_plan', 'material', 'subproduction_plan__number').annotate(total=Count('id'))
|
||||
# 创建入库记录
|
||||
remark = vdata.get('remark', '')
|
||||
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
|
||||
is_audited=True, auditor=request.user, inout_date=timezone.now(),
|
||||
create_by=request.user, remark=remark)
|
||||
fifo = FIFO.objects.create(
|
||||
type=FIFO.FIFO_TYPE_DO_IN,
|
||||
is_audited=True, auditor=request.user, inout_date=timezone.now(),
|
||||
create_by=request.user, remark=remark, number='RK'+ranstr(7))
|
||||
# 创建入库明细
|
||||
for i in wproducts_a:
|
||||
spi = SubProductionPlan.objects.get(pk=i['subproduction_plan'])
|
||||
|
@ -270,14 +277,14 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
ips.append(FIFOItemProduct(**ip))
|
||||
FIFOItemProduct.objects.bulk_create(ips)
|
||||
# 更新库存并修改半成品进行状态
|
||||
update_inm(fifo)
|
||||
InmService.update_inm(fifo)
|
||||
for i in wproducts:
|
||||
i.act_state = WProduct.WPR_ACT_STATE_INM
|
||||
i.warehouse = warehouse
|
||||
i.update_by = request.user
|
||||
i.update_time = timezone.now()
|
||||
i.save()
|
||||
WpmServies.add_wproduct_flow_log(i, 'putins')
|
||||
WpmService.add_wproduct_flow_log(i, 'putins')
|
||||
return Response()
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=WproductPutInSerializer)
|
||||
|
@ -320,11 +327,11 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
ips.append(FIFOItemProduct(**ip))
|
||||
FIFOItemProduct.objects.bulk_create(ips)
|
||||
# 更新库存并修改半成品进行状态
|
||||
update_inm(fifo)
|
||||
InmService.update_inm(fifo)
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_INM
|
||||
wproduct.warehouse = warehouse
|
||||
wproduct.save()
|
||||
WpmServies.add_wproduct_flow_log(wproduct, 'putin')
|
||||
WpmService.add_wproduct_flow_log(wproduct, 'putin')
|
||||
return Response()
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=ScrapSerializer)
|
||||
|
@ -350,9 +357,9 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
obj.update_by = request.user
|
||||
obj.update_time = timezone.now()
|
||||
obj.save()
|
||||
WpmServies.add_wproduct_flow_log(obj, 'scrap')
|
||||
WpmService.add_wproduct_flow_log(obj, 'scrap')
|
||||
if obj.step.process.id == 1: # 如果是冷加工
|
||||
WpmServies.update_cutting_list_with_operation(obj.coperation)
|
||||
WpmService.update_cutting_list_with_operation(obj.coperation)
|
||||
return Response()
|
||||
|
||||
# @action(methods=['get'], detail=False, perms_map={'get':'*'})
|
||||
|
@ -407,14 +414,14 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
is_mtestok = request.data.get('is_mtestok')
|
||||
obj.is_mtestok = is_mtestok
|
||||
if is_mtestok:
|
||||
WpmServies.update_plan_state_by_mtestok(
|
||||
WpmService.update_plan_state_by_mtestok(
|
||||
obj.subproduction_plan.production_plan)
|
||||
obj.update_by = request.user
|
||||
obj.save()
|
||||
change_str = 'mtest_notok'
|
||||
if is_mtestok:
|
||||
change_str = 'mtest_ok'
|
||||
WpmServies.add_wproduct_flow_log(instance=obj, change_str=change_str)
|
||||
WpmService.add_wproduct_flow_log(instance=obj, change_str=change_str)
|
||||
return Response()
|
||||
|
||||
@action(methods=['get'], detail=True, perms_map={'get': '*'})
|
||||
|
@ -457,7 +464,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
i.need_to_order = True
|
||||
i.update_by = request.user
|
||||
i.save()
|
||||
WpmServies.add_wproduct_flow_log(i, change_str='need_to_order')
|
||||
WpmService.add_wproduct_flow_log(i, change_str='need_to_order')
|
||||
return Response()
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductToOrderSerializer)
|
||||
|
@ -482,7 +489,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
i.to_order = order
|
||||
i.update_by = request.user
|
||||
i.save()
|
||||
WpmServies.add_wproduct_flow_log(i,change_str='to_order')
|
||||
WpmService.add_wproduct_flow_log(i,change_str='to_order')
|
||||
return Response()
|
||||
|
||||
class WproductTicketViewSet(ListModelMixin, GenericViewSet):
|
||||
|
@ -540,7 +547,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
i.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
i.update_by = request.user
|
||||
i.save()
|
||||
WpmServies.add_wproduct_flow_log(i, 'operation_delete')
|
||||
WpmService.add_wproduct_flow_log(i, 'operation_delete')
|
||||
self.perform_destroy(instance)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
@ -561,14 +568,14 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
# 创建操作所用半成品关联记录
|
||||
if 'wproducts' in vdata:
|
||||
owps = []
|
||||
splans = WpmServies.get_subplans_queryset_from_wproducts(
|
||||
splans = WpmService.get_subplans_queryset_from_wproducts(
|
||||
vdata['wproducts'])
|
||||
for wpd in vdata['wproducts']:
|
||||
wpd.operation = op
|
||||
wpd.act_state = WProduct.WPR_ACT_STATE_DOING
|
||||
wpd.update_by = request.user
|
||||
wpd.save()
|
||||
WpmServies.add_wproduct_flow_log(wpd, 'operation_create')
|
||||
WpmService.add_wproduct_flow_log(wpd, 'operation_create')
|
||||
owp = {}
|
||||
owp['operation'] = op
|
||||
owp['wproduct'] = wpd
|
||||
|
@ -579,7 +586,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
owps.append(OperationWproduct(**owp))
|
||||
OperationWproduct.objects.bulk_create(owps)
|
||||
else:
|
||||
splans = WpmServies.get_subplans_queryset_from_wproducts(
|
||||
splans = WpmService.get_subplans_queryset_from_wproducts(
|
||||
vdata['wproducts'])
|
||||
# 查询需要填写的自定义表格
|
||||
forms = RecordForm.objects.filter(
|
||||
|
@ -673,22 +680,31 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
wsp = i.subproduction_plan
|
||||
|
||||
# 获取下一步子工序
|
||||
newstep, hasNext = WpmServies.get_next_step(wsp, step)
|
||||
newstep, needTest = WpmService.get_next_step(wsp, step)
|
||||
wp.step = newstep
|
||||
wp.pre_step = step
|
||||
if hasNext:
|
||||
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
else:
|
||||
|
||||
if step == newstep:
|
||||
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
||||
wp.material = wsp.product
|
||||
if wp.test:# 如果有正在进行的工序中检验
|
||||
wp.test.is_midtesting = False
|
||||
wp.test.is_submited = False
|
||||
wp.test.save()
|
||||
else:
|
||||
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
if needTest:
|
||||
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
||||
wp.material_check = wsp.product
|
||||
|
||||
wp.operation = None
|
||||
wp.update_by = request.user
|
||||
wp.save()
|
||||
WpmServies.add_wproduct_flow_log(wp, 'operation_submit')
|
||||
WpmService.add_wproduct_flow_log(wp, 'operation_submit')
|
||||
|
||||
for i in ows.values('subproduction_plan').distinct():
|
||||
# 更新进度
|
||||
WpmServies.update_subproduction_progress_main(sp=wsp)
|
||||
WpmService.update_subproduction_progress_main(sp=wsp)
|
||||
|
||||
elif step.type == Step.STEP_TYPE_DIV:
|
||||
# 更新物料产出情况
|
||||
|
@ -696,7 +712,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
raise exceptions.APIException('请选择物料产出')
|
||||
for i in omos:
|
||||
if i.subproduction_progress.is_main:
|
||||
newstep, _ = WpmServies.get_next_step(
|
||||
newstep, _ = WpmService.get_next_step(
|
||||
i.subproduction_plan, step)
|
||||
wpr = dict(material=i.material, step=newstep,
|
||||
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
|
||||
|
@ -705,33 +721,41 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
for x in range(i.count):
|
||||
ins = WProduct.objects.create(**wpr)
|
||||
# 添加日志
|
||||
WpmServies.add_wproduct_flow_log(
|
||||
WpmService.add_wproduct_flow_log(
|
||||
ins, 'wproduct_create')
|
||||
# 更新进度
|
||||
WpmServies.update_subproduction_progress_main(
|
||||
WpmService.update_subproduction_progress_main(
|
||||
sp=i.subproduction_plan)
|
||||
elif step.type == Step.STEP_TYPE_COMB:
|
||||
oms_w = omos.filter(subproduction_progress__is_main=True)
|
||||
if len(oms_w) == 1:
|
||||
oms_w = oms_w[0]
|
||||
# 校验单片数量是否正确, 暂时未写
|
||||
newstep, hasNext = WpmServies.get_next_step(
|
||||
newstep, needTest = WpmService.get_next_step(
|
||||
oms_w.subproduction_plan, step)
|
||||
wproduct = WProduct()
|
||||
wproduct.material = oms_w.material
|
||||
wproduct.step = newstep
|
||||
wproduct.subproduction_plan = oms_w.subproduction_plan
|
||||
if hasNext:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
else:
|
||||
if step == newstep:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
||||
# 更新子计划进度
|
||||
WpmServies.update_subproduction_progress_main(
|
||||
sp=oms_w.subproduction_plan)
|
||||
if wproduct.test:# 如果有正在进行的工序中检验
|
||||
wproduct.test.is_midtesting = False
|
||||
wproduct.test.is_submited = False
|
||||
wproduct.test.save()
|
||||
else:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
if needTest:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
||||
wproduct.material_check = wproduct.product
|
||||
|
||||
# 更新子计划进度
|
||||
WpmService.update_subproduction_progress_main(
|
||||
sp=oms_w.subproduction_plan)
|
||||
wproduct.create_by = request.user
|
||||
wproduct.coperation = op
|
||||
wproduct.save()
|
||||
WpmServies.add_wproduct_flow_log(wproduct, 'wproduct_create')
|
||||
WpmService.add_wproduct_flow_log(wproduct, 'wproduct_create')
|
||||
# 隐藏原半成品
|
||||
wps = WProduct.objects.filter(ow_wproduct__operation=op)
|
||||
wps.update(is_hidden=True, child=wproduct,
|
||||
|
@ -743,7 +767,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
|
||||
# 如果是冷加工
|
||||
if step.process.id == 1:
|
||||
WpmServies.update_cutting_list_with_operation(op=op)
|
||||
WpmService.update_cutting_list_with_operation(op=op)
|
||||
return Response()
|
||||
|
||||
|
||||
|
@ -967,213 +991,3 @@ class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyMode
|
|||
return Response()
|
||||
|
||||
|
||||
class DoFormInit(CreateAPIView, GenericAPIView):
|
||||
perms_map = {'*': '*'}
|
||||
serializer_class = OperationInitSerializer
|
||||
|
||||
def post(self, request, format=None):
|
||||
"""
|
||||
调用操作表单
|
||||
"""
|
||||
data = request.data
|
||||
serializer = OperationInitSerializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data
|
||||
ret = {}
|
||||
ret_0 = {}
|
||||
ret_0['step'] = data['step']
|
||||
splans = []
|
||||
ret_0['input'] = []
|
||||
# ret_0['subproduction_plan'] = data['subproduction_plan']
|
||||
if 'wproducts' in data and data['wproducts']:
|
||||
ret_0['wproducts'] = data['wproducts']
|
||||
splans = WProduct.objects.filter(id__in=data['wproducts']).values_list(
|
||||
'subproduction_plan', flat=True)
|
||||
# 调出所属子计划现有物料
|
||||
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(
|
||||
subproduction_plan__in=splans), many=True).data
|
||||
else:
|
||||
if 'subproduction_plan' in vdata:
|
||||
splans = [vdata['subproduction_plan']]
|
||||
else:
|
||||
splans = SubProductionPlan.objects.filter(is_deleted=False,
|
||||
subproduction__usedstep_subproduction__step=vdata[
|
||||
'step'],
|
||||
state=3)
|
||||
ret_0['wproducts'] = []
|
||||
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(
|
||||
subproduction_plan__in=splans), many=True).data
|
||||
|
||||
for i in ret_0['input']:
|
||||
i['count_input'] = 0
|
||||
# 需要输出的物料
|
||||
if ret_0['wproducts']:
|
||||
# 排除主要产物, 因为已经放到半成品里了, 由半成品进行处理, 夹层可能需要特殊处理
|
||||
o_objs = SubProductionProgress.objects.filter(
|
||||
subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT).exclude(is_main=True)
|
||||
|
||||
else:
|
||||
# 此时显示所有子计划需要输出的物料
|
||||
o_objs = SubProductionProgress.objects.filter(
|
||||
subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
||||
ret_0['output'] = list(o_objs.values(
|
||||
'subproduction_plan', 'material', 'material__name', 'material__number'))
|
||||
for i in ret_0['output']:
|
||||
i['count_output'] = 0
|
||||
ret['forms'] = []
|
||||
ret_0['id'] = 0
|
||||
ret_0['name'] = '基本信息'
|
||||
# 查询工具工装
|
||||
ret_0['tools'] = SubprodctionMaterialListSerializer(
|
||||
instance=SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
|
||||
subproduction__subplan_subprod__in=splans), many=True).data
|
||||
# 查询技术文档
|
||||
ret_0['techdocs'] = TechDocListSerializer(
|
||||
instance=TechDoc.objects.filter(
|
||||
subproduction__subplan_subprod__in=splans, enabled=True)
|
||||
.distinct(), many=True).data
|
||||
|
||||
ret['forms'].append(ret_0)
|
||||
forms = RecordForm.objects.filter(
|
||||
step=vdata['step'], type=RecordForm.RF_TYPE_DO)
|
||||
if forms.exists():
|
||||
ret['forms'].extend(RecordFormDetailSerializer(
|
||||
instance=forms, many=True).data)
|
||||
return Response(ret)
|
||||
|
||||
|
||||
class DoFormSubmit(CreateAPIView, GenericAPIView):
|
||||
perms_map = {'*': '*'}
|
||||
serializer_class = OperationSubmitSerializer
|
||||
|
||||
@transaction.atomic
|
||||
def post(self, request, format=None):
|
||||
"""
|
||||
提交操作表单
|
||||
"""
|
||||
data = request.data
|
||||
serializer = OperationSubmitSerializer(
|
||||
data=data, context={'request': self.request})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data # 校验之后的数据
|
||||
|
||||
# 创建一个生产操作记录
|
||||
action_obj = Operation()
|
||||
action_obj.step = vdata['step']
|
||||
action_obj.remark = vdata.get('remark', '') # 操作备注
|
||||
action_obj.create_by = request.user
|
||||
action_obj.use_scrap = vdata.get('use_scrap', False)
|
||||
action_obj.save()
|
||||
|
||||
# 保存关联半成品
|
||||
if 'wproducts' in data and data['wproducts']:
|
||||
owps = []
|
||||
for i in data['wproducts']:
|
||||
owp = {}
|
||||
owp['operation'] = action_obj
|
||||
wp = WProduct.objects.get(pk=i)
|
||||
owp['wproduct'] = wp
|
||||
owp['number'] = wp.number
|
||||
owp['material'] = wp.material
|
||||
owp['subproduction_plan'] = wp.subproduction_plan
|
||||
owps.append(OperationWproduct(**owp))
|
||||
OperationWproduct.objects.bulk_create(owps)
|
||||
|
||||
# 保存物料消耗
|
||||
for i in vdata['input']:
|
||||
if i['count_input']: # 如果有消耗
|
||||
i_wmat = i['id']
|
||||
OperationMaterial.objects.create(type=1, operation=action_obj,
|
||||
wmaterial=i_wmat, count=i['count_input'])
|
||||
# 更新车间物料
|
||||
i_wmat.count = i_wmat.count - i['count_input']
|
||||
i_wmat.save()
|
||||
# 更新子计划物料消耗情况
|
||||
sp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan,
|
||||
material=i_wmat.material)
|
||||
sp.count_real = sp.count_real + i['count_input']
|
||||
sp.save()
|
||||
|
||||
# 物料产出
|
||||
if 'output' in data and data['output']:
|
||||
for i in vdata['output']: # 已经序列化好的数据
|
||||
ma = i['material']
|
||||
if i['subproduction_plan'].product == ma: # 如果是该计划主产物
|
||||
# 如果是切割
|
||||
# 获取下一步子工序
|
||||
if vdata['step'].type == Step.STEP_TYPE_DIV:
|
||||
newstep, _ = WpmServies.get_next_step(
|
||||
i['subproduction_plan'], vdata['step'])
|
||||
wpr = dict(material=ma, step=newstep,
|
||||
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
|
||||
subproduction_plan=i['subproduction_plan'])
|
||||
for x in range(i['count_output']):
|
||||
WProduct.objects.create(**wpr)
|
||||
else:
|
||||
# 更新操作产出物料表
|
||||
OperationMaterial.objects.create(type=2, operation=action_obj,
|
||||
material=ma, count=i['count_output'])
|
||||
# 更新车间物料表
|
||||
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i['subproduction_plan'],
|
||||
material=ma)
|
||||
ins.count = ins.count + i['count_output']
|
||||
ins.save()
|
||||
# 更新子计划进度表
|
||||
sp = SubProductionProgress.objects.get(subproduction_plan=i['subproduction_plan'],
|
||||
material=ma)
|
||||
sp.count_real = sp.count_real + i['count_input']
|
||||
sp.save()
|
||||
|
||||
# 更新动态产品表
|
||||
if 'wproducts' in vdata and vdata['wproducts']:
|
||||
if vdata['step'].type == Step.STEP_TYPE_COMB:
|
||||
wproducts = vdata['wproducts']
|
||||
if 'suproduction_plan' in vdata:
|
||||
wproducts.update(is_hidden=True) # 隐藏
|
||||
newstep, hasNext = WpmServies.get_next_step(
|
||||
i['subproduction_plan'], vdata['step'])
|
||||
wproduct = WProduct()
|
||||
wproduct.material = vdata['subproduction_plan'].product
|
||||
wproduct.step = newstep
|
||||
wproduct.subproduction_plan = vdata['subproduction_plan']
|
||||
wproduct.parent = data['wproducts']
|
||||
if hasNext:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
else:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
||||
wproduct.save()
|
||||
else:
|
||||
raise exceptions.APIException('请指定子计划')
|
||||
else:
|
||||
for wproduct in vdata['wproducts']:
|
||||
# 获取下一步子工序
|
||||
newstep, hasNext = WpmServies.get_next_step(
|
||||
wproduct.subproduction_plan, vdata['step'])
|
||||
wproduct.step = newstep
|
||||
wproduct.pre_step = vdata['step']
|
||||
if hasNext:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||
else:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
||||
wproduct.material = wproduct.subproduction_plan.product
|
||||
wproduct.save()
|
||||
|
||||
# 保存自定义表单结果
|
||||
for i in vdata['forms']:
|
||||
wr = OperationRecord()
|
||||
wr.form = i['form']
|
||||
wr.create_by = request.user
|
||||
wr.operation = action_obj
|
||||
wr.save()
|
||||
wrds = []
|
||||
for m in i['record_data']: # 保存记录详情
|
||||
form_field = m['form_field']
|
||||
m['field_name'] = form_field.field_name
|
||||
m['field_key'] = form_field.field_key
|
||||
m['field_type'] = form_field.field_type
|
||||
m['field_value'] = m['field_value']
|
||||
m['sort'] = form_field.sort
|
||||
m['operation_record'] = wr
|
||||
wrds.append(OperationRecordItem(**m))
|
||||
OperationRecordItem.objects.bulk_create(wrds)
|
||||
return Response()
|
||||
|
|
Loading…
Reference in New Issue