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

This commit is contained in:
shijing 2021-11-22 14:08:30 +08:00
commit d0f9030cfc
35 changed files with 1024 additions and 154 deletions

View File

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

View File

@ -167,9 +167,7 @@
label-position="right" label-position="right"
:rules="rule1" :rules="rule1"
> >
<el-form-item label="生产计划编号" prop="number">
<el-input v-model="orderplan.number" placeholder="生产计划编号" />
</el-form-item>
<el-form-item label="排产数量" prop="count"> <el-form-item label="排产数量" prop="count">
<el-input-number v-model="orderplan.count" :min="0"></el-input-number> <el-input-number v-model="orderplan.count" :min="0"></el-input-number>
</el-form-item> </el-form-item>

View File

@ -14,7 +14,7 @@
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="半成品名称"> <el-table-column label="半成品名称">
<template slot-scope="scope">{{ scope.row.m_state_.name }}</template> <template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column> </el-table-column>
<el-table-column label="半成品编号"> <el-table-column label="半成品编号">
@ -27,7 +27,7 @@
</el-table-column> </el-table-column>
<el-table-column label="所在子工序"> <el-table-column label="所在子工序">
<template slot-scope="scope">{{ scope.row.p_state_.name }}</template> <template slot-scope="scope">{{ scope.row.step_.name }}</template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="操作" width="220px"> <el-table-column align="center" label="操作" width="220px">
@ -62,7 +62,7 @@
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="半成品名称"> <el-table-column label="半成品名称">
<template slot-scope="scope">{{ scope.row.m_state_.name }}</template> <template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column> </el-table-column>
<el-table-column label="半成品编号"> <el-table-column label="半成品编号">
@ -75,7 +75,7 @@
</el-table-column> </el-table-column>
<el-table-column label="所在子工序"> <el-table-column label="所在子工序">
<template slot-scope="scope">{{ scope.row.p_state_.name }}</template> <template slot-scope="scope">{{ scope.row.step_.name }}</template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="操作" width="220px"> <el-table-column align="center" label="操作" width="220px">
@ -389,7 +389,7 @@ export default {
//调该物料对应的检查表 //调该物料对应的检查表
this.outerVisible = true; this.outerVisible = true;
this.wproduct=scope.row.id;//半成品ID this.wproduct=scope.row.id;//半成品ID
this.listQueryrecordform.material = scope.row.m_state;// this.listQueryrecordform.material = scope.row.material;//
this.listQueryrecordform.type = 2; this.listQueryrecordform.type = 2;
getrecordformList(this.listQueryrecordform).then((response) => { getrecordformList(this.listQueryrecordform).then((response) => {
if (response.data) { if (response.data) {

View File

@ -74,7 +74,7 @@
<el-table-column align="center" label="操作" width="130px"> <el-table-column align="center" label="操作" width="130px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link v-if="scope.row.state == 1" @click="handleNeed(scope)" <el-link @click="handleNeed(scope)"
>领料</el-link >领料</el-link
> >
</template> </template>
@ -132,13 +132,13 @@
<el-table-column label="半成品状态"> <el-table-column label="半成品状态">
<template slot-scope="scope">{{ <template slot-scope="scope">{{
scope.row.m_state_.name scope.row.material_.name
}}</template> }}</template>
</el-table-column> </el-table-column>
<el-table-column label="所在子工序"> <el-table-column label="所在子工序">
<template slot-scope="scope">{{ <template slot-scope="scope">{{
scope.row.p_state_.name scope.row.step_.name
}}</template> }}</template>
</el-table-column> </el-table-column>
<el-table-column label="所在子工序执行状态"> <el-table-column label="所在子工序执行状态">
@ -227,8 +227,8 @@
> >
</div> </div>
<template> <template>
<el-table :data="havewl" style="width: 100%" ref="multipleTable"> <el-table :data="havewl" style="width: 100%" >
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column prop="batch" label="物料批次"> </el-table-column> <el-table-column prop="batch" label="物料批次"> </el-table-column>
<el-table-column prop="material_.name" label="物料名称"> <el-table-column prop="material_.name" label="物料名称">
</el-table-column> </el-table-column>
@ -627,7 +627,8 @@ export default {
from: [], from: [],
workdata: {}, workdata: {},
wproductdata: {}, wproductdata: {},
iproducts: [] workData:{},
}; };
}, },
process: "", process: "",
@ -719,7 +720,7 @@ export default {
this.listLoading = false; this.listLoading = false;
}); });
//半成品 //半成品
getwproductList({page:0,p_state__process:this.process}).then((response) => { getwproductList({page:0,step__process:this.process}).then((response) => {
if (response.data) { if (response.data) {
this.wproductData = response.data; this.wproductData = response.data;
//console.log( this.wproductData) //console.log( this.wproductData)
@ -731,7 +732,7 @@ export default {
//大工序下子工序产出的半成品 //大工序下子工序产出的半成品
getwproductLists() { getwproductLists() {
this.wproductdata.page = 0; this.wproductdata.page = 0;
this.wproductdata.p_state__process = this.process; this.wproductdata.step__process = this.process;
if (this.subproduction_plan != "") { if (this.subproduction_plan != "") {
this.wproductdata.subproduction_plan = this.subproduction_plan; this.wproductdata.subproduction_plan = this.subproduction_plan;
} }
@ -746,22 +747,37 @@ export default {
handlewproduct(scope){ handlewproduct(scope){
this.dialogTableVisible = true; this.dialogTableVisible = true;
this.pcId=scope.row.id;
getiproductList({page:0,material:scope.row.material,warehouse:scope.row.warehouse,batch:scope.row.batch}).then((response) => { getiproductList({page:0,material:scope.row.material,warehouse:scope.row.warehouse,batch:scope.row.batch}).then((response) => {
if (response.data) { if (response.data) {
this.iproductData= response.data; this.iproductData= response.data;
} }
this.listLoading = false; this.listLoading = false;
}); });
}, },
//勾选半成品 //勾选半成品
handleSelectionChanges(val){ handleSelectionChanges(val){
let _this = this; this.iproducts= [];
_this.wpID = [];
val.forEach((item) => { val.forEach((item) => {
_this.wpID.push(item.id); this.iproducts.push(item.id);
}); });
}, },
//提交半成品
iproductsSubmit(){
this.dialogTableVisible = false;
this.havewl.forEach((item) => {
if(item.id== this.pcId)
{
item.iproducts=this.iproducts;
}
});
},
//领料 //领料
handleNeed(scope) { handleNeed(scope) {
this.need = Object.assign({}, defaulteneed); this.need = Object.assign({}, defaulteneed);
@ -778,17 +794,18 @@ export default {
//确认领料 //确认领料
handlePick() { handlePick() {
this.pickData.subproduction_plan = this.id; this.pickData.subproduction_plan = this.id;
this.pickData.picks = this.havewl;
// console.log(this.pickData); this.pickData.picks = this.havewl;
createPick(this.pickData).then((res) => { createPick(this.pickData).then((res) => {
if (res.code >= 200) { if (res.code >= 200) {
this.dialogVisiblenw = false; this.dialogVisiblenw = false;
this.$message.success("领料成功!"); this.$message.success("领料成功!");
} }
}); });
}, },
prev() { prev() {
--this.values; --this.values;
@ -865,18 +882,21 @@ export default {
record_data: _this.field1, record_data: _this.field1,
}); });
}); });
this.workData.step=this.step;
this.workData.wproducts=this.wproducts;
this.workData.input=this.input;
this.workData.output=this.output;
this.workData.forms=this.from;
this.workData.remark=this.remark;
if (this.subproduction_plan != "") {
this.wproductdata.subproduction_plan = this.subproduction_plan;
}
console.log(this.remark); console.log(this.remark);
submitWork({ submitWork(this.workData).then((res) => {
step: this.step,
subproduction_plan: this.subproduction_plan,
wproducts: this.wproducts,
input: this.input,
output: this.output,
forms: this.from,
remark: this.remark,
}).then((res) => {
if (res.code >= 200) { if (res.code >= 200) {
this.dialogVisiblework = false; this.dialogVisiblework = false;
this.$message.success("成功!"); this.$message.success("成功!");

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.6 on 2021-11-17 15:06
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pm', '0013_alter_subproductionplan_subproduction'),
('inm', '0017_alter_iproduct_number'),
]
operations = [
migrations.AlterField(
model_name='fifoitem',
name='subproduction_plan',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子生产计划'),
),
]

View File

@ -82,7 +82,7 @@ class FIFOItem(BaseModel):
count = models.IntegerField('数量', default=0, validators=[MinValueValidator(0)]) count = models.IntegerField('数量', default=0, validators=[MinValueValidator(0)])
batch = models.CharField('批次号', max_length=100, default='') batch = models.CharField('批次号', max_length=100, default='')
fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE) fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.DO_NOTHING, null=True, blank=True) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True)
class FIFOItemProduct(BaseModel): class FIFOItemProduct(BaseModel):
""" """

View File

@ -0,0 +1,34 @@
# Generated by Django 3.2.6 on 2021-11-17 08:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0034_auto_20211116_1603'),
]
operations = [
migrations.AddField(
model_name='techdoc',
name='enabled',
field=models.BooleanField(default=True, verbose_name='是否启用'),
),
migrations.AlterField(
model_name='step',
name='type',
field=models.IntegerField(choices=[(1, '常规'), (2, '分割'), (3, '结合')], default=1, verbose_name='操作类型'),
),
migrations.AlterField(
model_name='subprodctionmaterial',
name='subproduction',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subm_subprod', to='mtm.subproduction', verbose_name='关联生产分解'),
),
migrations.AlterField(
model_name='techdoc',
name='subproduction',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tech_subprod', to='mtm.subproduction', verbose_name='关联生产分解'),
),
]

View File

@ -72,7 +72,7 @@ class Step(CommonAModel):
STEP_TYPE_DIV = 2 STEP_TYPE_DIV = 2
STEP_TYPE_COMB = 3 STEP_TYPE_COMB = 3
step_type_choices=( step_type_choices=(
(STEP_TYPE_NOM, '普通'), (STEP_TYPE_NOM, '常规'),
(STEP_TYPE_DIV, '分割'), (STEP_TYPE_DIV, '分割'),
(STEP_TYPE_COMB, '结合') (STEP_TYPE_COMB, '结合')
) )
@ -199,7 +199,7 @@ class SubprodctionMaterial(CommonADModel):
material = models.ForeignKey(Material, verbose_name='物料', on_delete=models.CASCADE, related_name='subplan_material') material = models.ForeignKey(Material, verbose_name='物料', on_delete=models.CASCADE, related_name='subplan_material')
is_main = models.BooleanField('是否主产出', default=False) # 以该产品完成度计算进度 is_main = models.BooleanField('是否主产出', default=False) # 以该产品完成度计算进度
count = models.FloatField('消耗量/产出量', default=0) count = models.FloatField('消耗量/产出量', default=0)
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE) subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subm_subprod')
type = models.IntegerField('物料应用类型', default=1) type = models.IntegerField('物料应用类型', default=1)
sort = models.IntegerField('排序号', default=1) sort = models.IntegerField('排序号', default=1)
@ -223,8 +223,9 @@ class TechDoc(CommonADModel):
""" """
name = models.CharField('名称', max_length=50) name = models.CharField('名称', max_length=50)
file = models.ForeignKey(File, verbose_name='技术文件', on_delete=models.CASCADE) file = models.ForeignKey(File, verbose_name='技术文件', on_delete=models.CASCADE)
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE) subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='tech_subprod')
content = models.TextField('内容', null=True, blank=True) content = models.TextField('内容', null=True, blank=True)
enabled = models.BooleanField('是否启用', default=True)
class Meta: class Meta:
verbose_name = '技术文件' verbose_name = '技术文件'

View File

@ -26,7 +26,7 @@ class MaterialDetailSerializer(serializers.ModelSerializer):
class MaterialSimpleSerializer(serializers.ModelSerializer): class MaterialSimpleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Material model = Material
fields = ['id', 'name', 'number', 'unit','specification'] fields = ['id', 'name', 'number', 'unit','specification', 'type']
class ProcessSerializer(serializers.ModelSerializer): class ProcessSerializer(serializers.ModelSerializer):
instruction_ = FileSimpleSerializer(source='instruction', read_only=True) instruction_ = FileSimpleSerializer(source='instruction', read_only=True)
@ -209,6 +209,12 @@ class RecordFormDetailSerializer(serializers.ModelSerializer):
def get_form_fields(self, obj): def get_form_fields(self, obj):
serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False), many=True) serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False), many=True)
vdata = serializer.data
if obj.type == RecordForm.RF_TYPE_TEST:
for i in vdata:
if i['need_judge']:
i['is_testok'] = False
i['is_teskok_robot'] = False
return serializer.data return serializer.data
@ -241,9 +247,9 @@ class TechDocListSerializer(serializers.ModelSerializer):
class TechDocCreateSerializer(serializers.ModelSerializer): class TechDocCreateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = TechDoc model = TechDoc
fields = ['file', 'subproduction', 'name', 'content'] fields = ['file', 'subproduction', 'name', 'content', 'enabled']
class TechDocUpdateSerializer(serializers.ModelSerializer): class TechDocUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = TechDoc model = TechDoc
fields = ['file', 'name', 'content'] fields = ['file', 'name', 'content', 'enabled']

View File

@ -154,6 +154,7 @@ class RecordFormViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet
filterset_fields = ['step', 'type', 'material'] filterset_fields = ['step', 'type', 'material']
search_fields = ['name'] search_fields = ['name']
ordering='id' ordering='id'
def get_serializer_class(self): def get_serializer_class(self):
if self.action =='create': if self.action =='create':
@ -184,6 +185,8 @@ class RecordFormFieldViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelVi
queryset = RecordFormField.objects.all() queryset = RecordFormField.objects.all()
filterset_fields = ['field_type', 'form'] filterset_fields = ['field_type', 'form']
search_fields = ['field_name', 'field_key'] search_fields = ['field_name', 'field_key']
ordering = 'id'
ordering_fields = ['sort', 'id']
def get_serializer_class(self): def get_serializer_class(self):
if self.action =='create': if self.action =='create':

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.6 on 2021-11-17 08:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0035_auto_20211117_1637'),
('pm', '0012_alter_subproductionprogress_type'),
]
operations = [
migrations.AlterField(
model_name='subproductionplan',
name='subproduction',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subplan_subprod', to='mtm.subproduction', verbose_name='关联生产分解'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-11-19 02:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pm', '0013_alter_subproductionplan_subproduction'),
]
operations = [
migrations.AddField(
model_name='subproductionplan',
name='number',
field=models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='子计划编号'),
),
]

View File

@ -32,15 +32,21 @@ class SubProductionPlan(CommonAModel):
""" """
子生产计划 子生产计划
""" """
SUBPLAN_STATE_PLANING = 0
SUBPLAN_STATE_ASSGINED = 1
SUBPLAN_STATE_ACCEPTED = 2
SUBPLAN_STATE_WORKING = 3
SUBPLAN_STATE_DONE = 4
state_choices=( state_choices=(
(0, '制定中'), (SUBPLAN_STATE_PLANING, '制定中'),
(1, '已下达'), (SUBPLAN_STATE_ASSGINED, '已下达'),
(2, '已接收'), (SUBPLAN_STATE_ACCEPTED, '已接收'),
(3, '生产中'), (SUBPLAN_STATE_WORKING, '生产中'),
(4, '已完成') (SUBPLAN_STATE_DONE, '已完成')
) )
number = models.CharField('子计划编号', max_length=50, unique=True, null=True, blank=True)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE) production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE) subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod')
start_date = models.DateField('计划开工日期') start_date = models.DateField('计划开工日期')
end_date = models.DateField('计划完工日期') end_date = models.DateField('计划完工日期')
@ -53,7 +59,7 @@ class SubProductionPlan(CommonAModel):
steps = models.JSONField('工艺步骤', default=list) steps = models.JSONField('工艺步骤', default=list)
state = models.IntegerField('状态', default=0) state = models.IntegerField('状态', default=SUBPLAN_STATE_PLANING)
start_date_real = models.DateField('实际开工日期', null=True, blank=True) start_date_real = models.DateField('实际开工日期', null=True, blank=True)
end_date_real = models.DateField('实际完工日期', null=True, blank=True) end_date_real = models.DateField('实际完工日期', null=True, blank=True)
is_picked = models.BooleanField('是否已领料', default=False) is_picked = models.BooleanField('是否已领料', default=False)

View File

@ -8,7 +8,7 @@ from apps.system.serializers import OrganizationSimpleSerializer
class ProductionPlanCreateFromOrderSerializer(serializers.ModelSerializer): class ProductionPlanCreateFromOrderSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ProductionPlan model = ProductionPlan
fields = ['order', 'number', 'count', 'start_date', 'end_date'] fields = ['order', 'count', 'start_date', 'end_date']
class ProductionPlanSerializer(serializers.ModelSerializer): class ProductionPlanSerializer(serializers.ModelSerializer):
order_ = OrderSerializer(source='order', read_only=True) order_ = OrderSerializer(source='order', read_only=True)
@ -55,3 +55,8 @@ class PickNeedSerializer(serializers.Serializer):
class PlanDestorySerializer(serializers.Serializer): class PlanDestorySerializer(serializers.Serializer):
ids = serializers.ListField(child=serializers.IntegerField(), label='主计划ID列表') ids = serializers.ListField(child=serializers.IntegerField(), label='主计划ID列表')
class SubproductionPlanSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = SubProductionPlan
fields = ['id', 'number']

View File

@ -1,6 +1,6 @@
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from apps.pm.models import SubProductionProgress from apps.pm.models import SubProductionPlan, SubProductionProgress
@receiver(post_save, sender=SubProductionProgress) @receiver(post_save, sender=SubProductionProgress)
def update_subplan_main(sender, instance, created, **kwargs): def update_subplan_main(sender, instance, created, **kwargs):
@ -13,8 +13,8 @@ def update_subplan_main(sender, instance, created, **kwargs):
subplan.main_product = instance.material subplan.main_product = instance.material
subplan.main_count = instance.count subplan.main_count = instance.count
subplan.main_count_real = instance.count_real subplan.main_count_real = instance.count_real
if subplan.main_count >= instance.count_real: if instance.count_real>= instance.count and instance.count_real != 0:
subplan.state = 4 subplan.state = SubProductionPlan.SUBPLAN_STATE_DONE
subplan.save() subplan.save()

View File

@ -1,4 +1,5 @@
from datetime import timezone from datetime import timezone
from django.db import transaction
from rest_framework import serializers from rest_framework import serializers
from rest_framework.views import APIView from rest_framework.views import APIView
from apps.em.models import Equipment from apps.em.models import Equipment
@ -49,7 +50,8 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
elif self.action == 'list': elif self.action == 'list':
return ProductionPlanSerializer return ProductionPlanSerializer
return super().get_serializer_class() return super().get_serializer_class()
@transaction.atomic()
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
data = request.data data = request.data
serializer = self.get_serializer(data=data) serializer = self.get_serializer(data=data)
@ -60,7 +62,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
pass pass
else: else:
raise APIException('排产数量错误') raise APIException('排产数量错误')
instance = serializer.save(create_by=request.user, product=order.product, number='JH-'+ranstr(7)) instance = serializer.save(create_by=request.user, product=order.product, number='JH'+ranstr(7))
updateOrderPlanedCount(instance.order) updateOrderPlanedCount(instance.order)
return Response() return Response()
@ -81,13 +83,13 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
if production_plan.is_planed: if production_plan.is_planed:
raise APIException('已生成子计划') raise APIException('已生成子计划')
subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number') subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number')
for i in subps: for index, i in enumerate(subps):
steps = Step.objects.filter(usedstep__subproduction=i, usedstep__subproduction__is_deleted=False, 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')
instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i, instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i,
start_date=production_plan.start_date, end_date=production_plan.end_date, start_date=production_plan.start_date, end_date=production_plan.end_date,
workshop=i.process.workshop, process=i.process, create_by=request.user, workshop=i.process.workshop, process=i.process, create_by=request.user,
steps = list(steps)) steps = list(steps), number=production_plan.number + '-' + str(index+1))
# 生成子计划物料需求/进度 # 生成子计划物料需求/进度
for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'): for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
spro = SubProductionProgress.objects.create(material=m.material, type=m.type, spro = SubProductionProgress.objects.create(material=m.material, type=m.type,
@ -131,8 +133,8 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
下达任务 下达任务
""" """
obj = self.get_object() obj = self.get_object()
if obj.state == 0: if obj.state == SubProductionPlan.SUBPLAN_STATE_PLANING:
obj.state = 1 obj.state = SubProductionPlan.SUBPLAN_STATE_ASSGINED
obj.save() obj.save()
return Response() return Response()
raise APIException('计划状态有误') raise APIException('计划状态有误')
@ -143,8 +145,8 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
开始生产 开始生产
""" """
obj = self.get_object() obj = self.get_object()
if obj.state in [1,2]: if obj.state in [SubProductionPlan.SUBPLAN_STATE_ASSGINED, SubProductionPlan.SUBPLAN_STATE_ACCEPTED]:
obj.state = 3 obj.state = SubProductionPlan.SUBPLAN_STATE_WORKING
obj.start_date_real = timezone.now() obj.start_date_real = timezone.now()
obj.save() obj.save()
return Response() return Response()

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-11-17 15:32
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('qm', '0009_alter_testrecorditem_is_testok'),
]
operations = [
migrations.RenameField(
model_name='testrecord',
old_name='m_state',
new_name='material',
),
]

View File

@ -0,0 +1,35 @@
# Generated by Django 3.2.9 on 2021-11-19 00:48
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pm', '0013_alter_subproductionplan_subproduction'),
('qm', '0010_rename_m_state_testrecord_material'),
]
operations = [
migrations.AddField(
model_name='testrecord',
name='is_testok_robot',
field=models.BooleanField(default=True, verbose_name='自动判定的是否合格'),
),
migrations.AddField(
model_name='testrecord',
name='number',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='产品编号'),
),
migrations.AddField(
model_name='testrecord',
name='subproduction_plan',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联的生产子计划'),
),
migrations.AddField(
model_name='testrecorditem',
name='is_testok_robot',
field=models.BooleanField(blank=True, null=True, verbose_name='自动判定的是否合格'),
),
]

View File

@ -49,8 +49,11 @@ class TestRecord(CommonAModel):
""" """
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
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)
wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True) wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True)
m_state = 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)
subproduction_plan = models.ForeignKey('pm.subproductionplan', verbose_name='关联的生产子计划', on_delete=models.CASCADE, null=True, blank=True)
fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True) fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True)
remark = models.TextField('备注', default='') remark = models.TextField('备注', default='')
@ -66,5 +69,6 @@ class TestRecordItem(BaseModel):
field_value = models.JSONField('录入值', default=dict, blank=True) field_value = models.JSONField('录入值', default=dict, blank=True)
need_judge = models.BooleanField('是否需要判定', default=False) need_judge = models.BooleanField('是否需要判定', default=False)
sort = models.IntegerField('排序号', default=1) sort = models.IntegerField('排序号', default=1)
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

@ -0,0 +1,17 @@
from django_filters import rest_framework as filters
from .models import Operation, WMaterial, WProduct
class WMaterialFilterSet(filters.FilterSet):
operation = filters.NumberFilter(method='filter_operation')
class Meta:
model = WMaterial
fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop']
def filter_operation(self, queryset, name, value):
operation = Operation.objects.get(pk=value)
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
if wproducts.exists():
pass
else:
pass

View File

@ -0,0 +1,53 @@
# Generated by Django 3.2.6 on 2021-11-17 14:54
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('mtm', '0035_auto_20211117_1637'),
('pm', '0013_alter_subproductionplan_subproduction'),
('wpm', '0013_auto_20211116_0841'),
]
operations = [
migrations.RenameField(
model_name='operation',
old_name='p_state',
new_name='step',
),
migrations.RemoveField(
model_name='operation',
name='m_state',
),
migrations.RemoveField(
model_name='operation',
name='wproducts',
),
migrations.CreateModel(
name='OperationWproduct',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('number', models.CharField(blank=True, max_length=50, null=True, verbose_name='物品编号')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='操作时的物料状态')),
('operation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operation', verbose_name='关联操作')),
('production_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.productionplan', verbose_name='当前主生产计划')),
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='当前子生产计划')),
('wproduct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联半成品')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='operation',
name='wproducts',
field=models.ManyToManyField(through='wpm.OperationWproduct', to='wpm.WProduct', verbose_name='关联半成品'),
),
]

View File

@ -0,0 +1,38 @@
# Generated by Django 3.2.6 on 2021-11-17 15:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0035_auto_20211117_1637'),
('wpm', '0014_auto_20211117_2254'),
]
operations = [
migrations.RenameField(
model_name='wproduct',
old_name='m_state',
new_name='material',
),
migrations.RemoveField(
model_name='wproduct',
name='p_state',
),
migrations.RemoveField(
model_name='wproduct',
name='pre_pstate',
),
migrations.AddField(
model_name='wproduct',
name='pre_step',
field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='w_pre_step', to='mtm.step', verbose_name='已执行到'),
),
migrations.AddField(
model_name='wproduct',
name='step',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='w_step', to='mtm.step', verbose_name='所在步骤'),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.9 on 2021-11-19 00:48
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0015_auto_20211117_2332'),
]
operations = [
migrations.RemoveField(
model_name='operation',
name='wproducts',
),
migrations.AddField(
model_name='operation',
name='is_submited',
field=models.BooleanField(default=True, verbose_name='是否提交'),
),
migrations.AddField(
model_name='wproduct',
name='operation',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_operation', to='wpm.operation', verbose_name='关联操作'),
),
]

View File

@ -0,0 +1,49 @@
# Generated by Django 3.2.9 on 2021-11-19 02:34
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('em', '0009_auto_20210916_1108'),
('wpm', '0016_auto_20211119_0848'),
]
operations = [
migrations.RemoveField(
model_name='operationrecord',
name='create_by',
),
migrations.RemoveField(
model_name='operationrecord',
name='update_by',
),
migrations.AddField(
model_name='operationrecord',
name='is_filled',
field=models.BooleanField(default=True, verbose_name='是否填写'),
),
migrations.AlterField(
model_name='operation',
name='is_submited',
field=models.BooleanField(default=False, verbose_name='是否提交'),
),
migrations.CreateModel(
name='OperationEquip',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('remark', models.TextField(blank=True, null=True, verbose_name='备注')),
('equip', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='em.equipment', verbose_name='生产设备')),
('operation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operation', verbose_name='关联操作')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,29 @@
# Generated by Django 3.2.9 on 2021-11-19 05:40
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0017_auto_20211119_1034'),
]
operations = [
migrations.AlterField(
model_name='operationequip',
name='operation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='oe_operation', to='wpm.operation', verbose_name='关联操作'),
),
migrations.AlterField(
model_name='operationrecord',
name='operation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='or_operation', to='wpm.operation', verbose_name='关联的生产操作'),
),
migrations.AlterField(
model_name='operationwproduct',
name='operation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_operation', to='wpm.operation', verbose_name='关联操作'),
),
]

View File

@ -0,0 +1,46 @@
# Generated by Django 3.2.9 on 2021-11-22 03:10
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0035_auto_20211117_1637'),
('pm', '0014_subproductionplan_number'),
('wpm', '0018_auto_20211119_1340'),
]
operations = [
migrations.AddField(
model_name='operationmaterial',
name='batch',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='批次号'),
),
migrations.AddField(
model_name='operationmaterial',
name='subproduction_plan',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联的子计划'),
),
migrations.AddField(
model_name='operationmaterial',
name='subproduction_progress',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionprogress', verbose_name='关联的生产进度'),
),
migrations.AlterField(
model_name='operationmaterial',
name='material',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='可能产出的产品'),
),
migrations.AlterField(
model_name='operationmaterial',
name='type',
field=models.IntegerField(choices=[(1, '输入物料'), (2, '输出物料'), (3, '工具工装')], default=0, verbose_name='类型'),
),
migrations.AlterField(
model_name='wproduct',
name='subproduction_plan',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wproduct_subplan', to='pm.subproductionplan', verbose_name='当前子生产计划'),
),
]

View File

@ -3,12 +3,13 @@ from django.db.models.base import Model
import django.utils.timezone as timezone import django.utils.timezone as timezone
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from apps.inm.models import WareHouse from apps.inm.models import WareHouse
from apps.pm.models import ProductionPlan, SubProductionPlan from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from apps.em.models import Equipment
class WMaterial(BaseModel): class WMaterial(BaseModel):
""" """
车间生产物料 车间生产物料
@ -33,49 +34,64 @@ class WProduct(CommonAModel):
(WPR_ACT_STATE_INM, '库存中'), (WPR_ACT_STATE_INM, '库存中'),
) )
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50) number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
m_state = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE) material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
pre_pstate = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_pstate') pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_step')
p_state = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='w_ptate') step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='w_step')
act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices) act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices)
is_executed = models.BooleanField('子工序是否已执行', default=False) is_executed = models.BooleanField('子工序是否已执行', default=False)
is_hidden = models.BooleanField('是否隐藏', default=False) is_hidden = models.BooleanField('是否隐藏', default=False)
parent = models.JSONField('', default=list, blank=True) parent = models.JSONField('', default=list, blank=True)
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) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan')
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE) production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
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='关联操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation')
class Operation(CommonAModel): class Operation(CommonADModel):
""" """
生产操作 生产操作
""" """
wproducts = models.JSONField('关联产品ID列表', default=list, blank=True) step = models.ForeignKey(Step, verbose_name='操作步骤', on_delete=models.CASCADE, null=True, blank=True)
m_state = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE, null=True, blank=True)
p_state = models.ForeignKey(Step, verbose_name='操作步骤', on_delete=models.CASCADE, null=True, blank=True)
use_scrap = models.BooleanField('是否使用的边角料', default=False) use_scrap = models.BooleanField('是否使用的边角料', default=False)
remark = models.CharField('操作备注', max_length=200, null=True, blank=True) remark = models.CharField('操作备注', max_length=200, null=True, blank=True)
is_submited = models.BooleanField('是否提交', default=False)
class OperationWproduct(BaseModel):
"""
生产操作半成品关联表
"""
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='ow_operation')
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct')
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='当前主生产计划', on_delete=models.CASCADE)
class OperationMaterial(BaseModel): class OperationMaterial(BaseModel):
""" """
生产操作物料消耗产出表 生产操作物料消耗产出表
""" """
type_choices=( type = models.IntegerField('类型', default=0, choices=SubprodctionMaterial.type_choices)
(1, '消耗'),
(2, '产出')
)
type = models.IntegerField('类型', default=0, choices=type_choices)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
material = models.ForeignKey(Material, verbose_name='可能产出的副产品', on_delete=models.CASCADE, null=True, blank=True) material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, null=True, blank=True)
count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)]) count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)])
class OperationRecord(CommonAModel): wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE, null=True, blank=True)
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
class OperationRecord(BaseModel):
""" """
记录表格 记录表格
""" """
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE) form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='or_operation')
is_filled = models.BooleanField('是否填写', default=True)
class OperationRecordItem(BaseModel): class OperationRecordItem(BaseModel):
""" """
@ -89,3 +105,7 @@ class OperationRecordItem(BaseModel):
sort = models.IntegerField('排序号', default=1) sort = models.IntegerField('排序号', default=1)
operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE) operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE)
class OperationEquip(BaseModel):
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation')
equip = models.ForeignKey(Equipment, verbose_name='生产设备', on_delete=models.CASCADE)
remark = models.TextField('备注', null=True, blank=True)

View File

@ -1,19 +1,22 @@
from rest_framework import serializers, exceptions from rest_framework import serializers, exceptions
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from apps.em.serializers import EquipmentSimpleSerializer
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
from apps.inm.signals import update_inm from apps.inm.signals import update_inm
from apps.mtm.models import Material, RecordForm, Step from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial
from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer from apps.mtm.serializers import MaterialSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.models import SubProductionPlan, SubProductionProgress
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from apps.pm.serializers import SubproductionPlanSimpleSerializer
from apps.qm.models import TestRecord, TestRecordItem from apps.qm.models import TestRecord, TestRecordItem
from apps.system.serializers import UserSimpleSerializer from apps.system.serializers import UserSimpleSerializer
from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem
from django.db import transaction from django.db import transaction
class PickHalfSerializer(serializers.Serializer): class PickHalfSerializer(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'), wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'),
required=False) # 从半成品表里直接修改状态 required=False) # 从半成品表里直接修改状态
class PickDetailSerializer(serializers.Serializer): class PickDetailSerializer(serializers.Serializer):
@ -32,10 +35,11 @@ class PickSerializer(serializers.Serializer):
def create(self, validated_data): def create(self, validated_data):
picks = validated_data.pop('picks') picks = validated_data.pop('picks')
sp = validated_data.pop('subproduction_plan') sp = validated_data.pop('subproduction_plan')
if sp.state not in [1,2]: if sp.state not in [SubProductionPlan.SUBPLAN_STATE_ASSGINED, SubProductionPlan.SUBPLAN_STATE_ACCEPTED,
SubProductionPlan.SUBPLAN_STATE_WORKING]:
raise exceptions.ValidationError('该子计划状态错误') raise exceptions.ValidationError('该子计划状态错误')
if sp.is_picked: # if sp.is_picked:
raise exceptions.ValidationError('该子计划已领料') # raise exceptions.ValidationError('该子计划已领料')
# for i in picks: # for i in picks:
# try: # try:
# instance = MaterialBatch.objects.get(material=i['material'], batch=i['batch']) # instance = MaterialBatch.objects.get(material=i['material'], batch=i['batch'])
@ -48,6 +52,7 @@ class PickSerializer(serializers.Serializer):
with transaction.atomic(): with transaction.atomic():
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user) fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user)
for i in picks: for i in picks:
isLowLevel = False
# 更新出库详情 # 更新出库详情
i['count'] = i.pop('pick_count', 0) i['count'] = i.pop('pick_count', 0)
# 是否勾选每一个 # 是否勾选每一个
@ -55,6 +60,8 @@ class PickSerializer(serializers.Serializer):
i['count'] = len(i['iproducts']) i['count'] = len(i['iproducts'])
isLowLevel = True isLowLevel = True
if i['count']>0: if i['count']>0:
if isLowLevel:
iproducts = i.pop('iproducts')
i['fifo'] = fifo i['fifo'] = fifo
i['is_testok'] = True # 默认检测合格 i['is_testok'] = True # 默认检测合格
i['subproduction_plan'] = sp i['subproduction_plan'] = sp
@ -62,7 +69,7 @@ class PickSerializer(serializers.Serializer):
# 创建再下一个层级 # 创建再下一个层级
if isLowLevel: if isLowLevel:
mls = [] mls = []
for m in i['iproducts']: for m in iproducts:
ml = {} ml = {}
ml['material'] = m.material ml['material'] = m.material
ml['number'] = m.number ml['number'] = m.number
@ -82,17 +89,21 @@ class PickSerializer(serializers.Serializer):
wm.count = wm.count + i['count'] wm.count = wm.count + i['count']
wm.save() wm.save()
# 更新子计划物料情况 # 更新子计划物料情况
spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1) spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
spp.count_pick = spp.count_pick + i['count'] spp.count_pick = spp.count_pick + i['count']
spp.save() spp.save()
# 更新半成品表 if spp.count_pick > spp.count:
wproducts = WProduct.objects.filter(pk__in=[x.wproduct for x in i['iproducts']]) raise exceptions.APIException('超过计划需求数')
first_step = Step.objects.get(pk=sp.steps[0].id) if isLowLevel:
wproducts.update(p_state=first_step, is_executed=False, # 更新半成品表
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None, wids = IProduct.objects.filter(pk__in=[x.id for x in iproducts]).values_list('wproduct', flat=True)
subproduction_plan=sp, production_plan=sp.production_plan) wproducts = WProduct.objects.filter(pk__in=wids)
first_step = Step.objects.get(pk=sp.steps[0]['id'])
wproducts.update(step=first_step, is_executed=False,
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None,
subproduction_plan=sp, production_plan=sp.production_plan)
sp.is_picked=True sp.is_picked=True
sp.state = 3 #生产中 sp.state = SubProductionPlan.SUBPLAN_STATE_WORKING #生产中
sp.state_date_real = timezone.now() #实际开工日期 sp.state_date_real = timezone.now() #实际开工日期
sp.save() sp.save()
# 更新库存 # 更新库存
@ -114,32 +125,75 @@ class WProductListSerializer(serializers.ModelSerializer):
""" """
半成品列表 半成品列表
""" """
m_state_ = MaterialSimpleSerializer(source='m_state', read_only=True) material_ = MaterialSimpleSerializer(source='material', read_only=True)
p_state_ = StepSimpleSerializer(source='p_state', read_only=True) step_ = StepSimpleSerializer(source='step', read_only=True)
class Meta: class Meta:
model = WProduct model = WProduct
fields = '__all__' fields = '__all__'
class OperationDetailSerializer(serializers.ModelSerializer): class OperationDetailSerializer(serializers.ModelSerializer):
wproducts_ = serializers.SerializerMethodField()
create_by_ = UserSimpleSerializer(source='create_by', read_only=True) create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
m_state_ = MaterialSimpleSerializer(source='m_state', read_only=True) step_ = StepSimpleSerializer(source='step', read_only=True)
p_state_ = StepSimpleSerializer(source='p_state', read_only=True)
class Meta: class Meta:
model = Operation model = Operation
fields = '__all__' fields = '__all__'
def get_wproducts_(self, obj):
return list(WProduct.objects.filter(id__in=obj.wproducts).values('id', 'number'))
class OperationListSerializer(serializers.ModelSerializer): class OperationListSerializer(serializers.ModelSerializer):
create_by_ = UserSimpleSerializer(source='create_by', read_only=True) create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
m_state_ = MaterialSimpleSerializer(source='m_state', read_only=True) step_ = StepSimpleSerializer(source='step', read_only=True)
p_state_ = StepSimpleSerializer(source='p_state', read_only=True) wproduct_count = serializers.SerializerMethodField()
equip_count = serializers.SerializerMethodField()
record_count = serializers.SerializerMethodField()
class Meta: class Meta:
model = Operation model = Operation
fields = '__all__' fields = '__all__'
def get_wproduct_count(self, obj):
return obj.ow_operation.count()
def get_equip_count(self, obj):
return obj.oe_operation.count()
def get_record_count(self, obj):
return obj.or_operation.count()
class OperationCreateSerializer(serializers.Serializer):
"""
操作创建
"""
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
# subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
wproducts = serializers.ListField(child=
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
def validate(self, data):
# subproduction_plan = data['subproduction_plan']
step = data['step']
# stepIds=[i['id'] for i in subproduction_plan.steps]
# if step.id not in stepIds:
# raise exceptions.ValidationError('请选择正确的子工序操作')
if 'wproducts' in data and data['wproducts']:
if step.type == Step.STEP_TYPE_DIV:
raise exceptions.ValidationError(_('不可进行此操作'))
for i in data['wproducts']:
if i.is_executed:
raise exceptions.ValidationError('不可进行操作')
# if i.subproduction_plan != subproduction_plan:
# raise exceptions.ValidationError('半成品所属子计划不一致')
if i.step != step:
raise exceptions.ValidationError('半成品所属子工序不一致')
else:
if step.type != Step.STEP_TYPE_DIV:
raise exceptions.ValidationError(_('请选择半成品进行操作'))
return data
class OperationUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Operation
fields =['use_scrap', 'remark']
class OperationInitSerializer(serializers.Serializer): class OperationInitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID") step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
@ -163,7 +217,7 @@ class OperationInitSerializer(serializers.Serializer):
raise exceptions.ValidationError('不可进行操作') raise exceptions.ValidationError('不可进行操作')
# if i.subproduction_plan != subproduction_plan: # if i.subproduction_plan != subproduction_plan:
# raise exceptions.ValidationError('半成品所属子计划不一致') # raise exceptions.ValidationError('半成品所属子计划不一致')
if i.p_state != step: if i.step != step:
raise exceptions.ValidationError('半成品所属子工序不一致') raise exceptions.ValidationError('半成品所属子工序不一致')
else: else:
if step.type != Step.STEP_TYPE_DIV: if step.type != Step.STEP_TYPE_DIV:
@ -191,6 +245,19 @@ class OperationRecordSerializer(serializers.ModelSerializer):
model = OperationRecord model = OperationRecord
fields = ['form', 'record_data'] fields = ['form', 'record_data']
class OperationRecordSubmitSerializer(serializers.ModelSerializer):
record_data = OperationRecordItemSerializer(many=True)
class Meta:
model = OperationRecord
fields = ['record_data']
class OperationWproductListSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
class Meta:
model = OperationWproduct
fields = '__all__'
class OperationSubmitSerializer(serializers.Serializer): class OperationSubmitSerializer(serializers.Serializer):
@ -229,6 +296,60 @@ class WplanPutInSerializer(serializers.Serializer):
class WproductPutInSerializer(serializers.Serializer): class WproductPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False) remark = serializers.CharField(label="入库备注", required =False)
class OperationEquipListSerializer(serializers.Serializer):
equip_ = EquipmentSimpleSerializer(source='equip', read_only=True)
class Meta:
model = OperationEquip
fields = '__all__'
class OperationEquipUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = OperationEquip
fields = ['remark']
class OperationRecordListSerializer(serializers.ModelSerializer):
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
class Meta:
model = OperationRecord
fields = '__all__'
class OperationMaterialListSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
class Meta:
model = OperationMaterial
fields = '__all__'
class OperationMaterialCreate1Serailizer(serializers.ModelSerializer):
wmaterial = serializers.PrimaryKeyRelatedField(required=True, queryset=WMaterial.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'wmaterial', 'count']
def create(self, validated_data):
wmaterial = validated_data['wmaterial']
validated_data['material'] = wmaterial.material
validated_data['subproduction_plan'] = wmaterial.subproduction_plan
validated_data['batch'] = wmaterial.batch
return super().create(validated_data)
class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'subproduction_progress', 'count']
def create(self, validated_data):
subproduction_progress = validated_data['subproduction_progress']
validated_data['material'] = subproduction_progress.material
validated_data['subproduction_plan'] = subproduction_progress.subproduction_plan
return super().create(validated_data)
class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'material']

View File

@ -1,5 +1,7 @@
from typing import List
from apps.pm.models import SubProductionPlan from apps.pm.models import SubProductionPlan
from apps.mtm.models import Step from apps.mtm.models import Step, SubprodctionMaterial
from apps.wpm.models import WProduct
class WpmServies(object): class WpmServies(object):
@classmethod @classmethod
@ -12,4 +14,21 @@ class WpmServies(object):
if pindex + 1 < len(stepIds): if pindex + 1 < len(stepIds):
return Step.objects.get(pk=stepIds[pindex+1]), True return Step.objects.get(pk=stepIds[pindex+1]), True
else: else:
return nowstep, False return nowstep, False
@classmethod
def get_subplans_queryset_from_wproducts(cls, wproducts:List):
"""
通过半成品列表获取所属子计划
"""
splans = SubProductionPlan.objects.filter(is_deleted=False, wproduct_subplan__in=wproducts)
return splans
@classmethod
def get_subplans_queyset_from_step(cls, step:Step):
"""
通过当前操作获取所有正在进行的子计划
"""
splans = SubProductionPlan.objects.filter(is_deleted=False,
subproduction__usedstep_subproduction__step=step, state=SubProductionPlan.SUBPLAN_STATE_WORKING)
return splans

View File

@ -3,12 +3,18 @@ from rest_framework import urlpatterns
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from apps.wpm.views import DoFormInit, DoFormSubmit, OperationViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet from apps.wpm.views import DoFormInit, DoFormSubmit, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet
router = DefaultRouter() router = DefaultRouter()
router.register('wmaterial', WMaterialViewSet, basename='wmaterial') router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
router.register('wproduct', WProductViewSet, basename='wproduct') router.register('wproduct', WProductViewSet, basename='wproduct')
router.register('operation', OperationViewSet, basename='operation') router.register('operation', OperationViewSet, basename='operation')
router.register('operation_wproduct', OperationWproductViewSet, basename='operation_wproduct')
router.register('operation_equip', OperationEquipViewSet, basename='operation_equip')
router.register('operation_record', OperationRecordViewSet, basename='operation_record')
router.register('operation_input', OperationMaterialInputViewSet, basename='operation_input')
router.register('operation_output', OperationMaterialOutputViewSet, basename='operation_output')
router.register('operation_tool', OperationMaterialToolViewSet, basename='operation_tool')
router.register('subplan', WPlanViewSet, basename='wplan') router.register('subplan', WPlanViewSet, basename='wplan')
urlpatterns = [ urlpatterns = [
path('do/init/', DoFormInit.as_view()), path('do/init/', DoFormInit.as_view()),

View File

@ -1,23 +1,24 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.generics import CreateAPIView, GenericAPIView from rest_framework.generics import CreateAPIView, GenericAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.utils import serializer_helpers from rest_framework.utils import serializer_helpers
from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.utils.field_mapping import get_relation_kwargs
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
from apps.inm.signals import update_inm from apps.inm.signals import update_inm
from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial, TechDoc
from apps.mtm.serializers import RecordFormDetailSerializer from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.models import SubProductionPlan, SubProductionProgress
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from apps.qm.models import TestRecordItem from apps.qm.models import TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from apps.wpm.models import WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem from apps.wpm.filters import WMaterialFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
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
@ -25,6 +26,7 @@ from rest_framework import exceptions, serializers
from apps.wpm.services import WpmServies from apps.wpm.services import WpmServies
from django.utils import timezone from django.utils import timezone
from utils.tools import ranstr from utils.tools import ranstr
from rest_framework import status
# Create your views here. # Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet): class WPlanViewSet(ListModelMixin, GenericViewSet):
""" """
@ -49,19 +51,25 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
""" """
领半成品 领半成品
""" """
mIds = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN, spps = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN,
material__type=Material.MA_TYPE_HALFGOOD).values_list('material', flat=True) material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material')
queyset = WProduct.objects.filter(is_hidden=False, m_state__in=mIds, act_state=WProduct.WPR_ACT_STATE_OK) return Response(SubProductionProgressSerializer(instance=spps, many=True).data)
return Response(WProductListSerializer(instance=queyset, many=True).data)
elif request.method=='POST': elif request.method=='POST':
serializer= PickHalfSerializer(data=request.data) serializer= PickHalfSerializer(data=request.data, many=True)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.data vdata = serializer.data
wps = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']]) first_step = Step.objects.get(pk=sp.steps[0]['id'])
first_step = Step.objects.get(pk=sp.steps[0].id) for i in vdata:
wps.update(p_state=first_step, is_executed=False, if 'wproducts' in i and len(i['wproducts'])>0:
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None, spp = SubProductionProgress.objects.get(pk=i['id'])
subproduction_plan=sp, production_plan=sp.production_plan) spp.count_pick = spp.count_pick + len(i['wproducts'])
if spp.count_pick > spp.count:
raise exceptions.APIException('超过计划数')
spp.save()
wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']])
wps.update(step=first_step, is_executed=False,
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None,
subproduction_plan=sp, production_plan=sp.production_plan, update_by=request.user, update_time=timezone.now())
return Response() return Response()
@ -79,7 +87,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
batch = subplan.production_plan.number batch = subplan.production_plan.number
warehouse = WareHouse.objects.get(id=vdata['warehouse']) warehouse = WareHouse.objects.get(id=vdata['warehouse'])
wproducts = WProduct.objects.filter(subproduction_plan=subplan, wproducts = WProduct.objects.filter(subproduction_plan=subplan,
act_state=WProduct.WPR_ACT_STATE_OK, m_state=material, is_deleted=False) act_state=WProduct.WPR_ACT_STATE_OK, material=material, is_deleted=False)
if wproducts.exists(): if wproducts.exists():
# 创建入库记录 # 创建入库记录
remark = vdata.get('remark', '') remark = vdata.get('remark', '')
@ -119,7 +127,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
IProduct.objects.bulk_create(ips2) IProduct.objects.bulk_create(ips2)
# 更新库存并修改半成品进行状态 # 更新库存并修改半成品进行状态
update_inm(fifo) update_inm(fifo)
wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse) wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now())
return Response() return Response()
@ -131,7 +139,7 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
perms_map={'*':'*'} perms_map={'*':'*'}
queryset = WMaterial.objects.select_related('material').all() queryset = WMaterial.objects.select_related('material').all()
serializer_class = WMaterialListSerializer serializer_class = WMaterialListSerializer
filterset_fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop'] filterset_class = WMaterialFilterSet
ordering_fields = ['material__number'] ordering_fields = ['material__number']
ordering = ['material__number'] ordering = ['material__number']
@ -150,9 +158,9 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
半成品 半成品
""" """
perms_map={'*':'*'} perms_map={'*':'*'}
queryset = WProduct.objects.select_related('p_state', 'm_state').filter(is_hidden=False) queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False).exclude(operation=None)
serializer_class = WProductListSerializer serializer_class = WProductListSerializer
filterset_fields = ['p_state', 'subproduction_plan', 'm_state', 'production_plan', 'p_state__process', 'act_state'] filterset_fields = ['step', 'subproduction_plan', 'material', 'production_plan', 'step__process', 'act_state']
search_fields = ['number'] search_fields = ['number']
ordering_fields = ['id'] ordering_fields = ['id']
ordering = ['id'] ordering = ['id']
@ -173,7 +181,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
if 'is_testok' not in vdata: if 'is_testok' not in vdata:
raise exceptions.APIException('未填写检测结论') raise exceptions.APIException('未填写检测结论')
obj = serializer.save(create_by = self.request.user, m_state=wproduct.m_state) obj = serializer.save(create_by = self.request.user, material=wproduct.material)
tris = [] tris = []
for m in record_data: # 保存记录详情 for m in record_data: # 保存记录详情
form_field = m['form_field'] form_field = m['form_field']
@ -193,7 +201,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
if obj.is_testok: if obj.is_testok:
wproduct.act_state = WProduct.WPR_ACT_STATE_OK wproduct.act_state = WProduct.WPR_ACT_STATE_OK
if wproduct.number is None: # 产生半成品编号 if wproduct.number is None: # 产生半成品编号
wproduct.number = 'WP-'+ranstr(7) wproduct.number = 'WP'+ranstr(7)
wproduct.save() wproduct.save()
# 更新子计划状态 # 更新子计划状态
# 更新子计划主产品数 # 更新子计划主产品数
@ -219,7 +227,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
warehouse = WareHouse.objects.get(id=vdata['warehouse']) warehouse = WareHouse.objects.get(id=vdata['warehouse'])
if wproduct.act_state != WProduct.WPR_ACT_STATE_OK: if wproduct.act_state != WProduct.WPR_ACT_STATE_OK:
raise exceptions.APIException('半成品不可入库') raise exceptions.APIException('半成品不可入库')
material = wproduct.m_state material = wproduct.material
batch = wproduct.production_plan.number batch = wproduct.production_plan.number
# 创建入库记录 # 创建入库记录
remark = vdata.get('remark', '') remark = vdata.get('remark', '')
@ -253,20 +261,225 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
wproduct.save() wproduct.save()
return Response() return Response()
class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
""" """
生产操作记录 生产操作记录
""" """
perms_map={'*':'*'} perms_map={'*':'*'}
queryset = Operation.objects.select_related('p_state', 'm_state').all() queryset = Operation.objects.select_related('step').prefetch_related('ow_operation', 'oe_operation', 'or_operation').all()
serializer_class = OperationListSerializer serializer_class = OperationListSerializer
filterset_fields = ['p_state', 'm_state'] filterset_fields = ['step', 'step__process', 'is_submited']
ordering_fields = ['id'] ordering_fields = ['id']
ordering = ['-id'] ordering = ['-id']
def get_queryset(self):
return self.queryset.filter(create_by=self.request.user)
def get_serializer_class(self): def get_serializer_class(self):
if self.action == 'retrieve': if self.action == 'retrieve':
return OperationDetailSerializer return OperationDetailSerializer
elif self.action == 'create':
return OperationCreateSerializer
elif self.action == 'update':
return OperationUpdateSerializer
return super().get_serializer_class()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.is_submited:
raise exceptions.APIException('该操作已提交')
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
@transaction.atomic
def create(self, request, *args, **kwargs):
data = request.data
serializer = OperationCreateSerializer(data=data, context={'request':self.request})
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data #校验之后的数据
step = vdata['step']
op = Operation()
op.step = step
op.is_submited = False
op.create_by = request.user
op.save()
splans = []
# 创建操作所用半成品关联记录
if 'wproducts' in vdata:
owps = []
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts'])
for wpd in vdata['wproducts']:
owp = {}
owp['operation'] = op
owp['wproduct'] = wpd
owp['number'] = wpd.number
owp['material'] = wpd.material
owp['subproduction_plan'] = wpd.subproduction_plan
owp['production_plan'] = wpd.production_plan
owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps)
else:
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts'])
# 查询需要填写的自定义表格
forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO)
for i in forms:
opr = OperationRecord()
opr.operation = op
opr.form = i
opr.is_filled = False
opr.save()
# 查询需要使用的生产设备
for i in step.equipments.all():
ope = OperationEquip()
ope.operation = op
ope.equip = i
ope.save()
# 查询所需的工具工装
for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
subproduction__subplan_subprod__in = splans, is_deleted=False).distinct():
opm = OperationMaterial()
opm.operation = op
opm.material = i.material
opm.type = SubprodctionMaterial.SUB_MA_TYPE_TOOL
opm.save()
return Response()
class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
"""
操作使用的半成品
"""
perms_map={'*':'*'}
queryset = OperationWproduct.objects.select_related('subproduction_plan', 'material').all()
serializer_class = OperationWproductListSerializer
filterset_fields = ['material', 'subproduction_plan', 'operation']
ordering_fields = ['id']
ordering = ['-id']
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
wp = instance.wproduct
wp.operation = None
wp.save()
return Response()
class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
"""
操作使用的设备
"""
perms_map={'*':'*'}
queryset = OperationEquip.objects.select_related('operation', 'equip').all()
serializer_class = OperationEquipListSerializer
filterset_fields = ['operation', 'equip']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'update':
return OperationEquipUpdateSerializer
return super().get_serializer_class()
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
return Response()
class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
"""
操作使用的自定义表格
"""
perms_map={'*':'*'}
queryset = OperationRecord.objects.select_related('operation', 'form').all()
serializer_class = OperationRecordListSerializer
filterset_fields = ['operation', 'form']
ordering_fields = ['id']
ordering = ['-id']
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=OperationRecordSubmitSerializer)
def submit(self, request, pk=None):
serializer = OperationRecordSubmitSerializer(data=request.data, context={'request':self.request})
serializer.is_valid(raise_exception=True)
vdata = serializer.data
opr = self.get_object()
wrds = []
for m in vdata['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'] = opr
wrds.append(OperationRecordItem(**m))
OperationRecordItem.objects.bulk_create(wrds)
opr.is_filled = True
opr.save()
return Response()
class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
消耗物料
"""
perms_map={'*':'*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN)
serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'create':
return OperationMaterialCreate1Serailizer
return super().get_serializer_class()
class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
产出物料
"""
perms_map={'*':'*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'create':
return OperationMaterialCreate2Serailizer
return super().get_serializer_class()
class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
工具工装
"""
perms_map={'*':'*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL)
serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'create':
return OperationMaterialCreate3Serializer
return super().get_serializer_class() return super().get_serializer_class()
class DoFormInit(CreateAPIView, GenericAPIView): class DoFormInit(CreateAPIView, GenericAPIView):
@ -319,6 +532,15 @@ class DoFormInit(CreateAPIView, GenericAPIView):
ret['forms'] = [] ret['forms'] = []
ret_0['id'] = 0 ret_0['id'] = 0
ret_0['name'] = '基本信息' 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) ret['forms'].append(ret_0)
forms = RecordForm.objects.filter(step=vdata['step'], type=RecordForm.RF_TYPE_DO) forms = RecordForm.objects.filter(step=vdata['step'], type=RecordForm.RF_TYPE_DO)
if forms.exists(): if forms.exists():
@ -342,14 +564,26 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
# 创建一个生产操作记录 # 创建一个生产操作记录
action_obj = Operation() action_obj = Operation()
action_obj.p_state = vdata['step'] action_obj.step = vdata['step']
if 'wproducts' in data and data['wproducts']:
action_obj.wproducts = data['wproducts']
action_obj.m_state = vdata['wproducts'][0].m_state
action_obj.remark = vdata.get('remark', '') # 操作备注 action_obj.remark = vdata.get('remark', '') # 操作备注
action_obj.create_by = request.user action_obj.create_by = request.user
action_obj.use_scrap = vdata.get('use_scrap', False) action_obj.use_scrap = vdata.get('use_scrap', False)
action_obj.save() 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
owp['production_plan'] = wp.production_plan
owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps)
# 保存物料消耗 # 保存物料消耗
for i in vdata['input']: for i in vdata['input']:
@ -375,7 +609,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
# 获取下一步子工序 # 获取下一步子工序
if vdata['step'].type == Step.STEP_TYPE_DIV: if vdata['step'].type == Step.STEP_TYPE_DIV:
newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wpr = dict(m_state=ma, p_state=newstep, wpr = dict(material=ma, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='', act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
subproduction_plan=i['subproduction_plan'], subproduction_plan=i['subproduction_plan'],
production_plan=i['subproduction_plan'].production_plan) production_plan=i['subproduction_plan'].production_plan)
@ -404,8 +638,8 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproducts.update(is_hidden=True) # 隐藏 wproducts.update(is_hidden=True) # 隐藏
newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wproduct = WProduct() wproduct = WProduct()
wproduct.m_state = vdata['subproduction_plan'].main_product wproduct.material = vdata['subproduction_plan'].main_product
wproduct.p_state = newstep wproduct.step = newstep
wproduct.subproduction_plan=vdata['subproduction_plan'] wproduct.subproduction_plan=vdata['subproduction_plan']
wproduct.production_plan=vdata['subproduction_plan'].production_plan wproduct.production_plan=vdata['subproduction_plan'].production_plan
wproduct.parent = data['wproducts'] wproduct.parent = data['wproducts']
@ -421,15 +655,15 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
else: else:
for wproduct in vdata['wproducts']: for wproduct in vdata['wproducts']:
# 获取下一步子工序 # 获取下一步子工序
newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) newstep, hasNext = WpmServies.get_next_step(wproduct.subproduction_plan, vdata['step'])
wproduct.p_state = newstep wproduct.step = newstep
wproduct.pre_pstate=vdata['step'] wproduct.pre_step=vdata['step']
if hasNext: if hasNext:
wproduct.is_executed= False wproduct.is_executed= False
else: else:
wproduct.is_executed= True wproduct.is_executed= True
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
wproduct.m_state=wproduct.subproduction_plan.main_product wproduct.material=wproduct.subproduction_plan.main_product
wproduct.save() wproduct.save()
# 保存自定义表单结果 # 保存自定义表单结果

View File

@ -1,5 +1,5 @@
celery==5.1.2 celery==5.1.2
Django==3.2.6 Django==3.2.9
django-celery-beat==2.2.1 django-celery-beat==2.2.1
django-cors-headers==3.7.0 django-cors-headers==3.7.0
django-filter==2.4.0 django-filter==2.4.0

View File

@ -26,7 +26,7 @@ from rest_framework.documentation import include_docs_urls
from rest_framework_simplejwt.views import (TokenObtainPairView, from rest_framework_simplejwt.views import (TokenObtainPairView,
TokenRefreshView) TokenRefreshView)
from django.views.generic import TemplateView from django.views.generic import TemplateView
from utils.view import GenSignature from utils.view import GenSignature, UpdateDevelop
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register('', FileViewSet, basename="file") router.register('', FileViewSet, basename="file")
@ -72,6 +72,7 @@ urlpatterns = [
# 工具 # 工具
path('api/utils/signature/', GenSignature.as_view()), path('api/utils/signature/', GenSignature.as_view()),
path('api/utils/develop/', UpdateDevelop.as_view()),
# 前端页面入口 # 前端页面入口
path('',TemplateView.as_view(template_name="index.html")) path('',TemplateView.as_view(template_name="index.html"))

View File

@ -2,6 +2,6 @@ import random
import string import string
def ranstr(num): def ranstr(num):
salt = ''.join(random.sample(string.ascii_letters + string.digits, num)) salt = ''.join(random.sample(string.ascii_lowercase + string.digits, num))
return salt return salt
ranstr(10) ranstr(10)

View File

@ -49,3 +49,22 @@ class GenSignature(APIView):
image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0 image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0
cv2.imwrite(path,image) cv2.imwrite(path,image)
return Response(request.data, status=status.HTTP_200_OK) return Response(request.data, status=status.HTTP_200_OK)
class UpdateDevelop(APIView):
"""
更新开发服务器
"""
authentication_classes = ()
permission_classes = ()
def post(self, request, *args, **kwargs):
import os
# 更新后端
os.chdir('/home/hberp')
ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git origin develop')
# 打包前端
# os.chdir('/home/hberp/hb_client')
# os.system('npm run build:prod')
# os.system('\cp -rf /home/hberp/hb_client/dist/* /home/hberp/hb_server/vuedist')
return Response(ret.read())