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

This commit is contained in:
shijing 2022-02-10 09:24:34 +08:00
commit 37b874036f
26 changed files with 829 additions and 303 deletions

61
hb_client/src/api/pum.js Normal file
View File

@ -0,0 +1,61 @@
import request from '@/utils/request'
export function getPuorderList(query) {
return request({
url: '/pum/pu_order/',
method: 'get',
params: query
})
}
export function createPuorder(data) {
return request({
url: '/pum/pu_order/',
method: 'post',
data
})
}
export function updatePuorder(id, data) {
return request({
url: `/pum/pu_order/${id}/`,
method: 'put',
data
})
}
export function deletePuorder(id, data) {
return request({
url: `/pum/pu_order/${id}/`,
method: 'delete',
data
})
}
//采购订单审核
export function createPuorderAudit(id,data) {
return request({
url: `/pum/pu_order/${id}/audit/`,
method: 'post',
data
})
}
//采购订单条目
export function getPuorderItemList(query) {
return request({
url: '/pum/pu_order_item/',
method: 'get',
params: query
})
}
export function createPuorderItem(data) {
return request({
url: '/pum/pu_order_item/',
method: 'post',
data
})
}
//采购订单条目删除
export function deletePuorderItem(id, data) {
return request({
url: `/pum/pu_order_item/${id}/`,
method: 'delete',
data
})
}

View File

@ -501,10 +501,17 @@ export const asyncRoutes = [
meta: { title: '供应商', icon: 'example', perms: ['vendor_manage'] }
},
{
path: 'vendor',
name: 'vendor',
component: () => import('@/views/procurement/vendor'),
path: 'puorder',
name: 'puorder',
component: () => import('@/views/procurement/puorder'),
meta: { title: '采购订单', icon: 'example', perms: ['vendor_manage'] }
},
{
path: 'puorderitem/:id',
name: 'puorderitem',
component: () => import('@/views/procurement/puorderitem'),
meta: { title: '采购订单项', perms: ['vendor_manage'] },
hidden: true
}
]
},

View File

@ -0,0 +1,292 @@
<template>
<div class="app-container">
<el-card>
<div>
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增采购订单</el-button
>
<el-input
v-model="listQuery.search"
placeholder="采购订单编号、供应商名称"
style="width: 300px"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索</el-button
>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>重置</el-button
>
</div>
</el-card>
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="puorderList.results"
border
fit
stripe
highlight-current-row
max-height="700"
height="100"
v-el-height-adaptive-table="{ bottomOffset: 43 }"
>
<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" v-if="scope.row.vendor_">{{
scope.row.vendor_.name
}}</template>
</el-table-column>
<el-table-column label="审核情况" width="150">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_audited == false">未审核</el-tag>
<el-tag v-else-if="scope.row.is_audited == true">已审核</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="220px">
<template slot-scope="scope">
<el-link
v-if="checkPermission(['vendor_update'])"
type="primary"
@click="handlePuOrderItem(scope)"
>订单项</el-link
>
<el-link
v-if="
checkPermission(['vendor_update']) &&
scope.row.is_audited == false
"
type="primary"
@click="handleAudit(scope)"
>审核</el-link
>
<el-link
v-if="checkPermission(['vendor_update'])"
type="primary"
@click="handleEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['vendor_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="puorderList.count > 0"
:total="puorderList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
:title="dialogType === 'edit' ? '编辑采购订单' : '新增采购订单'"
>
<el-form
ref="Form"
:model="puorder"
label-width="120px"
label-position="right"
:rules="rule1"
>
<el-form-item label="订单编号" prop="number">
<el-input v-model="puorder.number" placeholder="订单编号" />
</el-form-item>
<el-form-item label="供应商" prop="vendor">
<el-select
style="width: 100%"
v-model="puorder.vendor"
placeholder="请选择"
>
<el-option
v-for="item in vendorList"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getpVendorList } from "@/api/vendor";
import { getUserList } from "@/api/user";
import {
getPuorderList,
createPuorder,
updatePuorder,
deletePuorder,
createPuorderAudit,
createPuorderItem,
deletePuorderItem,
} from "@/api/pum";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultpuorder = {
number: "",
};
export default {
components: { Pagination },
data() {
return {
puorder: defaultpuorder,
puorderList: {
count: 0,
},
listQuery: {
page: 1,
page_size: 20,
},
vendorList: [],
dialogVisible: false,
dialogType: "new",
rule1: {
number: [{ required: true, message: "请输入", trigger: "blur" }],
vendor: [
{ required: true, message: "请选择供应商", trigger: "change" },
],
},
};
},
computed: {},
watch: {},
created() {
this.getList();
this.getVendorList();
},
methods: {
checkPermission,
//采购订单
getList() {
this.listLoading = true;
getPuorderList(this.listQuery).then((response) => {
if (response.data) {
this.puorderList = response.data;
}
this.listLoading = false;
});
},
//供应商列表
getVendorList() {
getpVendorList({ page: 0 }).then((response) => {
if (response.data) {
this.vendorList = response.data;
}
});
},
handleFilter() {
this.listQuery.page = 1;
this.getList();
},
resetFilter() {
this.listQuery = {
page: 1,
page_size: 20,
};
this.getList();
},
handleCreate() {
this.puorder = Object.assign({}, defaultpuorder);
this.dialogType = "new";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.puorder = 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 deletePuorder(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
async confirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogType === "edit";
if (isEdit) {
updatePuorder(this.puorder.id, this.puorder).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
} else {
createPuorder(this.puorder).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
handlePuOrderItem(scope) {
this.$router.push({ name: "puorderitem", params: { id: scope.row.id } });
},
handleAudit(scope) {
createPuorderAudit(scope.row.id).then((res) => {
if (res.code >= 200) {
this.getList();
this.$message.success("审核成功!");
}
});
},
},
};
</script>

View File

@ -0,0 +1,197 @@
<template>
<div class="app-container">
<el-card>
<div>
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增采购订单项</el-button
>
</div>
</el-card>
<el-card style="margin-top: 2px">
<el-table
v-loading="listLoading"
:data="puorderTtemList.results"
border
fit
stripe
highlight-current-row
max-height="700"
height="100"
v-el-height-adaptive-table="{ bottomOffset: 43 }"
>
<el-table-column type="index" width="50" />
<el-table-column label="物料名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column>
<el-table-column label="物料型号">
<template slot-scope="scope">{{ scope.row.material_.specification }}</template>
</el-table-column>
<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.delivered_count }}</template>
</el-table-column>
<el-table-column label="截止到货时间">
<template slot-scope="scope">{{ scope.row.delivery_date }}</template>
</el-table-column>
<el-table-column align="center" label="操作" width="220px">
<template slot-scope="scope">
<el-link
v-if="checkPermission(['vendor_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="puorderTtemList.count > 0"
:total="puorderTtemList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-card>
<el-dialog :visible.sync="dialogVisible" title="新增采购订单项">
<el-form
ref="Form"
:model="puorderTtem"
label-width="120px"
label-position="right"
:rules="rule1"
>
<el-form-item label="所需数量" prop="number">
<el-input v-model="puorderTtem.count" placeholder="所需数量" />
</el-form-item>
<el-form-item label="截止到货时间" prop="delivery_date">
<el-date-picker
v-model="puorderTtem.delivery_date"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
>
</el-date-picker>
</el-form-item>
<el-form-item class="material" label="采购物料:" :prop="material">
<el-select v-model="puorderTtem.material" filterable size="small">
<el-option
v-for="item in materialoptions"
:key="item.id"
:value="item.id"
:label="item.name"
>
</el-option>
</el-select>
</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">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getpVendorList } from "@/api/vendor";
import { getMaterialList } from "@/api/mtm";
import {
getPuorderItemList,
createPuorderItem,
deletePuorderItem,
} from "@/api/pum";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultpuorderItem = {
pu_order:null,
};
export default {
components: { Pagination },
data() {
return {
puorderTtem: defaultpuorderItem,
puorderTtemList: {
count: 0,
},
materialoptions: [],
listQuery: {
page: 1,
page_size: 20,
},
dialogVisible:false,
rule1: {
delivery_date: [{ required: true, message: "请选择日期", trigger: "blur" }],
material: [
{ required: true, message: "请选择物料", trigger: "change" },
],
},
};
},
computed: {},
watch: {},
created() {
this.id = this.$route.params.id;
this.getList();
this.getmaterialList();
},
methods: {
checkPermission,
//采购订单列表
getList() {
this.listQuery.pu_order= this.id;
getPuorderItemList(this.listQuery).then((response) => {
if (response.data) {
this.puorderTtemList = response.data;
}
});
},
//物料
getmaterialList() {
getMaterialList({ page: 0 }).then((response) => {
if (response.data) {
this.materialoptions = response.data;
}
});
},
handleCreate() {
this.puorderTtem = Object.assign({}, defaultpuorderItem);
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
async confirm() {
this.puorderTtem.pu_order=this.id
createPuorderItem(this.puorderTtem).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deletePuorderItem(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
},
};
</script>

View File

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

View File

@ -10,7 +10,7 @@ from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.sam.models import Order
from apps.wf.models import Ticket
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow
from apps.wpm.services import WpmServies
from apps.wpm.services import WpmService
from apps.em.tasks import update_equip_state_by_next_check_date
# Create your views here.
@ -46,7 +46,7 @@ class UpdateCuttingView(APIView):
i.coperation = op
i.save()
WproductFlow.objects.filter(wproduct=i).update(coperation=op)
WpmServies.update_cutting_list_with_operation(op)
WpmService.update_cutting_list_with_operation(op)
return Response()
from apps.qm.models import TestRecord
@ -90,7 +90,7 @@ class UpdateSpg(APIView):
冷加工重新计算合格率
"""
for i in SubProductionPlan.objects.filter(subproduction__process__id=1):
WpmServies.update_subproduction_progress_main(sp=i)
WpmService.update_subproduction_progress_main(sp=i)
return Response()

View File

@ -67,11 +67,13 @@ class FIFO(CommonADModel):
FIFO_TYPE_SALE_OUT = 2
FIFO_TYPE_PUR_IN = 3
FIFO_TYPE_DO_IN = 4
FIFO_TYPE_OTHER_IN = 5
type_choices = (
(FIFO_TYPE_DO_OUT, '生产领料'),
(FIFO_TYPE_SALE_OUT, '销售提货'),
(FIFO_TYPE_PUR_IN, '采购入库'),
(FIFO_TYPE_DO_IN, '生产入库')
(FIFO_TYPE_DO_IN, '生产入库'),
(FIFO_TYPE_OTHER_IN, '其他入库')
)
number = models.CharField('记录编号', max_length=100)
type = models.IntegerField('出入库类型', default=1)

View File

@ -80,7 +80,7 @@ class FIFOItemCreateSerializer(serializers.ModelSerializer):
class Meta:
model = FIFOItem
fields = ['warehouse',
'material', 'batch', 'fifo', 'files', 'pu_order_item']
'material', 'batch', 'fifo', 'files', 'pu_order_item', 'count']
def create(self, validated_data):
fifo = validated_data['fifo']
@ -97,7 +97,7 @@ class FIFOItemCreateSerializer(serializers.ModelSerializer):
class FIFOItemUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = FIFOItem
fields = ['warehouse', 'batch', 'files']
fields = ['warehouse', 'batch', 'files', 'count']
class FIFOItemSerializer(serializers.ModelSerializer):
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)

View File

@ -25,7 +25,8 @@ class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
仓库-增删改查
"""
perms_map = {'*': '*'}
perms_map = {'get': '*', 'post':'warehouse_create',
'put':'warehouse_update', 'delete':'warehouse_delete'}
queryset = WareHouse.objects.select_related('create_by').all()
serializer_class = WareHouseSerializer
search_fields = ['name', 'number', 'place']
@ -43,7 +44,7 @@ class InventoryViewSet(ListModelMixin, GenericViewSet):
"""
仓库物料表
"""
perms_map = {'*': '*'}
perms_map = {'get': '*'}
queryset = Inventory.objects.select_related(
'material', 'warehouse').filter(count__gt=0).all()
serializer_class = InventorySerializer
@ -54,7 +55,7 @@ class InventoryViewSet(ListModelMixin, GenericViewSet):
class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
perms_map = {'*': '*'}
perms_map = {'get': '*'}
queryset = MaterialBatch.objects.select_related(
'material', 'warehouse').filter(count__gt=0).all()
serializer_class = MaterialBatchSerializer
@ -81,7 +82,8 @@ class FIFOItemViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, Updat
"""
出入库记录详情表
"""
perms_map = {'*': '*'}
perms_map = {'get': '*', 'post':'fifoitem_create',
'put':'fifoitem_update', 'delete':'fifoitem_delete'}
queryset = FIFOItem.objects.select_related('material', 'fifo').prefetch_related('files').all()
serializer_class = FIFOItemSerializer
filterset_fields = ['material', 'fifo',
@ -115,7 +117,7 @@ class FIFOItemViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, Updat
raise ValidationError('该出入库记录已审核')
return super().destroy(request, *args, **kwargs)
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=InmTestRecordCreateSerializer)
@action(methods=['post'], detail=False, perms_map={'post': 'fifoitem_test'}, serializer_class=InmTestRecordCreateSerializer)
def test(self, request, pk=None):
"""
检验
@ -147,7 +149,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
"""
出入库记录
"""
perms_map = {'*': '*'}
perms_map = {'get': '*', 'delete':'fifo_delete'}
queryset = FIFO.objects.select_related('auditor', 'create_by')
serializer_class = FIFOListSerializer
filterset_fields = '__all__'
@ -166,7 +168,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
raise exceptions.APIException('该记录已审核,不可删除')
return super().destroy(request, *args, **kwargs)
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=FIFOInPurSerializer)
@action(methods=['post'], detail=False, perms_map={'post': 'fifo_in_pur'}, serializer_class=FIFOInPurSerializer)
def in_pur(self, request, pk=None):
"""
采购入库
@ -176,7 +178,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
serializer.save(create_by=request.user)
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'},
@action(methods=['post'], detail=False, perms_map={'post': 'fifo_in_other'},
serializer_class=FIFOInOtherSerializer)
def in_other(self, request, pk=None):
"""
@ -187,7 +189,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
serializer.save(create_by=request.user)
return Response()
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=serializers.Serializer)
@action(methods=['post'], detail=True, perms_map={'post': 'fifo_audit'}, serializer_class=serializers.Serializer)
def audit(self, request, pk=None):
"""
审核通过
@ -213,7 +215,7 @@ class IProductViewSet(ListModelMixin, GenericViewSet):
"""
半成品库存表
"""
perms_map = {'*': '*'}
perms_map = {'get': '*'}
queryset = IProduct.objects.select_related(
'material', 'warehouse',
'wproduct__subproduction_plan__production_plan__order',

View File

@ -45,7 +45,7 @@ def get_file_list(file_path):
return dir_list
class LogView(APIView):
permission_classes = [IsAuthenticated]
@swagger_auto_schema(manual_parameters=[
openapi.Parameter('name', openapi.IN_QUERY, description='日志文件名', type=openapi.TYPE_STRING)
])
@ -82,7 +82,7 @@ class LogView(APIView):
class LogDetailView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, name):
"""
查看日志详情

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-01-29 07:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0044_subproduction_need_combtest'),
]
operations = [
migrations.AddField(
model_name='usedstep',
name='need_test',
field=models.BooleanField(default=False, verbose_name='工序内检验'),
),
]

View File

@ -242,6 +242,7 @@ class UsedStep(CommonADModel):
涉及的生产子工序
"""
step = models.ForeignKey(Step, verbose_name='子工序', on_delete=models.CASCADE, related_name='usedstep')
need_test = models.BooleanField('工序内检验', default=False)
remark = models.TextField('生产备注', null=True, blank=True)
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='usedstep_subproduction')

View File

@ -3,7 +3,7 @@ from apps.mtm.models import Material, Step
from apps.pm.models import ProductionPlan, SubProductionProgress
from apps.wpm.models import Operation, WProduct
from datetime import *
from apps.wpm.services import WpmServies
from apps.wpm.services import WpmService
from django.db.models import F
from utils.mixins import DynamicFieldsFilterMixin
@ -52,9 +52,9 @@ class SubproductionProgressFilterSet(filters.FilterSet):
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
step = operation.step
if wproducts.exists():
subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts)
subplans = WpmService.get_subplans_queryset_from_wproducts(wproducts)
else:
subplans = WpmServies.get_subplans_queyset_from_step(step)
subplans = WpmService.get_subplans_queyset_from_step(step)
queryset = queryset.filter(subproduction_plan__in=subplans)
if step.type == Step.STEP_TYPE_NOM:
queryset = queryset.exclude(material__type__in =[Material.MA_TYPE_HALFGOOD, Material.MA_TYPE_GOOD])

View File

@ -89,7 +89,8 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number')
for index, i in enumerate(subps):
steps = Step.objects.filter(usedstep__subproduction=i, usedstep__subproduction__is_deleted=False,
usedstep__is_deleted=False, is_deleted=False).values('id', 'number', 'name', 'usedstep__remark')
usedstep__is_deleted=False, is_deleted=False
).values('id', 'number', 'name', 'usedstep__remark', need_test=F('usedstep__need_test'))
instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i,
start_date=production_plan.start_date, end_date=production_plan.end_date,
workshop=i.process.workshop, process=i.process, create_by=request.user,

View File

@ -0,0 +1,36 @@
# Generated by Django 3.2.9 on 2022-01-29 07:12
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('qm', '0022_auto_20211216_1401'),
]
operations = [
migrations.AddField(
model_name='testrecord',
name='is_midtesing',
field=models.BooleanField(default=False, verbose_name='是否子工序检验中'),
),
migrations.AddField(
model_name='testrecorditem',
name='create_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecorditem_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
),
migrations.AddField(
model_name='testrecorditem',
name='update_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecorditem_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
),
migrations.AlterField(
model_name='testrecord',
name='type',
field=models.PositiveSmallIntegerField(choices=[(20, '工序检验'), (30, '工序复检'), (36, '夹层检验'), (40, '成品检验')], default=20),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-01-29 07:24
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('qm', '0023_auto_20220129_1512'),
]
operations = [
migrations.RenameField(
model_name='testrecord',
old_name='is_midtesing',
new_name='is_midtesting',
),
]

View File

@ -47,13 +47,11 @@ class TestRecord(CommonADModel):
"""
检验记录
"""
TEST_STEP = 10
TEST_PROCESS = 20
TEST_PROCESS_RE = 30
TEST_COMB = 36
TEST_FINAL = 40
type_choice = (
(TEST_STEP, '子工序检验'),
(TEST_PROCESS, '工序检验'),
(TEST_PROCESS_RE, '工序复检'),
(TEST_COMB, '夹层检验'),
@ -70,6 +68,7 @@ class TestRecord(CommonADModel):
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)
is_submited = models.BooleanField('是否提交', default=False)
is_midtesting = models.BooleanField('是否子工序检验中', default=False)
remark = models.TextField('备注', default='')

View File

@ -135,7 +135,7 @@ class TestRecordUpdateSerializer(serializers.ModelSerializer):
if i['field_value'] != tri.field_value:
tri.field_value = i['field_value']
tri.update_by = update_by
tri.is_testok = i['is_testok']
tri.is_hidden = i['is_hidden']
tri.save()
tri.is_testok = i['is_testok']
tri.is_hidden = i['is_hidden']
tri.save()
return instance

View File

@ -12,7 +12,7 @@ from django.db import transaction
from rest_framework.decorators import action
from apps.wpm.models import WProduct
from apps.wpm.services import WpmServies
from apps.wpm.services import WpmService
# Create your views here.
class StandardViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
@ -69,7 +69,7 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De
def update(self, request, *args, **kwargs):
obj = self.get_object()
if obj.is_submited:
if obj.is_submited and obj.is_midtesting is False:
raise exceptions.APIException('该记录已提交不可编辑')
return super().update(request, *args, **kwargs)
@ -77,20 +77,22 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De
obj = self.get_object()
if obj.is_submited:
raise exceptions.APIException('该记录已提交不可删除')
WpmServies.add_wproduct_flow_log(obj.wproduct, 'test_delete')
WpmService.add_wproduct_flow_log(obj.wproduct, 'test_delete')
return super().destroy(request, *args, **kwargs)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=TestRecordUpdateSerializer)
def submit(self, request, pk=None):
obj = self.get_object()
if obj.is_submited and obj.is_midtesting is False:
raise exceptions.APIException('该记录已提交')
# 校验是否有未填项目
if obj.type != TestRecord.TEST_PROCESS_RE:
if obj.type != TestRecord.TEST_PROCESS_RE and obj.is_midtesting is False:
if TestRecordItem.objects.filter(field_value__isnull=True, is_hidden=False, test_record=obj).exists():
raise exceptions.APIException('存在未填写项目')
with transaction.atomic():
obj.is_submited=True
obj.save()
WpmServies.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算
WpmService.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算
return Response()
# def create(self, request, *args, **kwargs):

View File

@ -1,7 +1,7 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material, Step
from apps.wpm.services import WpmServies
from apps.wpm.services import WpmService
from utils.mixins import DynamicFieldsFilterMixin
from .models import Operation, OperationMaterial, OperationRecord, WMaterial, WProduct
@ -20,10 +20,10 @@ class WMaterialFilterSet(filters.FilterSet):
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
step = operation.step
if wproducts.exists():
subplans = WpmServies.get_subplans_queryset_from_wproducts(
subplans = WpmService.get_subplans_queryset_from_wproducts(
wproducts)
else:
subplans = WpmServies.get_subplans_queyset_from_step(step)
subplans = WpmService.get_subplans_queyset_from_step(step)
queryset = queryset.filter(subproduction_plan__in=subplans).exclude(
material__type=Material.MA_TYPE_HALFGOOD)
return queryset

View File

@ -0,0 +1,65 @@
# Generated by Django 3.2.9 on 2022-01-29 07:12
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0045_usedstep_need_test'),
('wpm', '0052_auto_20220125_1116'),
]
operations = [
migrations.AddField(
model_name='wproduct',
name='material_check',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_material_check', to='mtm.material', verbose_name='按物料状态检查'),
),
migrations.AddField(
model_name='wproductflow',
name='material_check',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_material_check', to='mtm.material', verbose_name='按物料状态检查'),
),
migrations.AlterField(
model_name='wproduct',
name='child',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_child', to='wpm.wproduct'),
),
migrations.AlterField(
model_name='wproduct',
name='material',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wp_material', to='mtm.material', verbose_name='所属物料状态'),
),
migrations.AlterField(
model_name='wproduct',
name='pre_step',
field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_pre_step', to='mtm.step', verbose_name='已执行到'),
),
migrations.AlterField(
model_name='wproduct',
name='step',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_step', to='mtm.step', verbose_name='所在步骤'),
),
migrations.AlterField(
model_name='wproductflow',
name='child',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_child', to='wpm.wproductflow'),
),
migrations.AlterField(
model_name='wproductflow',
name='material',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wpf_material', to='mtm.material', verbose_name='所属物料状态'),
),
migrations.AlterField(
model_name='wproductflow',
name='pre_step',
field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_pre_step', to='mtm.step', verbose_name='已执行到'),
),
migrations.AlterField(
model_name='wproductflow',
name='step',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_step', to='mtm.step', verbose_name='所在步骤'),
),
]

View File

@ -1,4 +1,5 @@
import re
from rest_framework import exceptions
from django.db import models
from django.db.models.base import Model
@ -88,16 +89,20 @@ class WProduct(CommonAModel):
number = models.CharField(
'物品编号', unique=True, null=True, blank=True, max_length=50)
material = models.ForeignKey(
Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
Material, verbose_name='所属物料状态', on_delete=models.CASCADE,
related_name='wp_material')
material_check = models.ForeignKey(
Material, verbose_name='按物料状态检查', on_delete=models.CASCADE,
null=True, blank=True, related_name='wp_material_check')
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
on_delete=models.CASCADE, related_name='w_pre_step')
on_delete=models.CASCADE, related_name='wp_pre_step')
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
related_name='w_step')
related_name='wp_step')
act_state = models.IntegerField(
'进行状态', default=0, choices=act_state_choices)
is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True,
on_delete=models.CASCADE, related_name='wproduct_child')
on_delete=models.CASCADE, related_name='wp_child')
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
related_name='wproduct_subplan')
@ -164,16 +169,19 @@ class WproductFlow(CommonAModel):
WProduct, on_delete=models.CASCADE, verbose_name='关联产品', null=True, blank=True)
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(
Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
Material, verbose_name='所属物料状态', on_delete=models.CASCADE, related_name='wpf_material')
material_check = models.ForeignKey(
Material, verbose_name='按物料状态检查', on_delete=models.CASCADE,
null=True, blank=True, related_name='wpf_material_check')
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
on_delete=models.CASCADE, related_name='wl_pre_step')
on_delete=models.CASCADE, related_name='wpf_pre_step')
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
related_name='wl_step')
related_name='wpf_step')
act_state = models.IntegerField(
'进行状态', default=0, choices=WProduct.act_state_choices)
is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True,
on_delete=models.CASCADE, related_name='wproduct_child')
on_delete=models.CASCADE, related_name='wpf_child')
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(
SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)

View File

@ -9,19 +9,21 @@ from apps.system.models import User
from apps.wf.models import State, TicketFlow, Transition
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow, WprouctTicket
from utils.tools import ranstr
class WpmServies(object):
class WpmService(object):
@classmethod
def get_next_step(cls, subproduction_plan:SubProductionPlan, nowstep:Step):
"""
获取下一步骤
"""
stepIds = [i['id'] for i in subproduction_plan.steps]
steps_list = subproduction_plan.steps
stepIds = [i['id'] for i in steps_list]
pindex = stepIds.index(nowstep.id)
need_test = steps_list[pindex].get('need_test', False)
if pindex + 1 < len(stepIds):
return Step.objects.get(pk=stepIds[pindex+1]), True
return Step.objects.get(pk=stepIds[pindex+1]), need_test
else:
return nowstep, False
return nowstep, need_test
@classmethod
def get_subplans_queryset_from_wproducts(cls, wproducts:List):
@ -47,9 +49,15 @@ class WpmServies(object):
"""
is_testok = test.is_testok
wproduct = test.wproduct
test_i = None
if is_testok:
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and \
test.is_midtesing is True:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
test_i = test
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: # 成品检验
wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST
@ -97,7 +105,7 @@ class WpmServies(object):
wproduct.update_by = user
wproduct.update_time = timezone.now()
wproduct.test = None
wproduct.test = test_i
wproduct.last_test_result = is_testok
wproduct.save()
# 添加日志

View File

@ -8,7 +8,7 @@ from django.dispatch import receiver
from rest_framework import exceptions
from apps.wpm.models import WProduct, WproductFlow, WprouctTicket
from apps.wpm.models import OperationWproduct
from apps.wpm.services import WpmServies
from apps.wpm.services import WpmService
@receiver(post_save, sender=Ticket)
@ -34,7 +34,7 @@ def handleTicket(sender, instance, created, **kwargs):
# 工单绑定半成品
wproduct.ticket = instance
wproduct.save()
WpmServies.add_wproduct_flow_log(wproduct, 'ticket_create')
WpmService.add_wproduct_flow_log(wproduct, 'ticket_create')
elif instance.act_state == Ticket.TICKET_ACT_STATE_FINISH:
@ -77,7 +77,7 @@ def handleTicket(sender, instance, created, **kwargs):
wp.save()
# 添加日志
WpmServies.add_wproduct_flow_log(wp, 'ticket_finish')
WpmService.add_wproduct_flow_log(wp, 'ticket_finish')
# 更新子计划合格进度
WpmServies.update_subproduction_progress_main(sp=wp.subproduction_plan)
WpmService.update_subproduction_progress_main(sp=wp.subproduction_plan)

View File

@ -3,7 +3,7 @@ from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.wpm.views import CuttingListViewSet, DoFormInit, DoFormSubmit, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet, WproductTicketViewSet
from apps.wpm.views import CuttingListViewSet, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet, WproductTicketViewSet
router = DefaultRouter()
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
@ -19,8 +19,6 @@ router.register('operation_tool', OperationMaterialToolViewSet, basename='operat
router.register('subplan', WPlanViewSet, basename='wplan')
router.register('cutting_list', CuttingListViewSet, basename='cutting_list')
urlpatterns = [
path('do/init/', DoFormInit.as_view()),
path('do/submit/', DoFormSubmit.as_view()),
path('', include(router.urls)),
]

View File

@ -32,7 +32,7 @@ from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerial
from rest_framework.response import Response
from django.db import transaction
from rest_framework import exceptions, serializers
from apps.wpm.services import WpmServies
from apps.wpm.services import WpmService
from django.utils import timezone
from rest_framework import status
from django.db.models import Count
@ -105,7 +105,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
m.update_by = request.user
m.update_time = timezone.now()
m.save()
WpmServies.add_wproduct_flow_log(
WpmService.add_wproduct_flow_log(
instance=m, change_str='pick_half')
pw = PickWproduct()
pw.pick = pick
@ -151,7 +151,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
perms_map = {'*': '*'}
queryset = WProduct.objects.select_related('step', 'material',
'subproduction_plan', 'warehouse', 'subproduction_plan__production_plan__order',
'to_order').prefetch_related('wproduct_child')
'to_order').prefetch_related('wp_child')
serializer_class = WProductListSerializer
filterset_class = WProductFilterSet
search_fields = ['number']
@ -188,7 +188,6 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST,
WProduct.WPR_ACT_STATE_TOCOMBTEST]:
raise exceptions.APIException('该产品当前状态不可检验')
savedict = dict(
create_by=request.user,
wproduct=wproduct,
@ -208,13 +207,16 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
savedict['type'] = TestRecord.TEST_FINAL
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOCOMBTEST:
savedict['type'] = TestRecord.TEST_COMB
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and\
wproduct.step != wproduct.pre_step: # 如果是工序内检验
savedict['is_midtesting'] = True
tr = TestRecord.objects.create(**savedict)
# 更新wproduct
wproduct.test = tr
wproduct.update_by = request.user
wproduct.update_time = timezone.now()
wproduct.save()
WpmServies.add_wproduct_flow_log(wproduct, 'test_init')
WpmService.add_wproduct_flow_log(wproduct, 'test_init')
# 创建检验条目
for i in RecordFormField.objects.filter(form=form, is_deleted=False):
tri = TestRecordItem()
@ -224,6 +226,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
tri.create_by = request.user
tri.save()
return Response(TestRecordDetailSerializer(instance=tr).data)
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductPutInsSerializer)
@transaction.atomic
@ -281,7 +284,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
i.update_by = request.user
i.update_time = timezone.now()
i.save()
WpmServies.add_wproduct_flow_log(i, 'putins')
WpmService.add_wproduct_flow_log(i, 'putins')
return Response()
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=WproductPutInSerializer)
@ -328,7 +331,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
wproduct.act_state = WProduct.WPR_ACT_STATE_INM
wproduct.warehouse = warehouse
wproduct.save()
WpmServies.add_wproduct_flow_log(wproduct, 'putin')
WpmService.add_wproduct_flow_log(wproduct, 'putin')
return Response()
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=ScrapSerializer)
@ -354,9 +357,9 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
obj.update_by = request.user
obj.update_time = timezone.now()
obj.save()
WpmServies.add_wproduct_flow_log(obj, 'scrap')
WpmService.add_wproduct_flow_log(obj, 'scrap')
if obj.step.process.id == 1: # 如果是冷加工
WpmServies.update_cutting_list_with_operation(obj.coperation)
WpmService.update_cutting_list_with_operation(obj.coperation)
return Response()
# @action(methods=['get'], detail=False, perms_map={'get':'*'})
@ -411,14 +414,14 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
is_mtestok = request.data.get('is_mtestok')
obj.is_mtestok = is_mtestok
if is_mtestok:
WpmServies.update_plan_state_by_mtestok(
WpmService.update_plan_state_by_mtestok(
obj.subproduction_plan.production_plan)
obj.update_by = request.user
obj.save()
change_str = 'mtest_notok'
if is_mtestok:
change_str = 'mtest_ok'
WpmServies.add_wproduct_flow_log(instance=obj, change_str=change_str)
WpmService.add_wproduct_flow_log(instance=obj, change_str=change_str)
return Response()
@action(methods=['get'], detail=True, perms_map={'get': '*'})
@ -461,7 +464,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
i.need_to_order = True
i.update_by = request.user
i.save()
WpmServies.add_wproduct_flow_log(i, change_str='need_to_order')
WpmService.add_wproduct_flow_log(i, change_str='need_to_order')
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductToOrderSerializer)
@ -486,7 +489,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
i.to_order = order
i.update_by = request.user
i.save()
WpmServies.add_wproduct_flow_log(i,change_str='to_order')
WpmService.add_wproduct_flow_log(i,change_str='to_order')
return Response()
class WproductTicketViewSet(ListModelMixin, GenericViewSet):
@ -544,7 +547,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
i.act_state = WProduct.WPR_ACT_STATE_DOWAIT
i.update_by = request.user
i.save()
WpmServies.add_wproduct_flow_log(i, 'operation_delete')
WpmService.add_wproduct_flow_log(i, 'operation_delete')
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
@ -565,14 +568,14 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 创建操作所用半成品关联记录
if 'wproducts' in vdata:
owps = []
splans = WpmServies.get_subplans_queryset_from_wproducts(
splans = WpmService.get_subplans_queryset_from_wproducts(
vdata['wproducts'])
for wpd in vdata['wproducts']:
wpd.operation = op
wpd.act_state = WProduct.WPR_ACT_STATE_DOING
wpd.update_by = request.user
wpd.save()
WpmServies.add_wproduct_flow_log(wpd, 'operation_create')
WpmService.add_wproduct_flow_log(wpd, 'operation_create')
owp = {}
owp['operation'] = op
owp['wproduct'] = wpd
@ -583,7 +586,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps)
else:
splans = WpmServies.get_subplans_queryset_from_wproducts(
splans = WpmService.get_subplans_queryset_from_wproducts(
vdata['wproducts'])
# 查询需要填写的自定义表格
forms = RecordForm.objects.filter(
@ -677,22 +680,31 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
wsp = i.subproduction_plan
# 获取下一步子工序
newstep, hasNext = WpmServies.get_next_step(wsp, step)
newstep, needTest = WpmService.get_next_step(wsp, step)
wp.step = newstep
wp.pre_step = step
if hasNext:
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else:
if step == newstep:
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material = wsp.product
if wp.test:# 如果有正在进行的工序中检验
wp.test.is_midtesting = False
wp.test.is_submited = False
wp.test.save()
else:
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
if needTest:
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material_check = wsp.product
wp.operation = None
wp.update_by = request.user
wp.save()
WpmServies.add_wproduct_flow_log(wp, 'operation_submit')
WpmService.add_wproduct_flow_log(wp, 'operation_submit')
for i in ows.values('subproduction_plan').distinct():
# 更新进度
WpmServies.update_subproduction_progress_main(sp=wsp)
WpmService.update_subproduction_progress_main(sp=wsp)
elif step.type == Step.STEP_TYPE_DIV:
# 更新物料产出情况
@ -700,7 +712,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
raise exceptions.APIException('请选择物料产出')
for i in omos:
if i.subproduction_progress.is_main:
newstep, _ = WpmServies.get_next_step(
newstep, _ = WpmService.get_next_step(
i.subproduction_plan, step)
wpr = dict(material=i.material, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
@ -709,33 +721,41 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
for x in range(i.count):
ins = WProduct.objects.create(**wpr)
# 添加日志
WpmServies.add_wproduct_flow_log(
WpmService.add_wproduct_flow_log(
ins, 'wproduct_create')
# 更新进度
WpmServies.update_subproduction_progress_main(
WpmService.update_subproduction_progress_main(
sp=i.subproduction_plan)
elif step.type == Step.STEP_TYPE_COMB:
oms_w = omos.filter(subproduction_progress__is_main=True)
if len(oms_w) == 1:
oms_w = oms_w[0]
# 校验单片数量是否正确, 暂时未写
newstep, hasNext = WpmServies.get_next_step(
newstep, needTest = WpmService.get_next_step(
oms_w.subproduction_plan, step)
wproduct = WProduct()
wproduct.material = oms_w.material
wproduct.step = newstep
wproduct.subproduction_plan = oms_w.subproduction_plan
if hasNext:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else:
if step == newstep:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
# 更新子计划进度
WpmServies.update_subproduction_progress_main(
sp=oms_w.subproduction_plan)
if wproduct.test:# 如果有正在进行的工序中检验
wproduct.test.is_midtesting = False
wproduct.test.is_submited = False
wproduct.test.save()
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
if needTest:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.material_check = wproduct.product
# 更新子计划进度
WpmService.update_subproduction_progress_main(
sp=oms_w.subproduction_plan)
wproduct.create_by = request.user
wproduct.coperation = op
wproduct.save()
WpmServies.add_wproduct_flow_log(wproduct, 'wproduct_create')
WpmService.add_wproduct_flow_log(wproduct, 'wproduct_create')
# 隐藏原半成品
wps = WProduct.objects.filter(ow_wproduct__operation=op)
wps.update(is_hidden=True, child=wproduct,
@ -747,7 +767,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 如果是冷加工
if step.process.id == 1:
WpmServies.update_cutting_list_with_operation(op=op)
WpmService.update_cutting_list_with_operation(op=op)
return Response()
@ -971,213 +991,3 @@ class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyMode
return Response()
class DoFormInit(CreateAPIView, GenericAPIView):
perms_map = {'*': '*'}
serializer_class = OperationInitSerializer
def post(self, request, format=None):
"""
调用操作表单
"""
data = request.data
serializer = OperationInitSerializer(data=data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
ret = {}
ret_0 = {}
ret_0['step'] = data['step']
splans = []
ret_0['input'] = []
# ret_0['subproduction_plan'] = data['subproduction_plan']
if 'wproducts' in data and data['wproducts']:
ret_0['wproducts'] = data['wproducts']
splans = WProduct.objects.filter(id__in=data['wproducts']).values_list(
'subproduction_plan', flat=True)
# 调出所属子计划现有物料
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(
subproduction_plan__in=splans), many=True).data
else:
if 'subproduction_plan' in vdata:
splans = [vdata['subproduction_plan']]
else:
splans = SubProductionPlan.objects.filter(is_deleted=False,
subproduction__usedstep_subproduction__step=vdata[
'step'],
state=3)
ret_0['wproducts'] = []
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(
subproduction_plan__in=splans), many=True).data
for i in ret_0['input']:
i['count_input'] = 0
# 需要输出的物料
if ret_0['wproducts']:
# 排除主要产物, 因为已经放到半成品里了, 由半成品进行处理, 夹层可能需要特殊处理
o_objs = SubProductionProgress.objects.filter(
subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT).exclude(is_main=True)
else:
# 此时显示所有子计划需要输出的物料
o_objs = SubProductionProgress.objects.filter(
subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
ret_0['output'] = list(o_objs.values(
'subproduction_plan', 'material', 'material__name', 'material__number'))
for i in ret_0['output']:
i['count_output'] = 0
ret['forms'] = []
ret_0['id'] = 0
ret_0['name'] = '基本信息'
# 查询工具工装
ret_0['tools'] = SubprodctionMaterialListSerializer(
instance=SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
subproduction__subplan_subprod__in=splans), many=True).data
# 查询技术文档
ret_0['techdocs'] = TechDocListSerializer(
instance=TechDoc.objects.filter(
subproduction__subplan_subprod__in=splans, enabled=True)
.distinct(), many=True).data
ret['forms'].append(ret_0)
forms = RecordForm.objects.filter(
step=vdata['step'], type=RecordForm.RF_TYPE_DO)
if forms.exists():
ret['forms'].extend(RecordFormDetailSerializer(
instance=forms, many=True).data)
return Response(ret)
class DoFormSubmit(CreateAPIView, GenericAPIView):
perms_map = {'*': '*'}
serializer_class = OperationSubmitSerializer
@transaction.atomic
def post(self, request, format=None):
"""
提交操作表单
"""
data = request.data
serializer = OperationSubmitSerializer(
data=data, context={'request': self.request})
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data # 校验之后的数据
# 创建一个生产操作记录
action_obj = Operation()
action_obj.step = vdata['step']
action_obj.remark = vdata.get('remark', '') # 操作备注
action_obj.create_by = request.user
action_obj.use_scrap = vdata.get('use_scrap', False)
action_obj.save()
# 保存关联半成品
if 'wproducts' in data and data['wproducts']:
owps = []
for i in data['wproducts']:
owp = {}
owp['operation'] = action_obj
wp = WProduct.objects.get(pk=i)
owp['wproduct'] = wp
owp['number'] = wp.number
owp['material'] = wp.material
owp['subproduction_plan'] = wp.subproduction_plan
owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps)
# 保存物料消耗
for i in vdata['input']:
if i['count_input']: # 如果有消耗
i_wmat = i['id']
OperationMaterial.objects.create(type=1, operation=action_obj,
wmaterial=i_wmat, count=i['count_input'])
# 更新车间物料
i_wmat.count = i_wmat.count - i['count_input']
i_wmat.save()
# 更新子计划物料消耗情况
sp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan,
material=i_wmat.material)
sp.count_real = sp.count_real + i['count_input']
sp.save()
# 物料产出
if 'output' in data and data['output']:
for i in vdata['output']: # 已经序列化好的数据
ma = i['material']
if i['subproduction_plan'].product == ma: # 如果是该计划主产物
# 如果是切割
# 获取下一步子工序
if vdata['step'].type == Step.STEP_TYPE_DIV:
newstep, _ = WpmServies.get_next_step(
i['subproduction_plan'], vdata['step'])
wpr = dict(material=ma, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i['subproduction_plan'])
for x in range(i['count_output']):
WProduct.objects.create(**wpr)
else:
# 更新操作产出物料表
OperationMaterial.objects.create(type=2, operation=action_obj,
material=ma, count=i['count_output'])
# 更新车间物料表
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i['subproduction_plan'],
material=ma)
ins.count = ins.count + i['count_output']
ins.save()
# 更新子计划进度表
sp = SubProductionProgress.objects.get(subproduction_plan=i['subproduction_plan'],
material=ma)
sp.count_real = sp.count_real + i['count_input']
sp.save()
# 更新动态产品表
if 'wproducts' in vdata and vdata['wproducts']:
if vdata['step'].type == Step.STEP_TYPE_COMB:
wproducts = vdata['wproducts']
if 'suproduction_plan' in vdata:
wproducts.update(is_hidden=True) # 隐藏
newstep, hasNext = WpmServies.get_next_step(
i['subproduction_plan'], vdata['step'])
wproduct = WProduct()
wproduct.material = vdata['subproduction_plan'].product
wproduct.step = newstep
wproduct.subproduction_plan = vdata['subproduction_plan']
wproduct.parent = data['wproducts']
if hasNext:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.save()
else:
raise exceptions.APIException('请指定子计划')
else:
for wproduct in vdata['wproducts']:
# 获取下一步子工序
newstep, hasNext = WpmServies.get_next_step(
wproduct.subproduction_plan, vdata['step'])
wproduct.step = newstep
wproduct.pre_step = vdata['step']
if hasNext:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.material = wproduct.subproduction_plan.product
wproduct.save()
# 保存自定义表单结果
for i in vdata['forms']:
wr = OperationRecord()
wr.form = i['form']
wr.create_by = request.user
wr.operation = action_obj
wr.save()
wrds = []
for m in i['record_data']: # 保存记录详情
form_field = m['form_field']
m['field_name'] = form_field.field_name
m['field_key'] = form_field.field_key
m['field_type'] = form_field.field_type
m['field_value'] = m['field_value']
m['sort'] = form_field.sort
m['operation_record'] = wr
wrds.append(OperationRecordItem(**m))
OperationRecordItem.objects.bulk_create(wrds)
return Response()