description

This commit is contained in:
shijing 2021-12-10 13:39:17 +08:00
commit b4a03a1feb
43 changed files with 1477 additions and 110 deletions

View File

@ -104,3 +104,13 @@ export function getiproductList(query) {
params: query params: query
}) })
} }
//军检
//军检
export function saleMtest(id, data) {
return request({
url: `/inm/iproduct/${id}/mtest/`,
method: 'POST',
data
})
}

View File

@ -369,3 +369,4 @@ export function deletetechdoc(id, data) {
data data
}) })
} }

View File

@ -73,6 +73,13 @@ export function createOrder(data) {
data data
}) })
} }
export function getOrder(id) {
return request({
url: `/sam/order/${id}/`,
method: 'get'
})
}
export function updateOrder(id, data) { export function updateOrder(id, data) {
return request({ return request({
url: `/sam/order/${id}/`, url: `/sam/order/${id}/`,
@ -94,3 +101,67 @@ export function getordertoplan() {
method: 'get', method: 'get',
}) })
} }
//销售记录列表
export function getSaleList(query) {
return request({
url: '/sam/sale/',
method: 'get',
params: query
})
}
//销售记录创建
export function createSale(data) {
return request({
url: '/sam/sale/',
method: 'post',
data
})
}
export function deleteSale(id, data) {
return request({
url: `/sam/sale/${id}/`,
method: 'delete',
data
})
}
export function getSale(id) {
return request({
url: `/sam/sale/${id}/`,
method: 'get'
})
}
//销售记录列表
export function getSaleproductList(query) {
return request({
url: '/sam/sale_product/',
method: 'get',
params: query
})
}
//删除销售记录关联产品
export function deleteSaleproduct(id, data) {
return request({
url: `/sam/sale_product/${id}/`,
method: 'delete',
data
})
}
//审核
export function saleAudit(id) {
return request({
url: `/sam/sale/${id}/audit/`,
method: 'POST',
})
}

View File

@ -261,6 +261,32 @@ export function createputins(data) {
data data
}) })
} }
//车间领料批量提交
export function createInputs(data) {
return request({
url: '/wpm/operation_input/creates/',
method: 'post',
data
})
}
//产出批量提交
export function createOutputs(data) {
return request({
url: '/wpm/operation_output/creates/',
method: 'post',
data
})
}
//表格初始化
export function recordInit(id) {
return request({
url: `/wpm/operation_record/${id}/init/`,
method: 'GET',
})
}
//半产品复检 //半产品复检
export function wproductReview(data) { export function wproductReview(data) {

View File

@ -262,7 +262,7 @@ export const asyncRoutes = [
component: Layout, component: Layout,
redirect: '/sam/customer', redirect: '/sam/customer',
name: 'sam', name: 'sam',
meta: { title: '合同管理', icon: 'example', perms: ['equipment_set'] }, meta: { title: '销售管理', icon: 'example', perms: ['equipment_set'] },
children: [ children: [
{ {
path: 'customer', path: 'customer',
@ -284,6 +284,21 @@ export const asyncRoutes = [
component: () => import('@/views/sam/order'), component: () => import('@/views/sam/order'),
meta: { title: '订单信息', icon: 'example', perms: ['index_manage'] } meta: { title: '订单信息', icon: 'example', perms: ['index_manage'] }
} }
,
{
path: 'sales',
name: 'sales',
component: () => import('@/views/sam/sales'),
meta: { title: '销售信息', icon: 'example', perms: ['index_manage'] }
}
,
{
path: 'salesdetail/:id',
name: 'salesdetail',
component: () => import('@/views/sam/salesdetail'),
meta: { title: '销售详情', perms: ['vendor_manage'] },
hidden: true
}
] ]
} }
, ,

View File

@ -49,7 +49,7 @@
</el-table-column> </el-table-column>
<el-table-column label="操作人员"> <el-table-column label="操作人员">
<template slot-scope="scope">{{ <template slot-scope="scope" v-if="scope.row.create_by">{{
scope.row.create_by_.name scope.row.create_by_.name
}}</template> }}</template>
</el-table-column> </el-table-column>

View File

@ -28,8 +28,38 @@
<el-table-column label="所在仓库"> <el-table-column label="所在仓库">
<template slot-scope="scope">{{ scope.row.warehouse_.name }}</template> <template slot-scope="scope">{{ scope.row.warehouse_.name }}</template>
</el-table-column> </el-table-column>
<el-table-column label="是否已军检">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_mtested == false">未军检</el-tag>
<el-tag v-else>已军检</el-tag></template>
</el-table-column>
<el-table-column label="军检">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_mtestok == false">不合格</el-tag>
<el-tag v-else-if="scope.row.is_mtestok == true">合格</el-tag></template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
v-if="scope.row.is_mtested == false"
@click="handleMtest(scope)"
>军检</el-link
>
</template>
</el-table-column>
</el-table> </el-table>
<pagination <pagination
v-show="iproductData.count > 0" v-show="iproductData.count > 0"
@ -38,14 +68,40 @@
:limit.sync="listQuery.page_size" :limit.sync="listQuery.page_size"
@pagination="getList" @pagination="getList"
/> />
<el-dialog
:visible.sync="dialogVisible"
:close-on-click-modal="false"
title="军检"
>
<el-form
ref="Form"
:model="mtest"
label-width="150px"
label-position="right"
>
<el-form-item label="军检是否合格">
<el-radio v-model="mtest.is_mtestok" label=True >合格</el-radio>
<el-radio v-model="mtest.is_mtestok" label=False >不合格</el-radio>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="mtest.remark" placeholder="备注" />
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="smtconfirm('Form')">确认</el-button>
</div>
</el-dialog>
</el-card> </el-card>
</div> </div>
</template> </template>
<script> <script>
import { import { getiproductList,saleMtest} from "@/api/inm";
getiproductList,
} from "@/api/inm";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import { genTree } from "@/utils"; import { genTree } from "@/utils";
@ -63,6 +119,10 @@ export default {
page: 1, page: 1,
page_size: 20, page_size: 20,
}, },
mtest: {},
salesdetail:"",
saleproduct:"",
dialogVisible:false,
}; };
}, },
@ -83,7 +143,22 @@ export default {
this.listLoading = false; this.listLoading = false;
}); });
}, },
handleMtest(scope){
this.saleproduct=scope.row.id;
this.dialogVisible=true;
},
smtconfirm(){
saleMtest(this.saleproduct,this.mtest).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
}, },
}; };
</script> </script>

View File

@ -98,7 +98,6 @@
</el-card> </el-card>
<el-dialog <el-dialog
:visible.sync="dialogVisible" :visible.sync="dialogVisible"
:close-on-click-modal="false"
:title="dialogType === 'edit' ? '编辑合同' : '新增合同'" :title="dialogType === 'edit' ? '编辑合同' : '新增合同'"
> >
<el-form <el-form

View File

@ -63,6 +63,10 @@
<el-table-column label="交货日期" width="150" > <el-table-column label="交货日期" width="150" >
<template slot-scope="scope">{{ scope.row.delivery_date }}</template> <template slot-scope="scope">{{ scope.row.delivery_date }}</template>
</el-table-column> </el-table-column>
<el-table-column label="已交货数量" width="150" >
<template slot-scope="scope">{{ scope.row.delivered_count }}</template>
</el-table-column>
<el-table-column label="创建时间" width="160" > <el-table-column label="创建时间" width="160" >
<template slot-scope="scope">{{ scope.row.create_time }}</template> <template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column> </el-table-column>

View File

@ -0,0 +1,410 @@
<template>
<div class="app-container">
<el-card>
<div>
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增销售记录</el-button
>
<el-input
v-model="listQuery.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
>
</div>
</el-card>
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="saleList.results"
border
fit
stripe
highlight-current-row
>
<el-table-column type="index" width="50" />
<el-table-column label="产品名称" show-overflow-tooltip>
<template slot-scope="scope" v-if="scope.row.product">{{ scope.row.product_.name }}</template>
</el-table-column>
<el-table-column label="产品型号" show-overflow-tooltip>
<template slot-scope="scope" v-if="scope.row.product">{{ scope.row.product_.specification }}</template>
</el-table-column>
<el-table-column label="客户名称" show-overflow-tooltip>
<template slot-scope="scope" v-if="scope.row.customer">{{ scope.row.customer_.name }}</template>
</el-table-column>
<el-table-column label="订单编号" show-overflow-tooltip>
<template slot-scope="scope" v-if="scope.row.order">{{ scope.row.order_.number }}</template>
</el-table-column>
<el-table-column label="合同名称" show-overflow-tooltip>
<template slot-scope="scope" v-if="scope.row.order&&scope.row.order_.contract">{{ scope.row.order_.contract_.name }}</template>
</el-table-column>
<el-table-column label="是否审核" >
<template slot-scope="scope" > <el-tag v-if="scope.row.is_audited == false"></el-tag>
<el-tag v-else></el-tag></template>
</el-table-column>
<el-table-column>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_delete'])"
@click="handleDetail(scope)"
>详情</el-link
>
<el-link
v-if="scope.row.is_audited==false"
@click="handleAudit(scope)"
>审核</el-link
>
<el-link
v-if="scope.row.is_audited==false"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="saleList.count > 0"
:total="saleList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
:close-on-click-modal="false"
width="60%"
:title="dialogType === 'edit' ? '编辑销售信息' : '新增销售信息'"
>
<el-form
ref="Form"
:model="sale"
label-width="80px"
label-position="right"
:rules="rule1"
>
<el-form-item label="关联订单" prop="name">
<el-select style="width: 100%" v-model="sale.order" @change="selectorder" placeholder="请选择">
<el-option
v-for="item in orderoptions"
:key="item.id"
:label="item.number"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="关联客户" prop="customer">
<el-select style="width: 100%" v-model="sale.customer" placeholder="请选择">
<el-option
v-for="item in customeroptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="所需产品" prop="product">
<el-select style="width: 100%" v-model="sale.product" @change="selectproduct" placeholder="请选择">
<el-option
v-for="item in materialoptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="选择产品" prop="iproducts">
<div class="trdiv">
<el-transfer v-model="sale.iproducts" :data="iproductoptions" :titles="['未选产品', '已选产品']" right-check-change="change"></el-transfer>
</div>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { createSale,getOrderList,getCustomerList,getSaleList,getOrder,deleteSale,getSale,saleAudit} from "@/api/sam";
import checkPermission from "@/utils/permission";
import { getMaterialList } from "@/api/mtm";
import { getiproductList,} from "@/api/inm";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaulteSale = {
order:null,
customer:null,
product:null
};
export default {
components: { Pagination },
data() {
return {
sale: defaulteSale,
saleList: {
count: 0,
},
listQuery: {
page: 1,
page_size: 20,
},
orderoptions:[],
customeroptions:[],
materialoptions:[],
iproductoptions:[],
dialogVisible: false,
dialogType: "new",
};
},
computed: {},
watch: {},
created() {
this.getList();
this.getCustomerLists();
this.getproductList();
this.getOrderLists();
this.getMaterialList();
},
methods: {
checkPermission,
//关联订单
getOrderLists() {
getOrderList({page:0}).then((response) => {
if (response.data) {
this.orderoptions = response.data;
}
});
},
//选择订单变化
selectorder(selval)
{
getOrder(selval).then((response) => {
if (response.data) {
this.sale.customer = response.data.customer;
this.sale.product = response.data.product;
this.iproductoptions=[];
getiproductList({material: this.sale.product,page:0}).then((response) => {
if (response.data) {
response.data.forEach((item) => {
this.iproductoptions.push({
label: item.number+"__"+item.material_.name+"__"+(item.is_mtested==true?"已军检":"未军检") ,
key: item.id
})
});
}
});
}
});
},
getList() {
getSaleList(this.listQuery).then((response) => {
if (response.data) {
this.saleList = response.data;
}
});
},
//关联客户
getCustomerLists() {
getCustomerList({page:0,}).then((response) => {
this.customeroptions = response.data;
});
},
//选择产品
getMaterialList()
{
getMaterialList({type:1,page:0}).then((response) => {
if (response.data) {
this.materialoptions = response.data;
}
});
},
selectproduct(selval)
{
this.iproductoptions=[];
getiproductList({material:selval,page:0}).then((response) => {
if (response.data) {
response.data.forEach((item) => {
this.iproductoptions.push({
label: item.number+"__"+item.material_.name+"__"+(item.is_mtested==true?"已军检":"未军检") ,
key: item.id
})
});
}
});
},
//成品
getproductList() {
this.iproductoptions=[],
getiproductList({page:0}).then((response) => {
if (response.data) {
response.data.forEach((item) => {
this.iproductoptions.push({
label: item.number+"__"+item.material_.name+"__"+(item.is_mtested==true?"已军检":"未军检") ,
key: item.id
})
});
}
});
},
handleFilter() {
this.listQuery.page = 1;
this.getList();
},
resetFilter() {
this.listQuery = {
page: 1,
page_size: 20,
}
this.getList();
},
handleCreate() {
this.sale = Object.assign({}, defaulteSale);
this.dialogType = "new";
this.dialogVisible = true;
this.iproductoptions=[];
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.sale = Object.assign({}, scope.row); // copy obj
console.log(this.sale);
this.dialogType = "edit";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deleteSale(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
async confirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogType === "edit";
if (isEdit) {
updateContract(this.sale.id, this.sale).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
} else {
createSale(this.sale).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
//销售详情
handleDetail(scope){
this.$router.push({name: "salesdetail", params: { id: scope.row.id }, })
},
//审核
handleAudit(scope){
saleAudit(scope.row.id).then((res) => {
if (res.code >= 200) {
this.$message.success("审核成功成功");
this.getList();
}
});
}
},
};
</script>
<style scoped>
.trdiv >>> .el-transfer-panel{
width:350px;
}
.trdiv >>> .el-transfer__buttons{
width:110px
}
</style>

View File

@ -0,0 +1,146 @@
<template>
<div class="app-container">
<el-card style="margin-top: 2px">
<el-descriptions title="基本信息" direction="vertical" :column="8" border>
<el-descriptions-item label="客户名称" v-if="salesdetail.customer"> {{salesdetail.customer_.name}}</el-descriptions-item>
<el-descriptions-item label="产品名称" v-if="salesdetail.product"> {{salesdetail.product_.name}}</el-descriptions-item>
<el-descriptions-item label="产品型号" :span="2" v-if="salesdetail.product"> {{salesdetail.product_.specification}}</el-descriptions-item>
<el-descriptions-item label="订单编号" v-if="salesdetail.order"> {{salesdetail.order_.number}} </el-descriptions-item>
<el-descriptions-item label="合同名称" v-if="salesdetail.order"> {{salesdetail.order_.contract_.name}}</el-descriptions-item>
</el-descriptions>
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>关联产品信息</span>
</div>
<el-table
ref="singleTable"
:data="saleproduct"
highlight-current-row
style="width: 100%">
<el-table-column type="index" width="50" />
<el-table-column label="产品编号" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="产品名称" show-overflow-tooltip>
<template slot-scope="scope" >{{ scope.row.iproduct_.material_.name }}</template>
</el-table-column>
<el-table-column label="批次" >
<template slot-scope="scope" >{{ scope.row.iproduct_.batch }}</template>
</el-table-column>
<el-table-column label="仓库">
<template slot-scope="scope">{{ scope.row.iproduct_.warehouse_.name }}</template>
</el-table-column>
<el-table-column label="是否已军检">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_mtested == false">未军检</el-tag>
<el-tag v-else>已军检</el-tag></template>
</el-table-column>
<el-table-column label="军检">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_mtestok == false">不合格</el-tag>
<el-tag v-else>合格</el-tag></template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
</el-card>
</el-card>
</div>
</template>
<script>
import {getSale,getSaleproductList,deleteSaleproduct} from "@/api/sam";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default {
components: { Pagination },
data() {
return {
salesdetail:"",
saleproduct:"",
};
},
computed: {},
watch: {},
created() {
this.id = this.$route.params.id;
this.getList();
this.getSaleproductLists();
},
methods: {
checkPermission,
//详情
getList() {
getSale(this.id).then((response) => {
if (response.data) {
this.salesdetail = response.data;
}
});
},
getSaleproductLists()
{
getSaleproductList({sale:this.id,page:0}).then((response) => {
if (response.data) {
this.saleproduct = response.data;
}
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deleteSaleproduct(scope.row.id);
this.getSaleproductLists();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
},
};
</script>

View File

@ -156,6 +156,54 @@
/> />
</el-card> </el-card>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="夹层半成品">
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="wproductList3.results"
border
fit
stripe
highlight-current-row
max-height="600"
>
<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.number }}</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 align="center" label="操作" width="220px">
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_update'])"
@click="handleInspection(scope)"
>检验
</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="wproductList3.count > 0"
:total="wproductList3.count"
:page.sync="listQuery3.page"
:limit.sync="listQuery3.page_size"
@pagination="getList3"
/>
</el-card>
</el-tab-pane>
</el-tabs> </el-tabs>
<el-dialog title="物料检查表" :close-on-click-modal="false" :visible.sync="outerVisible"> <el-dialog title="物料检查表" :close-on-click-modal="false" :visible.sync="outerVisible">
@ -269,6 +317,9 @@
}, },
wproductList2: { wproductList2: {
count: 0, count: 0,
},
wproductList3: {
count: 0,
}, },
listQuery: { listQuery: {
page: 1, page: 1,
@ -282,8 +333,12 @@
page: 1, page: 1,
page_size: 20, page_size: 20,
}, },
formLabelWidth: '', listQuery3: {
formLabelWidthL: '', page: 1,
page_size: 20,
},
formLabelWidth:'',
formLabelWidthL:'',
actstate_: { actstate_: {
6: "待复检", 6: "待复检",
10: "生产中", 10: "生产中",
@ -292,6 +347,7 @@
40: "库存中", 40: "库存中",
50: "不合格", 50: "不合格",
60: "待成品检验", 60: "待成品检验",
26:"待夹层检验",
}, },
choice: [ choice: [
{ {
@ -333,6 +389,7 @@
this.getList(); this.getList();
this.getList2(); this.getList2();
this.getList1(); this.getList1();
this.getList3();
// this.getLists(); // this.getLists();
}, },
methods: { methods: {
@ -363,7 +420,7 @@
getList1() { getList1() {
this.listQuery1.act_state = 30; this.listQuery1.act_state = 30;
this.listQuery1.material__type = 1; this.listQuery1.material__type = 2;
getwproductList(this.listQuery1).then((response) => { getwproductList(this.listQuery1).then((response) => {
if (response.data) { if (response.data) {
this.wproductList1 = response.data; this.wproductList1 = response.data;
@ -371,7 +428,17 @@
}); });
}, },
//夹层半成品列表
getList3() {
this.listQuery3.act_state = 26;
getwproductList(this.listQuery3).then((response) => {
if (response.data) {
this.wproductList3 = response.data;
}
});
},
//半成品批量入库 //半成品批量入库
handleCreate() { handleCreate() {
this.dialogFormVisibles = true; this.dialogFormVisibles = true;
@ -385,7 +452,7 @@
_this.mutipID = [] _this.mutipID = []
this.$refs.multipleTable.selection.forEach((item) => { this.$refs.multipleTable.selection.forEach((item) => {
_this.mutipID.push(item.id); _this.mutipID.push(item.id);
alert(_this.mutipID);
}); });
console.log(_this.mutipID); console.log(_this.mutipID);
@ -497,6 +564,7 @@
this.getList(); this.getList();
this.getList1(); this.getList1();
this.getList2(); this.getList2();
this.getList3();
} }
}); });

View File

@ -3,6 +3,7 @@
<el-card> <el-card>
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<span>基本信息</span> <span>基本信息</span>
<el-button style="float: right; padding: 3px 0" @click="readbook()" type="text">查看作业指导书</el-button>
</div> </div>
<el-form <el-form
ref="form" ref="form"
@ -49,6 +50,20 @@
<el-button>取消</el-button> <el-button>取消</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-drawer
title="作业指导书点击下载查看!"
:visible.sync="drawer"
direction="rtl"
size="10%">
<el-table :data="techdocList">
<el-table-column label="表名称" width="150">
<template slot-scope="scope">
<el-link type="primary" :href="scope.row.file_.file" target="_blank">{{ scope.row.file_.name }}</el-link>
</template>
</el-table-column>
</el-table>
</el-drawer>
</el-card> </el-card>
<el-row gutter="2"> <el-row gutter="2">
<el-col span="8"> <el-col span="8">
@ -160,10 +175,10 @@
:model="tableForm" :model="tableForm"
:visible.sync="dialogVisibleForm" :visible.sync="dialogVisibleForm"
:close-on-click-modal="false" :close-on-click-modal="false"
:title="tableForm.name" :title="fieldList.name"
> >
<el-form label-width="80px" label-position="right"> <el-form label-width="80px" label-position="right">
<el-row v-for="(item, $index) in fieldList" :key="$index"> <el-row v-for="(item, $index) in fieldList.form_fields" :key="$index">
<el-form-item <el-form-item
v-if="item.field_type === 'string'" v-if="item.field_type === 'string'"
:label="item.field_name" :label="item.field_name"
@ -312,9 +327,21 @@
stripe stripe
style="width: 100%" style="width: 100%"
max-height="400" max-height="400"
ref="multipleTable"
> >
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column
label="子计划编号"
>
<template slot-scope="scope">{{
scope.row.subproduction_plan_.number
}}</template>
</el-table-column>
<el-table-column label="物料名称"> <el-table-column label="物料名称">
<template slot-scope="scope">{{ <template slot-scope="scope">{{
scope.row.material_.name scope.row.material_.name
@ -349,7 +376,7 @@
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="操作" width="100px"> <!-- <el-table-column align="center" label="操作" width="100px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
@ -357,8 +384,13 @@
>提交</el-link >提交</el-link
> >
</template> </template>
</el-table-column> </el-table-column>!-->
</el-table> </el-table>
<div style="text-align: right">
<el-button type="danger" @click="dialogTablepick = false">取消</el-button>
<el-button type="primary" @click="handlepicks()">提交</el-button>
</div>
</el-dialog> </el-dialog>
</template> </template>
</el-card> </el-card>
@ -403,7 +435,12 @@
stripe stripe
style="width: 100%" style="width: 100%"
max-height="400" max-height="400"
> ref="multipleTables"
>
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="生产计划编号"> <el-table-column label="生产计划编号">
@ -439,7 +476,7 @@
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="操作" width="100px"> <!-- <el-table-column align="center" label="操作" width="100px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
@ -447,8 +484,12 @@
>提交</el-link >提交</el-link
> >
</template> </template>
</el-table-column> </el-table-column>!-->
</el-table> </el-table>
<div style="text-align: right">
<el-button type="danger" @click="dialogTableoutput = false">取消</el-button>
<el-button type="primary" @click="handleoutputs()">提交</el-button>
</div>
</el-dialog> </el-dialog>
</el-card> </el-card>
</el-col> </el-col>
@ -492,9 +533,12 @@ import {
deleteOperationwproduct, deleteOperationwproduct,
gettoolList, gettoolList,
createTool, createTool,
createInputs,
recordInit,
createOutputs
} from "@/api/wpm"; } from "@/api/wpm";
import { getrffieldList } from "@/api/mtm"; import { getrffieldList,gettechdocList } from "@/api/mtm";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import { getprogressList } from "@/api/pm"; import { getprogressList } from "@/api/pm";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
@ -504,9 +548,11 @@ export default {
inject: ["reload"], inject: ["reload"],
data() { data() {
return { return {
techdocList:"",
operationList: { operationList: {
count: 0, count: 0,
}, },
drawer:false,
listQuery: { listQuery: {
page: 1, page: 1,
page_size: 20, page_size: 20,
@ -629,6 +675,17 @@ export default {
}, },
methods: { methods: {
checkPermission, checkPermission,
//作业指导书
readbook(){
this.drawer=true;
gettechdocList({operation:this.id,page:0}).then((response) => {
if (response.data) {
this.techdocList= response.data;
}
});
},
//是否使用边角料 //是否使用边角料
getList() { getList() {
getoperation(this.id).then((response) => { getoperation(this.id).then((response) => {
@ -712,9 +769,7 @@ export default {
handlerecord(scope) { handlerecord(scope) {
this.tableForm = Object.assign({}, scope.row); // copy obj this.tableForm = Object.assign({}, scope.row); // copy obj
this.formID = scope.row.id; this.formID = scope.row.id;
this.listQueryfield.form = scope.row.form_.id; recordInit( this.formID).then((response) => {
this.listQueryfield.page = 0;
getrffieldList(this.listQueryfield).then((response) => {
if (response.data) { if (response.data) {
this.fieldList = response.data; this.fieldList = response.data;
} }
@ -777,6 +832,40 @@ export default {
} }
}); });
}, },
//车间领料批量提交
handlepicks() {
let _this = this;
this.pickDatas=[],
this.$refs.multipleTable.selection.forEach((item) => {
if(item.pick_count>0)
{
this.pickDatas.push({
"operation" :this.id,
"wmaterial":item.id,
"count": item.pick_count,
});
}
});
createInputs(this.pickDatas).then((res) => {
if (res.code >= 200) {
this.dialogTablepick = false;
this.$message.success("提交成功!");
_this.getinputLists();
}
});
},
//操作产出物料列表 //操作产出物料列表
getoutputLists() { getoutputLists() {
getoutputList({ operation: this.id, page: 0 }).then((response) => { getoutputList({ operation: this.id, page: 0 }).then((response) => {
@ -809,6 +898,38 @@ export default {
} }
}); });
}, },
//车间产出物料批量提交
handleoutputs() {
this.outputDatas=[],
this.$refs.multipleTables.selection.forEach((item) => {
if(item.output_count>0)
{
this.outputDatas.push({
"operation" :this.id,
"subproduction_progress":item.id,
"count": item.output_count,
});
}
});
createOutputs(this.outputDatas).then((res) => {
if (res.code >= 200) {
this.dialogTableoutput = false;
this.$message.success("提交成功!");
this.getoutputLists();
}
});
},
//提交本次操作 //提交本次操作
handlesubmit() { handlesubmit() {
submitOperation(this.id).then((res) => { submitOperation(this.id).then((res) => {

View File

@ -440,7 +440,7 @@ export default {
_this.mutipID=[] _this.mutipID=[]
this.$refs.multipleTable.selection.forEach((item) => { this.$refs.multipleTable.selection.forEach((item) => {
_this.mutipID.push( item.id ); _this.mutipID.push( item.id );
alert(_this.mutipID);
}); });
console.log(_this.mutipID); console.log(_this.mutipID);

View File

@ -703,6 +703,7 @@ export default {
50: "不合格", 50: "不合格",
60: "待成品检验", 60: "待成品检验",
8:"操作准备中", 8:"操作准备中",
26:"待夹层检验",
}, },
state_: { state_: {
0: "制定中", 0: "制定中",

View File

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

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.9 on 2021-12-07 00:42
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inm', '0020_iproduct_is_saled'),
]
operations = [
migrations.AddField(
model_name='fifoitemproduct',
name='iproduct',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='inm.iproduct', verbose_name='关联库存产品'),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.9 on 2021-12-08 06:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inm', '0021_fifoitemproduct_iproduct'),
]
operations = [
migrations.AddField(
model_name='iproduct',
name='is_mtested',
field=models.BooleanField(default=False, verbose_name='是否军检'),
),
migrations.AddField(
model_name='iproduct',
name='is_mtestok',
field=models.BooleanField(blank=True, null=True, verbose_name='是否军检合格'),
),
migrations.AddField(
model_name='iproduct',
name='remark_mtest',
field=models.TextField(blank=True, null=True, verbose_name='军检备注'),
),
]

View File

@ -84,15 +84,6 @@ class FIFOItem(BaseModel):
fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE) fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True)
class FIFOItemProduct(BaseModel):
"""
出入库产品
"""
fifoitem = models.ForeignKey(FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
number = models.CharField('物品编号', max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
class IProduct(BaseModel): class IProduct(BaseModel):
""" """
具体产品条目 具体产品条目
@ -102,6 +93,21 @@ class IProduct(BaseModel):
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库') warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, default='') 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) wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, 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_saled = models.BooleanField('是否售出', default=False) is_saled = models.BooleanField('是否售出', default=False)
class FIFOItemProduct(BaseModel):
"""
出入库产品
"""
fifoitem = models.ForeignKey(FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
number = models.CharField('物品编号', max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
iproduct = models.ForeignKey(IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL)

View File

@ -147,3 +147,9 @@ class InmTestRecordCreateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = TestRecord model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'fifo_item'] fields = ['form', 'record_data', 'is_testok', 'fifo_item']
class IProductMtestSerializer(serializers.ModelSerializer):
class Meta:
model = IProduct
fields = ['remark_mtest', 'is_mtestok']

View File

@ -36,7 +36,7 @@ def update_inm(instance:FIFO, type:int=1):
ips2.append(IProduct(**ip)) ips2.append(IProduct(**ip))
IProduct.objects.bulk_create(ips2) IProduct.objects.bulk_create(ips2)
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT]: # 生产领料 elif instance.type in [FIFO.FIFO_TYPE_DO_OUT, FIFO.FIFO_TYPE_SALE_OUT]: # 生产领料 销售出库
# 更新相关表 # 更新相关表
for i in FIFOItem.objects.filter(fifo=instance): for i in FIFOItem.objects.filter(fifo=instance):
material = i.material material = i.material
@ -50,7 +50,8 @@ def update_inm(instance:FIFO, type:int=1):
material.count = material.count - i.count material.count = material.count - i.count
material.save() material.save()
# 删除IProduct # 删除IProduct
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True) if instance.type == FIFO.FIFO_TYPE_DO_OUT:
IProduct.objects.filter(number__in=numbers).delete() numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
IProduct.objects.filter(number__in=numbers).delete()

View File

@ -1,13 +1,15 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework import serializers from rest_framework import serializers
from rest_framework import exceptions
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.filters import IProductFilterSet, MbFilterSet from apps.inm.filters import IProductFilterSet, MbFilterSet
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, IProductMtestSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
from apps.inm.signals import update_inm from apps.inm.signals import update_inm
from apps.mtm.models import Material
from apps.qm.models import TestRecordItem from apps.qm.models import TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action from rest_framework.decorators import action
@ -173,3 +175,20 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
search_fields = [] search_fields = []
ordering_fields = ['create_time'] ordering_fields = ['create_time']
ordering = ['-create_time'] ordering = ['-create_time']
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=IProductMtestSerializer)
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
obj.is_mtestok = request.data.get('is_mtestok')
obj.save()
return Response()

View File

@ -0,0 +1,15 @@
from django_filters import rest_framework as filters
from apps.mtm.models import TechDoc
class TechDocFilterset(filters.FilterSet):
# operation = filters.NumberFilter(method='filter_operation')
operation = filters.CharFilter(field_name="subproduction__subplan_subprod__ow_subplan__operation")
class Meta:
model = TechDoc
fields = ['subproduction', 'operation']
# def filter_operation(self, queryset, name, value):
# return queryset.filter(subproduction__subplan_subprod__ow_subplan__operation=value)

View File

@ -130,6 +130,20 @@ class RecordFormField(CommonAModel):
""" """
记录字段表 记录字段表
""" """
FIELD_STRING = 'string'
FIELD_INT = 'int'
FIELD_FLOAT = 'float'
FIELD_BOOL = 'boolean'
FIELD_DATE = 'date'
FIELD_TIME = 'time'
FIELD_DATETIME = 'datetime'
FIELD_RADIO = 'radio'
FIELD_CHECKBOX = 'checkbox'
FIELD_SELECT = 'select'
FIELD_SELECTS = 'selects'
FIELD_TEXTAREA = 'textarea'
FIELD_DRAW = 'draw'
FIELD_FROMSYSTEM = 'fromsystem'
field_type_choices = ( field_type_choices = (
('string', '字符串'), ('string', '字符串'),
('int', '整型'), ('int', '整型'),
@ -143,7 +157,7 @@ class RecordFormField(CommonAModel):
('select', '单选下拉'), ('select', '单选下拉'),
('selects', '多选下拉'), ('selects', '多选下拉'),
('textarea', '文本域'), ('textarea', '文本域'),
('draw', '绘图') ('draw', '绘图'),
) )
high_rule_choices = ( high_rule_choices = (
(1, '小于'), (1, '小于'),

View File

@ -1,6 +1,7 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
from apps.mtm.filters import TechDocFilterset
from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormDetailSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubprodctionMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer from apps.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
@ -201,7 +202,7 @@ class TechDocViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
""" """
perms_map = {'*':'*'} perms_map = {'*':'*'}
queryset = TechDoc.objects.select_related('file').all() queryset = TechDoc.objects.select_related('file').all()
filterset_fields = ['subproduction'] filterset_class = TechDocFilterset
search_fields = ['name'] search_fields = ['name']
ordering = ['-id'] ordering = ['-id']

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-12-09 08:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pm', '0015_auto_20211122_1556'),
]
operations = [
migrations.AddField(
model_name='productionplan',
name='count_ok',
field=models.IntegerField(default=0, verbose_name='合格数'),
),
migrations.AddField(
model_name='productionplan',
name='count_real',
field=models.IntegerField(default=0, verbose_name='实际产出数'),
),
]

View File

@ -18,6 +18,8 @@ class ProductionPlan(CommonAModel):
order = models.ForeignKey(Order, verbose_name='关联订单', null=True, blank=True, on_delete=models.SET_NULL) order = models.ForeignKey(Order, verbose_name='关联订单', null=True, blank=True, on_delete=models.SET_NULL)
product = models.ForeignKey(Material, verbose_name='生产产品', on_delete=models.CASCADE) product = models.ForeignKey(Material, verbose_name='生产产品', on_delete=models.CASCADE)
count = models.IntegerField('生产数量', default=1) count = models.IntegerField('生产数量', default=1)
count_real = models.IntegerField('实际产出数', default=0)
count_ok = models.IntegerField('合格数', default=0)
start_date = models.DateField('计划开工日期') start_date = models.DateField('计划开工日期')
end_date = models.DateField('计划完工日期') end_date = models.DateField('计划完工日期')
is_planed = models.BooleanField('是否已排产', default=False) is_planed = models.BooleanField('是否已排产', default=False)

View File

@ -1,5 +1,6 @@
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from apps.mtm.models import Material
from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.models import SubProductionPlan, SubProductionProgress
@receiver(post_save, sender=SubProductionProgress) @receiver(post_save, sender=SubProductionProgress)
@ -19,5 +20,12 @@ def update_subplan_main(sender, instance, created, **kwargs):
elif instance.count_ok < instance.count and instance.count_ok > 0: elif instance.count_ok < instance.count and instance.count_ok > 0:
subplan.state = SubProductionPlan.SUBPLAN_STATE_WORKING subplan.state = SubProductionPlan.SUBPLAN_STATE_WORKING
subplan.save() subplan.save()
if subplan.main_product.type == Material.MA_TYPE_GOOD:
# 如果是产品,更新主计划进度
plan = subplan.production_plan
plan.count_real = subplan.count_real
plan.count_ok = subplan.count_ok
plan.save()

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-08 06:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0013_auto_20211202_1620'),
]
operations = [
migrations.AlterField(
model_name='testrecord',
name='type',
field=models.PositiveSmallIntegerField(choices=[(10, '子工序检验'), (20, '工序检验'), (30, '工序复检'), (36, '夹层检验'), (40, '成品检验')], default=20),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.9 on 2021-12-09 08:38
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0014_alter_testrecord_type'),
]
operations = [
migrations.AlterField(
model_name='testrecord',
name='test_record',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord', verbose_name='关联的检验记录'),
),
]

View File

@ -50,11 +50,13 @@ class TestRecord(CommonAModel):
TEST_STEP = 10 TEST_STEP = 10
TEST_PROCESS = 20 TEST_PROCESS = 20
TEST_PROCESS_RE = 30 TEST_PROCESS_RE = 30
TEST_COMB = 36
TEST_FINAL = 40 TEST_FINAL = 40
type_choice = ( type_choice = (
(TEST_STEP, '子工序检验'), (TEST_STEP, '子工序检验'),
(TEST_PROCESS, '工序检验'), (TEST_PROCESS, '工序检验'),
(TEST_PROCESS_RE, '工序复检'), (TEST_PROCESS_RE, '工序复检'),
(TEST_COMB, '夹层检验'),
(TEST_FINAL, '成品检验') (TEST_FINAL, '成品检验')
) )
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
@ -67,7 +69,7 @@ class TestRecord(CommonAModel):
step = models.ForeignKey('mtm.step', verbose_name='关联的工序步骤', on_delete=models.CASCADE, null=True, blank=True) step = models.ForeignKey('mtm.step', verbose_name='关联的工序步骤', on_delete=models.CASCADE, null=True, blank=True)
subproduction_plan = models.ForeignKey('pm.subproductionplan', verbose_name='关联的生产子计划', on_delete=models.CASCADE, null=True, blank=True) subproduction_plan = models.ForeignKey('pm.subproductionplan', verbose_name='关联的生产子计划', on_delete=models.CASCADE, null=True, blank=True)
fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True) fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True)
test_record = models.ForeignKey('self', verbose_name='关联检验记录', on_delete=models.CASCADE, null=True, blank=True) test_record = models.ForeignKey('self', verbose_name='关联检验记录', on_delete=models.CASCADE, null=True, blank=True)
remark = models.TextField('备注', default='') remark = models.TextField('备注', default='')

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-07 00:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sam', '0008_alter_saleproduct_number'),
]
operations = [
migrations.AlterField(
model_name='saleproduct',
name='is_mtestok',
field=models.BooleanField(blank=True, null=True, verbose_name='是否军检合格'),
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 3.2.9 on 2021-12-08 06:08
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('sam', '0009_alter_saleproduct_is_mtestok'),
]
operations = [
migrations.RemoveField(
model_name='saleproduct',
name='is_mtested',
),
migrations.RemoveField(
model_name='saleproduct',
name='is_mtestok',
),
]

View File

@ -89,8 +89,6 @@ class SaleProduct(BaseModel):
sale = models.ForeignKey(Sale, verbose_name='关联销售记录', on_delete=models.CASCADE) sale = models.ForeignKey(Sale, verbose_name='关联销售记录', on_delete=models.CASCADE)
number = models.CharField('物品编号', max_length=50) number = models.CharField('物品编号', max_length=50)
iproduct = models.ForeignKey('inm.iproduct', verbose_name='关联库存产品', on_delete=models.CASCADE, related_name='sale_iproduct') iproduct = models.ForeignKey('inm.iproduct', verbose_name='关联库存产品', on_delete=models.CASCADE, related_name='sale_iproduct')
is_mtested = models.BooleanField('是否军检', default=False)
is_mtestok = models.BooleanField('是否军检合格', default=True)
remark = models.TextField('备注', null=True, blank=True) remark = models.TextField('备注', null=True, blank=True)
class Meta: class Meta:

View File

@ -72,7 +72,7 @@ class SaleCreateSerializer(serializers.ModelSerializer):
attrs['customer'] = order.customer attrs['customer'] = order.customer
attrs['product'] = order.product attrs['product'] = order.product
for i in attrs['iproducts']: for i in attrs['iproducts']:
if i.material is not attrs['product']: if i.material != attrs['product']:
raise exceptions.APIException('产品选取错误') raise exceptions.APIException('产品选取错误')
return super().validate(attrs) return super().validate(attrs)
@ -102,8 +102,3 @@ class SaleProductCreateSerializer(serializers.ModelSerializer):
instance.sale.count = SaleProduct.objects.filter(sale=instance.sale).count() instance.sale.count = SaleProduct.objects.filter(sale=instance.sale).count()
instance.sale.save() instance.sale.save()
return instance return instance
class SaleProductMtestSerializer(serializers.ModelSerializer):
class Meta:
model = SaleProduct
fields = ['remark', 'is_mtestok']

View File

@ -1,8 +1,11 @@
from django.db import transaction from django.db import transaction
from django.db.models.aggregates import Count
from rest_framework import exceptions, serializers from rest_framework import exceptions, serializers
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin
from apps.inm.models import FIFO from apps.mtm.models import Material
from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer, SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer, SaleProductMtestSerializer from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
from apps.inm.signals import update_inm
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 apps.sam.models import Contract, Customer, Order, Sale, SaleProduct
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.system.mixins import CreateUpdateCustomMixin from apps.system.mixins import CreateUpdateCustomMixin
@ -75,7 +78,7 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
return Response(serializer.data) return Response(serializer.data)
class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericViewSet): class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
""" """
销售记录 销售记录
""" """
@ -128,15 +131,53 @@ class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, C
fifo.is_audited = True fifo.is_audited = True
fifo.auditor = request.user fifo.auditor = request.user
fifo.inout_date = timezone.now() fifo.inout_date = timezone.now()
fifo.create_by = request.user
fifo.save() fifo.save()
# 出库条目 # 出库条目 暂时不校验是否军检
spds = SaleProduct.objects.filter(sale=obj) # spds = SaleProduct.objects.filter(sale=obj)
for i in spds: # for i in spds:
if i.is_mtested and i.is_mtestok: # if i.is_mtested and i.is_mtestok:
pass # pass
else: # else:
raise exceptions.APIException('存在未军检产品') # raise exceptions.APIException('存在未军检产品')
# 创建出库条目
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.is_tested = True
fifoitem.is_testok = True
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)
# 更新库存 # 更新库存
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() return Response()
class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, GenericViewSet): class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, GenericViewSet):
@ -158,20 +199,12 @@ class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, Ge
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
obj = self.get_object() obj = self.get_object()
obj.sale.count = SaleProduct.objects.filter(sale=obj.sale).count() sale = obj.sale
obj.sale.save() if sale.is_audited:
raise exceptions.APIException('该销售记录已审核,不可删除产品')
sale.count = SaleProduct.objects.filter(sale=obj.sale).count()
sale.save()
obj.delete() obj.delete()
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=SaleProductMtestSerializer)
def mtest(self, request, pk=None):
"""
军检
"""
obj = self.get_object()
if obj.is_mtested:
raise exceptions.APIException('已进行军检')
obj.remark = request.data.get('remark', None)
obj.is_mtestok = request.data.get('is_mtestok')
obj.save()
return Response()

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-08 06:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0029_auto_20211202_1630'),
]
operations = [
migrations.AlterField(
model_name='wproduct',
name='act_state',
field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '库存中'), (50, '不合格'), (60, '待成品检验')], default=0, verbose_name='进行状态'),
),
]

View File

@ -0,0 +1,55 @@
# Generated by Django 3.2.9 on 2021-12-09 08:38
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('wf', '0017_auto_20211203_1501'),
('pm', '0016_auto_20211209_1638'),
('mtm', '0041_alter_material_type'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('wpm', '0030_alter_wproduct_act_state'),
]
operations = [
migrations.AlterField(
model_name='operationmaterial',
name='count',
field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='消耗或产出数量'),
),
migrations.AlterField(
model_name='operationwproduct',
name='subproduction_plan',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_subplan', to='pm.subproductionplan', verbose_name='当前子生产计划'),
),
migrations.AlterField(
model_name='wproduct',
name='act_state',
field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '已入库'), (50, '不合格'), (60, '待成品检验')], default=0, verbose_name='进行状态'),
),
migrations.CreateModel(
name='WprouctTicket',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('number', models.CharField(blank=True, max_length=50, null=True, verbose_name='物品编号')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wprouctticket_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所在物料状态')),
('step', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='所在步骤')),
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='所在子生产计划')),
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wf.ticket', verbose_name='关联工单')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wprouctticket_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
('wproduct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联产品')),
],
options={
'abstract': False,
},
),
]

View File

@ -9,7 +9,6 @@ from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organi
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial
from django.core.validators import MinValueValidator
from apps.em.models import Equipment from apps.em.models import Equipment
class WMaterial(BaseModel): class WMaterial(BaseModel):
""" """
@ -28,6 +27,7 @@ class WProduct(CommonAModel):
WPR_ACT_STATE_DOWAIT = 8 WPR_ACT_STATE_DOWAIT = 8
WPR_ACT_STATE_DOING = 10 WPR_ACT_STATE_DOING = 10
WPR_ACT_STATE_TOTEST = 20 WPR_ACT_STATE_TOTEST = 20
WPR_ACT_STATE_TOCOMBTEST = 26
WPR_ACT_STATE_OK = 30 WPR_ACT_STATE_OK = 30
WPR_ACT_STATE_INM = 40 WPR_ACT_STATE_INM = 40
WPR_ACT_STATE_NOTOK = 50 WPR_ACT_STATE_NOTOK = 50
@ -37,8 +37,9 @@ class WProduct(CommonAModel):
(WPR_ACT_STATE_DOWAIT, '操作准备中'), (WPR_ACT_STATE_DOWAIT, '操作准备中'),
(WPR_ACT_STATE_DOING, '操作进行中'), (WPR_ACT_STATE_DOING, '操作进行中'),
(WPR_ACT_STATE_TOTEST, '待检验'), (WPR_ACT_STATE_TOTEST, '待检验'),
(WPR_ACT_STATE_TOCOMBTEST, '待夹层检验'),
(WPR_ACT_STATE_OK, '已合格'), (WPR_ACT_STATE_OK, '已合格'),
(WPR_ACT_STATE_INM, '存中'), (WPR_ACT_STATE_INM, '已入'),
(WPR_ACT_STATE_NOTOK, '不合格'), (WPR_ACT_STATE_NOTOK, '不合格'),
(WPR_ACT_STATE_TOFINALTEST, '待成品检验') (WPR_ACT_STATE_TOFINALTEST, '待成品检验')
) )
@ -55,6 +56,16 @@ class WProduct(CommonAModel):
operation = models.ForeignKey('wpm.operation', verbose_name='关联操作', operation = models.ForeignKey('wpm.operation', verbose_name='关联操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation') on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
class WprouctTicket(CommonAModel):
"""
玻璃审批工单
"""
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
wproduct = models.ForeignKey(WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
material = models.ForeignKey(Material, verbose_name='所在物料状态', on_delete=models.CASCADE)
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE)
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE)
class Pick(CommonADModel): class Pick(CommonADModel):
""" """
@ -97,7 +108,7 @@ class OperationWproduct(BaseModel):
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct') wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct')
number = models.CharField('物品编号', null=True, blank=True, max_length=50) number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE) material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='ow_subplan')
class OperationMaterial(BaseModel): class OperationMaterial(BaseModel):
@ -108,7 +119,7 @@ class OperationMaterial(BaseModel):
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, null=True, blank=True) material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, null=True, blank=True)
count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)], null=True, blank=True) count = models.PositiveSmallIntegerField('消耗或产出数量', null=True, blank=True)
wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True) wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE, null=True, blank=True) subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE, null=True, blank=True)

View File

@ -292,6 +292,11 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
model = TestRecord model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'wproduct'] fields = ['form', 'record_data', 'is_testok', 'wproduct']
class WpmTestFormInitSerializer(serializers.Serializer):
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True)
class WplanPutInSerializer(serializers.Serializer): class WplanPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False) remark = serializers.CharField(label="入库备注", required =False)
@ -336,6 +341,11 @@ class OperationMaterialCreate1Serailizer(serializers.ModelSerializer):
model = OperationMaterial model = OperationMaterial
fields = ['operation', 'wmaterial', 'count'] fields = ['operation', 'wmaterial', 'count']
def validate(self, attrs):
if attrs['count'] <=0:
raise exceptions.APIException('消耗物料数量错误')
return super().validate(attrs)
def create(self, validated_data): def create(self, validated_data):
wmaterial = validated_data['wmaterial'] wmaterial = validated_data['wmaterial']
validated_data['material'] = wmaterial.material validated_data['material'] = wmaterial.material
@ -344,6 +354,9 @@ class OperationMaterialCreate1Serailizer(serializers.ModelSerializer):
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_IN validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_IN
return super().create(validated_data) return super().create(validated_data)
class OperationMaterialCreate1ListSerailizer(serializers.ListSerializer):
child=OperationMaterialCreate1Serailizer()
class OperationMaterialCreate2Serailizer(serializers.ModelSerializer): class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all()) subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all())
class Meta: class Meta:
@ -357,6 +370,9 @@ class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_OUT validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_OUT
return super().create(validated_data) return super().create(validated_data)
class OperationMaterialCreate2ListSerailizer(serializers.ListSerializer):
child=OperationMaterialCreate2Serailizer()
class OperationMaterialCreate3Serializer(serializers.ModelSerializer): class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all()) material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all())
class Meta: class Meta:

View File

@ -12,13 +12,14 @@ from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMateria
from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.models import SubProductionPlan, SubProductionProgress
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from apps.qm.models import TestRecord, TestRecordItem from apps.qm.models import TestRecord, TestRecordItem
from apps.qm.serializers import TestRecordDetailSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from apps.wpm.filters import WMaterialFilterSet from apps.wpm.filters import WMaterialFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestFormInitSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer
from rest_framework.response import Response from rest_framework.response import Response
from django.db import transaction from django.db import transaction
from rest_framework import exceptions, serializers from rest_framework import exceptions, serializers
@ -183,6 +184,39 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
ordering_fields = ['id'] ordering_fields = ['id']
ordering = ['id'] ordering = ['id']
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestFormInitSerializer)
def test_init(self, request, pk=None):
"""
检验表单初始化
"""
serializer = WpmTestFormInitSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
wproduct = vdata['wproduct']
form = vdata['form']
# 如果是复检记录, 需要带入原数据
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST:
# 查找最近一条检验记录
trs = TestRecord.objects.filter(wproduct=wproduct, type=TestRecord.TEST_PROCESS).order_by('-id').first()
if trs:
origin_data = TestRecordDetailSerializer(instance=trs).data
data = RecordFormDetailSerializer(instance=form).data
data['origin_data'] = origin_data
o_dict = {}
for i in origin_data['record_data_']:
o_dict[i['field_key']] = i['field_value']
for i in data['form_fields']:
i['origin_value'] = o_dict[i['field_key']]
else:
raise exceptions.APIException('原工序检验记录不存在')
else:
data = RecordFormDetailSerializer(instance=form).data
# 后续加入系统自带数据
return Response(data)
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer) @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer)
@transaction.atomic @transaction.atomic
def test(self, request, pk=None): def test(self, request, pk=None):
@ -195,7 +229,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
record_data = vdata.pop('record_data') record_data = vdata.pop('record_data')
wproduct = vdata['wproduct'] wproduct = vdata['wproduct']
if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST, if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST,
WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST]: WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST, WProduct.WPR_ACT_STATE_TOCOMBTEST]:
raise exceptions.APIException('该产品当前状态不可检验') raise exceptions.APIException('该产品当前状态不可检验')
if 'is_testok' not in vdata: if 'is_testok' not in vdata:
raise exceptions.APIException('未填写检测结论') raise exceptions.APIException('未填写检测结论')
@ -206,6 +240,8 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
savedict['type'] = TestRecord.TEST_PROCESS_RE savedict['type'] = TestRecord.TEST_PROCESS_RE
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST: elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST:
savedict['type'] = TestRecord.TEST_FINAL savedict['type'] = TestRecord.TEST_FINAL
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOCOMBTEST:
savedict['type'] = TestRecord.TEST_COMB
obj = serializer.save(**savedict) obj = serializer.save(**savedict)
tris = [] tris = []
for m in record_data: # 保存记录详情 for m in record_data: # 保存记录详情
@ -224,15 +260,14 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
# 如果检测合格, 变更动态产品进行状态 # 如果检测合格, 变更动态产品进行状态
if obj.is_testok: if obj.is_testok:
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT # 复检 wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: # 成品检验
wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST # 成品检验 wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST
else: else:
wproduct.act_state = WProduct.WPR_ACT_STATE_OK wproduct.act_state = WProduct.WPR_ACT_STATE_OK
if wproduct.number is None: # 产生半成品编号 if wproduct.number is None: # 产生半成品编号
wproduct.number = 'WP'+ranstr(7) wproduct.number = 'WP'+ranstr(7)
wproduct.save()
# 更新子计划状态 # 更新子计划状态
# 更新子计划主产品数 # 更新子计划主产品数
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
@ -241,8 +276,9 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
instance.save() instance.save()
else:# 如果不合格 else:# 如果不合格
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
wproduct.save() # 需要走不合格品审理单
wproduct.update_by = request.user
wproduct.save()
return Response() return Response()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer) @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer)
@ -267,12 +303,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark)
# 创建入库明细 # 创建入库明细
for i in wproducts_a: for i in wproducts_a:
spi = i['subproduction_plan'] spi = SubProductionPlan.objects.get(pk=i['subproduction_plan'])
fifoitem = FIFOItem() fifoitem = FIFOItem()
fifoitem.is_tested = True fifoitem.is_tested = True
fifoitem.is_testok = True fifoitem.is_testok = True
fifoitem.warehouse = warehouse fifoitem.warehouse = warehouse
fifoitem.material = i['material'] fifoitem.material = Material.objects.get(pk=i['material'])
fifoitem.count = i['total'] fifoitem.count = i['total']
fifoitem.batch = spi.number fifoitem.batch = spi.number
fifoitem.fifo = fifo fifoitem.fifo = fifo
@ -292,7 +328,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
FIFOItemProduct.objects.bulk_create(ips) FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态 # 更新库存并修改半成品进行状态
update_inm(fifo) update_inm(fifo)
wproducts.update(act_state=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user) wproducts.update(act_state=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now())
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer) @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
@ -486,6 +522,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save() instance.save()
wp.operation = None wp.operation = None
wp.update_by = request.user
wp.save() wp.save()
elif step.type == Step.STEP_TYPE_DIV: elif step.type == Step.STEP_TYPE_DIV:
# 更新物料产出情况 # 更新物料产出情况
@ -498,25 +535,31 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
for x in range(i.count): for x in range(i.count):
WProduct.objects.create(**wpr) WProduct.objects.create(**wpr)
elif step.type == Step.STEP_TYPE_COMB: elif step.type == Step.STEP_TYPE_COMB:
if i.subproduction_progress.is_main: oms_w = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT,
newstep, hasNext = WpmServies.get_next_step(i.subproduction_plan, step) subproduction_progress__ismain=True)
if len(oms_w) == 1:
oms_w = oms_w[0]
# 校验单片数量是否正确, 暂时未写
newstep, hasNext = WpmServies.get_next_step(oms_w.subproduction_plan, step)
wproduct = WProduct() wproduct = WProduct()
wproduct.material = i.material wproduct.material = oms_w.material
wproduct.step = newstep wproduct.step = newstep
wproduct.subproduction_plan = i.subproduction_plan wproduct.subproduction_plan = oms_w.subproduction_plan
if hasNext: if hasNext:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else: else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
# 更新子计划进度 # 更新子计划进度
instance = SubProductionProgress.objects.get(subproduction_plan=i.subproduction_plan, instance = oms_w.subproduction_progress
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save() instance.save()
wproduct.create_by = request.user
wproduct.save() wproduct.save()
# 隐藏原半成品 # 隐藏原半成品
wps = WProduct.objects.filter(ow_wproduct__operation = op) wps = WProduct.objects.filter(ow_wproduct__operation = op)
wps.update(is_hidden=True, child=wproduct) wps.update(is_hidden=True, child=wproduct, update_by=request.user, update_time=timezone.now())
else:
raise exceptions.APIException('产出物料错误')
op.is_submited = True op.is_submited = True
op.save() op.save()
return Response() return Response()
@ -594,6 +637,16 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
instance.delete() instance.delete()
return Response() return Response()
@action(methods=['get'], detail=True, perms_map={'get':'*'})
def init(self, request, pk=None):
'''
表格初始化
'''
obj = self.get_object()
data = RecordFormDetailSerializer(instance=obj.form).data
# 后续加入系统带入数据
return Response(data)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=OperationRecordSubmitSerializer) @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=OperationRecordSubmitSerializer)
def submit(self, request, pk=None): def submit(self, request, pk=None):
serializer = OperationRecordSubmitSerializer(data=request.data, context={'request':self.request}) serializer = OperationRecordSubmitSerializer(data=request.data, context={'request':self.request})
@ -633,6 +686,17 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod
return OperationMaterialCreate1Serailizer return OperationMaterialCreate1Serailizer
return super().get_serializer_class() return super().get_serializer_class()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=OperationMaterialCreate1ListSerailizer)
def creates(self, request, pk=None):
"""
批量创建消耗物料
"""
serializer = OperationMaterialCreate1ListSerailizer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response()
@transaction.atomic() @transaction.atomic()
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
instance = self.get_object() instance = self.get_object()
@ -657,6 +721,16 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo
return OperationMaterialCreate2Serailizer return OperationMaterialCreate2Serailizer
return super().get_serializer_class() return super().get_serializer_class()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=OperationMaterialCreate2ListSerailizer)
def creates(self, request, pk=None):
"""
批量创建产出物料
"""
serializer = OperationMaterialCreate2ListSerailizer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response()
@transaction.atomic() @transaction.atomic()
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
instance = self.get_object() instance = self.get_object()

View File

@ -62,7 +62,7 @@ class UpdateDevelop(APIView):
import os import os
# 更新后端 # 更新后端
os.chdir('/home/hberp') os.chdir('/home/hberp')
ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git develop') ret = os.popen('git pull https://caoqianming%40foxmail.com:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git develop')
# 打包前端 # 打包前端
# os.chdir('/home/hberp/hb_client') # os.chdir('/home/hberp/hb_client')
# os.system('npm run build:prod') # os.system('npm run build:prod')