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

This commit is contained in:
shijing 2021-12-16 23:37:45 +08:00
commit f41c41836c
50 changed files with 757 additions and 233 deletions

View File

@ -36,6 +36,12 @@ export function getContractList(query) {
params: query params: query
}) })
} }
export function getContract(id) {
return request({
url: `/sam/contract/${id}/`,
method: 'get'
})
}
export function createContract(data) { export function createContract(data) {
return request({ return request({
url: '/sam/contract/', url: '/sam/contract/',

View File

@ -276,13 +276,21 @@ export const asyncRoutes = [
path: 'customer', path: 'customer',
name: 'customer', name: 'customer',
component: () => import('@/views/sam/customer'), component: () => import('@/views/sam/customer'),
meta: { title: '客户信息', icon: 'example', perms: ['index_manage'] } meta: { title: '客户管理', icon: 'example', perms: ['index_manage'] }
}, },
{ {
path: 'contract', path: 'contract',
name: 'contract', name: 'contract',
component: () => import('@/views/sam/contract'), component: () => import('@/views/sam/contract'),
meta: { title: '合同信息', icon: 'example', perms: ['index_manage'] } meta: { title: '合同管理', icon: 'example', perms: ['index_manage'] }
}
,
{
path: 'contractdetail/:id',
name: 'contractdetail',
component: () => import('@/views/sam/contractdetail'),
meta: { title: '合同详情', perms: ['vendor_manage'] },
hidden: true
} }
, ,
@ -290,9 +298,17 @@ export const asyncRoutes = [
path: 'order', path: 'order',
name: 'order', name: 'order',
component: () => import('@/views/sam/order'), component: () => import('@/views/sam/order'),
meta: { title: '订单信息', icon: 'example', perms: ['index_manage'] } meta: { title: '订单管理', icon: 'example', perms: ['index_manage'] }
} }
, ,
{
path: 'orderdetail/:id',
name: 'orderdetail',
component: () => import('@/views/sam/orderdetail'),
meta: { title: '订单详情', perms: ['vendor_manage'] },
hidden: true
},
{ {
path: 'sales', path: 'sales',
name: 'sales', name: 'sales',

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="equipmentList.results" :data="equipmentList.results"
@ -37,8 +37,8 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="设备编号"> <el-table-column label="设备编号">
@ -104,6 +104,7 @@
<el-link <el-link
v-if="checkPermission(['equipment_update'])" v-if="checkPermission(['equipment_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="equipmentList.results" :data="equipmentList.results"
@ -38,7 +38,7 @@
stripe stripe
highlight-current-row highlight-current-row
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="设备名称" width="120" show-overflow-tooltip> <el-table-column label="设备名称" width="120" show-overflow-tooltip>
@ -113,6 +113,7 @@
<el-link <el-link
v-if="checkPermission(['equipment_update'])" v-if="checkPermission(['equipment_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="equipmentrecordList.results" :data="equipmentrecordList.results"
@ -37,7 +37,8 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="600" height="100"
v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -72,6 +73,7 @@
<el-link <el-link
v-if="checkPermission(['equipment_update'])" v-if="checkPermission(['equipment_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -28,7 +28,7 @@
> >
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
@ -37,9 +37,9 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="700"
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="出入记录ID"> <el-table-column label="出入记录ID">
@ -70,11 +70,13 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="primary"
@click="handleDetail(scope)" @click="handleDetail(scope)"
>查看</el-link >查看</el-link
> >
<el-link <el-link
v-if="scope.row.is_audited == false" v-if="scope.row.is_audited == false"
type="primary"
@click="handleAudit(scope)" @click="handleAudit(scope)"
>审核</el-link >审核</el-link
> >

View File

@ -52,6 +52,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="scope.row.is_tested == false" v-if="scope.row.is_tested == false"
type="primary"
@click="handleMaterial(scope)" @click="handleMaterial(scope)"
>检查</el-link >检查</el-link
> >

View File

@ -25,7 +25,7 @@
> >
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
@ -34,7 +34,8 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="600" height="100"
v-el-height-adaptive-table="{bottomOffset: 42}"
> >

View File

@ -25,7 +25,7 @@
> >
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="InventoryList.results" :data="InventoryList.results"
@ -33,9 +33,9 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="700"
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="物料批次"> <el-table-column label="物料批次">

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="iproductData.results" :data="iproductData.results"
@ -9,9 +9,9 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="700"
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="成品编号"> <el-table-column label="成品编号">

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="warehouseList.results" :data="warehouseList.results"
@ -37,9 +37,9 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="700"
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="仓库名称"> <el-table-column label="仓库名称">
@ -60,11 +60,13 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="primary"
@click="handleMaterial(scope)" @click="handleMaterial(scope)"
>查看物料</el-link >查看物料</el-link
> >
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="iproductData.results" :data="iproductData.results"
@ -9,9 +9,9 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="700"
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="半成品编号"> <el-table-column label="半成品编号">

View File

@ -49,7 +49,7 @@
highlight-current-row highlight-current-row
max-height="620" max-height="620"
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 10}" v-el-height-adaptive-table="{bottomOffset: 40}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="物料编号"> <el-table-column label="物料编号">
@ -89,17 +89,20 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handlebind(scope)" @click="handlebind(scope)"
>检查表</el-link >检查表</el-link
> >
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handledetail(scope)" @click="handledetail(scope)"
>详情</el-link >详情</el-link
> >
@ -391,3 +394,4 @@ export default {
}, },
}; };
</script> </script>

View File

@ -228,3 +228,4 @@ getMaterial(){
}, },
}; };
</script> </script>

View File

@ -311,6 +311,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handlefieldEdit(scope)" @click="handlefieldEdit(scope)"
>编辑 >编辑
</el-link </el-link

View File

@ -55,6 +55,7 @@
> >
<el-link <el-link
v-if="checkPermission(['process_update'])" v-if="checkPermission(['process_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -41,16 +41,10 @@
</el-card> </el-card>
<el-card > <el-card >
<el-descriptions class="margin-top" title="产品信息" :column="3" border> <el-descriptions class="margin-top" title="产品信息" :column="1" border>
<el-descriptions-item>
<template slot="label">
产品名称
</template>
{{products.name}}
</el-descriptions-item>
<el-descriptions-item> <el-descriptions-item>
<template slot="label"> <template slot="label">
@ -59,6 +53,14 @@
{{products.number}} {{products.number}}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item>
<template slot="label">
产品名称
</template>
{{products.name}}
</el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-card> </el-card>
@ -115,6 +117,7 @@
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handlesubproducationEdit(scope)" @click="handlesubproducationEdit(scope)"
>编辑</el-link >编辑</el-link
> >
@ -213,6 +216,7 @@
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handleinputEdit(scope)" @click="handleinputEdit(scope)"
>编辑</el-link >编辑</el-link
> >
@ -314,6 +318,7 @@
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handleoutputEdit(scope)" @click="handleoutputEdit(scope)"
>编辑</el-link >编辑</el-link
> >
@ -411,6 +416,7 @@
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handleotherEdit(scope)" @click="handleotherEdit(scope)"
>编辑</el-link >编辑</el-link
> >
@ -498,6 +504,7 @@
<el-link <el-link
type="primary" type="primary"
@click="handlesearch(scope)" @click="handlesearch(scope)"
>查看</el-link >查看</el-link
> >
<el-link <el-link
@ -576,6 +583,7 @@
<el-link <el-link
v-if="checkPermission(['process_update'])" v-if="checkPermission(['process_update'])"
type="primary"
@click="handletechdocEdit(scope)" @click="handletechdocEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -47,6 +47,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['step_update'])" v-if="checkPermission(['step_update'])"
type="primary"
@click="handleEditStep(scope)" @click="handleEditStep(scope)"
>编辑</el-link >编辑</el-link
> >
@ -160,10 +161,12 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handleLook(scope)" @click="handleLook(scope)"
>查看</el-link> >查看</el-link>
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link> >编辑</el-link>
<el-link <el-link
@ -332,6 +335,7 @@
<el-link <el-link
v-if="checkPermission(['material_update'])" v-if="checkPermission(['material_update'])"
type="primary"
@click="handlefieldEdit(scope)" @click="handlefieldEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -13,7 +13,7 @@
stripe stripe
style="width: 100%" style="width: 100%"
height="300" height="300"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -254,6 +254,7 @@ export default {
}, },
methods: { methods: {
checkPermission, checkPermission,
//订单列表 //订单列表
getorderList() { getorderList() {
this.listLoading = true; this.listLoading = true;
@ -345,4 +346,15 @@ export default {
}, },
}; };
</script> </script>
<style>
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
</style>

View File

@ -17,7 +17,7 @@
stripe stripe
highlight-current-row highlight-current-row
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 40}"
> >
<el-table-column <el-table-column
type="selection" type="selection"
@ -93,7 +93,7 @@
fit fit
stripe stripe
style="width: 100%" style="width: 100%"
height="320" height="310"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -134,7 +134,7 @@
fit fit
stripe stripe
style="width: 100%" style="width: 100%"
height="300" height="320"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />

View File

@ -17,7 +17,9 @@
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="子计划编号">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="产品名称"> <el-table-column label="产品名称">
<template slot-scope="scope">{{ scope.row.product_.name }}</template> <template slot-scope="scope">{{ scope.row.product_.name }}</template>
</el-table-column> </el-table-column>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card style="margin-top: 2px"> <el-card>
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="iproductData.results" :data="iproductData.results"
@ -10,8 +10,8 @@
stripe stripe
highlight-current-row highlight-current-row
max-height="700" max-height="700"
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="成品编号"> <el-table-column label="成品编号">

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="contractList.results" :data="contractList.results"
@ -38,27 +38,27 @@
stripe stripe
highlight-current-row highlight-current-row
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="合同名称" width="130" show-overflow-tooltip> <el-table-column label="合同名称" width="130" show-overflow-tooltip>
<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 label="合同编号" width="130"> <el-table-column 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 label="合同金额(元)" width="130"> <el-table-column label="合同金额(元)">
<template slot-scope="scope">{{ scope.row.amount }}</template> <template slot-scope="scope">{{ scope.row.amount }}</template>
</el-table-column> </el-table-column>
<el-table-column label="开票金额(元)" width="130"> <el-table-column label="开票金额(元)" >
<template slot-scope="scope">{{ scope.row.invoice }}</template> <template slot-scope="scope">{{ scope.row.invoice }}</template>
</el-table-column> </el-table-column>
<el-table-column label="客户名称" width="130" show-overflow-tooltip> <el-table-column label="客户名称" width="130" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.customer_.name }}</template> <template slot-scope="scope">{{ scope.row.customer_.name }}</template>
</el-table-column> </el-table-column>
<el-table-column label="签订日期" width="130"> <el-table-column label="签订日期" >
<template slot-scope="scope">{{ scope.row.sign_date }}</template> <template slot-scope="scope">{{ scope.row.sign_date }}</template>
</el-table-column> </el-table-column>
<el-table-column label="描述" width="130" show-overflow-tooltip> <el-table-column label="描述" width="130" show-overflow-tooltip>
@ -76,6 +76,7 @@
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >
@ -85,6 +86,14 @@
@click="handleDelete(scope)" @click="handleDelete(scope)"
>删除</el-link >删除</el-link
> >
<el-link
v-if="checkPermission(['warehouse_delete'])"
type="primary"
@click="handleDetail(scope)"
>详情</el-link
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -279,6 +288,10 @@ export default {
} }
}); });
}, },
//合同详情
handleDetail(scope){
this.$router.push({name: "contractdetail", params: { id: scope.row.id }, })
}
}, },
}; };
</script> </script>

View File

@ -0,0 +1,129 @@
<template>
<div class="app-container">
<el-card style="margin-top: 2px">
<el-descriptions title="基本信息" direction="vertical" :column="8" border>
<el-descriptions-item label="合同名称"> {{contractdetail.name}}</el-descriptions-item>
<el-descriptions-item label="编号" > {{contractdetail.number}}</el-descriptions-item>
<el-descriptions-item label="金额" :span="2" > {{contractdetail.amount}}</el-descriptions-item>
<el-descriptions-item label="客户名称" v-if="contractdetail.customer"> {{contractdetail.customer_.name}} </el-descriptions-item>
</el-descriptions>
</el-card>
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>关联订单</span>
</div>
<el-table
v-loading="listLoading"
:data="OrderList"
border
fit
stripe
highlight-current-row
>
<el-table-column type="index" width="50" />
<el-table-column label="订单编号" width="160" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="客户" width="200" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.customer_.name }}</template>
</el-table-column>
<el-table-column label="产品名称" width="200" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.product_.name }}</template>
</el-table-column>
<el-table-column label="产品型号" width="120" 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.delivered_count }}</template>
</el-table-column>
<el-table-column label="创建时间" width="160" >
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_delete'])"
type="primary"
@click="handleDetail(scope)"
>详情</el-link
>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import {getContract,getOrderList} from "@/api/sam";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default {
components: { Pagination },
data() {
return {
contractdetail:"",
OrderList:"",
};
},
computed: {},
watch: {},
created() {
this.id = this.$route.params.id;
this.getdetail();
this.getList();
},
methods: {
checkPermission,
getList() {
getOrderList({contract:this.id,page:0}).then((response) => {
if (response.data) {
this.OrderList = response.data;
}
})
},
//详情
getdetail() {
getContract(this.id).then((response) => {
if (response.data) {
this.contractdetail = response.data;
}
})
},
//订单详情
handleDetail(scope){
this.$router.push({name: "orderdetail", params: { id: scope.row.id }, })
}
},
};
</script>

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="customerList.results" :data="customerList.results"
@ -38,7 +38,7 @@
stripe stripe
highlight-current-row highlight-current-row
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="客户名称" width="200" show-overflow-tooltip> <el-table-column label="客户名称" width="200" show-overflow-tooltip>
@ -70,6 +70,7 @@
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
@click="handleEdit(scope)" @click="handleEdit(scope)"
type="primary"
>编辑</el-link >编辑</el-link
> >
<el-link <el-link

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="orderList.results" :data="orderList.results"
@ -38,7 +38,7 @@
stripe stripe
highlight-current-row highlight-current-row
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -79,8 +79,9 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="scope.row.planed_count==0&&checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
@click="handleEdit(scope)" @click="handleEdit(scope)"
type="primary"
>编辑</el-link >编辑</el-link
> >
<el-link <el-link
@ -89,6 +90,12 @@
@click="handleDelete(scope)" @click="handleDelete(scope)"
>删除</el-link >删除</el-link
> >
<el-link
v-if="checkPermission(['warehouse_delete'])"
type="primary"
@click="handleDetail(scope)"
>详情</el-link
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -127,8 +134,8 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="所需数量" prop="count"> <el-form-item label="所需数量" prop="count" >
<el-input type="number" v-model="order.count"></el-input> <el-input-number type="number" v-model="order.count" :min="0"></el-input-number>
</el-form-item> </el-form-item>
<el-form-item label="交货日期" prop="delivery_date"> <el-form-item label="交货日期" prop="delivery_date">
<el-date-picker <el-date-picker
@ -322,6 +329,10 @@ export default {
} }
}); });
}, },
//订单详情
handleDetail(scope){
this.$router.push({name: "orderdetail", params: { id: scope.row.id }, })
}
}, },
}; };
</script> </script>

View File

@ -0,0 +1,127 @@
<template>
<div class="app-container">
<el-card style="margin-top: 2px">
<el-descriptions title="基本信息" :column="4" border>
<el-descriptions-item label="订单编号"> {{orderdetail.number}}</el-descriptions-item>
<el-descriptions-item label="产品名称" > {{orderdetail.product_.name}}</el-descriptions-item>
<el-descriptions-item label="产品型号" > {{orderdetail.product_.specification}}</el-descriptions-item>
<el-descriptions-item label="产品数量" > {{orderdetail.count}} </el-descriptions-item>
<el-descriptions-item label="已交货数量" > {{orderdetail.delivered_count}}</el-descriptions-item>
<el-descriptions-item label="已排产数量"> {{orderdetail.planed_count}}</el-descriptions-item>
<el-descriptions-item label="交货日期" > {{orderdetail.delivery_date}}</el-descriptions-item>
</el-descriptions>
</el-card>
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>关联生产任务</span>
</div>
<el-table
:data="productionplan"
border
fit
stripe
style="width: 100%"
height="300"
>
<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_.contract_.number }}</template>
</el-table-column>
<el-table-column label="产品名称" width="150" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.product_.name }}</template>
</el-table-column>
<el-table-column label="产品型号" >
<template slot-scope="scope">{{ scope.row.product_.specification }}</template>
</el-table-column>
<el-table-column label="产品单位">
<template slot-scope="scope">{{ scope.row.product_.unit }}</template>
</el-table-column>
<el-table-column label="生产数量" >
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
<el-table-column label="计划开工时间" >
<template slot-scope="scope">{{ scope.row.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" >
<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="创建时间" width="160">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import {getOrder} from "@/api/sam";
import {getProductionplanList} from "@/api/pm";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default {
components: { Pagination },
data() {
return {
productionplan:"",
orderdetail:"",
};
},
computed: {},
watch: {},
created() {
this.id = this.$route.params.id;
this.getdetail();
this.getList();
},
methods: {
checkPermission,
getList() {
getProductionplanList({order:this.id,page:0}).then((response) => {
if (response.data) {
this.productionplan = response.data;
}
})
},
//详情
getdetail() {
getOrder(this.id).then((response) => {
if (response.data) {
this.orderdetail = response.data;
}
})
},
},
};
</script>

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="contractList.results" :data="contractList.results"
@ -37,7 +37,8 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="600" height="100"
v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="合同名称"> <el-table-column label="合同名称">
@ -75,6 +76,7 @@
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="primary"
@click="handleEdit(scope)" @click="handleEdit(scope)"
>编辑</el-link >编辑</el-link
> >

View File

@ -29,7 +29,7 @@
</div> </div>
</el-card> </el-card>
<el-card style="margin-top: 2px"> <el-card >
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="saleList.results" :data="saleList.results"
@ -37,7 +37,8 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
height="100"
v-el-height-adaptive-table="{bottomOffset: 42}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="产品名称" show-overflow-tooltip> <el-table-column label="产品名称" show-overflow-tooltip>
@ -66,14 +67,14 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_delete'])" v-if="checkPermission(['warehouse_delete'])"
type="primary"
@click="handleDetail(scope)" @click="handleDetail(scope)"
>详情</el-link >详情</el-link
> >
<el-link <el-link
v-if="scope.row.is_audited==false" v-if="scope.row.is_audited==false"
type="primary"
@click="handleAudit(scope)" @click="handleAudit(scope)"
>审核</el-link >审核</el-link
> >
@ -152,6 +153,7 @@
stripe stripe
highlight-current-row highlight-current-row
ref="multipleTable" ref="multipleTable"
> >
<el-table-column <el-table-column
type="selection" type="selection"

View File

@ -10,7 +10,8 @@
fit fit
stripe stripe
highlight-current-row highlight-current-row
max-height="600" max-height="700"
> >
<el-table-column type="index" width="50"/> <el-table-column type="index" width="50"/>
<el-table-column label="半成品名称"> <el-table-column label="半成品名称">

View File

@ -11,7 +11,7 @@
style="width: 100%" style="width: 100%"
max-height="670" max-height="670"
highlight-current-row highlight-current-row
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 30}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -70,11 +70,13 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="primary"
@click="handleoperation(scope)" @click="handleoperation(scope)"
>前往操作</el-link> >前往操作</el-link>
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="danger"
@click="handleDelete(scope)" @click="handleDelete(scope)"
>删除</el-link> >删除</el-link>

View File

@ -97,6 +97,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="danger"
@click="handleDeletewproduct(scope)" @click="handleDeletewproduct(scope)"
>删除</el-link >删除</el-link
> >
@ -129,6 +130,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="danger"
@click="handleDeletequip(scope)" @click="handleDeletequip(scope)"
>删除</el-link >删除</el-link
> >
@ -165,6 +167,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-link <el-link
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
type="primary"
@click="handlerecord(scope)" @click="handlerecord(scope)"
>填写表单</el-link >填写表单</el-link
> >

View File

@ -18,7 +18,9 @@
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="子计划编号">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="任务编号"> <el-table-column label="任务编号">
<template slot-scope="scope">{{ <template slot-scope="scope">{{
scope.row.number scope.row.number

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-12-16 01:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inm', '0022_auto_20211208_1408'),
]
operations = [
migrations.AlterField(
model_name='fifoitem',
name='is_tested',
field=models.BooleanField(default=False, verbose_name='是否已检验'),
),
migrations.AlterField(
model_name='fifoitem',
name='is_testok',
field=models.BooleanField(default=False, verbose_name='是否检验合格'),
),
]

View File

@ -0,0 +1,37 @@
# Generated by Django 3.2.9 on 2021-12-16 01:45
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0042_alter_recordformfield_field_type'),
('qm', '0019_auto_20211214_1504'),
]
operations = [
migrations.RemoveField(
model_name='testrecorditem',
name='field_key',
),
migrations.RemoveField(
model_name='testrecorditem',
name='field_name',
),
migrations.RemoveField(
model_name='testrecorditem',
name='field_type',
),
migrations.AlterField(
model_name='testrecorditem',
name='form_field',
field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='mtm.recordformfield', verbose_name='关联自定义表格字段'),
),
migrations.AlterField(
model_name='testrecorditem',
name='test_record',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='item_test_record', to='qm.testrecord', verbose_name='关联的检验记录'),
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 3.2.9 on 2021-12-16 02:20
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('qm', '0020_auto_20211216_0945'),
]
operations = [
migrations.RemoveField(
model_name='testrecord',
name='is_testok_robot',
),
migrations.RemoveField(
model_name='testrecorditem',
name='is_testok_robot',
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.9 on 2021-12-16 06:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0042_alter_recordformfield_field_type'),
('qm', '0021_auto_20211216_1020'),
]
operations = [
migrations.AlterField(
model_name='testrecorditem',
name='field_value',
field=models.JSONField(blank=True, null=True, verbose_name='录入值'),
),
migrations.AlterField(
model_name='testrecorditem',
name='form_field',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.recordformfield', verbose_name='关联自定义表格字段'),
),
]

View File

@ -62,7 +62,6 @@ class TestRecord(CommonADModel):
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('是否合格', default=True)
is_testok_robot = models.BooleanField('自动判定的是否合格', default=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)
@ -78,12 +77,8 @@ class TestRecordItem(BaseModel):
""" """
记录表格字段值 记录表格字段值
""" """
form_field = models.ForeignKey(RecordFormField, verbose_name='关联自定义表格字段', on_delete=models.CASCADE, db_constraint=False) form_field = models.ForeignKey(RecordFormField, verbose_name='关联自定义表格字段', on_delete=models.CASCADE)
field_name = models.CharField('字段名', max_length=50) field_value = models.JSONField('录入值', null=True, blank=True)
field_key = models.CharField('字段标识', max_length=50)
field_type = models.CharField('字段类型', choices=RecordForm.type_choices, max_length=50)
field_value = models.JSONField('录入值', default=dict, blank=True)
is_hidden = models.BooleanField('是否隐藏', default=False) is_hidden = models.BooleanField('是否隐藏', default=False)
is_testok = models.BooleanField('是否合格', null=True, blank=True) is_testok = models.BooleanField('是否合格', null=True, blank=True)
is_testok_robot = models.BooleanField('自动判定的是否合格', null=True, blank=True)
test_record = models.ForeignKey(TestRecord, verbose_name='关联的检验记录', on_delete=models.CASCADE, related_name='item_test_record') test_record = models.ForeignKey(TestRecord, verbose_name='关联的检验记录', on_delete=models.CASCADE, related_name='item_test_record')

View File

@ -48,10 +48,15 @@ class TestRecordItemUpdateSerializer(serializers.ModelSerializer):
class TestRecordItemSerializer(serializers.ModelSerializer): class TestRecordItemSerializer(serializers.ModelSerializer):
field_key = serializers.CharField(source='form_field.field_key', read_only=True)
field_name = serializers.CharField(source='form_field.field_name', read_only=True)
field_type = serializers.CharField(source='form_field.field_type', read_only=True)
need_judge = serializers.BooleanField(source='form_field.need_judge', read_only=True) need_judge = serializers.BooleanField(source='form_field.need_judge', read_only=True)
field_choice = serializers.JSONField(source='form_field.field_choice', read_only=True)
rule_expression = serializers.JSONField(source='form_field.rule_expression', read_only=True) rule_expression = serializers.JSONField(source='form_field.rule_expression', read_only=True)
display_expression = serializers.JSONField(source='form_field.display_expression', read_only=True) display_expression = serializers.JSONField(source='form_field.display_expression', read_only=True)
is_hidden = serializers.BooleanField(source='form_field.is_hidden', read_only=True) is_hidden = serializers.BooleanField(source='form_field.is_hidden', read_only=True)
parent = serializers.PrimaryKeyRelatedField(source='form_field.parent', read_only=True)
help_text = serializers.CharField(source='form_field.help_text', read_only=True) help_text = serializers.CharField(source='form_field.help_text', read_only=True)
sort = serializers.IntegerField(source='form_field.sort', read_only=True) sort = serializers.IntegerField(source='form_field.sort', read_only=True)
class Meta: class Meta:
@ -97,7 +102,7 @@ class TestRecordDetailSerializer(serializers.ModelSerializer):
def to_representation(self, instance): def to_representation(self, instance):
ret = super().to_representation(instance) ret = super().to_representation(instance)
if instance.origin_test and instance.type == TestRecord.TEST_PROCESS_RE: if instance.origin_test and instance.type == TestRecord.TEST_PROCESS_RE:
origin_test = ret['origin_test'] origin_test = ret['origin_test_']
o_dict = {} o_dict = {}
for i in origin_test['record_data']: for i in origin_test['record_data']:
o_dict[i['field_key']] = i['field_value'] o_dict[i['field_key']] = i['field_value']

View File

@ -84,9 +84,11 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De
obj = self.get_object() obj = self.get_object()
# 校验是否有未填项目 # 校验是否有未填项目
if obj.type != TestRecord.TEST_PROCESS_RE: if obj.type != TestRecord.TEST_PROCESS_RE:
if TestRecordItem.objects.filter(field_value__isnull=True, is_hidden=False).exists(): if TestRecordItem.objects.filter(field_value__isnull=True, is_hidden=False, test_record=obj).exists():
raise exceptions.APIException('存在未填写项目') raise exceptions.APIException('存在未填写项目')
with transaction.atomic(): with transaction.atomic():
obj.is_submited=True
obj.save()
WpmServies.update_wproduct_by_test(obj, request.user) WpmServies.update_wproduct_by_test(obj, request.user)
return Response() return Response()

View File

@ -15,7 +15,7 @@ class Workflow(CommonAModel):
name = models.CharField('名称', max_length=50) name = models.CharField('名称', max_length=50)
key = models.CharField('工作流标识', unique=True, max_length=20, null=True, blank=True) key = models.CharField('工作流标识', unique=True, max_length=20, null=True, blank=True)
sn_prefix = models.CharField('流水号前缀', max_length=50, default='hb') sn_prefix = models.CharField('流水号前缀', max_length=50, default='hb')
description = models.CharField('描述', max_length=200) description = models.CharField('描述', max_length=200, null=True, blank=True)
view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单') view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单')
limit_expression = models.JSONField('限制表达式', default=dict, blank=True, help_text='限制周期({"period":24} 24小时), 限制次数({"count":1}在限制周期内只允许提交1次), 限制级别({"level":1} 针对(1单个用户 2全局)限制周期限制次数,默认特定用户);允许特定人员提交({"allow_persons":"zhangsan,lisi"}只允许张三提交工单,{"allow_depts":"1,2"}只允许部门id为1和2的用户提交工单{"allow_roles":"1,2"}只允许角色id为1和2的用户提交工单)') limit_expression = models.JSONField('限制表达式', default=dict, blank=True, help_text='限制周期({"period":24} 24小时), 限制次数({"count":1}在限制周期内只允许提交1次), 限制级别({"level":1} 针对(1单个用户 2全局)限制周期限制次数,默认特定用户);允许特定人员提交({"allow_persons":"zhangsan,lisi"}只允许张三提交工单,{"allow_depts":"1,2"}只允许部门id为1和2的用户提交工单{"allow_roles":"1,2"}只允许角色id为1和2的用户提交工单)')
display_form_str = models.JSONField('展现表单字段', default=list, blank=True, help_text='默认"[]",用于用户只有对应工单查看权限时显示哪些字段,field_key的list的json,如["days","sn"],内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称)state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') display_form_str = models.JSONField('展现表单字段', default=list, blank=True, help_text='默认"[]",用于用户只有对应工单查看权限时显示哪些字段,field_key的list的json,如["days","sn"],内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称)state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称')
@ -68,7 +68,7 @@ class State(CommonAModel):
STATE_FIELD_READONLY= 1 # 字段只读 STATE_FIELD_READONLY= 1 # 字段只读
STATE_FIELD_REQUIRED = 2 # 字段必填 STATE_FIELD_REQUIRED = 2 # 字段必填
STATE_FIELD_OPTIONAL = 3 # 字段可选 STATE_FIELD_OPTIONAL = 3 # 字段可选
STATE_FIELD_HIDDEN = 4 # 字段隐藏
state_filter_choices=( state_filter_choices=(
(0, ''), (0, ''),
(1, '和工单同属一及上级部门'), (1, '和工单同属一及上级部门'),
@ -83,7 +83,7 @@ class State(CommonAModel):
enable_retreat = models.BooleanField('允许撤回', default=False, help_text='开启后允许工单创建人在此状态直接撤回工单到初始状态') enable_retreat = models.BooleanField('允许撤回', default=False, help_text='开启后允许工单创建人在此状态直接撤回工单到初始状态')
participant_type = models.IntegerField('参与者类型', choices=state_participanttype_choices, default=1, blank=True, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5参与人填create_by') participant_type = models.IntegerField('参与者类型', choices=state_participanttype_choices, default=1, blank=True, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5参与人填create_by')
participant = models.JSONField('参与者', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表\部门id\角色id\变量(create_by,create_by_tl)\脚本记录的id等包含子工作流的需要设置处理人为loonrobot') participant = models.JSONField('参与者', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表\部门id\角色id\变量(create_by,create_by_tl)\脚本记录的id等包含子工作流的需要设置处理人为loonrobot')
state_fields = models.JSONField('表单字段', default=dict, help_text='json格式字典存储,包括读写属性1只读2必填3可选. 示例:{"create_time":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称)state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') # json格式存储,包括读写属性1只读2必填3可选4不显示, 字典的字典 state_fields = models.JSONField('表单字段', default=dict, help_text='json格式字典存储,包括读写属性1只读2必填3可选, 4:隐藏 示例:{"create_time":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称)state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') # json格式存储,包括读写属性1只读2必填3可选4不显示, 字典的字典
distribute_type = models.IntegerField('分配方式', default=1, choices=state_distribute_choices, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)') distribute_type = models.IntegerField('分配方式', default=1, choices=state_distribute_choices, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)')
filter_policy = models.IntegerField('参与人过滤策略', default=0, choices=state_filter_choices) filter_policy = models.IntegerField('参与人过滤策略', default=0, choices=state_filter_choices)
participant_cc = models.JSONField('抄送给', default=list, blank=True, help_text='抄送给(userid列表)') participant_cc = models.JSONField('抄送给', default=list, blank=True, help_text='抄送给(userid列表)')
@ -197,7 +197,7 @@ class Ticket(CommonBModel):
('worked', '我处理的'), ('worked', '我处理的'),
('cc', '抄送我的') ('cc', '抄送我的')
) )
title = models.CharField('标题', max_length=500, blank=True, default='', help_text="工单标题") title = models.CharField('标题', max_length=500, null=True, blank=True, help_text="工单标题")
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='关联工作流') workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='关联工作流')
sn = models.CharField('流水号', max_length=25, help_text="工单的流水号") sn = models.CharField('流水号', max_length=25, help_text="工单的流水号")
state = models.ForeignKey(State, on_delete=models.CASCADE, verbose_name='当前状态', related_name='ticket_state') state = models.ForeignKey(State, on_delete=models.CASCADE, verbose_name='当前状态', related_name='ticket_state')

View File

@ -49,7 +49,7 @@ class TicketSimpleSerializer(serializers.ModelSerializer):
fields = '__all__' fields = '__all__'
class TicketCreateSerializer(serializers.ModelSerializer): class TicketCreateSerializer(serializers.ModelSerializer):
transition = serializers.IntegerField(label='流转ID') transition = serializers.PrimaryKeyRelatedField(queryset=Transition.objects.all(), write_only=True)
class Meta: class Meta:
model=Ticket model=Ticket
fields=['title','workflow', 'ticket_data', 'transition'] fields=['title','workflow', 'ticket_data', 'transition']

View File

@ -54,6 +54,13 @@ class WfService(object):
""" """
return CustomField.objects.filter(is_deleted=False, workflow=workflow).order_by('sort') return CustomField.objects.filter(is_deleted=False, workflow=workflow).order_by('sort')
@staticmethod
def get_workflow_custom_fields_list(workflow:Workflow):
"""
获取工单字段key List
"""
return list(CustomField.objects.filter(is_deleted=False, workflow=workflow).order_by('sort').values_list('field_key', flat=True))
@classmethod @classmethod
def get_ticket_transitions(cls, ticket:Ticket): def get_ticket_transitions(cls, ticket:Ticket):
""" """

View File

@ -77,6 +77,11 @@ class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
ret['workflow'] = pk ret['workflow'] = pk
ret['transitions'] = TransitionSerializer(instance=transitions, many=True).data ret['transitions'] = TransitionSerializer(instance=transitions, many=True).data
field_list = CustomFieldSerializer(instance=WfService.get_workflow_custom_fields(wf), many=True).data field_list = CustomFieldSerializer(instance=WfService.get_workflow_custom_fields(wf), many=True).data
for i in field_list:
if i['field_key'] in start_state.state_fields:
i['field_attribute'] = start_state.state_fields[i['field_key']]
else:
i['field_attribute'] = State.STATE_FIELD_READONLY
ret['field_list'] = field_list ret['field_list'] = field_list
return Response(ret) return Response(ret)
@ -137,15 +142,27 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
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)
start_state = WfService.get_workflow_start_state(rdata['workflow']) vdata = serializer.validated_data #校验之后的数据
transition = Transition.objects.get(pk=rdata['transition']) start_state = WfService.get_workflow_start_state(vdata['workflow'])
ticket_data = rdata['ticket_data'] transition = vdata['transition']
ticket_data = vdata['ticket_data']
save_ticket_data = {}
#校验必填项
if transition.field_require_check: if transition.field_require_check:
for key, value in start_state.state_fields.items(): #校验必填项 for key, value in start_state.state_fields.items():
if value == State.STATE_FIELD_REQUIRED: if value == State.STATE_FIELD_REQUIRED:
if key not in ticket_data or not ticket_data[key]: if key not in ticket_data or not ticket_data[key]:
raise APIException('字段{}必填'.format(key)) raise APIException('字段{}必填'.format(key))
ticket = serializer.save(state=start_state, create_by=request.user, act_state=Ticket.TICKET_ACT_STATE_DRAFT, belong_dept=request.user.dept) # 先创建出来 save_ticket_data[key] = ticket_data[key]
elif value == State.STATE_FIELD_OPTIONAL:
save_ticket_data[key] = ticket_data[key]
ticket = serializer.save(state=start_state,
create_by=request.user,
act_state=Ticket.TICKET_ACT_STATE_DRAFT,
belong_dept=request.user.dept,
ticket_data=save_ticket_data) # 先创建出来
next_state = WfService.get_next_state_by_transition_and_ticket_info(ticket=ticket, transition=transition) next_state = WfService.get_next_state_by_transition_and_ticket_info(ticket=ticket, transition=transition)
participant_info = WfService.get_ticket_state_participant_info(state=next_state, ticket=ticket, ticket_data=ticket.ticket_data) participant_info = WfService.get_ticket_state_participant_info(state=next_state, ticket=ticket, ticket_data=ticket.ticket_data)
@ -159,7 +176,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
act_state = Ticket.TICKET_ACT_STATE_DRAFT act_state = Ticket.TICKET_ACT_STATE_DRAFT
else: else:
act_state = Ticket.TICKET_ACT_STATE_ONGOING act_state = Ticket.TICKET_ACT_STATE_ONGOING
title = rdata.get('title', '') title = vdata['title']
title_template = ticket.workflow.title_template title_template = ticket.workflow.title_template
if title_template: if title_template:
all_ticket_data = {**rdata, **rdata['ticket_data']} all_ticket_data = {**rdata, **rdata['ticket_data']}
@ -224,6 +241,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
if value == State.STATE_FIELD_REQUIRED: if value == State.STATE_FIELD_REQUIRED:
if key not in ticket_data or not ticket_data[key]: if key not in ticket_data or not ticket_data[key]:
raise APIException('字段{}必填'.format(key)) raise APIException('字段{}必填'.format(key))
destination_state = WfService.get_next_state_by_transition_and_ticket_info(ticket, transition, ticket_data, request) destination_state = WfService.get_next_state_by_transition_and_ticket_info(ticket, transition, ticket_data, request)
multi_all_person = ticket.multi_all_person multi_all_person = ticket.multi_all_person
if multi_all_person: if multi_all_person:
@ -265,7 +283,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
ticket.act_state = Ticket.TICKET_ACT_STATE_BACK ticket.act_state = Ticket.TICKET_ACT_STATE_BACK
# 只更新必填和可选的字段 # 只更新必填和可选的字段
for key, value in ticket.state.state_fields.items(): for key, value in source_state.state_fields.items():
if value in (State.STATE_FIELD_REQUIRED, State.STATE_FIELD_OPTIONAL): if value in (State.STATE_FIELD_REQUIRED, State.STATE_FIELD_OPTIONAL):
source_ticket_data[key] = ticket_data[key] source_ticket_data[key] = ticket_data[key]
ticket.ticket_data = source_ticket_data ticket.ticket_data = source_ticket_data

View File

@ -0,0 +1,29 @@
# Generated by Django 3.2.9 on 2021-12-16 01:45
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wpm', '0032_auto_20211214_1245'),
]
operations = [
migrations.RemoveField(
model_name='operationrecorditem',
name='field_key',
),
migrations.RemoveField(
model_name='operationrecorditem',
name='field_name',
),
migrations.RemoveField(
model_name='operationrecorditem',
name='field_type',
),
migrations.RemoveField(
model_name='operationrecorditem',
name='sort',
),
]

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.9 on 2021-12-16 03:27
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0042_alter_recordformfield_field_type'),
('wpm', '0033_auto_20211216_0945'),
]
operations = [
migrations.AlterField(
model_name='operationrecorditem',
name='form_field',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ori_form_field', to='mtm.recordformfield', verbose_name='关联字段'),
),
migrations.AlterField(
model_name='operationrecorditem',
name='operation_record',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='item_operation_record', to='wpm.operationrecord', verbose_name='关联的生产记录'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-16 06:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0034_auto_20211216_1127'),
]
operations = [
migrations.AlterField(
model_name='operationrecorditem',
name='field_value',
field=models.JSONField(blank=True, null=True, verbose_name='录入值'),
),
]

View File

@ -35,6 +35,7 @@ class WProduct(CommonAModel):
WPR_ACT_STATE_INM = 40 WPR_ACT_STATE_INM = 40
WPR_ACT_STATE_NOTOK = 50 WPR_ACT_STATE_NOTOK = 50
WPR_ACT_STATE_TOFINALTEST = 60 WPR_ACT_STATE_TOFINALTEST = 60
WPR_ACT_STATE_SCRAP = 70
act_state_choices=( act_state_choices=(
(WPR_ACT_STATE_TORETEST, '待复检'), (WPR_ACT_STATE_TORETEST, '待复检'),
(WPR_ACT_STATE_DOWAIT, '操作准备中'), (WPR_ACT_STATE_DOWAIT, '操作准备中'),
@ -44,7 +45,8 @@ class WProduct(CommonAModel):
(WPR_ACT_STATE_OK, '已合格'), (WPR_ACT_STATE_OK, '已合格'),
(WPR_ACT_STATE_INM, '已入库'), (WPR_ACT_STATE_INM, '已入库'),
(WPR_ACT_STATE_NOTOK, '不合格'), (WPR_ACT_STATE_NOTOK, '不合格'),
(WPR_ACT_STATE_TOFINALTEST, '待成品检验') (WPR_ACT_STATE_TOFINALTEST, '待成品检验'),
(WPR_ACT_STATE_SCRAP, '已报废')
) )
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50) number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE) material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
@ -55,6 +57,7 @@ class WProduct(CommonAModel):
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE) child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
remark = models.CharField('备注', max_length=200, null=True, blank=True) remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan') subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan')
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作', operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation') on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
@ -69,40 +72,7 @@ class WProduct(CommonAModel):
最后提交的工序自检 最后提交的工序自检
""" """
return self.test_wproduct.filter(type=TestRecord.TEST_PROCESS, is_submited=True).order_by('-id').first() return self.test_wproduct.filter(type=TestRecord.TEST_PROCESS, is_submited=True).order_by('-id').first()
# @property
# def last_test(self):
# """
# 最后提交的检验
# """
# return self.test_wproduct.filter(is_submited=True).order_by('-id').first()
# @property
# def current_test(self):
# """
# 当前未提交的检验
# """
# trs = self.test_wproduct.filter(is_submited=False).order_by('-id')
# if trs.count() == 1:
# return trs[0]
# elif trs.count() == 0:
# return None
# else:
# raise exceptions.APIException('存在多条未提交检验记录')
# @property
# def current_ticket(self):
# """
# 当前是否有进行中工单
# """
# tickets = Ticket.objects.filter(wt_ticket__wproduct=self, act_state=Ticket.TICKET_ACT_STATE_ONGOING).order_by('-id')
# if tickets.count() == 1:
# return tickets[0]
# elif tickets.count() == 0:
# return None
# else:
# raise exceptions.APIException('存在多条进行中工单')
class WprouctTicket(CommonAModel): class WprouctTicket(CommonAModel):
""" """
@ -187,13 +157,9 @@ class OperationRecordItem(BaseModel):
""" """
记录表格字段值 记录表格字段值
""" """
form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE, db_constraint=False) form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE, related_name='ori_form_field')
field_name = models.CharField('字段名', max_length=50) field_value = models.JSONField('录入值', null=True, blank=True)
field_key = models.CharField('字段标识', max_length=50) operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE, related_name='item_operation_record')
field_type = models.CharField('字段类型', choices=RecordForm.type_choices, max_length=50)
field_value = models.JSONField('录入值', default=dict, blank=True)
sort = models.IntegerField('排序号', default=1)
operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE)
class OperationEquip(BaseModel): class OperationEquip(BaseModel):
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation') operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation')

View File

@ -244,19 +244,18 @@ class DoOutputSerializer(serializers.Serializer):
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label='物料ID') material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label='物料ID')
count_output = serializers.IntegerField(min_value=0, label='产出数量') count_output = serializers.IntegerField(min_value=0, label='产出数量')
class OperationRecordItemSerializer(serializers.ModelSerializer): class OperationRecordItemUpdateSerializer(serializers.Serializer):
class Meta: id = serializers.PrimaryKeyRelatedField(queryset=OperationRecordItem.objects.all())
model = OperationRecordItem field_value = serializers.JSONField(allow_null=True, required=False)
fields = ['form_field', 'field_value']
class OperationRecordSubmitSerializer(serializers.ModelSerializer): class OperationRecordSubmitSerializer(serializers.ModelSerializer):
record_data = OperationRecordItemSerializer(many=True) record_data = OperationRecordItemUpdateSerializer(many=True)
class Meta: class Meta:
model = OperationRecord model = OperationRecord
fields = ['record_data'] fields = ['record_data']
class OperationRecordSerializer(serializers.ModelSerializer): class OperationRecordSerializer(serializers.ModelSerializer):
record_data = OperationRecordItemSerializer(many=True) record_data = OperationRecordItemUpdateSerializer(many=True)
class Meta: class Meta:
model = OperationRecord model = OperationRecord
fields = ['form', 'record_data'] fields = ['form', 'record_data']
@ -392,4 +391,26 @@ class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_TOOL validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_TOOL
return super().create(validated_data) return super().create(validated_data)
class OperationRecordItemSerializer(serializers.ModelSerializer):
field_key = serializers.CharField(source='form_field.field_key', read_only=True)
field_name = serializers.CharField(source='form_field.field_name', read_only=True)
field_type = serializers.CharField(source='form_field.field_type', read_only=True)
field_choice = serializers.JSONField(source='form_field.field_choice', read_only=True)
is_hidden = serializers.BooleanField(source='form_field.is_hidden', read_only=True)
help_text = serializers.CharField(source='form_field.help_text', read_only=True)
sort = serializers.IntegerField(source='form_field.sort', read_only=True)
class Meta:
model = OperationRecordItem
fields = '__all__'
class OperationRecordDetailSerializer(serializers.ModelSerializer):
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
record_data = serializers.SerializerMethodField()
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
class Meta:
model = OperationRecord
fields = '__all__'
def get_record_data(self, obj):
return OperationRecordItemSerializer(instance=obj.item_operation_record.order_by('form_field__sort'), many=True).data

View File

@ -17,10 +17,11 @@ from apps.qm.serializers import TestRecordDetailSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from apps.wf.models import Workflow from apps.wf.models import Workflow
from apps.wf.serializers import WorkflowSimpleSerializer
from apps.wpm.filters import WMaterialFilterSet from apps.wpm.filters import WMaterialFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestFormInitSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordDetailSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestFormInitSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer
from rest_framework.response import Response from rest_framework.response import Response
from django.db import transaction from django.db import transaction
from rest_framework import exceptions, serializers from rest_framework import exceptions, serializers
@ -188,7 +189,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestFormInitSerializer) @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestFormInitSerializer)
def test_init(self, request, pk=None): def test_init(self, request, pk=None):
""" """
检验表单初始化 检验记录创建及初始化
""" """
serializer = WpmTestFormInitSerializer(data=request.data) serializer = WpmTestFormInitSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
@ -198,78 +199,41 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
if wproduct.test: if wproduct.test:
raise exceptions.APIException('存在进行中检验') raise exceptions.APIException('存在进行中检验')
data = RecordFormDetailSerializer(instance=form).data # 根据情况创建一条检验记录
data['origin_test'] = None
data['form'] = form.id
# 如果是复检, 需要带入原数据
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST:
# 查找最近一条检验记录
trs = wproduct.last_process_test
if trs:
origin_test = TestRecordDetailSerializer(instance=trs).data
data['origin_test_'] = origin_test
data['origin_test'] = origin_test.get('id', None)
o_dict = {}
for i in origin_test['record_data']:
o_dict[i['field_key']] = i['field_value']
for i in data['form_fields']:
i['origin_value'] = o_dict[i['field_key']] if i['field_key'] in o_dict else None
i['is_hidden'] = o_dict[i['is_hidden']] if i['is_hidden'] in o_dict else False
else:
raise exceptions.APIException('原工序检验记录不存在')
# 后续加入系统自带数据
return Response(data)
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer)
@transaction.atomic
def test(self, request, pk=None):
"""
检验记录提交
"""
serializer = WpmTestRecordCreateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
record_data = vdata.pop('record_data')
wproduct = vdata['wproduct']
if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST, if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST,
WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST, WProduct.WPR_ACT_STATE_TOCOMBTEST]: WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST, WProduct.WPR_ACT_STATE_TOCOMBTEST]:
raise exceptions.APIException('该产品当前状态不可检验') raise exceptions.APIException('该产品当前状态不可检验')
if 'is_testok' not in vdata:
raise exceptions.APIException('未填写检验结论') savedict = dict(
create_by = self.request.user,
savedict = dict(create_by = self.request.user, wproduct=wproduct,
material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan, step=wproduct.step) material=wproduct.material,
number=wproduct.number,
subproduction_plan=wproduct.subproduction_plan,
step=wproduct.step,
form=form)
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST:
if not vdata['origin_test']: # 查找最近一条检验记录
raise exceptions.APIException('自检记录不存在') trs = wproduct.last_process_test
savedict['origin_test'] = trs
if not trs:
raise exceptions.APIException('原工序检验记录不存在')
savedict['type'] = TestRecord.TEST_PROCESS_RE savedict['type'] = TestRecord.TEST_PROCESS_RE
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST: elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST:
savedict['type'] = TestRecord.TEST_FINAL savedict['type'] = TestRecord.TEST_FINAL
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOCOMBTEST: elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOCOMBTEST:
savedict['type'] = TestRecord.TEST_COMB savedict['type'] = TestRecord.TEST_COMB
obj = serializer.save(**savedict) tr = TestRecord.objects.create(**savedict)
tris = [] wproduct.test = tr
for m in record_data: # 保存记录详情 wproduct.save()
form_field = m['form_field'] # 创建检验条目
m['field_name'] = form_field.field_name for i in RecordFormField.objects.filter(form=form, is_deleted=False):
m['field_key'] = form_field.field_key tri = TestRecordItem()
m['field_type'] = form_field.field_type tri.test_record = tr
m['is_testok'] = m['is_testok'] if 'is_testok' in m else None tri.form_field = i
m['is_hidden'] = m['is_hidden'] if 'is_hidden' in m else None tri.is_hidden = i.is_hidden
m['test_record'] = obj tri.save()
tris.append(TestRecordItem(**m)) return Response(TestRecordDetailSerializer(instance=tr).data)
TestRecordItem.objects.bulk_create(tris)
# 如果提交检验
if obj.is_submited:
WpmServies.update_wproduct_by_test(obj, request.user)
else:
# 保存当前检验
wproduct.test = obj
wproduct.update_by = request.user
wproduct.save()
return Response()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer) @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer)
@transaction.atomic @transaction.atomic
@ -368,12 +332,29 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
wproduct.save() wproduct.save()
return Response() return Response()
@action(methods=['get'], detail=False, perms_map={'post':'*'}) @action(methods=['post'], detail=True, perms_map={'post':'*'})
def scrap(self, request, pk=None):
"""
报废操作
"""
obj = self.get_object()
if obj.ow_wproduct.ow_operation.count() >4 or obj.act_state != WProduct.WPR_ACT_STATE_NOTOK:
raise exceptions.APIException('该产品不支持直接报废')
obj.act_state = WProduct.WPR_ACT_STATE_SCRAP
obj.update_by = request.user
obj.save()
return Response()
@action(methods=['get'], detail=False, perms_map={'get':'*'})
def workflows(self, request, pk=None): def workflows(self, request, pk=None):
""" """
可发起的工作流 可发起的工作流
""" """
wfs = Workflow.objects.get() wfs = Workflow.objects.filter(key__startswith= 'wp')
return WorkflowSimpleSerializer(instance=wfs, many=True).data
class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet): class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
""" """
生产操作记录 生产操作记录
@ -449,6 +430,13 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
opr.form = i opr.form = i
opr.is_filled = False opr.is_filled = False
opr.save() opr.save()
opri_list = []
for m in RecordFormField.objects.filter(form=i, is_deleted=False):
opri_dict = {}
opri_dict['operation_record'] = opr
opri_dict['form_field'] = m
opri_list.append(OperationRecordItem(**opri_dict))
OperationRecordItem.objects.bulk_create(opri_list)
# 查询需要使用的生产设备 # 查询需要使用的生产设备
for i in step.equipments.all(): for i in step.equipments.all():
ope = OperationEquip() ope = OperationEquip()
@ -532,7 +520,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
WProduct.objects.create(**wpr) WProduct.objects.create(**wpr)
elif step.type == Step.STEP_TYPE_COMB: elif step.type == Step.STEP_TYPE_COMB:
oms_w = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT, oms_w = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT,
subproduction_progress__ismain=True) subproduction_progress__is_main=True)
if len(oms_w) == 1: if len(oms_w) == 1:
oms_w = oms_w[0] oms_w = oms_w[0]
# 校验单片数量是否正确, 暂时未写 # 校验单片数量是否正确, 暂时未写
@ -555,7 +543,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
wps = WProduct.objects.filter(ow_wproduct__operation = op) wps = WProduct.objects.filter(ow_wproduct__operation = op)
wps.update(is_hidden=True, child=wproduct, update_by=request.user, update_time=timezone.now()) wps.update(is_hidden=True, child=wproduct, update_by=request.user, update_time=timezone.now())
else: else:
raise exceptions.APIException('产出物料错误') raise exceptions.APIException('产出物料未填写或填写错误')
op.is_submited = True op.is_submited = True
op.save() op.save()
return Response() return Response()
@ -614,7 +602,7 @@ class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin,
instance.delete() instance.delete()
return Response() return Response()
class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet): class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin, GenericViewSet):
""" """
操作使用的自定义表格 操作使用的自定义表格
""" """
@ -628,6 +616,8 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin
def get_serializer_class(self): def get_serializer_class(self):
if self.action == 'update': if self.action == 'update':
return OperationRecordSubmitSerializer return OperationRecordSubmitSerializer
elif self.action == 'retrieve':
return OperationRecordDetailSerializer
return super().get_serializer_class() return super().get_serializer_class()
@transaction.atomic() @transaction.atomic()
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
@ -637,16 +627,6 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin
instance.delete() instance.delete()
return Response() return Response()
@action(methods=['get'], detail=True, perms_map={'get':'*'})
def init(self, request, pk=None):
'''
表格初始化
'''
obj = self.get_object()
data = RecordFormDetailSerializer(instance=obj.form).data
# 后续加入系统带入数据
return Response(data)
def update(self, request, *args, **kwargs): def update(self, request, *args, **kwargs):
serializer = OperationRecordSubmitSerializer(data=request.data) serializer = OperationRecordSubmitSerializer(data=request.data)
@ -655,18 +635,12 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin
opr = self.get_object() opr = self.get_object()
if opr.operation.is_submited: if opr.operation.is_submited:
raise exceptions.APIException('操作已提交不可修改') raise exceptions.APIException('操作已提交不可修改')
wrds = [] for i in vdata['record_data']:
for m in vdata['record_data']: # 保存记录详情 ori = i['id']
form_field = m['form_field'] ori.field_value = i['field_value']
m['form_field'] = form_field ori.save()
m['field_name'] = form_field.field_name
m['field_key'] = form_field.field_key
m['field_type'] = form_field.field_type
m['sort'] = form_field.sort
m['operation_record'] = opr
wrds.append(OperationRecordItem(**m))
OperationRecordItem.objects.bulk_create(wrds)
opr.is_filled = True opr.is_filled = True
opr.update_by = request.user
opr.save() opr.save()
return Response() return Response()