Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
2c937c983f
|
|
@ -63,4 +63,7 @@ export default {
|
||||||
.overFlowShow .el-tabs__content{
|
.overFlowShow .el-tabs__content{
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
#warningTabs .el-tabs__item{
|
||||||
|
padding: 0 10px!important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,12 @@
|
||||||
@expand-change="handlerExpand"
|
@expand-change="handlerExpand"
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
>
|
>
|
||||||
<el-table-column label="任务编号" prop="name" width="140" show-overflow-tooltip>
|
<el-table-column label="任务编号" prop="name" min-width="140" show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="产品名称" prop="productName" width="120" show-overflow-tooltip>
|
<el-table-column label="产品名称" prop="productName" min-width="120" show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="产品型号" prop="productNum">
|
<el-table-column label="产品型号" prop="productNum">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="生产数量" prop="per">
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -255,11 +255,11 @@
|
||||||
<span>{{ currentProjectMsg.allTime }}天</span>
|
<span>{{ currentProjectMsg.allTime }}天</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="lineMsg" v-if="currentProjectMsg.per1">
|
<div class="lineMsg" v-if="currentProjectMsg.per1">
|
||||||
<span class="title">当前进度:</span>
|
<span class="title">订单计划:</span>
|
||||||
<span>{{ currentProjectMsg.per }}</span>
|
<span>{{ currentProjectMsg.per }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="lineMsg" v-if="currentProjectMsg.per1">
|
<div class="lineMsg" v-if="currentProjectMsg.per1">
|
||||||
<span class="title">合格数量:</span>
|
<span class="title">当前进度:</span>
|
||||||
<span>{{ currentProjectMsg.per1 }}</span>
|
<span>{{ currentProjectMsg.per1 }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="lineMsg">
|
<div class="lineMsg">
|
||||||
|
|
@ -1389,8 +1389,9 @@
|
||||||
.searchWrap{
|
.searchWrap{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
top: -38px;
|
top: -35px;
|
||||||
display: flex
|
right: 10px;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
#searchWrap .el-range-editor--medium.el-input__inner{
|
#searchWrap .el-range-editor--medium.el-input__inner{
|
||||||
height: 30px!important;
|
height: 30px!important;
|
||||||
|
|
|
||||||
|
|
@ -86,22 +86,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="dashboardMiddle" class="dashboardMiddle">
|
<div id="dashboardMiddle" class="dashboardMiddle">
|
||||||
<el-row>
|
<div class="dashboardCardPadding">
|
||||||
<el-col :span="15">
|
<div style="width: 65%;float: left;">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">任务进度</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">任务进度</span>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1" style="height: 1px"></el-col>
|
|
||||||
<el-col :span="8">
|
|
||||||
<div class="CardTitleWrap">
|
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">成品率</span>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row class="dashboardCardPadding">
|
|
||||||
<el-col :span="15">
|
|
||||||
<div style="height: 40px;line-height: 40px;"></div>
|
|
||||||
<div>
|
<div>
|
||||||
<gantt
|
<gantt
|
||||||
v-if="proList.length>0"
|
v-if="proList.length>0"
|
||||||
|
|
@ -110,45 +99,37 @@
|
||||||
:ganttHeight="ganttHeight"
|
:ganttHeight="ganttHeight"
|
||||||
></gantt>
|
></gantt>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</div>
|
||||||
<el-col :span="1" style="height: 1px"></el-col>
|
<div style="width: 34%;position:relative;float: right" >
|
||||||
<el-col :span="8">
|
<div class="CardTitleWrap">
|
||||||
<div class="dashboardCardHand">
|
<span class="verticalLine"></span><span class="dashboardCardTitle">成品率</span>
|
||||||
<div class="dashboardCardFilter">
|
</div>
|
||||||
<el-date-picker
|
<div class="dashboardCardHand" style="position: absolute;top: 0;right: 10px;">
|
||||||
v-model="chartDate"
|
<el-date-picker
|
||||||
type="monthrange"
|
v-model="chartDate"
|
||||||
start-placeholder="开始日期"
|
type="monthrange"
|
||||||
end-placeholder="结束日期"
|
start-placeholder="开始日期"
|
||||||
range-separator="至"
|
end-placeholder="结束日期"
|
||||||
format="yyyy 年 MM 月"
|
range-separator="至"
|
||||||
value-format="yyyy-MM"
|
format="yyyy 年 MM 月"
|
||||||
@change="searchTimeChange('1')"
|
value-format="yyyy-MM"
|
||||||
>
|
@change="searchTimeChange('1')"
|
||||||
</el-date-picker>
|
>
|
||||||
<div class="convenientWrap">
|
</el-date-picker>
|
||||||
<div class="convenientBtn" :class="{activeIndex:chartIndex==='1'}" @click="convenientClick('1','week')">
|
|
||||||
本周
|
|
||||||
</div>
|
|
||||||
<div class="convenientBtn" :class="{activeIndex:chartIndex==='2'}"
|
|
||||||
@click="convenientClick('1','month')">本月
|
|
||||||
</div>
|
|
||||||
<div class="convenientBtn" :class="{activeIndex:chartIndex==='3'}"
|
|
||||||
@click="convenientClick('1','quarter')">三个月
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="chartColumn" style="width:100%;" :style="{height:ganttHeight+'px'}"></div>
|
<div id="chartColumn" style="width:100%;" :style="{height:ganttHeight+'px'}"></div>
|
||||||
</el-col>
|
</div>
|
||||||
</el-row>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-row :gutter="5">
|
<el-row :gutter="5">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<div class="dashboardBottomRow">
|
<div class="dashboardBottomRow">
|
||||||
<div class="dashboardCardHand">
|
<div class="dashboardCardHand">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap" style="border-bottom: 0">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">生产设备</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">生产设备</span>
|
||||||
|
<span @click="refreshBottomTabel('1')">
|
||||||
|
<el-icon class="el-icon-refresh refreshIcon"></el-icon>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
|
|
@ -183,7 +164,7 @@
|
||||||
<el-table-column label="设备状态" prop="material_">
|
<el-table-column label="设备状态" prop="material_">
|
||||||
<!--type=1生产设备-->
|
<!--type=1生产设备-->
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<div v-if="scope.row.type===1">
|
<div v-if="scope.row.type===2">
|
||||||
<el-tag v-if="scope.row.state===40" type="danger">
|
<el-tag v-if="scope.row.state===40" type="danger">
|
||||||
禁用
|
禁用
|
||||||
</el-tag>
|
</el-tag>
|
||||||
|
|
@ -207,14 +188,14 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="下次校准日期" prop="model">
|
<!-- <el-table-column label="下次校准日期" prop="model">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.next_check_date" :type="setClass(scope.row.next_check_date)">
|
<el-tag v-if="scope.row.next_check_date" :type="setClass(scope.row.next_check_date)">
|
||||||
{{scope.row.next_check_date}}
|
{{scope.row.next_check_date}}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<div v-else></div>
|
<div v-else></div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>-->
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -222,8 +203,11 @@
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<div class="dashboardBottomRow">
|
<div class="dashboardBottomRow">
|
||||||
<div class="dashboardCardHand">
|
<div class="dashboardCardHand">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap" style="border-bottom: 0">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">人员到岗</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">人员到岗</span>
|
||||||
|
<span @click="refreshBottomTabel('2')">
|
||||||
|
<el-icon class="el-icon-refresh refreshIcon"></el-icon>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
|
|
@ -274,8 +258,11 @@
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<div class="dashboardBottomRow">
|
<div class="dashboardBottomRow">
|
||||||
<div class="dashboardCardHand">
|
<div class="dashboardCardHand">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap" style="border-bottom: 0">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">提醒</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">提醒</span>
|
||||||
|
<span @click="refreshBottomTabel('3')" style="cursor: pointer">
|
||||||
|
<el-icon class="el-icon-refresh refreshIcon"></el-icon>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
|
|
@ -293,13 +280,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboardCardPadding">
|
<div class="dashboardCardPadding">
|
||||||
<el-tabs type="card" :style="{height:cardTabelHeight+'px'}" v-model="activeName"
|
<el-tabs type="card" :style="{height:cardTabelHeight+'px'}" v-model="activeName"
|
||||||
@tab-click="activeNameClick">
|
@tab-click="activeNameClick" id="warningTabs">
|
||||||
<el-tab-pane label="库存警告" name="库存警告">
|
<el-tab-pane label="库存警告" name="库存警告">
|
||||||
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
||||||
@mouseleave="Up()">
|
@mouseleave="Up()">
|
||||||
<li class="listItem" v-for="item in warningList" :key="item.id">
|
<li class="listItem" v-for="(item,$index) in warningList" :key="$index">
|
||||||
<div class="itemText">
|
<div class="itemText">
|
||||||
<span>{{item.name}}({{item.unit}})</span><span>剩余{{item.count}},低于安全库存{{item.count_safe}}</span>
|
<span>{{item.name}}({{item.unit}})</span><span>低于安全库存</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -307,9 +294,9 @@
|
||||||
<el-tab-pane label="临近交货" name="临近交货">
|
<el-tab-pane label="临近交货" name="临近交货">
|
||||||
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
||||||
@mouseleave="Up()">
|
@mouseleave="Up()">
|
||||||
<li class="listItem" v-for="item in warningList" :key="item.id">
|
<li class="listItem" v-for="(item,$index) in warningList" :key="$index">
|
||||||
<div class="itemText">
|
<div class="itemText">
|
||||||
<span>{{item.name}}({{item.number}})</span><span>{{item.delivery_date}}到交货日期</span>
|
<span>{{item.name}}({{item.number}})</span><span>{{item.delivery_date}}为交货日期</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -317,13 +304,39 @@
|
||||||
<el-tab-pane label="过期提醒" name="过期提醒">
|
<el-tab-pane label="过期提醒" name="过期提醒">
|
||||||
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
||||||
@mouseleave="Up()">
|
@mouseleave="Up()">
|
||||||
<li class="listItem" v-for="item in warningList" :key="item.id">
|
<li class="listItem" v-for="(item,$index) in warningList" :key="$index">
|
||||||
<div class="itemText">
|
<div class="itemText">
|
||||||
<span>{{item.name}}({{item.number}})</span><span>{{item.delivery_date}}到期</span>
|
<span>{{item.name}}({{item.number}})</span><span>{{item.delivery_date}}到期</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="设备检测" name="设备检测">
|
||||||
|
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
||||||
|
@mouseleave="Up()">
|
||||||
|
<li class="listItem" v-for="(item,$index) in warningList" :key="$index"
|
||||||
|
:class="{nearStatus:item.warningType===1,outStatus:item.warningType===2}">
|
||||||
|
<div class="itemText">
|
||||||
|
<span>{{item.name}}({{item.number}})</span>
|
||||||
|
<span v-if="item.warningType===1">接近校准日期</span>
|
||||||
|
<span v-else>已过校准日期</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="任务到期" name="任务到期">
|
||||||
|
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()"
|
||||||
|
@mouseleave="Up()">
|
||||||
|
<li class="listItem" v-for="(item,$index) in warningList" :key="$index"
|
||||||
|
:class="{nearStatus:item.warningType===1,outStatus:item.warningType===2}">
|
||||||
|
<div class="itemText">
|
||||||
|
<span>{{item.name}}({{item.number}})</span>
|
||||||
|
<span v-if="item.warningType===1">接近计划日期</span>
|
||||||
|
<span v-else>已过计划日期</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -331,7 +344,6 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import echarts from 'echarts'
|
import echarts from 'echarts'
|
||||||
import {mapGetters} from 'vuex';
|
import {mapGetters} from 'vuex';
|
||||||
|
|
@ -544,11 +556,9 @@
|
||||||
this.drawChart();
|
this.drawChart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//获取库存警告
|
//获取库存警告
|
||||||
getMaterialList({page: 1, page_size:that.warningPageSize,tag: 'low_inm'}).then((response) => {
|
getMaterialList({page: 1, page_size:that.warningPageSize,tag: 'low_inm'}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
debugger;
|
|
||||||
that.warningList = response.data.results;
|
that.warningList = response.data.results;
|
||||||
that.warningTotal = response.data.count;
|
that.warningTotal = response.data.count;
|
||||||
}
|
}
|
||||||
|
|
@ -558,6 +568,7 @@
|
||||||
getEquipmentList() {
|
getEquipmentList() {
|
||||||
let that = this;
|
let that = this;
|
||||||
this.listLoadingEm = true;
|
this.listLoadingEm = true;
|
||||||
|
that.equipmentPage = 1;
|
||||||
getpEquipmentList({page: that.equipmentPage, page_size: that.equipmentPageSize}).then((response) => {
|
getpEquipmentList({page: that.equipmentPage, page_size: that.equipmentPageSize}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.equipmentList = response.data.results;
|
that.equipmentList = response.data.results;
|
||||||
|
|
@ -583,6 +594,7 @@
|
||||||
getUserList() {
|
getUserList() {
|
||||||
let that = this;
|
let that = this;
|
||||||
that.listLoadingUser = true;
|
that.listLoadingUser = true;
|
||||||
|
that.userPage =1;
|
||||||
getUserList({page: that.userPage, page_size: that.userPageSize, fields: 'id,name,dept_name,is_atwork'}).then((response) => {
|
getUserList({page: that.userPage, page_size: that.userPageSize, fields: 'id,name,dept_name,is_atwork'}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.userList = response.data.results;
|
that.userList = response.data.results;
|
||||||
|
|
@ -633,40 +645,6 @@
|
||||||
this.$router.push({name: 'ticket', params: {}})
|
this.$router.push({name: 'ticket', params: {}})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//任务排期列表
|
|
||||||
/*getPlanList() {
|
|
||||||
let that = this;
|
|
||||||
this.listLoadingPlan = true;
|
|
||||||
getProductionplanList({page: 0}).then((response) => {
|
|
||||||
if (response.data) {
|
|
||||||
that.planList = response.data;
|
|
||||||
}
|
|
||||||
this.listLoadingPlan = false;
|
|
||||||
});
|
|
||||||
},*/
|
|
||||||
//库存列表
|
|
||||||
/*getStockList() {
|
|
||||||
let that = this;
|
|
||||||
this.listLoadingStock = true;
|
|
||||||
getInventoryList({page: this.stockPage, page_size: this.stockPageSize}).then((response) => {
|
|
||||||
if (response.data) {
|
|
||||||
that.stockList = response.data.results;
|
|
||||||
that.stockTotal = response.data.count;
|
|
||||||
}
|
|
||||||
this.listLoadingStock = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//更多库存
|
|
||||||
stockMore() {
|
|
||||||
this.$router.push({name: 'warehouse', params: {}})
|
|
||||||
},
|
|
||||||
//库存pageSize改变
|
|
||||||
// @size-change="handleStockSizeChange"
|
|
||||||
handleEquipmentSizeChange(val) {
|
|
||||||
this.stockPageSize = val;
|
|
||||||
this.stockPage = 1;
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
//图标渲染
|
//图标渲染
|
||||||
drawChart() {
|
drawChart() {
|
||||||
let that = this;
|
let that = this;
|
||||||
|
|
@ -794,60 +772,6 @@
|
||||||
this.$router.push({name: 'unproduct'})
|
this.$router.push({name: 'unproduct'})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//便捷查询按钮
|
|
||||||
convenientClick(index, type) {
|
|
||||||
let that = this;
|
|
||||||
let startTime = '', endTime = '', activeIndex = '1';
|
|
||||||
let dat = new Date();
|
|
||||||
let week = dat.getDay();//0-6
|
|
||||||
let currentTime = dat.getTime();
|
|
||||||
let currentYear = dat.getFullYear();
|
|
||||||
let currentMonth = dat.getMonth() + 1;
|
|
||||||
let currentDay = dat.getDate();
|
|
||||||
endTime = currentYear + '-' + currentMonth + '-' + currentDay;
|
|
||||||
if (type === 'week') {
|
|
||||||
activeIndex = '1';
|
|
||||||
let num = week === 0 ? 6 : week - 1;
|
|
||||||
let time = currentTime - num * 24 * 60 * 60 * 1000;
|
|
||||||
let start = new Date(time);
|
|
||||||
startTime = start.getFullYear() + '-' + (start.getMonth() + 1) + '-' + start.getDate();
|
|
||||||
} else if (type === 'month') {
|
|
||||||
activeIndex = '2';
|
|
||||||
startTime = currentYear + '-' + currentMonth + '-01';
|
|
||||||
} else if (type === 'quarter') {
|
|
||||||
activeIndex = '3';
|
|
||||||
let mon = null, yea = null;
|
|
||||||
if (currentMonth > 2) {
|
|
||||||
mon = currentMonth - 2;
|
|
||||||
yea = currentYear;
|
|
||||||
} else if (currentMonth === 2) {
|
|
||||||
mon = 12;
|
|
||||||
yea = currentYear - 1;
|
|
||||||
} else if (currentMonth === 1) {
|
|
||||||
mon = 11;
|
|
||||||
yea = currentYear - 1;
|
|
||||||
}
|
|
||||||
startTime = yea + '-' + mon + '-01';
|
|
||||||
}
|
|
||||||
if (index === '1') {
|
|
||||||
this.chartIndex = activeIndex;
|
|
||||||
getProcessYield({datetime_start: startTime, datetime_end: endTime}).then((response) => {
|
|
||||||
if (response.data) {
|
|
||||||
let list = response.data;
|
|
||||||
let xAxisData = [], seriesData = [];
|
|
||||||
list.forEach(item => {
|
|
||||||
xAxisData.push(item.name);
|
|
||||||
let rate = item.rate * 100;
|
|
||||||
seriesData.push(rate.toFixed(2))
|
|
||||||
});
|
|
||||||
that.chartData.xAxisData = xAxisData;
|
|
||||||
that.chartData.seriesData = seriesData;
|
|
||||||
this.drawChart();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//根据时间和类型获取数据
|
|
||||||
},
|
|
||||||
//选择月份
|
//选择月份
|
||||||
searchTimeChange(index) {
|
searchTimeChange(index) {
|
||||||
let that = this;
|
let that = this;
|
||||||
|
|
@ -878,33 +802,93 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//提示
|
//提示
|
||||||
activeNameClick(tab) {
|
activeNameClick() {
|
||||||
debugger;
|
|
||||||
debugger;
|
|
||||||
let that = this;
|
let that = this;
|
||||||
that.warningPage = 1;
|
that.warningPage = 1;
|
||||||
that.warningList = [];
|
that.warningList = [];
|
||||||
if (tab.label === '库存警告') {
|
if (that.activeName === '库存警告') {
|
||||||
getMaterialList({page: 1, page_size:that.warningPageSize, tag: 'low_inm'}).then((response) => {
|
getMaterialList({page: 1, page_size:that.warningPageSize, tag: 'low_inm'}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.warningList = response.data.results;
|
that.warningList = response.data.results;
|
||||||
that.warningTotal = response.data.count;
|
that.warningTotal = response.data.count;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (tab.label === '临近交货') {
|
} else if (that.activeName === '临近交货') {
|
||||||
getOrderList({page: 1, page_size:that.warningPageSize,tag:'near_delivery'}).then((response) => {
|
getOrderList({page: 1, page_size:that.warningPageSize,tag:'near_delivery'}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.warningList = response.data.results;
|
that.warningList = response.data.results;
|
||||||
that.warningTotal = response.data.count;
|
that.warningTotal = response.data.count;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (tab.label === '过期提醒') {
|
} else if (that.activeName === '过期提醒') {
|
||||||
getmaterialbatchList({page: 1, page_size:that.warningPageSize, tag: 'expired'}).then((response) => {
|
getmaterialbatchList({page: 1, page_size:that.warningPageSize, tag: 'expired'}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.warningList = response.data.results;
|
that.warningList = response.data.results;
|
||||||
that.warningTotal = response.data.count;
|
that.warningTotal = response.data.count;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}else if (that.activeName === '设备检测') {
|
||||||
|
that.warningPageSize = 100;
|
||||||
|
let warningList = [];
|
||||||
|
getpEquipmentList({page: 0,tag:'near_done'}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
let results = response.data;
|
||||||
|
if(results.length>0){
|
||||||
|
results.forEach(item=>{
|
||||||
|
let obj = new Object();
|
||||||
|
obj = item;
|
||||||
|
obj.warningType = 1;
|
||||||
|
warningList.push(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getpEquipmentList({page: 0,tag:'out_done'}).then((res) => {
|
||||||
|
if (response.data) {
|
||||||
|
let resData = res.data;
|
||||||
|
if(resData.length>0){
|
||||||
|
resData.forEach(item=>{
|
||||||
|
let obj1 = new Object();
|
||||||
|
obj1 = item;
|
||||||
|
obj1.warningType = 2;
|
||||||
|
warningList.push(obj1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
that.warningList = warningList;
|
||||||
|
that.warningTotal = warningList.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else if (that.activeName === '任务到期') {
|
||||||
|
that.warningPageSize = 100;
|
||||||
|
let warningList = [];
|
||||||
|
getProductionplanList({page: 0,tag:'near_done'}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
let results = response.data;
|
||||||
|
if(results.length>0){
|
||||||
|
results.forEach(item=>{
|
||||||
|
let obj = new Object();
|
||||||
|
obj = item;
|
||||||
|
obj.warningType = 1;
|
||||||
|
warningList.push(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getProductionplanList({page: 0,tag:'out_done'}).then((res) => {
|
||||||
|
if (response.data) {
|
||||||
|
let resData = res.data;
|
||||||
|
if(resData.length>0) {
|
||||||
|
resData.forEach(item => {
|
||||||
|
let obj1 = new Object();
|
||||||
|
obj1 = item;
|
||||||
|
obj1.warningType = 2;
|
||||||
|
warningList.push(obj1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
that.warningList = warningList;
|
||||||
|
that.warningTotal = warningList.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleWarningSizeChange(val) {
|
handleWarningSizeChange(val) {
|
||||||
|
|
@ -912,7 +896,30 @@
|
||||||
this.warningPage = 1;
|
this.warningPage = 1;
|
||||||
},
|
},
|
||||||
handleWarningCurrentChange(val) {
|
handleWarningCurrentChange(val) {
|
||||||
console.log(`当前页: ${val}`);
|
let that = this;
|
||||||
|
that.warningPage = val;
|
||||||
|
if (that.activeName === '库存警告') {
|
||||||
|
getMaterialList({page: val, page_size:that.warningPageSize, tag: 'low_inm'}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
that.warningList = response.data.results;
|
||||||
|
that.warningTotal = response.data.count;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (that.activeName === '临近交货') {
|
||||||
|
getOrderList({page: val, page_size:that.warningPageSize,tag:'near_delivery'}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
that.warningList = response.data.results;
|
||||||
|
that.warningTotal = response.data.count;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (that.activeName === '过期提醒') {
|
||||||
|
getmaterialbatchList({page: val, page_size:that.warningPageSize, tag: 'expired'}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
that.warningList = response.data.results;
|
||||||
|
that.warningTotal = response.data.count;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
getGanttData() {
|
getGanttData() {
|
||||||
let that = this;
|
let that = this;
|
||||||
|
|
@ -986,13 +993,23 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
refreshBottomTabel(index){
|
||||||
|
if(index==='1') {//生产设备
|
||||||
|
this.getEquipmentList();//设备列表
|
||||||
|
}else if(index==='2'){//人员到岗
|
||||||
|
this.getUserList();//用户列表
|
||||||
|
}else{//提醒
|
||||||
|
this.activeNameClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let hei = document.getElementsByClassName('app-main')[0].clientHeight;
|
let hei = document.getElementsByClassName('app-main')[0].clientHeight;
|
||||||
let heig = document.getElementsByClassName('dashboardTopCard')[0].clientHeight;
|
let heig = document.getElementsByClassName('dashboardTopCard')[0].clientHeight;
|
||||||
let domHeight = ((hei - heig - 140) / 2);
|
let domHeight = ((hei - heig - 140) / 2);
|
||||||
this.cardTabelHeight = domHeight-35;
|
this.cardTabelHeight = domHeight-37;
|
||||||
this.ganttHeight = domHeight - 10;
|
this.ganttHeight = domHeight+35;
|
||||||
document.getElementById('chartColumn').style.height = domHeight + 'px';
|
document.getElementById('chartColumn').style.height = domHeight + 'px';
|
||||||
this.getUserList();//用户列表
|
this.getUserList();//用户列表
|
||||||
this.getEquipmentList();//设备列表
|
this.getEquipmentList();//设备列表
|
||||||
|
|
@ -1015,12 +1032,14 @@
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
|
overflow: hidden;
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
|
||||||
}
|
}
|
||||||
.dashboardBottomRow {
|
.dashboardBottomRow {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.dashboardCardPadding {
|
.dashboardCardPadding {
|
||||||
|
overflow: hidden;
|
||||||
padding: 5px 20px 20px 20px;
|
padding: 5px 20px 20px 20px;
|
||||||
}
|
}
|
||||||
/**/
|
/**/
|
||||||
|
|
@ -1130,7 +1149,9 @@
|
||||||
/*成品率筛选条件*/
|
/*成品率筛选条件*/
|
||||||
.dashboardCardHand {
|
.dashboardCardHand {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding-left: 1%;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
.dashboardCardFilter {
|
.dashboardCardFilter {
|
||||||
display: flex;
|
display: flex;
|
||||||
.convenientWrap {
|
.convenientWrap {
|
||||||
|
|
@ -1161,6 +1182,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.refreshIcon{
|
||||||
|
color: #409EFF;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.anim {
|
.anim {
|
||||||
transition: all 0.5s;
|
transition: all 0.5s;
|
||||||
margin-top: -35px; //高度等于行高
|
margin-top: -35px; //高度等于行高
|
||||||
|
|
@ -1175,13 +1202,19 @@
|
||||||
.listItem {
|
.listItem {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
font-size: 16px;
|
font-size: 12px;
|
||||||
.itemText {
|
.itemText {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.nearStatus{
|
||||||
|
color: #e6a23c;
|
||||||
|
}
|
||||||
|
.outStatus{
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
#chartColumn > div {
|
#chartColumn > div {
|
||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
canvas {
|
canvas {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from django.db.models import base
|
||||||
from rest_framework import urlpatterns
|
from rest_framework import urlpatterns
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateEquipState, UpdateFIFOItem, UpdateLastTestResult, UpdateSpg
|
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateEquipState, UpdateFIFOItem, UpdateLastTestResult, UpdateNeedToOrder, UpdateSpg
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('cleandata/', CleanDataView.as_view()),
|
path('cleandata/', CleanDataView.as_view()),
|
||||||
|
|
@ -11,6 +11,7 @@ urlpatterns = [
|
||||||
path('update_last_result/', UpdateLastTestResult.as_view()),
|
path('update_last_result/', UpdateLastTestResult.as_view()),
|
||||||
path('update_fifoitem/', UpdateFIFOItem.as_view()),
|
path('update_fifoitem/', UpdateFIFOItem.as_view()),
|
||||||
path('update_spg/', UpdateSpg.as_view()),
|
path('update_spg/', UpdateSpg.as_view()),
|
||||||
path('update_equip_state/', UpdateEquipState.as_view())
|
path('update_equip_state/', UpdateEquipState.as_view()),
|
||||||
|
path('update_need_to_order/', UpdateNeedToOrder.as_view())
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,3 +100,9 @@ class UpdateEquipState(APIView):
|
||||||
def post(self, request, format=None):
|
def post(self, request, format=None):
|
||||||
update_equip_state_by_next_check_date()
|
update_equip_state_by_next_check_date()
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
class UpdateNeedToOrder(APIView):
|
||||||
|
permission_classes = [IsAdminUser]
|
||||||
|
def post(self, request):
|
||||||
|
WProduct.objects.exclude(to_order=None).update(need_to_order=True)
|
||||||
|
return Response()
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
from django_filters import rest_framework as filters
|
||||||
|
|
||||||
|
from apps.em.models import Equipment
|
||||||
|
from datetime import *
|
||||||
|
|
||||||
|
from utils.mixins import DynamicFieldsFilterMixin
|
||||||
|
|
||||||
|
|
||||||
|
class EquipFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
|
tag = filters.CharFilter(method='filter_tag')
|
||||||
|
class Meta:
|
||||||
|
model = Equipment
|
||||||
|
fields = ['keeper', 'type', 'tag']
|
||||||
|
|
||||||
|
def filter_tag(self, queryset, name, value):
|
||||||
|
now = datetime.now()
|
||||||
|
day7_after = now + timedelta(days=7)
|
||||||
|
if value == 'near_check':
|
||||||
|
queryset = queryset.filter(
|
||||||
|
next_check_date__lte = datetime.date(day7_after))
|
||||||
|
elif value == 'out_check':
|
||||||
|
queryset = queryset.filter(
|
||||||
|
next_check_date__gt = datetime.date(now))
|
||||||
|
return queryset
|
||||||
|
|
@ -2,11 +2,13 @@ from apps.mtm.models import Step
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
|
|
||||||
|
from utils.mixins import DynamicFieldsSerializerMixin
|
||||||
from .models import Equipment, ECheckRecord
|
from .models import Equipment, ECheckRecord
|
||||||
from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer
|
from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer
|
||||||
|
|
||||||
|
|
||||||
class EquipmentListSerializer(ModelSerializer):
|
class EquipmentListSerializer(DynamicFieldsSerializerMixin, ModelSerializer):
|
||||||
keeper_ = UserSimpleSerializer(source='keeper', read_only=True)
|
keeper_ = UserSimpleSerializer(source='keeper', read_only=True)
|
||||||
step_ = serializers.SerializerMethodField()
|
step_ = serializers.SerializerMethodField()
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -37,7 +39,7 @@ class EquipmentCreateUpdateSerializer(ModelSerializer):
|
||||||
class EquipmentSimpleSerializer(ModelSerializer):
|
class EquipmentSimpleSerializer(ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Equipment
|
model = Equipment
|
||||||
fields = ['id', 'number', 'name', 'state', 'model']
|
fields = ['id', 'number', 'name', 'state', 'model', 'type']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||||
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, ListModelMixin, DestroyModelMixin
|
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, ListModelMixin, DestroyModelMixin
|
||||||
from rest_framework import serializers, status
|
from rest_framework import serializers, status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from apps.em.filters import EquipFilterSet
|
||||||
from apps.em.models import Equipment, ECheckRecord
|
from apps.em.models import Equipment, ECheckRecord
|
||||||
from apps.em.serializers import DaqCreateSerializer, EChcekRecordCreateSerializer, ECheckRecordListSerializer, \
|
from apps.em.serializers import DaqCreateSerializer, EChcekRecordCreateSerializer, ECheckRecordListSerializer, \
|
||||||
EquipmentCreateUpdateSerializer, EquipmentListSerializer
|
EquipmentCreateUpdateSerializer, EquipmentListSerializer
|
||||||
|
|
@ -26,7 +27,7 @@ class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet)
|
||||||
queryset = Equipment.objects.all()
|
queryset = Equipment.objects.all()
|
||||||
serializer_class = EquipmentListSerializer
|
serializer_class = EquipmentListSerializer
|
||||||
search_fields = ['number', 'name','description']
|
search_fields = ['number', 'name','description']
|
||||||
filterset_fields = ['keeper', 'type']
|
filterset_class = EquipFilterSet
|
||||||
ordering_fields = ['create_time']
|
ordering_fields = ['create_time']
|
||||||
ordering = ['-create_time']
|
ordering = ['-create_time']
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from django_filters import rest_framework as filters
|
from django_filters import rest_framework as filters
|
||||||
from apps.hrm.models import ClockRecord
|
from apps.hrm.models import ClockRecord, Employee
|
||||||
|
from utils.mixins import DynamicFieldsFilterMixin
|
||||||
|
|
||||||
class ClockRecordFilterSet(filters.FilterSet):
|
class ClockRecordFilterSet(filters.FilterSet):
|
||||||
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
||||||
|
|
@ -7,3 +8,9 @@ class ClockRecordFilterSet(filters.FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClockRecord
|
model = ClockRecord
|
||||||
fields = ['create_by', 'create_time_start', 'create_time_end']
|
fields = ['create_by', 'create_time_start', 'create_time_end']
|
||||||
|
|
||||||
|
class EmployeeFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Employee
|
||||||
|
fields = ['job_state']
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Generated by Django 3.2.9 on 2022-01-26 05:51
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hrm', '0004_clockrecord'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='employee',
|
||||||
|
old_name='birthdate',
|
||||||
|
new_name='birthday',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='employee',
|
||||||
|
old_name='ID_number',
|
||||||
|
new_name='id_number',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='employee',
|
||||||
|
old_name='jobstate',
|
||||||
|
new_name='job_state',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='employee',
|
||||||
|
old_name='academic',
|
||||||
|
new_name='qualification',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='employee',
|
||||||
|
name='job',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -14,20 +14,21 @@ class Employee(CommonAModel):
|
||||||
"""
|
"""
|
||||||
员工信息
|
员工信息
|
||||||
"""
|
"""
|
||||||
|
JOB_ON = 1
|
||||||
|
JOB_OFF = 2
|
||||||
jobstate_choices = (
|
jobstate_choices = (
|
||||||
(1, '在职'),
|
(JOB_ON, '在职'),
|
||||||
(2, '离职'),
|
(JOB_OFF, '离职'),
|
||||||
)
|
)
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee_user')
|
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee_user')
|
||||||
number = models.CharField('人员编号', max_length=50,null=True, blank=True, unique=True)
|
number = models.CharField('人员编号', max_length=50,null=True, blank=True, unique=True)
|
||||||
photo = models.CharField('证件照', max_length=1000, null=True, blank=True)
|
photo = models.CharField('证件照', max_length=1000, null=True, blank=True)
|
||||||
ID_number = models.CharField('身份证号', max_length=100, null=True, blank=True)
|
id_number = models.CharField('身份证号', max_length=100, null=True, blank=True)
|
||||||
gender = models.CharField('性别', max_length=10, default='男')
|
gender = models.CharField('性别', max_length=10, default='男')
|
||||||
signature = models.CharField('签名图片', max_length=200, null=True, blank=True)
|
signature = models.CharField('签名图片', max_length=200, null=True, blank=True)
|
||||||
birthdate = models.DateField('出生年月', null=True, blank=True)
|
birthday = models.DateField('出生年月', null=True, blank=True)
|
||||||
academic = models.CharField('学历', max_length=50, null=True, blank=True)
|
qualification = models.CharField('学历', max_length=50, null=True, blank=True)
|
||||||
jobstate = models.IntegerField('在职状态', choices=jobstate_choices, default=1)
|
job_state = models.IntegerField('在职状态', choices=jobstate_choices, default=1)
|
||||||
job = models.ForeignKey(Position, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='岗位')
|
|
||||||
face_data = models.JSONField('人脸识别数据', null=True, blank=True)
|
face_data = models.JSONField('人脸识别数据', null=True, blank=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '员工补充信息'
|
verbose_name = '员工补充信息'
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
from apps.system.models import User
|
from apps.system.models import User
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from utils.mixins import DynamicFieldsSerializerMixin
|
||||||
from .models import ClockRecord, Employee
|
from .models import ClockRecord, Employee
|
||||||
from apps.system.serializers import UserListSerializer, UserSimpleSerializer
|
from apps.system.serializers import OrganizationSimpleSerializer, UserListSerializer, UserSimpleSerializer
|
||||||
from django.db.models.query import Prefetch
|
from django.db.models.query import Prefetch
|
||||||
|
|
||||||
class EmployeeSerializer(ModelSerializer):
|
class EmployeeSerializer(DynamicFieldsSerializerMixin, ModelSerializer):
|
||||||
|
name = serializers.CharField(source='user.name', read_only=True)
|
||||||
|
dept_ = OrganizationSimpleSerializer(source='user.dept_', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Employee
|
model = Employee
|
||||||
exclude = ['face_data']
|
exclude = ['face_data']
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,11 @@ class HRMService:
|
||||||
face_users = cache.get('face_users')
|
face_users = cache.get('face_users')
|
||||||
if face_datas is None:
|
if face_datas is None:
|
||||||
update_all_user_facedata_cache()
|
update_all_user_facedata_cache()
|
||||||
|
try:
|
||||||
results = face_recognition.compare_faces(face_datas, unknown_face_encoding, tolerance=0.5)
|
results = face_recognition.compare_faces(face_datas,
|
||||||
|
unknown_face_encoding, tolerance=0.5)
|
||||||
|
except:
|
||||||
|
return None, '识别失败'
|
||||||
for index, value in enumerate(results):
|
for index, value in enumerate(results):
|
||||||
if value:
|
if value:
|
||||||
# 识别成功
|
# 识别成功
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ def update_all_user_not_atwork():
|
||||||
"""
|
"""
|
||||||
将所有员工设为非在岗状态
|
将所有员工设为非在岗状态
|
||||||
"""
|
"""
|
||||||
User.objects.all().update(is_atwork=False)
|
User.objects.all().update(is_atwork=False, last_check_time = None)
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def update_all_user_facedata_cache():
|
def update_all_user_facedata_cache():
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from django.utils import timezone
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||||
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin
|
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin
|
||||||
from apps.hrm.filters import ClockRecordFilterSet
|
from apps.hrm.filters import ClockRecordFilterSet, EmployeeFilterSet
|
||||||
from apps.hrm.services import HRMService
|
from apps.hrm.services import HRMService
|
||||||
from apps.hrm.tasks import update_all_user_facedata_cache
|
from apps.hrm.tasks import update_all_user_facedata_cache
|
||||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
|
|
@ -30,6 +30,7 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix
|
||||||
"""
|
"""
|
||||||
perms_map = {'get': '*', 'put': 'employee_update'}
|
perms_map = {'get': '*', 'put': 'employee_update'}
|
||||||
queryset = Employee.objects.all()
|
queryset = Employee.objects.all()
|
||||||
|
filterset_class = EmployeeFilterSet
|
||||||
serializer_class = EmployeeSerializer
|
serializer_class = EmployeeSerializer
|
||||||
ordering = ['-pk']
|
ordering = ['-pk']
|
||||||
|
|
||||||
|
|
@ -91,6 +92,7 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
||||||
ins.save()
|
ins.save()
|
||||||
# 设为在岗
|
# 设为在岗
|
||||||
user.is_atwork = True
|
user.is_atwork = True
|
||||||
|
user.last_check_time = now
|
||||||
user.save()
|
user.save()
|
||||||
return Response(UserSimpleSerializer(instance=user).data)
|
return Response(UserSimpleSerializer(instance=user).data)
|
||||||
return Response(msg, status=status.HTTP_400_BAD_REQUEST)
|
return Response(msg, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ from django_filters import rest_framework as filters
|
||||||
from apps.mtm.models import Material
|
from apps.mtm.models import Material
|
||||||
from .models import IProduct, MaterialBatch
|
from .models import IProduct, MaterialBatch
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from utils.mixins import DynamicFieldsFilterMixin
|
||||||
|
|
||||||
|
class MbFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
class MbFilterSet(filters.FilterSet):
|
|
||||||
material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all())
|
material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all())
|
||||||
tag = filters.CharFilter(method="filter_tag")
|
tag = filters.CharFilter(method="filter_tag")
|
||||||
|
|
||||||
|
|
@ -20,12 +20,14 @@ class MbFilterSet(filters.FilterSet):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class IProductFilterSet(filters.FilterSet):
|
class IProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
|
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
|
||||||
to_order = filters.NumberFilter(field_name="wproduct__to_order")
|
to_order = filters.NumberFilter(field_name="wproduct__to_order")
|
||||||
|
need_to_order = filters.BooleanFilter(field_name="wproduct__need_to_order")
|
||||||
update_time_start = filters.DateFilter(field_name="update_time", lookup_expr='gte')
|
update_time_start = filters.DateFilter(field_name="update_time", lookup_expr='gte')
|
||||||
update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte')
|
update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte')
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IProduct
|
model = IProduct
|
||||||
fields = ['material', 'warehouse', 'batch', 'order', 'material__type',
|
fields = ['material', 'warehouse', 'batch', 'order', 'material__type',
|
||||||
'is_saled', 'update_time_start', 'update_time_end', 'to_order']
|
'is_saled', 'update_time_start', 'update_time_end',
|
||||||
|
'to_order', 'need_to_order']
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,13 @@ from rest_framework import serializers
|
||||||
|
|
||||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse, Inventory
|
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse, Inventory
|
||||||
from apps.qm.models import TestRecord, TestRecordItem
|
from apps.qm.models import TestRecord, TestRecordItem
|
||||||
|
from apps.sam.serializers import OrderSimpleSerializer
|
||||||
|
|
||||||
|
|
||||||
from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer
|
from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from utils.mixins import DynamicFieldsSerializerMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -39,7 +42,7 @@ class InventorySerializer(serializers.ModelSerializer):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class MaterialBatchSerializer(serializers.ModelSerializer):
|
class MaterialBatchSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializer):
|
||||||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||||
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||||
|
|
||||||
|
|
@ -48,12 +51,15 @@ class MaterialBatchSerializer(serializers.ModelSerializer):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class IProductListSerializer(serializers.ModelSerializer):
|
class IProductListSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializer):
|
||||||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||||
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||||
|
need_to_order = serializers.BooleanField(source='wproduct.need_to_order', read_only=True)
|
||||||
is_mtestok = serializers.BooleanField(source='wproduct.is_mtestok', read_only=True)
|
is_mtestok = serializers.BooleanField(source='wproduct.is_mtestok', read_only=True)
|
||||||
remark_mtest = serializers.CharField(source='wproduct.remark_mtest', read_only=True)
|
remark_mtest = serializers.CharField(source='wproduct.remark_mtest', read_only=True)
|
||||||
|
to_order_ = OrderSimpleSerializer(source='wproduct.to_order', read_only=True)
|
||||||
|
order_ = OrderSimpleSerializer(
|
||||||
|
source='wproduct.subproduction_plan.production_plan.order', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IProduct
|
model = IProduct
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,9 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
perms_map = {'*': '*'}
|
perms_map = {'*': '*'}
|
||||||
queryset = IProduct.objects.select_related(
|
queryset = IProduct.objects.select_related(
|
||||||
'material', 'warehouse', 'wproduct__subproduction_plan__production_plan__order')
|
'material', 'warehouse',
|
||||||
|
'wproduct__subproduction_plan__production_plan__order',
|
||||||
|
'wproduct__to_order')
|
||||||
serializer_class = IProductListSerializer
|
serializer_class = IProductListSerializer
|
||||||
filterset_class = IProductFilterSet
|
filterset_class = IProductFilterSet
|
||||||
search_fields = []
|
search_fields = []
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from django.db.models.expressions import F
|
from django.db.models.expressions import F
|
||||||
from django_filters import rest_framework as filters
|
from django_filters import rest_framework as filters
|
||||||
from apps.mtm.models import Material, TechDoc
|
from apps.mtm.models import Material, TechDoc
|
||||||
|
from utils.mixins import DynamicFieldsFilterMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -15,7 +16,7 @@ class TechDocFilterset(filters.FilterSet):
|
||||||
def filter_operation(self, queryset, name, value):
|
def filter_operation(self, queryset, name, value):
|
||||||
return queryset.filter(subproduction__subplan_subprod__ow_subplan__operation=value).distinct()
|
return queryset.filter(subproduction__subplan_subprod__ow_subplan__operation=value).distinct()
|
||||||
|
|
||||||
class MaterialFilterSet(filters.FilterSet):
|
class MaterialFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
tag = filters.CharFilter(method='filter_tag')
|
tag = filters.CharFilter(method='filter_tag')
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Material
|
model = Material
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
from apps.em.serializers import EquipmentSimpleSerializer
|
from apps.em.serializers import EquipmentSimpleSerializer
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import ParseError, ValidationError
|
from rest_framework.exceptions import ParseError, ValidationError
|
||||||
|
|
||||||
|
from utils.mixins import DynamicFieldsSerializerMixin
|
||||||
from .models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
|
from .models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
|
||||||
from apps.system.serializers import FileSimpleSerializer, OrganizationSimpleSerializer
|
from apps.system.serializers import FileSimpleSerializer, OrganizationSimpleSerializer
|
||||||
|
|
||||||
|
|
||||||
class MaterialSerializer(serializers.ModelSerializer):
|
class MaterialSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Material
|
model = Material
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@ from django_filters import rest_framework as filters
|
||||||
from apps.mtm.models import Material, Step
|
from apps.mtm.models import Material, Step
|
||||||
from apps.pm.models import ProductionPlan, SubProductionProgress
|
from apps.pm.models import ProductionPlan, SubProductionProgress
|
||||||
from apps.wpm.models import Operation, WProduct
|
from apps.wpm.models import Operation, WProduct
|
||||||
|
from datetime import *
|
||||||
from apps.wpm.services import WpmServies
|
from apps.wpm.services import WpmServies
|
||||||
|
from django.db.models import F
|
||||||
|
|
||||||
class PlanFilterSet(filters.FilterSet):
|
from utils.mixins import DynamicFieldsFilterMixin
|
||||||
|
|
||||||
|
class PlanFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
||||||
create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte')
|
create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte')
|
||||||
tag = filters.CharFilter(method='filter_tag')
|
tag = filters.CharFilter(method='filter_tag')
|
||||||
|
|
@ -15,10 +18,19 @@ class PlanFilterSet(filters.FilterSet):
|
||||||
fields = ['product', 'order', 'create_time_start', 'create_time_end']
|
fields = ['product', 'order', 'create_time_start', 'create_time_end']
|
||||||
|
|
||||||
def filter_tag(self, queryset, name, value):
|
def filter_tag(self, queryset, name, value):
|
||||||
|
now = datetime.now()
|
||||||
|
day7_after = now + timedelta(days=7)
|
||||||
if value == 'planed':
|
if value == 'planed':
|
||||||
queryset = queryset.filter(is_planed=True)
|
queryset = queryset.filter(is_planed=True)
|
||||||
elif value == 'working':
|
elif value == 'working':
|
||||||
queryset = queryset.exclude(state__in=[ProductionPlan.PLAN_STATE_DONE, ProductionPlan.PLAN_MTEST_DONE])
|
queryset = queryset.exclude(state__in=[ProductionPlan.PLAN_STATE_DONE,
|
||||||
|
ProductionPlan.PLAN_MTEST_DONE])
|
||||||
|
elif value == 'near_done':
|
||||||
|
queryset = queryset.filter(count_ok__lt=F('count'),
|
||||||
|
end_date__lte = datetime.date(day7_after))
|
||||||
|
elif value == 'out_done':
|
||||||
|
queryset = queryset.filter(count_ok__lt=F('count'),
|
||||||
|
end_date__gt = datetime.date(now))
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def filter_material(self, queryset, name, value):
|
def filter_material(self, queryset, name, value):
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from rest_framework import serializers
|
||||||
from apps.sam.serializers import OrderSerializer, OrderSimpleSerializer
|
from apps.sam.serializers import OrderSerializer, OrderSimpleSerializer
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, SubProductionSimpleSerializer
|
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, SubProductionSimpleSerializer
|
||||||
from apps.system.serializers import OrganizationSimpleSerializer
|
from apps.system.serializers import OrganizationSimpleSerializer
|
||||||
|
from utils.mixins import DynamicFieldsSerializerMixin
|
||||||
|
|
||||||
|
|
||||||
class ProductionPlanCreateFromOrderSerializer(serializers.ModelSerializer):
|
class ProductionPlanCreateFromOrderSerializer(serializers.ModelSerializer):
|
||||||
|
|
@ -10,7 +11,7 @@ class ProductionPlanCreateFromOrderSerializer(serializers.ModelSerializer):
|
||||||
model = ProductionPlan
|
model = ProductionPlan
|
||||||
fields = ['order', 'count', 'start_date', 'end_date']
|
fields = ['order', 'count', 'start_date', 'end_date']
|
||||||
|
|
||||||
class ProductionPlanSerializer(serializers.ModelSerializer):
|
class ProductionPlanSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializer):
|
||||||
order_ = OrderSimpleSerializer(source='order', read_only=True)
|
order_ = OrderSimpleSerializer(source='order', read_only=True)
|
||||||
product_ = MaterialSimpleSerializer(source='product', read_only=True)
|
product_ = MaterialSimpleSerializer(source='product', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from apps.em.models import Equipment
|
||||||
from apps.em.serializers import EquipmentSimpleSerializer
|
from apps.em.serializers import EquipmentSimpleSerializer
|
||||||
from apps.inm.models import MaterialBatch
|
from apps.inm.models import MaterialBatch
|
||||||
from apps.inm.serializers import MaterialBatchSerializer
|
from apps.inm.serializers import MaterialBatchSerializer
|
||||||
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
|
from apps.mtm.models import Material, Step, SubProduction, SubprodctionMaterial
|
||||||
from apps.pm.filters import PlanFilterSet, SubproductionProgressFilterSet
|
from apps.pm.filters import PlanFilterSet, SubproductionProgressFilterSet
|
||||||
from apps.system.mixins import CreateUpdateModelAMixin
|
from apps.system.mixins import CreateUpdateModelAMixin
|
||||||
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
|
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
|
||||||
|
|
@ -220,8 +220,12 @@ class ResourceViewSet(GenericViewSet):
|
||||||
for i in rdata:
|
for i in rdata:
|
||||||
# 计算输入物料
|
# 计算输入物料
|
||||||
materials = SubprodctionMaterial.objects.filter(subproduction__product__id=i['id'],
|
materials = SubprodctionMaterial.objects.filter(subproduction__product__id=i['id'],
|
||||||
subproduction__is_deleted=False, is_deleted=False, material__type__in=[3,4], type=1).order_by('material__number')\
|
subproduction__is_deleted=False, is_deleted=False,
|
||||||
.values('material__id', 'material__name', 'material__number', 'material__type', 'count', 'material__count')
|
material__type__in=[Material.MA_TYPE_MAINSO,
|
||||||
|
Material.MA_TYPE_HELPSO], type= SubprodctionMaterial.SUB_MA_TYPE_IN).order_by('material__number')\
|
||||||
|
.values('material__id', 'material__name',
|
||||||
|
'material__number', 'material__type',
|
||||||
|
'count', 'material__count', 'material__count_safe')
|
||||||
l_m = list(materials)
|
l_m = list(materials)
|
||||||
for m in l_m:
|
for m in l_m:
|
||||||
if m['material__id'] in res_d_list:
|
if m['material__id'] in res_d_list:
|
||||||
|
|
@ -231,7 +235,8 @@ class ResourceViewSet(GenericViewSet):
|
||||||
res_d_list.append(m['material__id'])
|
res_d_list.append(m['material__id'])
|
||||||
res.append({'id':m['material__id'], 'name':m['material__name'],
|
res.append({'id':m['material__id'], 'name':m['material__name'],
|
||||||
'type':m['material__type'], 'number':m['material__number'],
|
'type':m['material__type'], 'number':m['material__number'],
|
||||||
'count':m['count']*i['count'], 'inv_count':m['material__count']})
|
'count':m['count']*i['count'], 'inv_count':m['material__count'],
|
||||||
|
'count_safe':m['material__count_safe']})
|
||||||
return Response(res)
|
return Response(res)
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=ResourceCalListSerializer)
|
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=ResourceCalListSerializer)
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ from apps.sam.models import Order
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from utils.mixins import DynamicFieldsFilterMixin
|
||||||
|
|
||||||
class OrderFilterSet(filters.FilterSet):
|
|
||||||
|
class OrderFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
||||||
create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte')
|
create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte')
|
||||||
material = filters.NumberFilter(method='filter_material')
|
material = filters.NumberFilter(method='filter_material')
|
||||||
|
|
@ -23,13 +25,16 @@ class OrderFilterSet(filters.FilterSet):
|
||||||
plan_order__subplan_plan__progress_subplan__material__id=value).distinct()
|
plan_order__subplan_plan__progress_subplan__material__id=value).distinct()
|
||||||
|
|
||||||
def filter_tag(self, queryset, name, value):
|
def filter_tag(self, queryset, name, value):
|
||||||
|
now = datetime.now()
|
||||||
|
day7_after = now + timedelta(days=7)
|
||||||
if value == 'near_delivery':
|
if value == 'near_delivery':
|
||||||
day7_after = datetime.now() + timedelta(days=7)
|
|
||||||
queryset = queryset.filter(delivered_count__lt=F('count'),
|
queryset = queryset.filter(delivered_count__lt=F('count'),
|
||||||
delivery_date__lte = datetime.date(day7_after))
|
delivery_date__lte = datetime.date(day7_after))
|
||||||
elif value == 'out_delivery':
|
elif value == 'out_delivery':
|
||||||
queryset = queryset.filter(delivered_count__lt=F('count'),
|
queryset = queryset.filter(delivered_count__lt=F('count'),
|
||||||
delivery_date__gt = datetime.date(datetime.now()))
|
delivery_date__gt = datetime.date(datetime.now()))
|
||||||
|
elif value == 'not_done':
|
||||||
|
queryset = queryset.filter(delivered_count__lt=F('count'))
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
class ContractFilterSet(filters.FilterSet):
|
class ContractFilterSet(filters.FilterSet):
|
||||||
|
|
|
||||||
|
|
@ -32,17 +32,10 @@ class Contract(CommonAModel):
|
||||||
"""
|
"""
|
||||||
合同信息
|
合同信息
|
||||||
"""
|
"""
|
||||||
state_choices = (
|
|
||||||
(0, '完好'),
|
|
||||||
(1, '限用'),
|
|
||||||
(2, '在修'),
|
|
||||||
(3, '禁用')
|
|
||||||
)
|
|
||||||
name = models.CharField('合同名称', max_length=100)
|
name = models.CharField('合同名称', max_length=100)
|
||||||
number = models.CharField('合同编号', max_length=100, unique=True)
|
number = models.CharField('合同编号', max_length=100, unique=True)
|
||||||
amount = models.IntegerField('合同金额', default=0)
|
amount = models.IntegerField('合同金额', default=0)
|
||||||
invoice = models.IntegerField('开票金额', default=0)
|
invoice = models.IntegerField('开票金额', default=0)
|
||||||
#state = models.CharField('合同状态', choices= state_choices, max_length=20, default=1)
|
|
||||||
customer = models.ForeignKey(Customer, verbose_name='关联客户', on_delete=models.CASCADE, related_name='contact_customer')
|
customer = models.ForeignKey(Customer, verbose_name='关联客户', on_delete=models.CASCADE, related_name='contact_customer')
|
||||||
sign_date = models.DateField('签订日期')
|
sign_date = models.DateField('签订日期')
|
||||||
description = models.CharField('描述', max_length=200, blank=True, null=True)
|
description = models.CharField('描述', max_length=200, blank=True, null=True)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
from django.db import transaction
|
|
||||||
from rest_framework import exceptions, serializers
|
|
||||||
|
|
||||||
from apps.inm.models import IProduct
|
from rest_framework import serializers
|
||||||
from apps.inm.serializers import IProductListSerializer
|
|
||||||
|
|
||||||
from .models import Contract, Customer, Order, Sale, SaleProduct
|
from utils.mixins import DynamicFieldsSerializerMixin
|
||||||
|
|
||||||
|
from .models import Contract, Customer, Order
|
||||||
|
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||||
from utils.tools import ranstr
|
from utils.tools import ranstr
|
||||||
|
|
@ -44,13 +43,13 @@ class ContractCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
class OrderCreateUpdateSerializer(serializers.ModelSerializer):
|
class OrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
fields = ['customer', 'contract', 'product', 'count', 'delivery_date']
|
fields = ['customer', 'contract', 'product', 'count', 'delivery_date', 'need_mtest']
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['number'] = 'DD' + ranstr(7)
|
validated_data['number'] = 'DD' + ranstr(7)
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
class OrderSerializer(serializers.ModelSerializer):
|
class OrderSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializer):
|
||||||
contract_ = ContractSimpleSerializer(source='contract', read_only=True)
|
contract_ = ContractSimpleSerializer(source='contract', read_only=True)
|
||||||
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
||||||
product_ = MaterialSimpleSerializer(source='product', read_only=True)
|
product_ = MaterialSimpleSerializer(source='product', read_only=True)
|
||||||
|
|
@ -63,48 +62,5 @@ class OrderSimpleSerializer(serializers.ModelSerializer):
|
||||||
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
fields = ['id', 'number', 'contract_', 'customer_', 'need_mtest']
|
fields = ['id', 'number', 'contract_', 'customer_', 'need_mtest', 'delivery_date']
|
||||||
|
|
||||||
class SaleCreateSerializer(serializers.ModelSerializer):
|
|
||||||
iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), many=True)
|
|
||||||
class Meta:
|
|
||||||
model = Sale
|
|
||||||
fields = ['customer', 'order', 'product', 'iproducts']
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
order = attrs.get('order', None)
|
|
||||||
if order:
|
|
||||||
if order.customer:
|
|
||||||
attrs['customer'] = order.customer
|
|
||||||
attrs['product'] = order.product
|
|
||||||
for i in attrs['iproducts']:
|
|
||||||
if i.material != attrs['product']:
|
|
||||||
raise exceptions.APIException('产品选取错误')
|
|
||||||
return super().validate(attrs)
|
|
||||||
|
|
||||||
|
|
||||||
class SaleListSerializer(serializers.ModelSerializer):
|
|
||||||
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
|
||||||
order_ = OrderSimpleSerializer(source='order', read_only=True)
|
|
||||||
product_ = MaterialSimpleSerializer(source='product', read_only=True)
|
|
||||||
class Meta:
|
|
||||||
model = Sale
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
class SaleProductListSerializer(serializers.ModelSerializer):
|
|
||||||
iproduct_ = IProductListSerializer(source='iproduct', read_only=True)
|
|
||||||
class Meta:
|
|
||||||
model = SaleProduct
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
class SaleProductCreateSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = SaleProduct
|
|
||||||
fields = ['sale', 'iproduct']
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
validated_data['number'] = validated_data['iproduct'].number
|
|
||||||
instance = SaleProduct.objects.create(**validated_data)
|
|
||||||
instance.sale.count = SaleProduct.objects.filter(sale=instance.sale).count()
|
|
||||||
instance.sale.save()
|
|
||||||
return instance
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from rest_framework import exceptions
|
||||||
|
from apps.inm.models import IProduct
|
||||||
|
from apps.inm.serializers import IProductListSerializer
|
||||||
|
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||||
|
from apps.sam.models import Sale, SaleProduct
|
||||||
|
from apps.sam.serializers import CustomerSimpleSerializer, OrderSimpleSerializer
|
||||||
|
class SaleCreateSerializer(serializers.ModelSerializer):
|
||||||
|
iproducts = serializers.PrimaryKeyRelatedField(queryset=
|
||||||
|
IProduct.objects.all(), many=True)
|
||||||
|
class Meta:
|
||||||
|
model = Sale
|
||||||
|
fields = ['customer', 'order', 'product', 'iproducts']
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
order = attrs.get('order', None)
|
||||||
|
if order:
|
||||||
|
if order.customer:
|
||||||
|
attrs['customer'] = order.customer
|
||||||
|
attrs['product'] = order.product
|
||||||
|
for i in attrs['iproducts']:
|
||||||
|
if i.material != attrs['product']:
|
||||||
|
raise exceptions.APIException('产品选取错误')
|
||||||
|
return super().validate(attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class SaleListSerializer(serializers.ModelSerializer):
|
||||||
|
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
||||||
|
order_ = OrderSimpleSerializer(source='order', read_only=True)
|
||||||
|
product_ = MaterialSimpleSerializer(source='product', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = Sale
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
class SaleProductListSerializer(serializers.ModelSerializer):
|
||||||
|
iproduct_ = IProductListSerializer(source='iproduct', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = SaleProduct
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
class SaleProductCreateSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = SaleProduct
|
||||||
|
fields = ['sale', 'iproduct']
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['number'] = validated_data['iproduct'].number
|
||||||
|
instance = SaleProduct.objects.create(**validated_data)
|
||||||
|
instance.sale.count = SaleProduct.objects.filter(sale=instance.sale).count()
|
||||||
|
instance.sale.save()
|
||||||
|
return instance
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
from django.db.models import base
|
from django.db.models import base
|
||||||
from rest_framework import urlpatterns
|
from rest_framework import urlpatterns
|
||||||
from apps.sam.views import CustomerViewSet,ContractViewSet,OrderViewSet, SaleProductViewSet, SaleViewSet
|
from apps.sam.views import CustomerViewSet,ContractViewSet, OrderViewSet
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
from apps.sam.views_sale import SaleProductViewSet, SaleViewSet
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register('customer', CustomerViewSet, basename='customer')
|
router.register('customer', CustomerViewSet, basename='customer')
|
||||||
router.register('contract', ContractViewSet, basename='contract')
|
router.register('contract', ContractViewSet, basename='contract')
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,12 @@
|
||||||
from django.db import transaction
|
|
||||||
from django.db.models.aggregates import Count
|
|
||||||
from rest_framework import exceptions, serializers
|
|
||||||
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin
|
|
||||||
from apps.mtm.models import Material
|
|
||||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
|
|
||||||
from apps.inm.signals import update_inm
|
|
||||||
from apps.sam.filters import ContractFilterSet, OrderFilterSet
|
from apps.sam.filters import ContractFilterSet, OrderFilterSet
|
||||||
from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer, SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer
|
from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, \
|
||||||
from apps.sam.models import Contract, Customer, Order, Sale, SaleProduct
|
CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
from apps.sam.models import Contract, Customer, Order
|
||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
from apps.system.mixins import CreateUpdateCustomMixin
|
from apps.system.mixins import CreateUpdateCustomMixin
|
||||||
from django.shortcuts import render
|
|
||||||
from rest_framework.decorators import action
|
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from django.utils import timezone
|
from rest_framework.decorators import action
|
||||||
|
|
||||||
from apps.wf.models import Workflow
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -81,129 +71,6 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
||||||
"""
|
|
||||||
销售记录
|
|
||||||
"""
|
|
||||||
perms_map = {'*': '*'}
|
|
||||||
queryset = Sale.objects.select_related('customer', 'order', 'product', 'order__contract').all()
|
|
||||||
serializer_class = SaleListSerializer
|
|
||||||
search_fields = ['customer__name', 'order__number']
|
|
||||||
filterset_fields = ['product', 'order', 'customer']
|
|
||||||
ordering_fields = ['create_time']
|
|
||||||
ordering = ['-create_time']
|
|
||||||
|
|
||||||
def get_serializer_class(self):
|
|
||||||
if self.action == 'create':
|
|
||||||
return SaleCreateSerializer
|
|
||||||
elif self.action == 'retrieve':
|
|
||||||
return SaleListSerializer
|
|
||||||
return super().get_serializer_class()
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
data = request.data
|
|
||||||
serializer = SaleCreateSerializer(data=data)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
vdata = serializer.validated_data
|
|
||||||
with transaction.atomic():
|
|
||||||
iproducts = vdata.pop('iproducts')
|
|
||||||
vdata['count'] = len(iproducts)
|
|
||||||
sale = Sale.objects.create(**vdata)
|
|
||||||
i_l = []
|
|
||||||
for i in iproducts:
|
|
||||||
i_d ={}
|
|
||||||
i_d['sale'] = sale
|
|
||||||
i_d['number'] = i.number
|
|
||||||
i_d['iproduct'] = i
|
|
||||||
i_l.append(SaleProduct(**i_d))
|
|
||||||
SaleProduct.objects.bulk_create(i_l)
|
|
||||||
return Response()
|
|
||||||
|
|
||||||
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
|
|
||||||
@transaction.atomic
|
|
||||||
def audit(self, request, pk=None):
|
|
||||||
"""
|
|
||||||
审核
|
|
||||||
"""
|
|
||||||
obj = self.get_object()
|
|
||||||
if obj.is_audited:
|
|
||||||
raise exceptions.APIException('已审核通过')
|
|
||||||
# 创建出库记录
|
|
||||||
fifo = FIFO()
|
|
||||||
fifo.type = FIFO.FIFO_TYPE_SALE_OUT
|
|
||||||
fifo.is_audited = True
|
|
||||||
fifo.auditor = request.user
|
|
||||||
fifo.inout_date = timezone.now()
|
|
||||||
fifo.create_by = request.user
|
|
||||||
fifo.save()
|
|
||||||
# 创建出库条目
|
|
||||||
ips = IProduct.objects.filter(sale_iproduct__sale=obj)
|
|
||||||
items = ips.values('warehouse', 'material', 'batch').annotate(total=Count('id'))
|
|
||||||
for i in items:
|
|
||||||
warehouse = WareHouse.objects.get(id=i['warehouse'])
|
|
||||||
material = Material.objects.get(id=i['material'])
|
|
||||||
fifoitem = FIFOItem()
|
|
||||||
fifoitem.need_test = False
|
|
||||||
fifoitem.warehouse = warehouse
|
|
||||||
fifoitem.material = material
|
|
||||||
fifoitem.count = i['total']
|
|
||||||
fifoitem.batch = i['batch']
|
|
||||||
fifoitem.fifo = fifo
|
|
||||||
fifoitem.save()
|
|
||||||
items_p = ips.filter(warehouse=warehouse, batch=i['batch'])
|
|
||||||
ipxs = []
|
|
||||||
for i in items_p:
|
|
||||||
# 创建出库明细半成品
|
|
||||||
ip = {}
|
|
||||||
ip['fifoitem'] = fifoitem
|
|
||||||
ip['number'] = i.number
|
|
||||||
ip['material'] = i.material
|
|
||||||
ip['iproduct'] = i
|
|
||||||
ipxs.append(FIFOItemProduct(**ip))
|
|
||||||
FIFOItemProduct.objects.bulk_create(ipxs)
|
|
||||||
# 更新成品库情况
|
|
||||||
ips.update(is_saled=True)
|
|
||||||
# 更新动态产品表情况
|
|
||||||
from apps.wpm.models import WProduct
|
|
||||||
WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
|
|
||||||
act_state=WProduct.WPR_ACT_STATE_SELLED)
|
|
||||||
# 更新库存
|
|
||||||
update_inm(fifo)
|
|
||||||
# 变更审核状态
|
|
||||||
obj.is_audited = True
|
|
||||||
obj.save()
|
|
||||||
# 变更订单状态
|
|
||||||
if obj.order:
|
|
||||||
order = obj.order
|
|
||||||
order.delivered_count = order.delivered_count + obj.count
|
|
||||||
order.save()
|
|
||||||
return Response()
|
|
||||||
|
|
||||||
class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, GenericViewSet):
|
|
||||||
"""
|
|
||||||
销售记录关联产品
|
|
||||||
"""
|
|
||||||
perms_map = {'*': '*'}
|
|
||||||
queryset = SaleProduct.objects.select_related('iproduct', 'iproduct__material', 'iproduct__warehouse').all()
|
|
||||||
serializer_class = SaleProductListSerializer
|
|
||||||
search_fields = []
|
|
||||||
filterset_fields = ['sale', 'iproduct']
|
|
||||||
ordering_fields = ['create_time']
|
|
||||||
ordering = ['id']
|
|
||||||
|
|
||||||
def get_serializer_class(self):
|
|
||||||
if self.action == 'create':
|
|
||||||
return SaleProductCreateSerializer
|
|
||||||
return super().get_serializer_class()
|
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
|
||||||
obj = self.get_object()
|
|
||||||
sale = obj.sale
|
|
||||||
if sale.is_audited:
|
|
||||||
raise exceptions.APIException('该销售记录已审核,不可删除产品')
|
|
||||||
sale.count = SaleProduct.objects.filter(sale=obj.sale).count()
|
|
||||||
sale.save()
|
|
||||||
obj.delete()
|
|
||||||
return Response()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModelMixin, RetrieveModelMixin
|
||||||
|
from rest_framework.viewsets import GenericViewSet
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
|
||||||
|
from apps.mtm.models import Material
|
||||||
|
from apps.sam.models import Sale, SaleProduct
|
||||||
|
from apps.sam.serializers_sale import SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer
|
||||||
|
from rest_framework import exceptions
|
||||||
|
from django.db import transaction
|
||||||
|
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
|
||||||
|
|
||||||
|
class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
|
||||||
|
"""
|
||||||
|
销售记录
|
||||||
|
"""
|
||||||
|
perms_map = {'*': '*'}
|
||||||
|
queryset = Sale.objects.select_related('customer', 'order', 'product', 'order__contract').all()
|
||||||
|
serializer_class = SaleListSerializer
|
||||||
|
search_fields = ['customer__name', 'order__number']
|
||||||
|
filterset_fields = ['product', 'order', 'customer']
|
||||||
|
ordering_fields = ['create_time']
|
||||||
|
ordering = ['-create_time']
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == 'create':
|
||||||
|
return SaleCreateSerializer
|
||||||
|
elif self.action == 'retrieve':
|
||||||
|
return SaleListSerializer
|
||||||
|
return super().get_serializer_class()
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
data = request.data
|
||||||
|
serializer = SaleCreateSerializer(data=data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.validated_data
|
||||||
|
with transaction.atomic():
|
||||||
|
iproducts = vdata.pop('iproducts')
|
||||||
|
vdata['count'] = len(iproducts)
|
||||||
|
sale = Sale.objects.create(**vdata)
|
||||||
|
i_l = []
|
||||||
|
for i in iproducts:
|
||||||
|
i_d ={}
|
||||||
|
i_d['sale'] = sale
|
||||||
|
i_d['number'] = i.number
|
||||||
|
i_d['iproduct'] = i
|
||||||
|
i_l.append(SaleProduct(**i_d))
|
||||||
|
SaleProduct.objects.bulk_create(i_l)
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def audit(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
审核
|
||||||
|
"""
|
||||||
|
obj = self.get_object()
|
||||||
|
if obj.is_audited:
|
||||||
|
raise exceptions.APIException('已审核通过')
|
||||||
|
# 创建出库记录
|
||||||
|
fifo = FIFO()
|
||||||
|
fifo.type = FIFO.FIFO_TYPE_SALE_OUT
|
||||||
|
fifo.is_audited = True
|
||||||
|
fifo.auditor = request.user
|
||||||
|
fifo.inout_date = timezone.now()
|
||||||
|
fifo.create_by = request.user
|
||||||
|
fifo.save()
|
||||||
|
# 创建出库条目
|
||||||
|
ips = IProduct.objects.filter(sale_iproduct__sale=obj)
|
||||||
|
items = ips.values('warehouse', 'material', 'batch').annotate(total=Count('id'))
|
||||||
|
for i in items:
|
||||||
|
warehouse = WareHouse.objects.get(id=i['warehouse'])
|
||||||
|
material = Material.objects.get(id=i['material'])
|
||||||
|
fifoitem = FIFOItem()
|
||||||
|
fifoitem.need_test = False
|
||||||
|
fifoitem.warehouse = warehouse
|
||||||
|
fifoitem.material = material
|
||||||
|
fifoitem.count = i['total']
|
||||||
|
fifoitem.batch = i['batch']
|
||||||
|
fifoitem.fifo = fifo
|
||||||
|
fifoitem.save()
|
||||||
|
items_p = ips.filter(warehouse=warehouse, batch=i['batch'])
|
||||||
|
ipxs = []
|
||||||
|
for i in items_p:
|
||||||
|
# 创建出库明细半成品
|
||||||
|
ip = {}
|
||||||
|
ip['fifoitem'] = fifoitem
|
||||||
|
ip['number'] = i.number
|
||||||
|
ip['material'] = i.material
|
||||||
|
ip['iproduct'] = i
|
||||||
|
ipxs.append(FIFOItemProduct(**ip))
|
||||||
|
FIFOItemProduct.objects.bulk_create(ipxs)
|
||||||
|
# 更新成品库情况
|
||||||
|
ips.update(is_saled=True)
|
||||||
|
# 更新动态产品表情况
|
||||||
|
from apps.wpm.models import WProduct
|
||||||
|
WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
|
||||||
|
act_state=WProduct.WPR_ACT_STATE_SELLED)
|
||||||
|
# 更新库存
|
||||||
|
update_inm(fifo)
|
||||||
|
# 变更审核状态
|
||||||
|
obj.is_audited = True
|
||||||
|
obj.save()
|
||||||
|
# 变更订单状态
|
||||||
|
if obj.order:
|
||||||
|
order = obj.order
|
||||||
|
order.delivered_count = order.delivered_count + obj.count
|
||||||
|
order.save()
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, GenericViewSet):
|
||||||
|
"""
|
||||||
|
销售记录关联产品
|
||||||
|
"""
|
||||||
|
perms_map = {'*': '*'}
|
||||||
|
queryset = SaleProduct.objects.select_related('iproduct', 'iproduct__material', 'iproduct__warehouse').all()
|
||||||
|
serializer_class = SaleProductListSerializer
|
||||||
|
search_fields = []
|
||||||
|
filterset_fields = ['sale', 'iproduct']
|
||||||
|
ordering_fields = ['create_time']
|
||||||
|
ordering = ['id']
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == 'create':
|
||||||
|
return SaleProductCreateSerializer
|
||||||
|
return super().get_serializer_class()
|
||||||
|
|
||||||
|
def destroy(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
sale = obj.sale
|
||||||
|
if sale.is_audited:
|
||||||
|
raise exceptions.APIException('该销售记录已审核,不可删除产品')
|
||||||
|
sale.count = SaleProduct.objects.filter(sale=obj.sale).count()
|
||||||
|
sale.save()
|
||||||
|
obj.delete()
|
||||||
|
return Response()
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.9 on 2022-01-25 08:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('system', '0004_user_is_atwork'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='last_check_time',
|
||||||
|
field=models.DateTimeField(blank=True, null=True, verbose_name='打卡时间'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -117,6 +117,7 @@ class User(AbstractUser):
|
||||||
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
|
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
|
||||||
roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')
|
roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')
|
||||||
is_atwork = models.BooleanField('当前在岗', default=False)
|
is_atwork = models.BooleanField('当前在岗', default=False)
|
||||||
|
last_check_time = models.DateTimeField('打卡时间', null=True, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '用户信息'
|
verbose_name = '用户信息'
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ class UserListSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializ
|
||||||
fields = ['id', 'name', 'phone', 'email', 'position',
|
fields = ['id', 'name', 'phone', 'email', 'position',
|
||||||
'username', 'is_active', 'date_joined',
|
'username', 'is_active', 'date_joined',
|
||||||
'dept_name', 'dept', 'roles', 'avatar',
|
'dept_name', 'dept', 'roles', 'avatar',
|
||||||
'roles_name', 'is_atwork']
|
'roles_name', 'is_atwork', 'last_check_time']
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def setup_eager_loading(queryset):
|
def setup_eager_loading(queryset):
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ class WProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WProduct
|
model = WProduct
|
||||||
fields = ['step', 'subproduction_plan', 'material',
|
fields = ['step', 'subproduction_plan', 'material',
|
||||||
'step__process', 'act_state', 'material__type']
|
'step__process', 'act_state', 'material__type', 'need_to_order']
|
||||||
|
|
||||||
def filter_tag(self, queryset, name, value):
|
def filter_tag(self, queryset, name, value):
|
||||||
if value == 'no_scrap':
|
if value == 'no_scrap':
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Generated by Django 3.2.9 on 2022-01-25 03:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wpm', '0051_auto_20220120_1541'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproduct',
|
||||||
|
name='is_mtested',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductflow',
|
||||||
|
name='is_mtested',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproduct',
|
||||||
|
name='need_to_order',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='是否要指派订单'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproductflow',
|
||||||
|
name='need_to_order',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='是否要指派订单'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -119,6 +119,7 @@ class WProduct(CommonAModel):
|
||||||
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
|
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
|
||||||
|
|
||||||
|
need_to_order = models.BooleanField('是否要指派订单', default=False)
|
||||||
to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
|
to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
|
||||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||||
remark_mtest = models.TextField('军检备注', null=True, blank=True)
|
remark_mtest = models.TextField('军检备注', null=True, blank=True)
|
||||||
|
|
@ -192,6 +193,8 @@ class WproductFlow(CommonAModel):
|
||||||
on_delete=models.SET_NULL, null=True, blank=True)
|
on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||||
on_delete=models.SET_NULL, null=True, blank=True)
|
on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
|
|
||||||
|
need_to_order = models.BooleanField('是否要指派订单', default=False)
|
||||||
to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
|
to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
|
||||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||||
remark_mtest = models.TextField('军检备注', null=True, blank=True)
|
remark_mtest = models.TextField('军检备注', null=True, blank=True)
|
||||||
|
|
|
||||||
|
|
@ -575,3 +575,6 @@ class WproductMtestSerializer(serializers.ModelSerializer):
|
||||||
class WproductToOrderSerializer(serializers.Serializer):
|
class WproductToOrderSerializer(serializers.Serializer):
|
||||||
wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), many=True)
|
wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), many=True)
|
||||||
order = serializers.PrimaryKeyRelatedField(queryset=Order.objects.all())
|
order = serializers.PrimaryKeyRelatedField(queryset=Order.objects.all())
|
||||||
|
|
||||||
|
class WproductNeedToOrderSerializer(serializers.Serializer):
|
||||||
|
wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), many=True)
|
||||||
|
|
@ -26,7 +26,7 @@ from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerial
|
||||||
OperationListSerializer, OperationWproductUpdateSerializer, PickHalfsSerializer, \
|
OperationListSerializer, OperationWproductUpdateSerializer, PickHalfsSerializer, \
|
||||||
PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, \
|
PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, \
|
||||||
WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, \
|
WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, \
|
||||||
WpmTestFormInitSerializer, WproductMtestSerializer, WproductPutInSerializer, \
|
WpmTestFormInitSerializer, WproductMtestSerializer, WproductNeedToOrderSerializer, WproductPutInSerializer, \
|
||||||
WproductPutInsSerializer, WproductTicketListSerializer, WproductToOrderSerializer
|
WproductPutInsSerializer, WproductTicketListSerializer, WproductToOrderSerializer
|
||||||
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
@ -399,7 +399,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
军检
|
军检
|
||||||
"""
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
if obj.is_mtestok is None:
|
if obj.is_mtestok is not None:
|
||||||
raise exceptions.APIException('已进行军检')
|
raise exceptions.APIException('已进行军检')
|
||||||
if obj.material.type != Material.MA_TYPE_GOOD:
|
if obj.material.type != Material.MA_TYPE_GOOD:
|
||||||
raise exceptions.APIException('军检必须是成品')
|
raise exceptions.APIException('军检必须是成品')
|
||||||
|
|
@ -409,6 +409,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
if is_mtestok:
|
if is_mtestok:
|
||||||
WpmServies.update_plan_state_by_mtestok(
|
WpmServies.update_plan_state_by_mtestok(
|
||||||
obj.subproduction_plan.production_plan)
|
obj.subproduction_plan.production_plan)
|
||||||
|
obj.update_by = request.user
|
||||||
obj.save()
|
obj.save()
|
||||||
change_str = 'mtest_notok'
|
change_str = 'mtest_notok'
|
||||||
if is_mtestok:
|
if is_mtestok:
|
||||||
|
|
@ -441,6 +442,24 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
ret.append([str(index + 1), item['step_name'], item['actions']])
|
ret.append([str(index + 1), item['step_name'], item['actions']])
|
||||||
return Response(ret)
|
return Response(ret)
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductNeedToOrderSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def need_to_order(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
设为需要指派订单
|
||||||
|
"""
|
||||||
|
serializer = WproductNeedToOrderSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.validated_data
|
||||||
|
wps = WProduct.objects.filter(id__in = [i.id for i in vdata.get('wproducts')])
|
||||||
|
wps.update()
|
||||||
|
for i in wps:
|
||||||
|
i.need_to_order = True
|
||||||
|
i.update_by = request.user
|
||||||
|
i.save()
|
||||||
|
WpmServies.add_wproduct_flow_log(i, change_str='need_to_order')
|
||||||
|
return Response()
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductToOrderSerializer)
|
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductToOrderSerializer)
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def to_order(self, request, pk=None):
|
def to_order(self, request, pk=None):
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,13 @@ class FitJSONRenderer(JSONRenderer):
|
||||||
response_body = BaseResponse()
|
response_body = BaseResponse()
|
||||||
response = renderer_context.get("response")
|
response = renderer_context.get("response")
|
||||||
status_code = response.status_code # Http状态异常码
|
status_code = response.status_code # Http状态异常码
|
||||||
|
print(status_code)
|
||||||
if status_code >= 400: # 如果http响应异常
|
if status_code >= 400: # 如果http响应异常
|
||||||
if isinstance(data, dict) and 'code' in data: # 如果自定义了异常码
|
if isinstance(data, dict) and 'code' in data: # 如果自定义了异常码
|
||||||
response_body = data
|
response_body = data
|
||||||
else:
|
else:
|
||||||
response_body.data = data # data里是详细异常信息
|
response_body.data = data # data里是详细异常信息
|
||||||
|
response_body.code = status_code
|
||||||
prefix = ""
|
prefix = ""
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
prefix = list(data.keys())[0]
|
prefix = list(data.keys())[0]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue