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

This commit is contained in:
shijing 2022-01-12 10:33:50 +08:00
commit dc3067a101
42 changed files with 826 additions and 366 deletions

View File

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

View File

@ -324,3 +324,13 @@ export function getwproductticketList(query) {
params: query
})
}
//下料清单
export function getcutList(query) {
return request({
url: '/wpm/cutting_list/',
method: 'get',
params: query
})
}

View File

@ -184,7 +184,25 @@ export const asyncRoutes = [
name: 'management',
component: () => import('@/views/pm/management'),
meta: { title: '生产任务管理', icon: 'example', perms: ['pm_resources'] }
},
{
path: 'plandetails/:id',
name: 'plandetails',
component: () => import('@/views/pm/plandetails'),
meta: { title: '生产任务详情', perms: ['vendor_manage'] },
hidden: true
}
,
{
path: 'processcard/:id',
name: 'processcard',
component: () => import('@/views/pm/processcard'),
meta: { title: '流程卡', perms: ['vendor_manage'] },
hidden: true
}
]
}
,

View File

@ -65,8 +65,8 @@
<el-table-column label="生产数量" width="110">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
<el-table-column label="生产状态" width="110">
<template slot-scope="scope">{{ scope.row.count }}</template>
<el-table-column label="状态" width="110">
<template slot-scope="scope">{{ state_[scope.row.state] }}</template>
</el-table-column>
<el-table-column label="计划开工时间" width="110">
<template slot-scope="scope">{{ scope.row.start_date }}</template>
@ -131,7 +131,13 @@ export default {
page: 1,
page_size: 20,
},
state_:{
10:'制定中',
20:'已下达',
30:'已接受',
40:'生产中',
50:'已完成',
60:'军检完成'},
listLoading: true,
proList: [],
@ -271,6 +277,10 @@ export default {
this.listLoading = false;
});
},
//详情
handleselectplan(scope){
this.$router.push({ name: "plandetails", params: { id: scope.row.id } });
},
},
};
</script>

View File

@ -5,7 +5,27 @@
<span>生产任务列表</span>
</div>
<el-input
v-model="listQuery1.search"
placeholder="任务编号/订单编号/合同编号/产品名称"
style="width: 300px"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索</el-button
>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>重置</el-button
>
<el-table
:data="productionplanList.results"
border
@ -285,7 +305,7 @@
getplanList() {
let that = this;
this.listLoading = true;
getProductionplanList(this.listQuery).then((response) => {
getProductionplanList(this.listQuery1).then((response) => {
if (response.data) {
this.productionplanList = response.data;
let list = response.data.results;
@ -313,6 +333,18 @@
}
this.listLoading = false;
});
},
//搜索生产计划
handleFilter() {
this.listQuery1.page = 1;
this.getplanList();
},
resetFilter() {
this.listQuery1 = {
page: 1,
page_size: 20,
}
this.getplanList();
},
handleclick(scope) {
this.orderID = scope.row.id;

View File

@ -0,0 +1,179 @@
<template>
<div class="app-container">
<el-card style="margin-top: 2px">
<el-descriptions title="任务详情" :column="4" border style="margin-bottom: 20px">
<el-descriptions-item label="任务编号">{{productionplan.number}}</el-descriptions-item>
<el-descriptions-item label="产品名称" v-if="productionplan.product_">{{productionplan.product_.name}}</el-descriptions-item>
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}</el-descriptions-item>
<el-descriptions-item label="生产数量">{{productionplan.count}}</el-descriptions-item>
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
<el-descriptions-item label="计划开工时间">{{productionplan.start_date}}</el-descriptions-item>
<el-descriptions-item label="计划完工时间">{{productionplan.end_date}}</el-descriptions-item>
</el-descriptions>
<el-table
:data="wproduct"
border
fit
stripe
style="width: 100%"
height="500"
>
<el-table-column type="index" label="序号" width="50" />
<el-table-column label="玻璃编号/产品编号" >
<template slot-scope="scope" >{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="所在子工序">
<template slot-scope="scope" >{{
scope.row.step_.name
}}</template>
</el-table-column>
<el-table-column label="产品状态" >
<template slot-scope="scope">{{
actstate_[scope.row.act_state]
}}</template>
</el-table-column>
<el-table-column label="生产状态">
<template slot-scope="scope" >{{
scope.row.step_.name
}}</template>
</el-table-column>
<el-table-column label="最后检验结果">
<template slot-scope="scope" >{{
scope.row.step_.name
}}</template>
</el-table-column>
<el-table-column label="生成记录">
<template slot-scope="scope" >{{
scope.row.step_.name
}}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['material_delete'])"
type="primary"
@click="handleoption(scope)"
>生成流程卡</el-link
>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import { getProductionplan,getsubproductionplanList } from "@/api/pm";
import { getwproductList} from "@/api/wpm";
import checkPermission from "@/utils/permission";
import {getTestRecord} from "@/api/qm";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default {
components: { Pagination },
data() {
return {
productionplan:{
number:""
},
activeName:"1",
wproduct:[],
listQuery: {
page: 1,
page_size: 20,
},
state_:{
10:'制定中',
20:'已下达',
30:'已接受',
40:'生产中',
50:'已完成',
60:'军检完成'},
actstate_: {
6: "待复检",
10: "操作进行中",
20: "待检验",
30: "已合格",
40: "库存中",
50: "不合格",
60: "待成品检验",
8: "操作准备中",
26: "待夹层检验",
70: "报废",
},
process_json:null,
productionplanID:null,
};
},
computed: {},
watch: {},
created() {
this.id = this.$route.params.id;
this.getList();
this.getwproductList();
},
methods: {
checkPermission,
getList() {
getProductionplan(this.id).then((response) => {
if (response.data) {
this.productionplan = response.data;
this.productionplanID=response.data.id;
let process_json = [];
for(let item in response.data.process_json){
let obj = new Object();
obj = response.data.process_json[item];
process_json.push(obj)
}
this.process_json= process_json;
}
});
},
getwproductList()
{
getwproductList({production_plan:this.id,page:0,}).then((response) => {
if (response.data) {
this.wproduct = response.data;
}
});
},
//查看该玻璃检验记录表
handleoption(scope){
this.$router.push({name: "processcard", params: { id: scope.row.id }, })
},
},
};
</script>

View File

@ -0,0 +1,34 @@
<template>
<div class="app-container">
<el-card style="margin-top: 2px">
流程卡界面正在更新
</el-card>
</div>
</template>
<script>
import checkPermission from "@/utils/permission";
import { getProductionplan,getsubproductionplanList } from "@/api/pm";
import { getMaterialList, getrecordformList, getrffieldList } from "@/api/mtm";
import customForm from "@/components/customForm/index";
import { getTestRecord ,getTestRecordItem} from "@/api/qm";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default {
components: { Pagination, customForm },
data() {
return {
};
},
computed: {},
watch: {},
created() {
},
methods: {
checkPermission,
},
};
</script>

View File

@ -43,25 +43,25 @@
>
</el-table-column>
<el-table-column label="镀膜">
<template slot-scope="scope" v-if="scope.row.process_json['04']"
>{{ scope.row.process_json["04"].rate }}%</template
>
</el-table-column>
<el-table-column label="夹层">
<template slot-scope="scope" v-if="scope.row.process_json['05']"
>{{ scope.row.process_json["05"].rate }}%</template
>
</el-table-column>
<el-table-column label="包边">
<el-table-column label="夹层">
<template slot-scope="scope" v-if="scope.row.process_json['06']"
>{{ scope.row.process_json["06"].rate }}%</template
>
</el-table-column>
<el-table-column label="装框">
<el-table-column label="包边">
<template slot-scope="scope" v-if="scope.row.process_json['07']"
>{{ scope.row.process_json["07"].rate }}%</template
>
</el-table-column>
<el-table-column label="装框">
<template slot-scope="scope" v-if="scope.row.process_json['08']"
>{{ scope.row.process_json["08"].rate }}%</template
>
</el-table-column>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{
@ -251,10 +251,10 @@ export default {
"01": "冷加工",
"02": "热弯",
"03": "化学钢化",
"04": "镀膜",
"05": "夹层",
"06": "包边",
"07": "装框",
"05": "镀膜",
"06": "夹层",
"07": "包边",
"08": "装框",
},
decision_: {
10: "返工",

View File

@ -1,191 +1,67 @@
<template>
<div class="app-container">
<el-card style="margin-top: 2px">
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
<el-tabs v-model="activeName" type="card" >
<el-tab-pane label="总览" name="1" >
</el-tab-pane>
<el-tab-pane label="待检成品" name="2">
<el-table
v-loading="listLoading"
:data="fifodetailList1.results"
:data="wproductList.results"
border
fit
stripe
highlight-current-row
height="620"
v-el-height-adaptive-table="{bottomOffset: 40}"
max-height="600"
>
<el-table-column type="index" width="50" />
<el-table-column label="物料批次">
<template slot-scope="scope">{{ scope.row.batch }}</template>
</el-table-column>
<el-table-column label="物料名称">
<el-table-column type="index" width="50"/>
<el-table-column label="成品名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column>
<el-table-column label="规格型号">
<template slot-scope="scope">{{
scope.row.material_.specification
}}</template>
<el-table-column label="成品编号">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="物料单位">
<template slot-scope="scope">{{ scope.row.material_.unit }}</template>
</el-table-column>
<el-table-column label="总数量">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
<el-table-column label="检查状态">
<el-table-column label="检测状态">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_tested == false">未检查</el-tag>
<el-tag v-else>已检查</el-tag>
{{ actstate_[scope.row.act_state] }}
</template>
</el-table-column>
<el-table-column label="检查是否合格">
<template slot-scope="scope" v-if="scope.row.is_tested == true">
<el-tag v-if="scope.row.is_testok == false">不合格</el-tag>
<el-tag v-else>合格</el-tag>
<el-table-column label="所在子工序">
<template slot-scope="scope">{{ scope.row.step_.name }}</template>
</el-table-column>
<el-table-column align="center" label="操作" width="220px">
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_update'])&&scope.row.test===null"
@click="handleInspection(scope)"
>检验
</el-link>
<el-link
v-if="scope.row.test!==null"
@click="checkRecord(scope)"
>检验记录
</el-link>
</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
<pagination
v-show="fifodetailList1.count > 0"
:total="fifodetailList1.count"
:page.sync="listQuery1.page"
:limit.sync="listQuery1.page_size"
@pagination="getList1"
/>
</el-tab-pane>
<el-tab-pane label="待检物料" name="2">
<el-table
v-loading="listLoading"
:data="fifodetailList2.results"
border
fit
stripe
highlight-current-row
height="620"
v-el-height-adaptive-table="{bottomOffset: 40}"
>
<el-table-column type="index" width="50" />
<el-table-column label="物料批次">
<template slot-scope="scope">{{ scope.row.batch }}</template>
</el-table-column>
<el-table-column label="物料名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column>
<el-table-column label="规格型号">
<template slot-scope="scope">{{
scope.row.material_.specification
}}</template>
</el-table-column>
<el-table-column label="物料单位">
<template slot-scope="scope">{{ scope.row.material_.unit }}</template>
</el-table-column>
<el-table-column label="总数量">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
<pagination
v-show="fifodetailList2.count > 0"
:total="fifodetailList2.count"
:page.sync="listQuery2.page"
:limit.sync="listQuery2.page_size"
@pagination="getList2"
v-show="wproductList.count > 0"
:total="wproductList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-tab-pane>
<el-tab-pane label="合格物料" name="3">
<el-table
v-loading="listLoading"
:data="fifodetailList3.results"
border
fit
stripe
highlight-current-row
height="620"
v-el-height-adaptive-table="{bottomOffset: 40}"
>
<el-table-column type="index" width="50" />
<el-table-column label="物料批次">
<template slot-scope="scope">{{ scope.row.batch }}</template>
</el-table-column>
<el-table-column label="物料名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column>
<el-table-column label="规格型号">
<template slot-scope="scope">{{
scope.row.material_.specification
}}</template>
</el-table-column>
<el-table-column label="物料单位">
<template slot-scope="scope">{{ scope.row.material_.unit }}</template>
</el-table-column>
<el-table-column label="仓库">
<template slot-scope="scope">{{ scope.row.warehouse_.name }}</template>
</el-table-column>
<el-tab-pane label="合格成品" name="3">
<el-table-column label="入库数量">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
<pagination
v-show="fifodetailList3.count > 0"
:total="fifodetailList3.count"
:page.sync="listQuery3.page"
:limit.sync="listQuery3.page_size"
@pagination="getList3"
/>
</el-tab-pane>
<el-tab-pane label="不合格物料" name="4">
<el-table
v-loading="listLoading"
:data="fifodetailList4.results"
border
fit
stripe
highlight-current-row
height="620"
v-el-height-adaptive-table="{bottomOffset: 40}"
>
<el-table-column type="index" width="50" />
<el-table-column label="物料批次">
<template slot-scope="scope">{{ scope.row.batch }}</template>
</el-table-column>
<el-table-column label="物料名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column>
<el-table-column label="规格型号">
<template slot-scope="scope">{{
scope.row.material_.specification
}}</template>
</el-table-column>
<el-table-column label="物料单位">
<template slot-scope="scope">{{ scope.row.material_.unit }}</template>
</el-table-column>
<el-tab-pane label="不合格成品" name="4">
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
<pagination
v-show="fifodetailList4.count > 0"
:total="fifodetailList4.count"
:page.sync="listQuery4.page"
:limit.sync="listQuery4.page_size"
@pagination="getList4"
/>
</el-tab-pane>
</el-tabs>
@ -200,127 +76,49 @@
import { getfifodetailList } from "@/api/inm";
import checkPermission from "@/utils/permission";
import { createTestrecord } from "@/api/inm";
import {getwproductList, wproductTest, wproductPutin, createputins} from "@/api/wpm";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default {
components: { Pagination },
data() {
return {
InventoryList: {
wproductList: {
count: 0,
},
fifodetailList1: {
count: 0,
},
listQuery1: {
listQuery: {
page: 1,
page_size: 20,
},
listQuery2: {
page: 1,
page_size: 20,
},
listQuery3: {
page: 1,
page_size: 20,
},
listQuery4: {
page: 1,
page_size: 20,
},
is_testok: "true",
fifodetailList2:{
count: 0,
},
fifodetailList3:{
count: 0,
},
fifodetailList4:{
count: 0,
},
activeName:"1"
};
},
computed: {},
watch: {},
created() {
this.getList1();
this.getList();
},
methods: {
checkPermission,
getList1() {
this.listLoading = true;
this.listQuery1.material=1;
this.listQuery1.fifo__type = 1;
getfifodetailList(this.listQuery1).then((response) => {
if (response.data) {
this.fifodetailList1 = response.data;
}
this.listLoading = false;
});
},
//待检
getList2() {
this.listLoading = true;
this.listQuery2.fifo__type = 1;
this.listQuery2.material=1;
this.listQuery2.is_tested = false;
getfifodetailList(this.listQuery2).then((response) => {
if (response.data) {
this.fifodetailList2 = response.data;
}
this.listLoading = false;
});
},
//合格物料
getList3() {
this.listLoading = true;
this.listQuery3.fifo__type = 1;
this.listQuery3.material=1;
this.listQuery3.is_testok = true;
getfifodetailList(this.listQuery3).then((response) => {
if (response.data) {
this.fifodetailList3 = response.data;
}
this.listLoading = false;
});
},
//不合格物料
getList4() {
this.listLoading = true;
this.listQuery4.fifo__type = 1;
this.listQuery1.material=1;
this.listQuery4.is_testok = false;
this.listQuery4.is_tested = true;
getfifodetailList(this.listQuery4).then((response) => {
if (response.data) {
this.fifodetailList4 = response.data;
}
this.listLoading = false;
});
},
//选项卡切换
handleClick(tab) {
if(tab.name==1)
{
this.getList1()
}
else if(tab.name==2)
{
this.getList2()
}
else if(tab.name==3)
{
this.getList3()
}
else
{
this.getList4()
//待检成品列表
getList() {
this.listQuery.act_state = 60;
this.listQuery.material__type = 1;
getwproductList(this.listQuery).then((response) => {
if (response.data) {
this.wproductList = response.data;
}
});
},
},
};
</script>

View File

@ -8,7 +8,65 @@
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
<el-descriptions-item label="不合格品数量">不合格数没有</el-descriptions-item>
</el-descriptions>
<el-card style="margin-bottom: 20px">
<div slot="header" class="clearfix">
<span>下料清单</span>
</div>
<el-table
:data="cut"
border
fit
stripe
style="width: 100%"
>
<el-table-column label="序号" type="index" width="50" />
<el-table-column label="玻璃批次" >
<template slot-scope="scope" >{{ scope.row.from_batch }}</template>
</el-table-column>
<el-table-column label="生产型号" >
<template slot-scope="scope" >{{ scope.row.from_material_.specification }}</template>
</el-table-column>
<el-table-column label="切裁规格" >
<template slot-scope="scope" >{{ scope.row.from_material_.specification }}</template>
</el-table-column>
<el-table-column label="切裁板数" >
<template slot-scope="scope" >{{ scope.row.count_cut }}</template>
</el-table-column>
<el-table-column label="切裁片数" >
<template slot-scope="scope" >{{ scope.row.count_real }}</template>
</el-table-column>
<el-table-column label="成品数量" >
<template slot-scope="scope" >{{ scope.row.count_ok }}</template>
</el-table-column>
<el-table-column label="操作人" >
<template slot-scope="scope" >{{ scope.row.create_by_.username }}</template>
</el-table-column>
<el-table-column label="甩片原因及数量(片)" >
<el-table-column label="气泡" >
<template slot-scope="scope" >{{ scope.row.count_qipao }}</template>
</el-table-column>
<el-table-column label="破点" >
<template slot-scope="scope" >{{ scope.row.count_podian }}</template>
</el-table-column>
<el-table-column label="划伤" >
<template slot-scope="scope" >{{ scope.row.count_hua }}</template>
</el-table-column>
<el-table-column label="其他" >
<template slot-scope="scope" >{{ scope.row.count_other }}</template>
</el-table-column>
</el-table-column>
<el-table-column label="检验员" >
<template slot-scope="scope" >{{ scope.row.create_by_.username }}</template>
</el-table-column>
</el-table>
</el-card>
<el-tabs v-model="activeName" type="card" >
<el-tab-pane label="玻璃" name="1" >
<el-table
@ -116,7 +174,7 @@
<script>
import { getProductionplan,getsubproductionplanList } from "@/api/pm";
import { getwproductList} from "@/api/wpm";
import { getwproductList,getcutList} from "@/api/wpm";
import checkPermission from "@/utils/permission";
import {getTestRecord} from "@/api/qm";
@ -129,6 +187,7 @@ export default {
productionplan:{
number:""
},
cut:[],
activeName:"1",
wproduct:[],
subproductionplanList: "",
@ -164,6 +223,7 @@ export default {
created() {
this.id = this.$route.params.id;
this.getList();
this.gecutList();
this.getspList();
this.getwproductList();
@ -209,6 +269,17 @@ export default {
});
},
//下料清单
gecutList()
{
getcutList({production_plan:this.id,page:0}).then((response) => {
if (response.data) {
this.cut = response.data;
}
});
},
//查看该玻璃检验记录表
handleoption(scope){

View File

@ -2,9 +2,10 @@ from django.db.models import base
from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.develop.views import CleanDataView
from apps.develop.views import CleanDataView, UpdateCuttingView
urlpatterns = [
path('cleandata/', CleanDataView.as_view()),
path('update_cutting/', UpdateCuttingView.as_view())
]

View File

@ -1,4 +1,6 @@
from django.db import transaction
from django.shortcuts import render
from rest_framework.decorators import permission_classes
from rest_framework.views import APIView
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
@ -7,7 +9,8 @@ from apps.mtm.models import Material
from apps.pm.models import ProductionPlan
from apps.sam.models import Order
from apps.wf.models import Ticket
from apps.wpm.models import Operation
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow
from apps.wpm.services import WpmServies
# Create your views here.
class CleanDataView(APIView):
@ -26,3 +29,21 @@ class CleanDataView(APIView):
Ticket.objects.all().delete(soft=False)
Operation.objects.all().delete()
return Response()
class UpdateCuttingView(APIView):
permission_classes = [IsAdminUser]
@transaction.atomic
def post(self, request, format=None):
"""
更新下料清单
"""
for i in WProduct.objects.all():
sp = WproductFlow.objects.filter(wproduct=i).order_by('id').first().subproduction_plan
op_q = OperationMaterial.objects.filter(subproduction_plan=sp, operation__step__id=1, operation__is_submited=True)
op = op_q.first().operation
i.coperation = op
i.save()
WproductFlow.objects.filter(wproduct=i).update(coperation=op)
WpmServies.update_cutting_list_with_operation(op)
return Response()

View File

@ -85,6 +85,7 @@ class FaceLogin(CreateAPIView):
unknown_face_encoding = face_recognition.face_encodings(unknown_picture)[0]
os.remove(filepath)
except:
os.remove(filepath)
return Response('头像解码失败', status=status.HTTP_400_BAD_REQUEST)
# 匹配人脸库

View File

@ -14,4 +14,4 @@ class IProductFilterSet(filters.FilterSet):
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
class Meta:
model = IProduct
fields = ['material', 'warehouse', 'batch', 'order', 'is_mtested', 'is_mtestok', 'material__type']
fields = ['material', 'warehouse', 'batch', 'order', 'material__type']

View File

@ -94,9 +94,6 @@ class IProduct(BaseModel):
batch = models.CharField('所属批次号', max_length=100, default='')
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False,
null=True, blank=True, related_name='iproduct_wproduct')
is_mtested = models.BooleanField('是否军检', default=False)
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
remark_mtest = models.TextField('军检备注', null=True, blank=True)
is_saled = models.BooleanField('是否售出', default=False)
class FIFOItemProduct(BaseModel):

View File

@ -40,6 +40,9 @@ class MaterialBatchSerializer(serializers. ModelSerializer):
class IProductListSerializer(serializers.ModelSerializer):
material_= MaterialSimpleSerializer(source='material', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
is_mtested = serializers.BooleanField(source='wproduct.is_mtested', read_only=True)
is_mtestok = serializers.BooleanField(source='wproduct.is_mtestok', read_only=True)
remark_mtest = serializers.CharField(source='wproduct.remark_mtest', read_only=True)
class Meta:
model = IProduct
fields = '__all__'
@ -148,8 +151,3 @@ class InmTestRecordCreateSerializer(serializers.ModelSerializer):
model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'fifo_item']
class IProductMtestSerializer(serializers.ModelSerializer):
class Meta:
model = IProduct
fields = ['remark_mtest', 'is_mtestok']

View File

@ -30,7 +30,8 @@ def update_inm(instance:FIFO, type:int=1):
ip = {}
ip['warehouse'] = warehouse
ip['batch'] = i.batch
ip['wproduct'] = m.wproduct
wp = m.wproduct
ip['wproduct'] = wp
ip['number'] = m.number
ip['material'] = m.material
ips2.append(IProduct(**ip))

View File

@ -7,7 +7,7 @@ from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.filters import IProductFilterSet, MbFilterSet
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, IProductMtestSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
from apps.inm.signals import update_inm
from apps.mtm.models import Material
from apps.pm.services import PmService
@ -172,24 +172,3 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
search_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=IProductMtestSerializer)
@transaction.atomic
def mtest(self, request, pk=None):
"""
军检
"""
obj = self.get_object()
if obj.is_mtested:
raise exceptions.APIException('已进行军检')
if obj.wproduct:
if obj.wproduct.material.type != Material.MA_TYPE_GOOD:
raise exceptions.APIException('军检必须是成品')
obj.remark_mtest = request.data.get('remark_mtest', None)
obj.is_mtested = True
is_mtestok = request.data.get('is_mtestok')
obj.is_mtestok = is_mtestok
if is_mtestok:
WpmServies.update_plan_state_by_mtestok(obj.wproduct.subproduction_plan.production_plan)
obj.save()
return Response()

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class MnsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.mns'
verbose_name = '消息通知系统'

View File

@ -0,0 +1,6 @@
from django.db import models
from utils.model import BaseModel
# Create your models here.
class Notify(BaseModel)
pass

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -1,5 +1,6 @@
from django.db.models.expressions import F
from django_filters import rest_framework as filters
from apps.mtm.models import TechDoc
from apps.mtm.models import Material, TechDoc
@ -13,3 +14,14 @@ class TechDocFilterset(filters.FilterSet):
def filter_operation(self, queryset, name, value):
return queryset.filter(subproduction__subplan_subprod__ow_subplan__operation=value).distinct()
class MaterialFilterSet(filters.FilterSet):
tag = filters.CharFilter(method='filter_tag')
class Meta:
model = Material
fields = ['type', 'tag']
def filter_tag(self, queryset, name, value):
if value == 'low_inm':
queryset = queryset.exclude(count_safe=None).filter(count__lte = F('count_safe'))
return queryset

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2022-01-06 01:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0042_alter_recordformfield_field_type'),
]
operations = [
migrations.AddField(
model_name='material',
name='count_safe',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='安全库存总数'),
),
migrations.AlterField(
model_name='material',
name='count',
field=models.PositiveIntegerField(default=0, verbose_name='物料库存总数'),
),
]

View File

@ -39,7 +39,8 @@ class Material(CommonAModel):
type = models.PositiveSmallIntegerField('物料类型', choices= type_choices, default=1)
sort_str = models.CharField('排序字符', max_length=100, null=True, blank=True)
unit = models.CharField('基准计量单位', choices=unit_choices, default='', max_length=10)
count = models.IntegerField('物料总数', default=0)
count = models.PositiveIntegerField('物料库存总数', default=0)
count_safe = models.PositiveIntegerField('安全库存总数', null=True, blank=True)
piece_count = models.PositiveSmallIntegerField('单片玻璃数量', null=True, blank=True)
class Meta:
verbose_name = '物料表'

View File

@ -1,7 +1,7 @@
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
from apps.mtm.filters import TechDocFilterset
from apps.mtm.filters import MaterialFilterSet, TechDocFilterset
from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormDetailSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubprodctionMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer
@ -22,7 +22,7 @@ class MaterialViewSet(PageOrNot, CreateUpdateModelAMixin, ModelViewSet):
queryset = Material.objects.all()
serializer_class = MaterialSerializer
search_fields = ['name', 'number']
filterset_fields = ['type']
filterset_class = MaterialFilterSet
ordering_fields = ['number', 'sort_str']
ordering = ['number']

View File

@ -1,10 +1,24 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material, Step
from apps.pm.models import SubProductionProgress
from apps.pm.models import ProductionPlan, SubProductionProgress
from apps.wpm.models import Operation, WProduct
from apps.wpm.services import WpmServies
class PlanFilterSet(filters.FilterSet):
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
create_time_end = filters.NumberFilter(field_name="create_time", lookup_expr='lte')
tag = filters.CharFilter(method='filter_tag')
class Meta:
model = ProductionPlan
fields = ['product', 'order', 'create_time_start', 'create_time_end']
def filter_tag(self, queryset, name, value):
if value == 'planed':
queryset = queryset.filter(is_planed=True)
elif value == 'working':
queryset = queryset.exclude(state__in=[ProductionPlan.PLAN_STATE_DONE, ProductionPlan.PLAN_MTEST_DONE])
return queryset
class SubproductionProgressFilterSet(filters.FilterSet):
@ -25,3 +39,4 @@ class SubproductionProgressFilterSet(filters.FilterSet):
if step.type == Step.STEP_TYPE_NOM:
queryset = queryset.exclude(material__type__in =[Material.MA_TYPE_HALFGOOD, Material.MA_TYPE_GOOD])
return queryset

View File

@ -8,7 +8,7 @@ from apps.em.serializers import EquipmentSerializer
from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
from apps.pm.filters import SubproductionProgressFilterSet
from apps.pm.filters import PlanFilterSet, SubproductionProgressFilterSet
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
@ -43,7 +43,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
queryset = ProductionPlan.objects.select_related('order', 'order__contract', 'product')
serializer_class = ProductionPlanSerializer
search_fields = ['number', 'order__number', 'order__contract__number', 'product__number']
filterset_fields = ['product', 'order']
filterset_class = PlanFilterSet
ordering_fields = ['id']
ordering = ['-id']

View File

@ -0,0 +1,18 @@
from django_filters import rest_framework as filters
from apps.sam.models import Order
class OrderFilterSet(filters.FilterSet):
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
create_time_end = filters.NumberFilter(field_name="create_time", lookup_expr='lte')
class Meta:
model = Order
fields = ['product', 'contract', 'customer', 'create_time_start', 'create_time_end']
class ContractFilterSet(filters.FilterSet):
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
create_time_end = filters.NumberFilter(field_name="create_time", lookup_expr='lte')
class Meta:
fields = ['customer', 'create_time_start', 'create_time_end']

View File

@ -5,6 +5,7 @@ from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModel
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.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer, SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer
from apps.sam.models import Contract, Customer, Order, Sale, SaleProduct
from rest_framework.viewsets import GenericViewSet, ModelViewSet
@ -43,7 +44,7 @@ class ContractViewSet(CreateUpdateCustomMixin, ModelViewSet):
queryset = Contract.objects.select_related('customer').all()
serializer_class = ContractSerializer
search_fields = ['name']
filterset_fields = []
filterset_class = ContractFilterSet
ordering_fields = ['create_time']
ordering = ['-create_time']
@ -60,7 +61,7 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
queryset = Order.objects.select_related('contract', 'customer').all()
serializer_class = OrderSerializer
search_fields = ['number', 'product']
filterset_fields = ['product', 'contract', 'customer']
filterset_class = OrderFilterSet
ordering_fields = ['create_time']
ordering = ['-create_time']

View File

@ -15,3 +15,4 @@ class GanttPlan(ListAPIView):
queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process')
ordering = ['-id']

View File

@ -1,4 +1,4 @@
from apps.system.models import User
from apps.system.models import Organization, User
from apps.system.serializers import UserSimpleSerializer
import rest_framework
from rest_framework import serializers
@ -135,6 +135,11 @@ class TicketDetailSerializer(serializers.ModelSerializer):
i['field_display'] = ','.join(list(User.objects.filter(id__in=i['field_value']).values_list('name', flat=True)))
else:
i['field_display'] = User.objects.get(id=i['field_value']).name
elif 'deptSelect' in i['label']:
if isinstance(i['field_value'], list):
i['field_display'] = ','.join(list(Organization.objects.filter(id__in=i['field_value']).values_list('name', flat=True)))
else:
i['field_display'] = Organization.objects.get(id=i['field_value']).name
elif i['field_type'] in ['radio', 'select']:
for m in i['field_choice']:
if m['id'] == i['field_value']:

View File

@ -2,7 +2,7 @@ from django_filters import rest_framework as filters
from apps.mtm.models import Material, Step
from apps.wpm.services import WpmServies
from .models import Operation, WMaterial, WProduct
from .models import Operation, OperationMaterial, WMaterial, WProduct
class WMaterialFilterSet(filters.FilterSet):
@ -34,3 +34,9 @@ class WProductFilterSet(filters.FilterSet):
if value == 'no_scrap':
queryset = queryset.exclude(act_state=WProduct.WPR_ACT_STATE_SCRAP)
return queryset
class CuttingFilterSet(filters.FilterSet):
production_plan = filters.NumberFilter(field_name='subproduction_plan__production_plan')
class Meta:
model = OperationMaterial
fields = ['operation', 'subproduction_plan', 'material']

View File

@ -0,0 +1,43 @@
# Generated by Django 3.2.9 on 2022-01-07 01:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0044_auto_20220104_1641'),
]
operations = [
migrations.AddField(
model_name='wproduct',
name='is_mtested',
field=models.BooleanField(default=False, verbose_name='是否军检'),
),
migrations.AddField(
model_name='wproduct',
name='is_mtestok',
field=models.BooleanField(blank=True, null=True, verbose_name='是否军检合格'),
),
migrations.AddField(
model_name='wproduct',
name='remark_mtest',
field=models.TextField(blank=True, null=True, verbose_name='军检备注'),
),
migrations.AddField(
model_name='wproductflow',
name='is_mtested',
field=models.BooleanField(default=False, verbose_name='是否军检'),
),
migrations.AddField(
model_name='wproductflow',
name='is_mtestok',
field=models.BooleanField(blank=True, null=True, verbose_name='是否军检合格'),
),
migrations.AddField(
model_name='wproductflow',
name='remark_mtest',
field=models.TextField(blank=True, null=True, verbose_name='军检备注'),
),
]

View File

@ -86,7 +86,7 @@ class WProduct(CommonAModel):
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='w_step')
act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices)
is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE, related_name='wproduct_child')
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan')
@ -94,6 +94,7 @@ class WProduct(CommonAModel):
ng_sign = models.PositiveSmallIntegerField('不合格标记', choices=ng_choices, null=True, blank=True)
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作',
@ -103,6 +104,10 @@ class WProduct(CommonAModel):
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
is_mtested = models.BooleanField('是否军检', default=False)
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
remark_mtest = models.TextField('军检备注', null=True, blank=True)
@property
def last_process_test(self):
"""
@ -137,7 +142,7 @@ class WproductFlow(CommonAModel):
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='wl_step')
act_state = models.IntegerField('进行状态', default=0, choices=WProduct.act_state_choices)
is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE, related_name='wproduct_child')
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
@ -154,6 +159,10 @@ class WproductFlow(CommonAModel):
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
on_delete=models.SET_NULL, null=True, blank=True)
is_mtested = models.BooleanField('是否军检', default=False)
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
remark_mtest = models.TextField('军检备注', null=True, blank=True)
is_lastlog = models.BooleanField('是否该子计划下的最后一条日志', default=True)
change_str = models.CharField('变动描述', default='', max_length=1000)
@ -210,7 +219,7 @@ class OperationMaterial(BaseModel):
生产操作物料消耗产出表
"""
type = models.IntegerField('类型', default=0, choices=SubprodctionMaterial.type_choices)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='om_operation')
material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE,
null=True, blank=True, related_name='om_material')

View File

@ -1,9 +1,11 @@
from django.db.models.query_utils import Q
from rest_framework import serializers, exceptions
from rest_framework.serializers import ModelSerializer
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
from apps.inm.signals import update_inm
from apps.inm.serializers import WareHouseSimpleSerializer
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer
@ -133,6 +135,18 @@ class WMaterialListSerializer(serializers.ModelSerializer):
model = WMaterial
fields = '__all__'
class WProductBaseSerializer(serializers.ModelSerializer):
"""
半成品列表
"""
material_ = MaterialSimpleSerializer(source='material', read_only=True)
step_ = StepSimpleSerializer(source='step', read_only=True)
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
class Meta:
model = WProduct
fields = '__all__'
class WProductListSerializer(serializers.ModelSerializer):
"""
半成品列表
@ -140,10 +154,86 @@ class WProductListSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
step_ = StepSimpleSerializer(source='step', read_only=True)
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
children = serializers.SerializerMethodField()
class Meta:
model = WProduct
fields = '__all__'
def get_children(self, obj):
wps = WProduct.objects.filter(child=obj)
if wps.exists():
return WProductBaseSerializer(instance=wps, many=True).data
return []
class WProductCardBaseSerializer(serializers.ModelSerializer):
"""
产品流程序列化
"""
material_ = MaterialSimpleSerializer(source='material', read_only=True)
step_ = StepSimpleSerializer(source='step', read_only=True)
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
step_list_full = serializers.SerializerMethodField()
class Meta:
model = WProduct
fields = '__all__'
def get_step_list_full(self, obj):
"""
获取所有步骤信息
"""
step_list_full = []
comb_step = Step.objects.filter(type=Step.STEP_TYPE_COMB, is_deleted=False).first()
if obj.material.type == Material.MA_TYPE_GOOD:
# 如果是成品获取可能经过的步骤
steps = Step.objects.filter(number__gte=comb_step.number).order_by('number')
elif obj.material.type == Material.MA_TYPE_HALFGOOD:
steps = Step.objects.filter(number__lt=comb_step.number).order_by('number')
for i in steps:
actions = []
ops = Operation.objects.filter(Q(ow_operation__wproduct=obj)|Q(wp_coperation=obj))\
.filter(step=i, is_submited=True).distinct()
for m in ops:
actions.append({'action_by_name':m.create_by.name, 'action_time':m.update_time.strftime('%Y-%m-%d %H:%M:%S')})
step_list_full.append({'step_name':i.name, 'actions':actions})
return step_list_full
class WProductCardSerializer(WProductCardBaseSerializer):
"""
产品流程序列化
"""
parents = serializers.SerializerMethodField()
def get_parents(self, obj):
parent_wps = WProduct.objects.filter(child=obj)
return WProductCardBaseSerializer(instance=parent_wps, many=True).data
class WProductDetailSerializer(serializers.ModelSerializer):
"""
半成品列表
"""
material_ = MaterialSimpleSerializer(source='material', read_only=True)
step_ = StepSimpleSerializer(source='step', read_only=True)
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
children = serializers.SerializerMethodField()
class Meta:
model = WProduct
fields = '__all__'
def get_children(self, obj):
wps = WProduct.objects.filter(child=obj)
if wps.exists():
print(wps)
return WProductBaseSerializer(instance=wps, many=True).data
return []
class OperationDetailSerializer(serializers.ModelSerializer):
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
step_ = StepSimpleSerializer(source='step', read_only=True)
@ -207,7 +297,7 @@ class OperationCreateSerializer(serializers.Serializer):
class OperationUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Operation
fields =['use_scrap', 'remark']
fields =['remark']
class OperationInitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
@ -449,7 +539,12 @@ class WproductTicketListSerializer(serializers.ModelSerializer):
class CuttingListSerializer(serializers.ModelSerializer):
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
from_material_ = MaterialSimpleSerializer(source='from_material', read_only=True)
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
create_by_ = UserSimpleSerializer(source='operation.create_by', read_only=True)
class Meta:
model = OperationMaterial
fields = '__all__'
class WproductMtestSerializer(serializers.ModelSerializer):
class Meta:
model = WProduct
fields = ['remark_mtest', 'is_mtestok']

View File

@ -126,7 +126,7 @@ class WpmServies(object):
根据军检结果更新主计划状态
"""
# 计算计划军检合格数并进行状态变更
count_mtestok = WProduct.objects.filter(material=plan.product, iproduct_wproduct__ismtestok=True, is_deleted=False).count()
count_mtestok = WProduct.objects.filter(material=plan.product, is_mtestok=True, is_deleted=False).count()
plan.count_mtestok = count_mtestok
if count_mtestok >= plan.count:
plan.state = ProductionPlan.PLAN_MTEST_DONE
@ -166,11 +166,16 @@ class WpmServies(object):
from_batch = ''
for m in input_q:
count_cut = count_cut + m.count
from_batch = from_batch + ';' + m.batch if m.batch else from_batch
if from_batch and m.batch:
from_batch = from_batch + ';' + m.batch
else:
from_batch = m.batch
i.count_cut = count_cut
i.from_batch = from_batch
wpfs = WproductFlow.objects.filter(subproduction_plan=i.subproduction_plan,
is_lastlog=True, coperation=op)# 筛选本次操作下子计划的产品日志
i.count_real = wpfs.count()
i.count_ok = wpfs.exclude(scrap_reason=None).count()
i.count_ok = wpfs.filter(scrap_reason=None).count()
i.count_qipao = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_QIPAO).count()
i.count_podian = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_PODIAN).count()
i.count_hua = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_HUA).count()

View File

@ -19,10 +19,10 @@ from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
from apps.wf.models import Workflow
from apps.wf.serializers import WorkflowSimpleSerializer
from apps.wpm.filters import WMaterialFilterSet, WProductFilterSet
from apps.wpm.filters import CuttingFilterSet, WMaterialFilterSet, WProductFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem, WprouctTicket
from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordDetailSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestFormInitSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer, WproductTicketListSerializer
from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordDetailSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestFormInitSerializer, WpmTestRecordCreateSerializer, WproductMtestSerializer, WproductPutInSerializer, WproductPutInsSerializer, WproductTicketListSerializer
from rest_framework.response import Response
from django.db import transaction
from rest_framework import exceptions, serializers
@ -185,18 +185,24 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
serializer.save()
return Response()
class WProductViewSet(ListModelMixin, GenericViewSet):
class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
"""
半成品
"""
perms_map={'*':'*'}
queryset = WProduct.objects.select_related('step', 'material', 'subproduction_plan')
queryset = WProduct.objects.select_related('step', 'material',
'subproduction_plan', 'warehouse').prefetch_related('wproduct_child')
serializer_class = WProductListSerializer
filterset_class = WProductFilterSet
search_fields = ['number']
ordering_fields = ['id']
ordering = ['id']
def get_serializer_class(self):
if self.action == 'retrieve':
return WProductDetailSerializer
return super().get_serializer_class()
def get_queryset(self):
queryset = self.queryset
if self.request.query_params.get('tag', None) != 'show_hidden':
@ -424,7 +430,54 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
else:
raise exceptions.APIException('未找到对应审批流程')
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductMtestSerializer)
@transaction.atomic
def mtest(self, request, pk=None):
"""
军检
"""
obj = self.get_object()
if obj.is_mtested:
raise exceptions.APIException('已进行军检')
if obj.material.type != Material.MA_TYPE_GOOD:
raise exceptions.APIException('军检必须是成品')
obj.remark_mtest = request.data.get('remark_mtest', None)
obj.is_mtested = True
is_mtestok = request.data.get('is_mtestok')
obj.is_mtestok = is_mtestok
if is_mtestok:
WpmServies.update_plan_state_by_mtestok(obj.subproduction_plan.production_plan)
obj.save()
change_str = 'mtest_notok'
if is_mtestok:
change_str = 'mtest_ok'
WpmServies.add_wproduct_flow_log(instance=obj, change_str=change_str)
return Response()
@action(methods=['get'], detail=True, perms_map={'get':'*'})
def card(self, request, pk=None):
"""
流程卡
"""
obj = self.get_object()
card_data = WProductCardSerializer(instance=obj).data
ret = []
if card_data['parents']:
line1 = ['序号', '工序']
for i in card_data['parents']:
line1.append(i['number'])
ret.append(line1)
steps_list_full_1 = card_data['parents'][0]['step_list_full']
for index, item in enumerate(steps_list_full_1):
linex = [str(index+1), item['step_name']]
for i in card_data['parents']:
linex.append(i['step_list_full'][index]['actions'])
ret.append(linex)
ret.append(['序号', '工序', card_data['number']])
step_list_full = card_data['step_list_full']
for index, item in enumerate(step_list_full):
ret.append([str(index+1), item['step_name'], item['actions']])
return Response(ret)
class WproductTicketViewSet(ListModelMixin, GenericViewSet):
"""
@ -563,7 +616,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
omos = OperationMaterial.objects.filter(operation=op,
type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
sps_omo_l = omos.filter(use_scrap=False).values_list('subproduction_plan', flat=True)
if set(list(sps_omi_l)) == set(list(sps_omo_l)):
if set(list(sps_omi_l)) == set(list(sps_omo_l)) or op.step.type == Step.STEP_TYPE_COMB:
pass
else:
raise exceptions.APIException('消耗与产出不一致')
@ -805,9 +858,9 @@ class CuttingListViewSet(ListModelMixin, GenericViewSet):
"""
perms_map={'*':'*'}
queryset = OperationMaterial.objects.select_related('operation',
'subproduction_plan', 'material', 'create_by').filter(operation__step__process__id=1)
'subproduction_plan', 'material', 'operation__create_by').filter(operation__step__id=1, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
serializer_class = CuttingListSerializer
filterset_fields = ['operation', 'subproduction_plan', 'material']
filterset_class = CuttingFilterSet
ordering_fields = ['id']
ordering = ['-id']

View File

@ -71,6 +71,7 @@ urlpatterns = [
path('api/wpm/', include('apps.wpm.urls')),
path('api/srm/', include('apps.srm.urls')),
path('api/develop/', include('apps.develop.urls')),
# 工具
path('api/utils/signature/', GenSignature.as_view()),
path('api/utils/develop/', UpdateDevelop.as_view()),