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

This commit is contained in:
shijing 2022-02-22 16:31:45 +08:00
commit 52b0f469d9
40 changed files with 1476 additions and 628 deletions

View File

@ -29,3 +29,22 @@ export function getEmployee(data) {
data data
}) })
} }
//个人离岗说明
export function getNotWorkList(query) {
return request({
url: '/hrm/not_work_remark/',
method: 'get',
params: query
})
}
export function getClockrecordList(query) {
return request({
url: '/hrm/clock_record/',
method: 'get',
params: query
})
}

View File

@ -377,3 +377,34 @@ export function deletetechdoc(id, data) {
}) })
} }
//装箱
//记录表格字段表
export function getpackitemList(query) {
return request({
url: '/mtm/packitem/',
method: 'get',
params: query
})
}
export function createpackitem(data) {
return request({
url: '/mtm/packitem/',
method: 'post',
data
})
}
export function updatepackitem(id, data) {
return request({
url: `/mtm/packitem/${id}/`,
method: 'put',
data
})
}
export function deletepackitem(id, data) {
return request({
url: `/mtm/packitem/${id}/`,
method: 'delete',
data
})
}

View File

@ -1,223 +1,371 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card> <el-card>
<el-card > <el-card>
<el-descriptions title="物料基本信息" direction="vertical" :column="8" border> <el-descriptions
<el-descriptions-item label="物料编号"> {{materialdetail.number}}</el-descriptions-item> title="物料基本信息"
<el-descriptions-item label="物料名称"> {{materialdetail.name}}</el-descriptions-item> direction="vertical"
<el-descriptions-item label="规格型号" :span="2"> {{materialdetail.specification}}</el-descriptions-item> :column="8"
<el-descriptions-item label="计量单位"> {{materialdetail.unit}} </el-descriptions-item> border
<el-descriptions-item label="数量"> {{materialdetail.count}}</el-descriptions-item> >
</el-descriptions> <el-descriptions-item label="物料编号">
{{ materialdetail.number }}</el-descriptions-item
>
</el-card> <el-descriptions-item label="物料名称">
{{ materialdetail.name }}</el-descriptions-item
>
<el-descriptions-item label="规格型号" :span="2">
{{ materialdetail.specification }}</el-descriptions-item
>
<el-descriptions-item label="计量单位">
{{ materialdetail.unit }}
</el-descriptions-item>
<el-descriptions-item label="数量">
{{ materialdetail.count }}</el-descriptions-item
>
</el-descriptions>
</el-card>
<el-tabs v-model="activeName" type="card"> <el-tabs v-model="activeName" type="card">
<el-tab-pane label="供应商" name="5" v-if="this.type==3||this.type==4"> <el-tab-pane
label="供应商"
name="5"
v-if="this.type == 3 || this.type == 4"
>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="批次" name="3"> <el-tab-pane label="批次" name="3">
<el-table
:data="InventoryList"
border
fit
stripe
height="460"
highlight-current-row
>
<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 <el-table-column label="物料编号">
<template slot-scope="scope">{{
:data="InventoryList" scope.row.material_.number
border }}</template>
fit </el-table-column>
stripe <el-table-column label="仓库名称">
height="460" <template slot-scope="scope">{{
highlight-current-row scope.row.warehouse_.name
}}</template>
> </el-table-column>
<el-table-column type="index" width="50" /> <el-table-column label="仓库编号">
<el-table-column label="物料批次"> <template slot-scope="scope">{{
<template slot-scope="scope">{{ scope.row.batch }}</template> scope.row.warehouse_.number
</el-table-column> }}</template>
<el-table-column label="物料名称"> </el-table-column>
<template slot-scope="scope">{{ scope.row.material_.name }}</template> <el-table-column label="物料总存量">
</el-table-column> <template slot-scope="scope">{{ scope.row.count }}</template>
<el-table-column label="规格型号"> </el-table-column>
<template slot-scope="scope">{{ scope.row.material_.specification }}</template> </el-table>
</el-table-column> </el-tab-pane>
<el-table-column label="物料编号">
<template slot-scope="scope">{{
scope.row.material_.number
}}</template>
</el-table-column>
<el-table-column label="仓库名称">
<template slot-scope="scope">{{
scope.row.warehouse_.name
}}</template>
</el-table-column>
<el-table-column label="仓库编号">
<template slot-scope="scope">{{
scope.row.warehouse_.number
}}</template>
</el-table-column>
<el-table-column label="物料总存量">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
</el-table>
</el-tab-pane> <el-tab-pane label="关联的订单" name="1">
<el-table
<el-tab-pane label="关联的订单" name="1"> :data="orderlist"
<el-table border
fit
:data="orderlist" stripe
border highlight-current-row
fit height="460"
stripe >
highlight-current-row <el-table-column type="index" width="50" />
height="460"
<el-table-column label="订单编号" show-overflow-tooltip>
> <template slot-scope="scope">{{ scope.row.number }}</template>
<el-table-column type="index" width="50" /> </el-table-column>
<el-table-column label="客户" show-overflow-tooltip>
<el-table-column label="订单编号" show-overflow-tooltip> <template slot-scope="scope">{{
<template slot-scope="scope">{{ scope.row.number }}</template> scope.row.customer_.name
}}</template>
</el-table-column>
<el-table-column label="所属合同" show-overflow-tooltip>
<template slot-scope="scope">{{
scope.row.contract_.name
}}</template>
</el-table-column>
<el-table-column label="产品名称" show-overflow-tooltip>
<template slot-scope="scope">{{
scope.row.product_.name
}}</template>
</el-table-column>
<el-table-column label="产品型号" show-overflow-tooltip>
<template slot-scope="scope">{{
scope.row.product_.specification
}}</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.delivery_date
}}</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{
scope.row.create_time
}}</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="关联的计划" name="2">
<el-table
:data="productionplanList"
border
fit
stripe
style="width: 100%"
height="460"
>
<el-table-column type="index" 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.order_.number
}}</template>
</el-table-column>
<el-table-column label="合同编号">
<template slot-scope="scope">{{
scope.row.order_.contract_.number
}}</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.start_date }}</template>
</el-table-column>
<el-table-column label="计划完工时间">
<template slot-scope="scope">{{ scope.row.end_date }}</template>
</el-table-column>
<el-table-column label="交付截止时间">
<template slot-scope="scope">{{
scope.row.order_.delivery_date
}}</template>
</el-table-column>
<el-table-column label="是否生成子计划">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_planed == false"></el-tag>
<el-tag v-if="scope.row.is_planed == true"></el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{
scope.row.create_time
}}</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane
label="物料"
name="4"
v-if="this.type == 1 || this.type == 2"
>
<el-table
:data="wproductList"
border
fit
stripe
style="width: 100%"
height="460"
>
<el-table-column type="index" 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" v-if="scope.row.warehouse_">{{
scope.row.warehouse_.name
}}</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="装箱单" name="5" v-if="this.type == 1">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate">
新增装箱单
</el-button>
<el-table
:data="pickList"
border
fit
stripe
style="width: 100%"
height="460"
>
<el-table-column type="index" width="50" />
<el-table-column label="名称">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column label="单位">
<template slot-scope="scope">{{ scope.row.unit }}</template>
</el-table-column>
<el-table-column label="数量">
<template slot-scope="scope" >{{
scope.row.count
}}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
type="primary"
@click="handleEdit(scope)"
>编辑
</el-link>
<el-link
type="danger"
@click="handleDelete(scope)"
>删除
</el-link>
</template>
</el-table-column> </el-table-column>
<el-table-column label="客户" show-overflow-tooltip> </el-table>
<template slot-scope="scope">{{ scope.row.customer_.name }}</template> <el-dialog
</el-table-column> :visible.sync="dialogVisible"
<el-table-column label="所属合同" show-overflow-tooltip> :close-on-click-modal="false"
<template slot-scope="scope">{{ scope.row.contract_.name }}</template> :title="dialogType === 'edit' ? '编辑装箱单' : '新增装箱单'"
</el-table-column> >
<el-table-column label="产品名称" show-overflow-tooltip> <el-form
<template slot-scope="scope">{{ scope.row.product_.name }}</template> ref="Form"
</el-table-column> :model="packitem"
<el-table-column label="产品型号" show-overflow-tooltip> label-width="100px"
<template slot-scope="scope">{{ scope.row.product_.specification }}</template> label-position="right"
</el-table-column> :rules="rule1"
<el-table-column label="产品数量" > >
<template slot-scope="scope">{{ scope.row.count }}</template> <el-form-item label="物料"
</el-table-column> prop="material"
<el-table-column label="交货日期" >
<template slot-scope="scope">{{ scope.row.delivery_date }}</template>
</el-table-column>
<el-table-column label="创建时间" >
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="关联的计划" name="2">
<el-table
:data="productionplanList"
border
fit
stripe
style="width: 100%"
height="460"
>
<el-table-column type="index" 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.order_.number }}</template>
</el-table-column>
<el-table-column label="合同编号" >
<template slot-scope="scope">{{ scope.row.order_.contract_.number }}</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.start_date }}</template>
</el-table-column>
<el-table-column label="计划完工时间" >
<template slot-scope="scope">{{ scope.row.end_date }}</template>
</el-table-column>
<el-table-column label="交付截止时间" >
<template slot-scope="scope">{{ scope.row.order_.delivery_date }}</template>
</el-table-column>
<el-table-column label="是否生成子计划" >
<template slot-scope="scope" >
<el-tag v-if="scope.row.is_planed==false"></el-tag>
<el-tag v-if="scope.row.is_planed==true"></el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="物料" name="4" v-if="this.type==1||this.type==2">
<el-table
:data="wproductList"
border
fit
stripe
style="width: 100%"
height="460"
> >
<el-select v-model="packitem.material" @change="selectmaterial" >
<el-table-column type="index" width="50" /> <el-option
v-for="item in materialoptions"
:key="item.id"
<el-table-column label="玻璃编号" > :value="item.id"
<template slot-scope="scope" >{{ scope.row.number }}</template> :label="item.name"
</el-table-column> >
</el-option>
<el-table-column label="所在子工序"> </el-select>
<template slot-scope="scope" >{{ </el-form-item>
scope.row.step_.name <el-form-item label="名称" prop="name">
}}</template> <el-input v-model="packitem.name" placeholder="名称" />
</el-table-column> </el-form-item>
<el-table-column label="状态" > <el-form-item label="单位" prop="unit">
<template slot-scope="scope">{{ <el-input v-model="packitem.unit" placeholder="单位" />
actstate_[scope.row.act_state] </el-form-item>
}}</template> <el-form-item label="型号" prop="specification">
</el-table-column> <el-input v-model="packitem.specification" placeholder="型号" />
<el-table-column label="仓库" > </el-form-item>
<template slot-scope="scope" v-if=" scope.row.warehouse_">{{ scope.row.warehouse_.name }}</template> <el-form-item label="数量" prop="count">
</el-table-column> <el-input-number
warehouse_ style="width: 100%"
v-model="packitem.count"
</el-table> :step="1"
</el-tab-pane> :min="0"
</el-tabs> step-strictly
placeholder="数量"
></el-input-number>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number
v-model="packitem.sort"
:min="1"
placeholder="排序"
></el-input-number>
</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>
</el-tab-pane>
</el-tabs>
</el-card> </el-card>
</div> </div>
</template> </template>
<script> <script>
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import vueJsonEditor from "vue-json-editor"; import vueJsonEditor from "vue-json-editor";
import {upUrl, upHeaders} from "@/api/file"; import { upUrl, upHeaders } from "@/api/file";
import {getProductionplanList } from "@/api/pm"; import { getProductionplanList } from "@/api/pm";
import {getmaterialbatchList} from "@/api/inm"; import { getmaterialbatchList } from "@/api/inm";
import {getOrderList } from "@/api/sam"; import { getOrderList } from "@/api/sam";
import {getMaterial } from "@/api/mtm"; import { getMaterial,getpackitemList,createpackitem,updatepackitem,deletepackitem,getMaterialList } from "@/api/mtm";
import {getwproductList } from "@/api/wpm"; import { getwproductList } from "@/api/wpm";
import { upFile } from "@/api/file";
import {genTree} from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default { import { upFile } from "@/api/file";
components: {Pagination, vueJsonEditor, Treeselect}, import { genTree } from "@/utils";
data() { import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
return { import Treeselect from "@riophae/vue-treeselect";
materialdetail:"", import "@riophae/vue-treeselect/dist/vue-treeselect.css";
orderlist:[], const defaultpackitem = {
wproductList:[], name:"",
productionplanList:[], unit:"",
InventoryList:[], specification:"",
activeName:'3', };
actstate_: { export default {
components: { Pagination, vueJsonEditor, Treeselect },
data() {
return {
materialdetail: "",
orderlist: [],
wproductList: [],
productionplanList: [],
InventoryList: [],
activeName: "3",
packitem:defaultpackitem,
dialogVisible: false,
dialogType: "new",
pickList:[],
materialoptions:[],
actstate_: {
6: "待复检", 6: "待复检",
10: "操作进行中", 10: "操作进行中",
20: "待检验", 20: "待检验",
@ -229,67 +377,162 @@
26: "待夹层检验", 26: "待夹层检验",
70: "报废", 70: "报废",
}, },
}; rule1: {
name: [{required: true, message: "请输入名称", trigger: "blur"}],
unit: [{required: true, message: "请输入单位", trigger: "blur"}],
},
};
},
computed: {},
watch: {},
created() {
this.material = this.$route.params.id;
this.type = this.$route.params.type;
this.getMaterialist()
this.getMaterial();
this.getpickList();
this.getOrderList();
this.getplanList();
this.getmaterialbatchList();
this.getwproductList();
},
methods: {
//新增装箱单
getMaterialist()
{
getMaterialList({ pageoff: true,type:3 }).then((response) => {
if (response.data) {
this.materialoptions = response.data;
}
});
}, },
computed: {},
watch: {}, selectmaterial(selval){
created() { getMaterial(selval).then((response) => {
this.material = this.$route.params.id; if (response.data) {
this.type=this.$route.params.type; this.packitem.name = response.data.name;
this.getMaterial(); this.packitem.unit = response.data.unit;
this.packitem.specification = response.data.specification;
this.getOrderList();
this.getplanList();
this.getmaterialbatchList();
this.getwproductList(); }
});
}, },
methods: {
getMaterial(){ handleCreate() {
this.packitem = Object.assign({}, defaultpackitem);
this.dialogType = "new";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.packitem = Object.assign({}, scope.row); // copy obj
this.dialogType = "edit";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deletepackitem(scope.row.id);
this.getpickList();
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) {
updatepackitem(this.packitem.id, this.packitem).then((res) => {
if (res.code >= 200) {
this.getpickList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
} else {
this.packitem.product=this.material;
createpackitem(this.packitem).then((res) => {
if (res.code >= 200) {
this.getpickList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
getpickList()
{
getpackitemList({ product: this.material, page: 0 }).then((response) => {
if (response.data) {
this.pickList = response.data; //zhuangxiang信息
}
});
},
getMaterial() {
getMaterial(this.material).then((response) => { getMaterial(this.material).then((response) => {
if (response.data) { if (response.data) {
this.materialdetail = response.data;//物料基本信息 this.materialdetail = response.data; //物料基本信息
}
})
},
getOrderList(){
getOrderList({material:this.material,page:0}).then((response) => {
if (response.data) {
this.orderlist = response.data;//物料关联的订单
}
})
},
getplanList() {
getProductionplanList({material:this.material,page:0}).then((response) => {
if (response.data) {
this.productionplanList = response.data;//物料关联计划
} }
}); });
}, },
getOrderList() {
getOrderList({ material: this.material, page: 0 }).then((response) => {
if (response.data) {
this.orderlist = response.data; //物料关联的订单
}
});
},
getplanList() {
getProductionplanList({ material: this.material, page: 0 }).then(
(response) => {
if (response.data) {
this.productionplanList = response.data; //物料关联计划
}
}
);
},
getmaterialbatchList() { getmaterialbatchList() {
getmaterialbatchList({ material: this.material, page: 0 }).then(
(response) => {
getmaterialbatchList({material:this.material,page:0}).then((response) => { if (response.data) {
if (response.data) { this.InventoryList = response.data;
this.InventoryList = response.data; }
}
);
},
getwproductList() {
getwproductList({ material: this.material, page: 0 }).then((response) => {
if (response.data) {
this.wproductList = response.data; //半成品
} }
}); });
}, },
getwproductList(){ },
getwproductList({material:this.material,page:0}).then((response) => { };
if (response.data) {
this.wproductList = response.data;//半成品
}
});
}
},
};
</script> </script>

View File

@ -94,7 +94,7 @@
</el-form-item> </el-form-item>
<el-form-item label="子工序类型" prop="type"> <el-form-item label="子工序类型" prop="type">
<el-select style="width: 100%" v-model="step.type" placeholder="请选择"> <el-select style="width: 100%" v-model="step.type" placeholder="请选择">
<el-option <el-option
v-for="item in typeoption" v-for="item in typeoption"
:key="item.value" :key="item.value"
@ -411,6 +411,7 @@
const defaultstep = { const defaultstep = {
name: "", name: "",
number: "", number: "",
type:null,
}; };
const defaultrecordform = { const defaultrecordform = {
@ -486,15 +487,15 @@
'selects': '多选', 'selects': '多选',
}, },
typeoption: [{ typeoption: [{
value: '1', value: 1,
label: '常规' label: '常规'
}, },
{ {
value: '2', value: 2,
label: '分割' label: '分割'
}, },
{ {
value: '3', value: 3,
label: '结合' label: '结合'
}], }],
fieldtypeoptions: [{ fieldtypeoptions: [{
@ -684,7 +685,7 @@
recordformLists() recordformLists()
{ {
this.listQueryrecordform.step=this.stepid; this.listQueryrecordform.step=this.stepid;
this.listQueryrecordform.type=1; this.listQueryrecordform.type=10;
getrecordformList(this.listQueryrecordform).then((response) => { getrecordformList(this.listQueryrecordform).then((response) => {
if (response.data) { if (response.data) {
this.recordformList = response.data; this.recordformList = response.data;

View File

@ -2,154 +2,149 @@
<div class="app-container"> <div class="app-container">
<el-card> <el-card>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane label="今日到岗"> <el-tab-pane label="今日到岗">
<el-table <el-table
:data="userList.results"
:data="userList.results" style="width: 100%; margin-top: 6px"
style="width: 100%; margin-top: 6px" highlight-current-row
highlight-current-row row-key="id"
row-key="id" height="100"
height="100" stripe
stripe border
border v-el-height-adaptive-table="{ bottomOffset: 41 }"
v-el-height-adaptive-table="{ bottomOffset: 41 }" >
> <el-table-column type="index" width="50" label="序号" />
<el-table-column type="index" width="50" label="序号" /> <el-table-column align="center" label="工号">
<el-table-column align="center" label="工号"> <template slot-scope="scope">{{ scope.row.number }}</template>
<template slot-scope="scope">{{ scope.row.number }}</template> </el-table-column>
</el-table-column> <el-table-column align="center" label="姓名">
<el-table-column align="center" label="姓名"> <template slot-scope="scope">{{ scope.row.name }}</template>
<template slot-scope="scope">{{ scope.row.name }}</template> </el-table-column>
</el-table-column> <el-table-column align="center" label="到岗情况">
<el-table-column align="center" label="到岗情况"> <template slot-scope="scope">
<template slot-scope="scope"> <el-tag type="success" v-if="scope.row.is_atwork">在岗</el-tag>
<el-tag type="success" v-if="scope.row.is_atwork">在岗</el-tag>
<el-tag type="danger" v-else>离岗</el-tag> <el-tag type="danger" v-else>离岗</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="离岗备注"> <el-table-column align="center" label="离岗备注">
<template slot-scope="scope">{{ scope.row.not_work_remark }}</template> <template slot-scope="scope">{{
</el-table-column> scope.row.not_work_remark
}}</template>
</el-table-column>
<el-table-column align="header-center" label="部门"> <el-table-column align="header-center" label="部门">
<template v-if="scope.row.dept_" slot-scope="scope">{{ <template v-if="scope.row.dept_" slot-scope="scope">{{
scope.row.dept_.name scope.row.dept_.name
}}</template> }}</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column align="center" label="操作" fixed="right">
align="center" <template slot-scope="scope">
label="操作" <el-link
fixed="right" type="primary"
v-if="scope.row.is_atwork == false"
> @click="handlestopwork(scope)"
<template slot-scope="scope"> >离岗说明
<el-link </el-link>
type="primary" </template>
v-if="scope.row.is_atwork==false" </el-table-column>
@click="handlestopwork(scope)" </el-table>
>离岗说明
</el-link>
</template>
</el-table-column>
</el-table>
<pagination
v-show="userList.count > 0"
:total="userList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
<el-dialog
:visible.sync="dialogVisible"
:close-on-click-modal="false"
title="离岗备注"
>
<el-form
ref="Form"
:model="stopwork"
label-width="100px"
label-position="right"
>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="stopwork.not_work_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()">确认</el-button>
</div>
</el-dialog>
</el-tab-pane>
<el-tab-pane label="到岗统计">
<div class="container">
<pagination
<span class="demonstration"></span> v-show="userList.count > 0"
<el-date-picker :total="userList.count"
v-model="value2" :page.sync="listQuery.page"
type="month" :limit.sync="listQuery.page_size"
placeholder="选择年月"> @pagination="getList"
</el-date-picker> />
<el-button type="primary" @click="submit">查询</el-button>
</div> <el-dialog
<el-row> :visible.sync="dialogVisible"
<el-col :span="12"> :close-on-click-modal="false"
<el-table title="离岗备注"
>
:data="atworkList" <el-form
style="width: 100%; margin-top: 6px" ref="Form"
highlight-current-row :model="stopwork"
row-key="id" label-width="100px"
height="680" label-position="right"
stripe >
border <el-form-item label="备注" prop="remark">
v-el-height-adaptive-table="{ bottomOffset: 41 }" <el-input
> type="textarea"
<el-table-column type="index" width="50" label="序号" /> v-model="stopwork.not_work_remark"
<el-table-column align="center" label="工号"> placeholder="备注"
<template slot-scope="scope">{{ scope.row.number }}</template> />
</el-table-column> </el-form-item>
<el-table-column align="center" label="姓名"> </el-form>
<template slot-scope="scope">{{ scope.row.name }}</template> <div style="text-align: right">
</el-table-column> <el-button type="danger" @click="dialogVisible = false"
>取消</el-button
<el-table-column align="header-center" label="部门"> >
<template slot-scope="scope">{{ scope.row.dept_name }}</template> <el-button type="primary" @click="smtconfirm()">确认</el-button>
</el-table-column> </div>
<el-table-column align="center" label="出勤天数"> </el-dialog>
<template slot-scope="scope">{{ scope.row.count }}</template> </el-tab-pane>
</el-table-column> <el-tab-pane label="到岗统计">
<el-table-column align="center" label="应到天数"> <el-row>
<template slot-scope="scope">{{ scope.row.count_workday }}</template> <el-col :span="12">
</el-table-column> <div class="container">
<span class="demonstration"></span>
<el-date-picker
</el-table> v-model="value2"
</el-col> type="month"
<el-col :span="12"> placeholder="选择年月"
<el-calendar > >
</el-date-picker>
<template <el-button type="primary" @click="submit">查询</el-button>
slot="dateCell" </div>
slot-scope="{date, data}"> <el-table
<p> :data="atworkList"
{{ data.day.split('-').slice(1).join('-') }}<br /> {{dealMyDate(data.day)}} style="width: 100%; margin-top: 6px"
</p> highlight-current-row
</template> row-key="id"
</el-calendar> height="680"
</el-col> stripe
</el-row> border
</el-tab-pane> @current-change="handleCurrentChange"
v-el-height-adaptive-table="{ bottomOffset: 41 }"
</el-tabs> >
<el-table-column type="index" width="50" label="序号" />
<el-table-column align="center" label="工号">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column align="center" label="姓名">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column align="header-center" label="部门">
<template slot-scope="scope">{{
scope.row.dept_name
}}</template>
</el-table-column>
<el-table-column align="center" label="出勤天数">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
<el-table-column align="center" label="应到天数">
<template slot-scope="scope">{{
scope.row.count_workday
}}</template>
</el-table-column>
</el-table>
</el-col>
<el-col :span="12">
<el-calendar v-model="value">
<template slot="dateCell" slot-scope="{ date, data }">
<p>
{{ data.day.split("-").slice(1).join("-") }}<br />
{{ dealMyDate(data.day) }}
</p>
</template>
</el-calendar>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</el-card> </el-card>
</div> </div>
</template> </template>
@ -181,9 +176,9 @@
<script> <script>
import { getEmployeeList } from "@/api/employee"; import { getEmployeeList } from "@/api/employee";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import { notWork } from "@/api/hrm"; import { notWork, getNotWorkList ,getClockrecordList} from "@/api/hrm";
import {getatwork } from "@/api/srm"; import { getatwork } from "@/api/srm";
import { upUrl, upHeaders } from "@/api/file"; import { upUrl, upHeaders } from "@/api/file";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
@ -195,89 +190,114 @@ export default {
return { return {
userList: { count: 0 }, userList: { count: 0 },
atworkList: [], atworkList: [],
stopwork:{not_work_remark:""}, stopwork: { not_work_remark: "" },
value3:null, value3: null,
value2:null, value2: null,
listLoading: true, listLoading: true,
dialogVisible:false, dialogVisible: false,
stopworkID:null, stopworkID: null,
notworkList: "",
listQuery: { listQuery: {
page: 1, page: 1,
page_size: 20, page_size: 20,
}, },
resDate: [ resDate: [
{"date":"2022-02-20","content":"放假"}, { date: "2022-02-20", content: "放假" },
{"date":"2022-02-26","content":"去交电费"}, { date: "2022-02-26", content: "去交电费" },
{"date":"2022-02-25","content":"去学习vue"} { date: "2022-02-25", content: "去学习vue" },
], ],
atworkDate:{year:null,month:null}, atworkDate: { year: null, month: null },
value: new Date(),
}; };
}, },
computed: {}, computed: {},
watch: {}, watch: {},
created() { created() {
this.getList(); this.getList();
}, },
methods: { methods: {
checkPermission, checkPermission,
//今日到岗 //今日到岗
getList() { getList() {
this.listQuery.fields='number,name,is_atwork,dept_,id,not_work_remark'; this.listQuery.fields = "number,name,is_atwork,dept_,id,not_work_remark";
getEmployeeList(this.listQuery).then((response) => { getEmployeeList(this.listQuery).then((response) => {
if (response.data) { if (response.data) {
this.userList = response.data; this.userList = response.data;
} }
}); });
}, },
handlestopwork(scope) handlestopwork(scope) {
{ this.dialogVisible = true;
this.dialogVisible=true; this.stopworkID = scope.row.id;
this.stopworkID=scope.row.id; },
handleCurrentChange(row) {
this.resDate=[],
getNotWorkList({page:0,user:row.user_id}).then((response) => {
if (response.data) {
response.data.forEach((item) => {
this.resDate.push({
data: item.not_work_date,
content: item.remark,
});
});
}
});
getClockrecordList({page:0,create_by:row.user_id}).then((response) => {
if (response.data) {
response.data.forEach((item) => {
var curTime=(item.update_time).substring(0,10)
console.log(curTime);
this.resDate.push({
data: curTime,
content: "在岗",
});
});
}
});
}, },
//离职备注提交 //离职备注提交
smtconfirm() smtconfirm() {
{
console.log(this.stopwork); notWork(this.stopworkID, this.stopwork).then((res) => {
notWork(this.stopworkID, this.stopwork).then((res) => { if (res.code >= 200) {
if (res.code >= 200) { this.$message.success("离职备注提交成功!");
this.$message.success("离职备注提交成功!"); this.dialogVisible = false;
this.dialogVisible=false; this.getList();
this.getList(); }
} });
})
}, },
//到岗统计 //到岗统计
submit() submit() {
{ this.atworkDate.year = this.value2.getFullYear();
this.atworkDate.month = this.value2.getMonth() + 1;
this.atworkDate.year=this.value2.getFullYear(); this.value = this.value2;
this.atworkDate.month=this.value2.getMonth()+1; (this.resDate = []),
getatwork(this.atworkDate).then((response) => { getatwork(this.atworkDate).then((response) => {
if (response.data) { if (response.data) {
this.atworkList = response.data; this.atworkList = response.data;
} }
});
});
}, },
//考勤日历 //考勤日历
dealMyDate(v) { dealMyDate(v) {
console.log(v)
let len = this.resDate.length let len = this.resDate.length;
let res = "" let res = "";
for(let i=0; i<len; i++){ for (let i = 0; i < len; i++) {
if(this.resDate[i].date == v) { if (this.resDate[i].data == v) {
res = this.resDate[i].content res = this.resDate[i].content;
break break;
}
}
return res
} }
}
return res;
},
}, },
}; };
</script> </script>

View File

@ -192,33 +192,29 @@
</el-table-column> </el-table-column>
<el-table-column label="设备状态"> <el-table-column label="设备状态">
<template slot-scope="scope"> <template slot-scope="scope">
<div v-if="scope.row.equip_.type === 2"> <div v-if="scope.row.type===2">
<el-tag <el-tag v-if="scope.row.state===40" type="danger">
v-if="scope.row.equip_.state === 40" 禁用
type="danger" </el-tag>
> <el-tag v-else type="success">
禁用 合格
</el-tag> </el-tag>
<el-tag v-else type="success"> 合格 </el-tag> </div>
</div> <div v-else>
<div v-else> <el-tag v-if="scope.row.state===10" type="success">
<el-tag v-if="scope.row.state === 10" type="success"> {{ state_[scope.row.state] }}
{{ state_[scope.row.state] }} </el-tag>
</el-tag> <el-tag v-else-if="scope.row.state===20">
<el-tag v-else-if="scope.row.state === 20"> {{ state_[scope.row.state] }}
{{ state_[scope.row.state] }} </el-tag>
</el-tag> <el-tag v-else-if="scope.row.state===30" type="warning">
<el-tag v-else-if="scope.row.state === 30" type="warning"> {{ state_[scope.row.state] }}
{{ state_[scope.row.state] }} </el-tag>
</el-tag> <el-tag v-else type="danger">
<el-tag v-else type="danger"> {{ state_[scope.row.state] }}
{{ state_[scope.row.state] }} </el-tag>
</el-tag> </div>
</div> </template>
</template>
<template slot-scope="scope">
{{ state_[scope.row.state] }}</template
>
</el-table-column> </el-table-column>
<el-table-column label="设备编号"> <el-table-column label="设备编号">
<template slot-scope="scope"> <template slot-scope="scope">

View File

@ -1,16 +1,38 @@
from django_filters import rest_framework as filters from django_filters import rest_framework as filters
from apps.hrm.models import ClockRecord, Employee from apps.hrm.models import ClockRecord, Employee, NotWorkRemark
from utils.mixins import DynamicFieldsFilterMixin from utils.mixins import DynamicFieldsFilterMixin
class ClockRecordFilterSet(filters.FilterSet): class ClockRecordFilterSet(filters.FilterSet):
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte') create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte') create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte')
year = filters.NumberFilter(method='filter_year')
month = filters.NumberFilter(method='filter_month')
class Meta: class Meta:
model = ClockRecord model = ClockRecord
fields = ['create_by', 'create_time_start', 'create_time_end'] fields = ['create_by', 'create_time_start', 'create_time_end', 'year', 'month']
def filter_year(self, queryset, name, value):
return queryset.filter(create_time_date__year=value)
def filter_month(self, queryset, name, value):
return queryset.filter(create_time_date__month=value)
class EmployeeFilterSet(DynamicFieldsFilterMixin, filters.FilterSet): class EmployeeFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
class Meta: class Meta:
model = Employee model = Employee
fields = ['job_state'] fields = ['job_state']
class NotWorkRemarkFilterSet(filters.FilterSet):
year = filters.NumberFilter(method='filter_year')
month = filters.NumberFilter(method='filter_month')
class Meta:
model = NotWorkRemark
fields = ['year', 'month', 'user']
def filter_year(self, queryset, name, value):
return queryset.filter(not_work_date__year=value)
def filter_month(self, queryset, name, value):
return queryset.filter(not_work_date__month=value)

View File

@ -0,0 +1,32 @@
# Generated by Django 3.2.9 on 2022-02-22 03:12
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('hrm', '0007_auto_20220218_0843'),
]
operations = [
migrations.RemoveField(
model_name='notworkremark',
name='day',
),
migrations.RemoveField(
model_name='notworkremark',
name='month',
),
migrations.RemoveField(
model_name='notworkremark',
name='year',
),
migrations.AddField(
model_name='notworkremark',
name='not_work_date',
field=models.DateField(default=django.utils.timezone.now, verbose_name='未打卡日期'),
preserve_default=False,
),
]

View File

@ -44,9 +44,7 @@ class NotWorkRemark(CommonAModel):
""" """
离岗说明 离岗说明
""" """
year = models.PositiveSmallIntegerField('', default=2022) not_work_date = models.DateField('未打卡日期')
month = models.PositiveSmallIntegerField('', default=2)
day = models.PositiveSmallIntegerField('', default=1)
user = models.ForeignKey(User, verbose_name='用户', on_delete=models.CASCADE) user = models.ForeignKey(User, verbose_name='用户', on_delete=models.CASCADE)
remark = models.CharField('未打卡说明', null=True, blank=True, max_length=200) remark = models.CharField('未打卡说明', null=True, blank=True, max_length=200)
@ -58,4 +56,6 @@ class ClockRecord(CommonADModel):
type_choice = ( type_choice = (
(ClOCK_WORK1, '上班打卡'), (ClOCK_WORK1, '上班打卡'),
) )
type = models.PositiveSmallIntegerField('打卡类型', choices=type_choice, default=ClOCK_WORK1) type = models.PositiveSmallIntegerField('打卡类型', choices=type_choice, default=ClOCK_WORK1)

View File

@ -3,7 +3,7 @@ from rest_framework.serializers import ModelSerializer
from rest_framework import serializers from rest_framework import serializers
from utils.mixins import DynamicFieldsSerializerMixin from utils.mixins import DynamicFieldsSerializerMixin
from .models import ClockRecord, Employee from .models import ClockRecord, Employee, NotWorkRemark
from apps.system.serializers import OrganizationSimpleSerializer, UserListSerializer, UserSimpleSerializer from apps.system.serializers import OrganizationSimpleSerializer, UserListSerializer, UserSimpleSerializer
from django.db.models.query import Prefetch from django.db.models.query import Prefetch
@ -30,3 +30,8 @@ class ClockRecordListSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ClockRecord model = ClockRecord
fields = '__all__' fields = '__all__'
class NotWorkRemarkListSerializer(serializers.ModelSerializer):
class Meta:
model = NotWorkRemark
fields = '__all__'

View File

@ -10,7 +10,7 @@ def update_all_employee_not_atwork():
""" """
将所有员工设为非在岗状态 将所有员工设为非在岗状态
""" """
Employee.objects.all().update(is_atwork=False, last_check_time = None) Employee.objects.all().update(is_atwork=False, last_check_time = None, not_work_remark=None)
@shared_task @shared_task
def update_all_user_facedata_cache(): def update_all_user_facedata_cache():

View File

@ -1,12 +1,13 @@
from django.db.models import base from django.db.models import base
from rest_framework import urlpatterns from rest_framework import urlpatterns
from apps.hrm.views import ClockRecordViewSet, EmployeeViewSet, FaceLogin from apps.hrm.views import ClockRecordViewSet, EmployeeViewSet, FaceLogin, NotWorkRemarkViewSet
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
router.register('employee', EmployeeViewSet, basename='employee') router.register('employee', EmployeeViewSet, basename='employee')
router.register('clock_record', ClockRecordViewSet, basename='clock_record') router.register('clock_record', ClockRecordViewSet, basename='clock_record')
router.register('not_work_remark', NotWorkRemarkViewSet, basename='not_work_reamrk')
urlpatterns = [ urlpatterns = [
path('facelogin/', FaceLogin.as_view()), path('facelogin/', FaceLogin.as_view()),
path('', include(router.urls)), path('', include(router.urls)),

View File

@ -5,12 +5,12 @@ from django.utils import timezone
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin
from apps.hrm.filters import ClockRecordFilterSet, EmployeeFilterSet from apps.hrm.filters import ClockRecordFilterSet, EmployeeFilterSet, NotWorkRemarkFilterSet
from apps.hrm.services import HRMService from apps.hrm.services import HRMService
from apps.hrm.tasks import update_all_user_facedata_cache from apps.hrm.tasks import update_all_user_facedata_cache
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from apps.hrm.models import ClockRecord, Employee, NotWorkRemark from apps.hrm.models import ClockRecord, Employee, NotWorkRemark
from apps.hrm.serializers import ClockRecordListSerializer, EmployeeNotWorkRemarkSerializer, EmployeeSerializer, FaceClockCreateSerializer, FaceLoginSerializer from apps.hrm.serializers import ClockRecordListSerializer, EmployeeNotWorkRemarkSerializer, EmployeeSerializer, FaceClockCreateSerializer, FaceLoginSerializer, NotWorkRemarkListSerializer
@ -67,16 +67,12 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix
remark = request.data.get('not_work_remark', '') remark = request.data.get('not_work_remark', '')
obj.not_work_remark = remark obj.not_work_remark = remark
obj.save() obj.save()
now_local = timezone.localtime() now = timezone.now()
instance, created = NotWorkRemark.objects.get_or_create( instance, created = NotWorkRemark.objects.get_or_create(
year = now_local.year, not_work_date = now.date(),
month = now_local.month,
day = now_local.day,
user = obj.user, user = obj.user,
defaults={ defaults={
"year":now_local.year, "not_work_date":now.date(),
"month":now_local.month,
"day":now_local.day,
"user":obj.user, "user":obj.user,
"remark":remark, "remark":remark,
"create_by":request.user, "create_by":request.user,
@ -134,7 +130,15 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
return Response('非打卡时间范围', status=status.HTTP_400_BAD_REQUEST) return Response('非打卡时间范围', status=status.HTTP_400_BAD_REQUEST)
class NotWorkRemarkViewSet(ListModelMixin, GenericViewSet):
"""
离岗说明
"""
perms_map = {'get':'*'}
queryset = NotWorkRemark.objects.select_related('user').all()
serializer_class = NotWorkRemarkListSerializer
filterset_class = NotWorkRemarkFilterSet
ordering = ['-pk']
import base64 import base64

View File

@ -28,6 +28,5 @@ class IProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte') update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte')
class Meta: class Meta:
model = IProduct model = IProduct
fields = ['material', 'warehouse', 'batch', 'order', 'material__type', fields = ['material', 'warehouse', 'batch', 'order', 'material__type', 'update_time_start', 'update_time_end',
'is_saled', 'update_time_start', 'update_time_end',
'to_order', 'need_to_order'] 'to_order', 'need_to_order']

View File

@ -0,0 +1,29 @@
# Generated by Django 3.2.9 on 2022-02-22 01:41
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('sam', '0013_auto_20220222_0941'),
('inm', '0031_fifoitem_pu_order_item'),
]
operations = [
migrations.RemoveField(
model_name='iproduct',
name='is_saled',
),
migrations.AddField(
model_name='fifo',
name='sale',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sam.sale', verbose_name='关联销售记录'),
),
migrations.AddField(
model_name='iproduct',
name='state',
field=models.IntegerField(choices=[(10, '可销售'), (20, '已锁定'), (30, '已售出')], default=10, verbose_name='状态'),
),
]

View File

@ -3,6 +3,7 @@ from django.db.models.base import Model
import django.utils.timezone as timezone import django.utils.timezone as timezone
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from apps.pum.models import PuOrder, PuOrderItem, Vendor from apps.pum.models import PuOrder, PuOrderItem, Vendor
from apps.sam.models import Sale
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
@ -86,6 +87,8 @@ class FIFO(CommonADModel):
on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE, null=True, blank=True)
pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单', pu_order = models.ForeignKey(PuOrder, verbose_name='关联采购订单',
null=True, blank=True, on_delete=models.CASCADE) null=True, blank=True, on_delete=models.CASCADE)
sale = models.ForeignKey(Sale, verbose_name='关联销售记录',
null=True, blank=True, on_delete=models.CASCADE)
class FIFOItem(BaseModel): class FIFOItem(BaseModel):
@ -113,6 +116,14 @@ class IProduct(BaseModel):
""" """
具体产品条目 具体产品条目
""" """
SALE_OK = 10
SALE_LOCK = 20
SALED = 30
state_choices = (
(SALE_OK, '可销售'),
(SALE_LOCK, '已锁定'),
(SALED, '已售出')
)
number = models.CharField('物品编号', unique=True, max_length=50) number = models.CharField('物品编号', unique=True, max_length=50)
material = models.ForeignKey( material = models.ForeignKey(
Material, verbose_name='物料类型', on_delete=models.CASCADE) Material, verbose_name='物料类型', on_delete=models.CASCADE)
@ -121,7 +132,7 @@ class IProduct(BaseModel):
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, wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False,
null=True, blank=True, related_name='iproduct_wproduct') null=True, blank=True, related_name='iproduct_wproduct')
is_saled = models.BooleanField('是否售出', default=False) state = models.IntegerField('状态', default=SALE_OK, choices=state_choices)
class FIFOItemProduct(BaseModel): class FIFOItemProduct(BaseModel):
@ -139,4 +150,4 @@ class FIFOItemProduct(BaseModel):
Material, verbose_name='物料类型', on_delete=models.CASCADE) Material, verbose_name='物料类型', on_delete=models.CASCADE)
iproduct = models.ForeignKey( iproduct = models.ForeignKey(
IProduct, verbose_name='关联库存产品', IProduct, verbose_name='关联库存产品',
null=True, blank=True, on_delete=models.SET_NULL) null=True, blank=True, on_delete=models.SET_NULL)

View File

@ -0,0 +1,17 @@
# Generated by Django 3.2.9 on 2022-02-21 06:00
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('mtm', '0047_packitem'),
]
operations = [
migrations.RemoveField(
model_name='step',
name='need_test',
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.9 on 2022-02-22 01:44
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0048_remove_step_need_test'),
]
operations = [
migrations.AddField(
model_name='packitem',
name='product',
field=models.ForeignKey(default=2, on_delete=django.db.models.deletion.CASCADE, related_name='pack_product', to='mtm.material', verbose_name='装箱产品'),
preserve_default=False,
),
migrations.AlterField(
model_name='packitem',
name='material',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='pack_material', to='mtm.material', verbose_name='装箱配件'),
),
]

View File

@ -23,7 +23,7 @@ class Material(CommonAModel):
(MA_TYPE_GOOD, '成品'), (MA_TYPE_GOOD, '成品'),
(MA_TYPE_HALFGOOD, '半成品'), (MA_TYPE_HALFGOOD, '半成品'),
(MA_TYPE_MAINSO, '主要原料'), (MA_TYPE_MAINSO, '主要原料'),
(MA_TYPE_HELPSO, '辅助材料') , (MA_TYPE_HELPSO, '辅助材料'),
(MA_TYPE_TOOL, '加工工具'), (MA_TYPE_TOOL, '加工工具'),
(MA_TYPE_HELPTOOL, '辅助工装') (MA_TYPE_HELPTOOL, '辅助工装')
) )
@ -54,8 +54,10 @@ class PackItem(CommonAModel):
""" """
装箱项目 装箱项目
""" """
material = models.ForeignKey(Material, verbose_name='关联成品', product = models.ForeignKey(Material, verbose_name='装箱产品',
on_delete=models.CASCADE) on_delete=models.CASCADE, related_name='pack_product')
material = models.ForeignKey(Material, verbose_name='装箱配件',
on_delete=models.CASCADE, null=True, blank=True, related_name='pack_material')
name = models.CharField('名称', max_length=100) name = models.CharField('名称', max_length=100)
specification = models.CharField('型号', max_length=100, null=True, blank=True) specification = models.CharField('型号', max_length=100, null=True, blank=True)
unit = models.CharField('单位', max_length=10) unit = models.CharField('单位', max_length=10)
@ -105,7 +107,6 @@ class Step(CommonAModel):
name = models.CharField('工序步骤名称', max_length=100) name = models.CharField('工序步骤名称', max_length=100)
number = models.CharField('步骤编号', max_length=100, null=True, blank=True) number = models.CharField('步骤编号', max_length=100, null=True, blank=True)
instruction_content = models.TextField('相应操作指导', null=True, blank=True) instruction_content = models.TextField('相应操作指导', null=True, blank=True)
need_test = models.BooleanField('是否需要检验', default=False)
sort = models.IntegerField('排序号', default=1) sort = models.IntegerField('排序号', default=1)
equipments = models.ManyToManyField(Equipment, verbose_name='使用设备', related_name='step_equips') equipments = models.ManyToManyField(Equipment, verbose_name='使用设备', related_name='step_equips')

View File

@ -24,6 +24,8 @@ class MaterialDetailSerializer(serializers.ModelSerializer):
objs = Process.objects.filter(subproduction_process__product=obj, subproduction_process__is_deleted=False, is_deleted=False).distinct().order_by('number') objs = Process.objects.filter(subproduction_process__product=obj, subproduction_process__is_deleted=False, is_deleted=False).distinct().order_by('number')
return ProcessSimpleSerializer(instance=objs, many=True).data return ProcessSimpleSerializer(instance=objs, many=True).data
class PackItemSerializer(serializers.ModelSerializer): class PackItemSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = PackItem model = PackItem
@ -32,7 +34,7 @@ class PackItemSerializer(serializers.ModelSerializer):
class PackItemCreateSerializer(serializers.ModelSerializer): class PackItemCreateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = PackItem model = PackItem
fields = ['material', 'name', 'specification', 'unit', 'count', 'sort'] fields = ['product', 'material', 'name', 'specification', 'unit', 'count', 'sort']
class PackItemUpdateSerializer(serializers.ModelSerializer): class PackItemUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@ -44,6 +46,12 @@ class MaterialSimpleSerializer(serializers.ModelSerializer):
model = Material model = Material
fields = ['id', 'name', 'number', 'unit','specification', 'type'] fields = ['id', 'name', 'number', 'unit','specification', 'type']
class PackItemDetailSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
class Meta:
model = PackItem
fields = '__all__'
class ProcessSerializer(serializers.ModelSerializer): class ProcessSerializer(serializers.ModelSerializer):
instruction_ = FileSimpleSerializer(source='instruction', read_only=True) instruction_ = FileSimpleSerializer(source='instruction', read_only=True)
workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True) workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True)

View File

@ -40,7 +40,7 @@ class PackItemViewSet(CreateUpdateModelAMixin, ModelViewSet):
queryset = PackItem.objects.all() queryset = PackItem.objects.all()
serializer_class = PackItemSerializer serializer_class = PackItemSerializer
search_fields = ['name', 'number'] search_fields = ['name', 'number']
filterset_fields = ['material'] filterset_fields = ['material', 'product']
ordering = ['sort'] ordering = ['sort']
def get_serializer_class(self): def get_serializer_class(self):

View File

@ -0,0 +1,35 @@
# Generated by Django 3.2.9 on 2022-02-21 02:27
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0025_alter_testrecord_type'),
('pm', '0026_auto_20220218_1636'),
]
operations = [
migrations.RemoveField(
model_name='subproductionplan',
name='form',
),
migrations.RemoveField(
model_name='subproductionplan',
name='is_testok',
),
migrations.RemoveField(
model_name='subproductionplan',
name='tester',
),
migrations.AddField(
model_name='subproductionplan',
name='first_test',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord'),
),
migrations.DeleteModel(
name='FirstItem',
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.9 on 2022-02-22 01:58
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0026_alter_testrecord_is_testok'),
('pm', '0027_auto_20220221_1027'),
]
operations = [
migrations.AlterField(
model_name='subproductionplan',
name='first_test',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='qm.testrecord'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.9 on 2022-02-22 02:45
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0026_alter_testrecord_is_testok'),
('pm', '0028_alter_subproductionplan_first_test'),
]
operations = [
migrations.AlterField(
model_name='subproductionplan',
name='first_test',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='qm.testrecord', verbose_name='首件检验'),
),
]

View File

@ -1,4 +1,5 @@
from apps.qm.models import TestRecord
from apps.system.models import CommonAModel, Organization, User from apps.system.models import CommonAModel, Organization, User
from django.db import models from django.db import models
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
@ -69,6 +70,7 @@ class SubProductionPlan(CommonAModel):
(SUBPLAN_STATE_WORKING, '生产中'), (SUBPLAN_STATE_WORKING, '生产中'),
(SUBPLAN_STATE_DONE, '已完成'), (SUBPLAN_STATE_DONE, '已完成'),
) )
number = models.CharField('子计划编号', max_length=50, unique=True, null=True, blank=True) number = models.CharField('子计划编号', max_length=50, unique=True, null=True, blank=True)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE, related_name='subplan_plan') production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE, related_name='subplan_plan')
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod') subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod')
@ -90,12 +92,9 @@ class SubProductionPlan(CommonAModel):
start_date_real = models.DateField('实际开工日期', null=True, blank=True) start_date_real = models.DateField('实际开工日期', null=True, blank=True)
end_date_real = models.DateField('实际完工日期', null=True, blank=True) end_date_real = models.DateField('实际完工日期', null=True, blank=True)
is_picked = models.BooleanField('是否已领料', default=False) is_picked = models.BooleanField('是否已领料', default=False)
# wproducts = models.JSONField('半成品表', default=list, blank=True) first_test = models.ForeignKey('qm.testrecord', on_delete=models.SET_NULL,
is_testok = models.BooleanField('首件是否合格', null=True, blank=True) null=True, blank=True, verbose_name='首件检验')
form = models.ForeignKey(RecordForm, verbose_name='首件检查表', on_delete=models.CASCADE, null=True, blank=True)
tester = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="首件检查员", null=True, blank=True, related_name='first_tester')
leader_1 = models.ForeignKey(User, on_delete=models.CASCADE, leader_1 = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="工序负责人", null=True, blank=True, related_name='first_leader_1') verbose_name="工序负责人", null=True, blank=True, related_name='first_leader_1')
leader_2 = models.ForeignKey(User, on_delete=models.CASCADE, leader_2 = models.ForeignKey(User, on_delete=models.CASCADE,
@ -108,16 +107,10 @@ class SubProductionPlan(CommonAModel):
class Meta: class Meta:
verbose_name = '子生产计划' verbose_name = '子生产计划'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name
class FirstItem(BaseModel): # @property
""" # def first_test(self):
首件确认表记录条目 # return self.test_subplan.filter(type=TestRecord.TEST_FIRST, is_deleted=False).first()
"""
form_field = models.ForeignKey(RecordFormField, verbose_name='关联自定义表格字段', on_delete=models.CASCADE)
field_value = models.JSONField('录入值', null=True, blank=True)
is_hidden = models.BooleanField('是否隐藏', default=False)
is_testok = models.BooleanField('是否合格', null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE, related_name='item_test_record')
class SubProductionProgress(BaseModel): class SubProductionProgress(BaseModel):
""" """

View File

@ -1,6 +1,8 @@
from apps.mtm.models import RecordForm from apps.mtm.models import RecordForm
from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
from rest_framework import serializers from rest_framework import serializers
from apps.qm.models import TestRecord
from apps.qm.serializers import TestRecordShortSerializer
from apps.sam.serializers import OrderSerializer, OrderSimpleSerializer from apps.sam.serializers import OrderSerializer, OrderSimpleSerializer
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, RecordFormSimpleSerializer, SubProductionSimpleSerializer from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, RecordFormSimpleSerializer, SubProductionSimpleSerializer
from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer
@ -33,12 +35,17 @@ class ResourceConvertListSerializer(serializers.ListSerializer):
class ResourceCalListSerializer(serializers.ListSerializer): class ResourceCalListSerializer(serializers.ListSerializer):
child = ResourceCalSerializer() child = ResourceCalSerializer()
class SubProductionPlanListSerializer(serializers.ModelSerializer): class SubProductionPlanListSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializer):
workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True) workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True)
process_ = ProcessSimpleSerializer(source='process', read_only=True) process_ = ProcessSimpleSerializer(source='process', read_only=True)
subproduction_ = SubProductionSimpleSerializer(source='subproduction', read_only=True) subproduction_ = SubProductionSimpleSerializer(source='subproduction', read_only=True)
product_ = MaterialSimpleSerializer(source='product', read_only=True) product_ = MaterialSimpleSerializer(source='product', read_only=True)
plan_product_ = serializers.SerializerMethodField() plan_product_ = serializers.SerializerMethodField()
leader_1_ = UserSimpleSerializer(source='leader_1', read_only=True)
leader_2_ = UserSimpleSerializer(source='leader_2', read_only=True)
leader_3_ = UserSimpleSerializer(source='leader_3', read_only=True)
first_test_ = TestRecordShortSerializer(source='first_test', read_only=True)
# first_test_ = serializers.SerializerMethodField()
class Meta: class Meta:
model=SubProductionPlan model=SubProductionPlan
fields = '__all__' fields = '__all__'
@ -46,7 +53,10 @@ class SubProductionPlanListSerializer(serializers.ModelSerializer):
def get_plan_product_(self, obj): def get_plan_product_(self, obj):
return MaterialSimpleSerializer(instance=obj.production_plan.product).data return MaterialSimpleSerializer(instance=obj.production_plan.product).data
# def get_first_test_(self, obj):
# if obj.first_test:
# return TestRecordShortSerializer(instance=obj.first_test).data
# return None
class SubProductionPlanUpdateSerializer(serializers.ModelSerializer): class SubProductionPlanUpdateSerializer(serializers.ModelSerializer):
@ -81,20 +91,6 @@ class SubProductionProgressSerializer(serializers.ModelSerializer):
class FirstTestInitSerializer(serializers.Serializer): class FirstTestInitSerializer(serializers.Serializer):
form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True) form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True)
class FirstTestDetailSerializer(serializers.ModelSerializer):
tester_ = UserSimpleSerializer(source='tester', read_only=True)
leader_1_ = UserSimpleSerializer(source='leader_1', read_only=True)
leader_2_ = UserSimpleSerializer(source='leader_2', read_only=True)
leader_3_ = UserSimpleSerializer(source='leader_3', read_only=True)
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
# record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True)
record_data = serializers.SerializerMethodField()
class Meta: class FirstTestAuditSerializer(serializers.Serializer):
model = SubProductionPlan leader = serializers.CharField()
fields = ['id', 'form', 'form_', 'is_testok', 'remark', 'first_sign_time'
'tester', 'tester_', 'leader_1', 'leader_1_', 'leader_2',
'leader_2_', 'leader_3', 'leader_3_']
def get_record_data(self, obj):
return None

View File

@ -5,23 +5,29 @@ from rest_framework import serializers
from rest_framework.views import APIView from rest_framework.views import APIView
from apps.em.models import Equipment from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer from apps.em.serializers import EquipmentSimpleSerializer
from apps.hrm.services import HRMService
from apps.inm.models import MaterialBatch from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Material, Step, SubProduction, SubprodctionMaterial from apps.mtm.models import Material, RecordFormField, Step, SubProduction, SubprodctionMaterial
from apps.pm.filters import PlanFilterSet, SubproductionProgressFilterSet from apps.pm.filters import PlanFilterSet, SubproductionProgressFilterSet
from apps.qm.models import TestRecord, TestRecordItem
from apps.qm.serializers import TestRecordDetailBaseSerializer
from apps.system.mixins import CreateUpdateModelAMixin from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import FirstTestInitSerializer, GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, ResourceConvertListSerializer, ResourceConvertSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.pm.serializers import FirstTestAuditSerializer, FirstTestInitSerializer, GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, ResourceConvertListSerializer, ResourceConvertSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from django.shortcuts import render from django.shortcuts import render
from apps.sam.models import Order from apps.sam.models import Order
from rest_framework.exceptions import APIException, ParseError from rest_framework.exceptions import APIException, ParseError, ValidationError
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.decorators import action from rest_framework.decorators import action
from django.db.models import F from django.db.models import F
from apps.system.serializers import UserSimpleSerializer
from utils.tools import ranstr from utils.tools import ranstr
from django.db import transaction from django.db import transaction
from rest_framework import status
from django.utils import timezone
# Create your views here. # Create your views here.
def updateOrderPlanedCount(order): def updateOrderPlanedCount(order):
@ -145,7 +151,9 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
子生产计划-列表/修改 子生产计划-列表/修改
""" """
perms_map = {'get': '*', 'put':'subplan_update'} perms_map = {'get': '*', 'put':'subplan_update'}
queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'product', 'production_plan__product') queryset = SubProductionPlan.objects.select_related('process',
'workshop', 'subproduction', 'product',
'production_plan__product', 'leader_1', 'leader_2', 'leader_3', 'first_test')
search_fields = [] search_fields = []
serializer_class = SubProductionPlanListSerializer serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state', 'product', 'workshop'] filterset_fields = ['production_plan', 'process', 'state', 'product', 'workshop']
@ -229,20 +237,68 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
have = MaterialBatchSerializer(instance=objs, many=True).data have = MaterialBatchSerializer(instance=objs, many=True).data
return Response({'need':need, 'have':have}) return Response({'need':need, 'have':have})
@action(methods=['put'], detail=True, perms_map={'post':'first_test'}, serializer_class=FirstTestInitSerializer) @action(methods=['post'], detail=True, perms_map={'post':'first_test'}, serializer_class=FirstTestInitSerializer)
@transaction.atomic @transaction.atomic
def first_test_init(self, request, pk=None): def first_test_init(self, request, pk=None):
""" """
获取首件检查表 首件检查表初始化
""" """
obj = self.get_object() obj = self.get_object()
if obj.is_testok is None: first_test = obj.first_test
if first_test:
return Response(TestRecordDetailBaseSerializer(instance=first_test).data)
else:
rdata = request.data rdata = request.data
serializer = self.get_serializer(data=rdata) serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
form = serializer.validated_data.get('form') form = serializer.validated_data.get('form')
savedict = dict(
raise APIException('已经过首件确认') create_by=request.user,
subproduction_plan=obj,
type = TestRecord.TEST_FIRST,
form=form)
tr = TestRecord.objects.create(**savedict)
for i in RecordFormField.objects.filter(form=form, is_deleted=False):
tri = TestRecordItem()
tri.test_record = tr
tri.form_field = i
tri.is_hidden = i.is_hidden
tri.create_by = request.user
tri.save()
obj.first_test = tr
obj.save()
return Response(TestRecordDetailBaseSerializer(instance=tr).data)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=FirstTestAuditSerializer)
@transaction.atomic
def first_audit(self, request, pk=None):
"""
首件审核
"""
obj = self.get_object()
if obj.leader_1 and obj.leader_2 and obj.leader_3:
raise ValidationError('首件确认已完成')
if obj.first_test is None:
raise ValidationError('未进行首件检查')
if not obj.first_test.is_submited:
raise ValidationError('首件检查未提交')
if not obj.first_test.is_testok:
raise ValidationError('首件检查不合格')
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
le = vdata.get('leader')
if le not in ['leader_1', 'leader_2', 'leader_3']:
return Response('审核人有误', status=status.HTTP_400_BAD_REQUEST)
if vdata.get('leader') == 'leader_1':
obj.leader_1 = request.user
elif vdata.get('leader') == 'leader_2':
obj.leader_2 = request.user
else:
obj.leader_3 = request.user
obj.first_sign_time = timezone.now()
obj.save()
return Response(UserSimpleSerializer(instance=request.user).data)

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-02-21 02:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0024_rename_is_midtesing_testrecord_is_midtesting'),
]
operations = [
migrations.AlterField(
model_name='testrecord',
name='type',
field=models.PositiveSmallIntegerField(choices=[(20, '工序检验'), (30, '工序复检'), (36, '夹层检验'), (40, '成品检验'), (10, '首件检验')], default=20),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-02-21 07:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0025_alter_testrecord_type'),
]
operations = [
migrations.AlterField(
model_name='testrecord',
name='is_testok',
field=models.BooleanField(blank=True, null=True, verbose_name='是否合格'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.9 on 2022-02-22 02:45
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pm', '0029_alter_subproductionplan_first_test'),
('qm', '0026_alter_testrecord_is_testok'),
]
operations = [
migrations.AlterField(
model_name='testrecord',
name='subproduction_plan',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='test_subplan', to='pm.subproductionplan', verbose_name='关联的生产子计划'),
),
]

View File

@ -47,6 +47,7 @@ class TestRecord(CommonADModel):
""" """
检验记录 检验记录
""" """
TEST_FIRST = 10
TEST_PROCESS = 20 TEST_PROCESS = 20
TEST_PROCESS_RE = 30 TEST_PROCESS_RE = 30
TEST_COMB = 36 TEST_COMB = 36
@ -55,16 +56,17 @@ class TestRecord(CommonADModel):
(TEST_PROCESS, '工序检验'), (TEST_PROCESS, '工序检验'),
(TEST_PROCESS_RE, '工序复检'), (TEST_PROCESS_RE, '工序复检'),
(TEST_COMB, '夹层检验'), (TEST_COMB, '夹层检验'),
(TEST_FINAL, '成品检验') (TEST_FINAL, '成品检验'),
(TEST_FIRST, '首件检验')
) )
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
type = models.PositiveSmallIntegerField(choices=type_choice, default=TEST_PROCESS) type = models.PositiveSmallIntegerField(choices=type_choice, default=TEST_PROCESS)
is_testok = models.BooleanField('是否合格', default=True) is_testok = models.BooleanField('是否合格', null=True, blank=True)
number = models.CharField('产品编号', null=True, blank=True, max_length=50) number = models.CharField('产品编号', null=True, blank=True, max_length=50)
wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True, related_name='test_wproduct') wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True, related_name='test_wproduct')
material = models.ForeignKey('mtm.material', verbose_name='关联的物料状态', on_delete=models.CASCADE, null=True, blank=True) material = models.ForeignKey('mtm.material', 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) 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, related_name='test_subplan')
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)
origin_test = models.ForeignKey('self', verbose_name='原检验记录', on_delete=models.CASCADE, null=True, blank=True) origin_test = models.ForeignKey('self', verbose_name='原检验记录', on_delete=models.CASCADE, null=True, blank=True)
is_submited = models.BooleanField('是否提交', default=False) is_submited = models.BooleanField('是否提交', default=False)

View File

@ -63,7 +63,11 @@ class TestRecordItemSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = TestRecordItem model = TestRecordItem
fields = '__all__' fields = '__all__'
class TestRecordShortSerializer(serializers.ModelSerializer):
class Meta:
model = TestRecord
fields = ['id', 'form', 'is_testok', 'is_submited']
class TestRecordCreateSerializer(serializers.ModelSerializer): class TestRecordCreateSerializer(serializers.ModelSerializer):
record_data = TestRecordItemCreateSerializer(many=True) record_data = TestRecordItemCreateSerializer(many=True)
class Meta: class Meta:

View File

@ -93,7 +93,8 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De
with transaction.atomic(): with transaction.atomic():
obj.is_submited=True obj.is_submited=True
obj.save() obj.save()
WpmService.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算 if obj.wproduct:
WpmService.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算
return Response() return Response()
# def create(self, request, *args, **kwargs): # def create(self, request, *args, **kwargs):

View File

@ -0,0 +1,53 @@
# Generated by Django 3.2.9 on 2022-02-22 01:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sam', '0012_alter_order_delivery_date'),
]
operations = [
migrations.AddField(
model_name='sale',
name='count_real',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='实际发货数量'),
),
migrations.AddField(
model_name='sale',
name='edelivery_date',
field=models.DateField(blank=True, null=True, verbose_name='预计发货日期'),
),
migrations.AddField(
model_name='sale',
name='receiver',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='收货人'),
),
migrations.AddField(
model_name='sale',
name='receiver_address',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='收获地址'),
),
migrations.AddField(
model_name='sale',
name='receiver_phone',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='收货人联系电话'),
),
migrations.AddField(
model_name='sale',
name='remark',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='备注'),
),
migrations.AddField(
model_name='sale',
name='trans_mode',
field=models.IntegerField(blank=True, choices=[(10, '铁路快运'), (20, '铁路慢件'), (30, '铁路整车'), (40, '汽车运输'), (50, '空运')], null=True, verbose_name='运输方式'),
),
migrations.AlterField(
model_name='sale',
name='count',
field=models.PositiveIntegerField(default=0, verbose_name='预计发货数量'),
),
]

View File

@ -0,0 +1,36 @@
# Generated by Django 3.2.9 on 2022-02-22 07:30
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('mtm', '0049_auto_20220222_0944'),
('sam', '0013_auto_20220222_0941'),
]
operations = [
migrations.AddField(
model_name='saleproduct',
name='packnum',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='装箱单号'),
),
migrations.CreateModel(
name='SalePack',
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='删除标记')),
('count', models.PositiveSmallIntegerField(verbose_name='打包数量')),
('packitem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.packitem', verbose_name='打包项目')),
('sale_product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sam.saleproduct', verbose_name='关联销售产品')),
],
options={
'abstract': False,
},
),
]

View File

@ -7,7 +7,7 @@ from django.db.models.query import QuerySet
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
from apps.mtm.models import Material from apps.mtm.models import Material, PackItem
@ -69,12 +69,30 @@ class Sale(CommonADModel):
""" """
销售记录 销售记录
""" """
TRANS_RAIL_FAST = 10
TRANS_RAIL_SLOW = 20
TRANS_RAIL_WHOLE = 30
TRANS_LORRY = 40
TRANS_AIR = 50
trans_choices=(
(TRANS_RAIL_FAST, '铁路快运'),
(TRANS_RAIL_SLOW, '铁路慢件'),
(TRANS_RAIL_WHOLE, '铁路整车'),
(TRANS_LORRY, '汽车运输'),
(TRANS_AIR, '空运'),
)
customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE) customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE)
order = models.ForeignKey(Order, verbose_name='关联订单', on_delete=models.CASCADE, null=True, blank=True) order = models.ForeignKey(Order, verbose_name='关联订单', on_delete=models.CASCADE, null=True, blank=True)
product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE) product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
count = models.PositiveIntegerField('交货数量', default=0) count = models.PositiveIntegerField('预计发货数量', default=0)
count_real = models.PositiveIntegerField('实际发货数量', null=True, blank=True)
is_audited = models.BooleanField('是否审核', default=False) is_audited = models.BooleanField('是否审核', default=False)
edelivery_date = models.DateField('预计发货日期', null=True, blank=True)
trans_mode = models.IntegerField('运输方式', null=True, blank=True, choices=trans_choices)
receiver = models.CharField('收货人', null=True, blank=True, max_length=200)
receiver_phone = models.CharField('收货人联系电话', null=True, blank=True, max_length=20)
receiver_address = models.CharField('收获地址', null=True, blank=True, max_length=200)
remark = models.CharField('备注', null=True, blank=True, max_length=200)
class SaleProduct(BaseModel): class SaleProduct(BaseModel):
""" """
@ -84,11 +102,22 @@ class SaleProduct(BaseModel):
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')
remark = models.TextField('备注', null=True, blank=True) remark = models.TextField('备注', null=True, blank=True)
packnum = models.CharField('装箱单号', max_length=100, null=True, blank=True)
class Meta: class Meta:
unique_together = ( unique_together = (
('sale','iproduct'), # 联合唯一 ('sale','iproduct'), # 联合唯一
) )
class SalePack(BaseModel):
"""
销售打包
"""
sale_product = models.ForeignKey(SaleProduct, verbose_name='关联销售产品',
on_delete=models.CASCADE)
packitem = models.ForeignKey(PackItem, verbose_name='打包项目',
on_delete=models.CASCADE)
count = models.PositiveSmallIntegerField('打包数量')

View File

@ -2,15 +2,20 @@ from rest_framework import serializers
from rest_framework import exceptions from rest_framework import exceptions
from apps.inm.models import IProduct from apps.inm.models import IProduct
from apps.inm.serializers import IProductListSerializer from apps.inm.serializers import IProductListSerializer
from apps.mtm.serializers import MaterialSimpleSerializer from apps.mtm.models import Material, PackItem
from apps.sam.models import Sale, SaleProduct from apps.mtm.serializers import MaterialSimpleSerializer, PackItemDetailSerializer
from apps.sam.models import Sale, SalePack, SaleProduct
from apps.sam.serializers import CustomerSimpleSerializer, OrderSimpleSerializer from apps.sam.serializers import CustomerSimpleSerializer, OrderSimpleSerializer
from django.db import transaction
from rest_framework.exceptions import ValidationError
class SaleCreateSerializer(serializers.ModelSerializer): class SaleCreateSerializer(serializers.ModelSerializer):
iproducts = serializers.PrimaryKeyRelatedField(queryset= iproducts = serializers.PrimaryKeyRelatedField(queryset=
IProduct.objects.all(), many=True) IProduct.objects.all(), many=True)
class Meta: class Meta:
model = Sale model = Sale
fields = ['customer', 'order', 'product', 'iproducts'] fields = ['customer', 'order', 'product', 'iproducts',
'edelivery_date', 'trans_mode', 'receiver', 'receiver_phone'
, 'receiver_address', 'remark']
def validate(self, attrs): def validate(self, attrs):
order = attrs.get('order', None) order = attrs.get('order', None)
@ -18,9 +23,11 @@ class SaleCreateSerializer(serializers.ModelSerializer):
if order.customer: if order.customer:
attrs['customer'] = order.customer attrs['customer'] = order.customer
attrs['product'] = order.product attrs['product'] = order.product
for i in attrs['iproducts']: ips = IProduct.objects.filter(id__in=[i.id for i in attrs['iproducts']])
if i.material != attrs['product']: if ips.exclude(state=IProduct.SALE_OK).exists():
raise exceptions.APIException('产品选取错误') raise exceptions.APIException('选取了非可用的产品')
if ips.count() != ips.filter(material=attrs['product']).count():
raise exceptions.APIException('产品选取错误')
return super().validate(attrs) return super().validate(attrs)
@ -44,8 +51,43 @@ class SaleProductCreateSerializer(serializers.ModelSerializer):
fields = ['sale', 'iproduct'] fields = ['sale', 'iproduct']
def create(self, validated_data): def create(self, validated_data):
validated_data['number'] = validated_data['iproduct'].number with transaction.atomic():
instance = SaleProduct.objects.create(**validated_data) validated_data['number'] = validated_data['iproduct'].number
instance.sale.count = SaleProduct.objects.filter(sale=instance.sale).count() instance = SaleProduct.objects.create(**validated_data)
instance.sale.save() sale = instance.sale
return instance sale.count = SaleProduct.objects.filter(sale=instance.sale).count()
sale.save()
order = sale.order
if order:
if sale.count+order.delivered_count>order.count:
raise exceptions.APIException('超过订单所需数量')
return instance
class SPackItemSerializer(serializers.ModelSerializer):
name = serializers.CharField(source='packitem.name', read_only=True)
specification = serializers.CharField(source='packitem.specification', read_only=True)
unit = serializers.CharField(source='packitem.unit', read_only=True)
material_ = MaterialSimpleSerializer(source='packitem.material', read_only=True)
class Meta:
model = SalePack
fields = '__all__'
class SaleProductPackDetailSerializer(serializers.ModelSerializer):
detail = serializers.SerializerMethodField()
class Meta:
model = ['packnum', 'detail']
def get_detail(self, obj):
return SPackItemSerializer(instance=SalePack.objects.filter(sale_product=obj)
, many=True).data
class SPackItemCreateSerializer(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(queryset=PackItem.objects.all())
count = serializers.IntegerField()
class SaleProductPackSerializer(serializers.ModelSerializer):
detail = SPackItemCreateSerializer(many=True)
class Meta:
model = SaleProduct
fields = ['packnum', 'detail']

View File

@ -1,11 +1,12 @@
from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModelMixin, RetrieveModelMixin from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModelMixin, RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response from rest_framework.response import Response
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
from apps.inm.services import InmService from apps.inm.services import InmService
from apps.mtm.models import Material from apps.mtm.models import Material, PackItem
from apps.sam.models import Sale, SaleProduct from apps.sam.models import Sale, SalePack, SaleProduct
from apps.sam.serializers_sale import SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer from apps.sam.serializers_sale import SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer, SaleProductPackDetailSerializer, SaleProductPackSerializer
from rest_framework import exceptions from rest_framework import exceptions
from django.db import transaction from django.db import transaction
from rest_framework.decorators import action from rest_framework.decorators import action
@ -35,6 +36,13 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
elif self.action == 'retrieve': elif self.action == 'retrieve':
return SaleListSerializer return SaleListSerializer
return super().get_serializer_class() return super().get_serializer_class()
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.is_audited:
raise exceptions.APIException('该销售记录已审核,不可删除')
obj.delete()
IProduct.objects.filter(sale_iproduct__sale=obj).update()
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
data = request.data data = request.data
@ -49,6 +57,8 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
sale = Sale.objects.create(**vdata) sale = Sale.objects.create(**vdata)
i_l = [] i_l = []
for i in iproducts: for i in iproducts:
i.state = IProduct.SALE_LOCK
i.save()
i_d ={} i_d ={}
i_d['sale'] = sale i_d['sale'] = sale
i_d['number'] = i.number i_d['number'] = i.number
@ -66,56 +76,59 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
obj = self.get_object() obj = self.get_object()
if obj.is_audited: if obj.is_audited:
raise exceptions.APIException('已审核通过') raise exceptions.APIException('已审核通过')
if obj.order:
if obj.count + obj.order.delivered_count > obj.order.count:
raise exceptions.APIException('超过订单所需数量')
# 创建出库记录 # 创建出库记录
fifo = FIFO() fifo = FIFO()
fifo.sale = obj
fifo.type = FIFO.FIFO_TYPE_SALE_OUT fifo.type = FIFO.FIFO_TYPE_SALE_OUT
fifo.is_audited = True fifo.is_audited = False
fifo.auditor = request.user fifo.auditor = request.user
fifo.inout_date = timezone.now() fifo.inout_date = timezone.now()
fifo.create_by = request.user fifo.create_by = request.user
fifo.number = 'CK' + ranstr(7) fifo.number = 'CK' + ranstr(7)
fifo.save() fifo.save()
# 创建出库条目 # 创建出库条目
ips = IProduct.objects.filter(sale_iproduct__sale=obj) # ips = IProduct.objects.filter(sale_iproduct__sale=obj)
items = ips.values('warehouse', 'material', 'batch').annotate(total=Count('id')) # items = ips.values('warehouse', 'material', 'batch').annotate(total=Count('id'))
for i in items: # for i in items:
warehouse = WareHouse.objects.get(id=i['warehouse']) # warehouse = WareHouse.objects.get(id=i['warehouse'])
material = Material.objects.get(id=i['material']) # material = Material.objects.get(id=i['material'])
fifoitem = FIFOItem() # fifoitem = FIFOItem()
fifoitem.need_test = False # fifoitem.need_test = False
fifoitem.warehouse = warehouse # fifoitem.warehouse = warehouse
fifoitem.material = material # fifoitem.material = material
fifoitem.count = i['total'] # fifoitem.count = i['total']
fifoitem.batch = i['batch'] # fifoitem.batch = i['batch']
fifoitem.fifo = fifo # fifoitem.fifo = fifo
fifoitem.save() # fifoitem.save()
items_p = ips.filter(warehouse=warehouse, batch=i['batch']) # items_p = ips.filter(warehouse=warehouse, batch=i['batch'])
ipxs = [] # ipxs = []
for i in items_p: # for i in items_p:
# 创建出库明细半成品 # # 创建出库明细半成品
ip = {} # ip = {}
ip['fifoitem'] = fifoitem # ip['fifoitem'] = fifoitem
ip['number'] = i.number # ip['number'] = i.number
ip['material'] = i.material # ip['material'] = i.material
ip['iproduct'] = i # ip['iproduct'] = i
ipxs.append(FIFOItemProduct(**ip)) # ipxs.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ipxs) # FIFOItemProduct.objects.bulk_create(ipxs)
# 更新成品库情况
ips.update(is_saled=True)
# 更新动态产品表情况 # 更新动态产品表情况
from apps.wpm.models import WProduct # from apps.wpm.models import WProduct
WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update( # WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
act_state=WProduct.WPR_ACT_STATE_SELLED) # act_state=WProduct.WPR_ACT_STATE_SELLED)
# 更新库存 # 更新库存
InmService.update_inm(fifo) # InmService.update_inm(fifo)
# 变更审核状态 # 变更销售提货审核状态
obj.is_audited = True obj.is_audited = True
obj.save() obj.save()
# 变更订单状态 # 变更订单状态
if obj.order: # if obj.order:
order = obj.order # order = obj.order
order.delivered_count = order.delivered_count + obj.count # order.delivered_count = order.delivered_count + obj.count
order.save() # order.save()
return Response() return Response()
@ -136,13 +149,41 @@ class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, Ge
if self.action == 'create': if self.action == 'create':
return SaleProductCreateSerializer return SaleProductCreateSerializer
return super().get_serializer_class() return super().get_serializer_class()
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
obj = self.get_object() obj = self.get_object()
sale = obj.sale sale = obj.sale
if sale.is_audited: if sale.is_audited:
raise exceptions.APIException('该销售记录已审核,不可删除产品') raise exceptions.APIException('该销售记录已审核,不可删除产品')
obj.delete()
sale.count = SaleProduct.objects.filter(sale=obj.sale).count() sale.count = SaleProduct.objects.filter(sale=obj.sale).count()
sale.save() sale.save()
obj.delete() return Response()
return Response()
@action(methods=['get', 'post'], detail=True, perms_map={'post':'sale_pack'}, serializer_class=serializers.Serializer)
@transaction.atomic
def pack(self, request, pk=None):
"""
打包装箱
"""
obj = self.get_object()
if request.method == 'GET':
for i in PackItem.objects.filter(product=obj.product.material, is_deleted=False):
SalePack.objects.get_or_create(sale_product=obj, packitem=i,
defaults={
"sale_product":obj,
"packitem":i,
"count":i.count
})
return Response(SaleProductPackDetailSerializer(instance=obj).data)
elif request.method == 'POST':
serializer = SaleProductPackSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
obj.packnum = vdata['packnum']
for i in vdata['detail']:
pi = i['id']
pi.count = i['count']
pi.save()
return Response()

View File

@ -90,7 +90,7 @@ class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
class StateViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet): class StateViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'get':'*', 'post':'workflow_update', perms_map = {'get':'*', 'post':'workflow_update',
'put':'workflow_update', 'delete':'workflow_delete'} 'put':'workflow_update', 'delete':'workflow_update'}
queryset = State.objects.all() queryset = State.objects.all()
serializer_class = StateSerializer serializer_class = StateSerializer
search_fields = ['name'] search_fields = ['name']
@ -99,7 +99,7 @@ class StateViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, Destr
class TransitionViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet): class TransitionViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'get':'*', 'post':'workflow_update', perms_map = {'get':'*', 'post':'workflow_update',
'put':'workflow_update', 'delete':'workflow_delete'} 'put':'workflow_update', 'delete':'workflow_update'}
queryset = Transition.objects.all() queryset = Transition.objects.all()
serializer_class = TransitionSerializer serializer_class = TransitionSerializer
search_fields = ['name'] search_fields = ['name']
@ -108,7 +108,7 @@ class TransitionViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin,
class CustomFieldViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet): class CustomFieldViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'get':'*', 'post':'workflow_update', perms_map = {'get':'*', 'post':'workflow_update',
'put':'workflow_update', 'delete':'workflow_delete'} 'put':'workflow_update', 'delete':'workflow_update'}
queryset = CustomField.objects.all() queryset = CustomField.objects.all()
serializer_class = CustomFieldSerializer serializer_class = CustomFieldSerializer
search_fields = ['field_name'] search_fields = ['field_name']

View File

@ -62,8 +62,8 @@ class FitJSONRenderer(JSONRenderer):
if isinstance(data, list): if isinstance(data, list):
data = data[0] data = data[0]
response_body.msg = prefix + ":" + str(data) # 取一部分放入msg,方便前端alert response_body.msg = prefix + str(data) # 取一部分放入msg,方便前端alert
else: else:
response_body.data = data response_body.data = data
renderer_context.get("response").status_code = 200 # 统一成200响应, 可用body里code区分业务异常 renderer_context.get("response").status_code = 200 # 统一成200响应, 可用body里code区分业务异常
return super(FitJSONRenderer, self).render(response_body.dict, accepted_media_type, renderer_context) return super(FitJSONRenderer, self).render(response_body.dict, accepted_media_type, renderer_context)