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

This commit is contained in:
shijing 2021-12-03 09:57:00 +08:00
commit 269ce6b9bc
9 changed files with 186 additions and 71 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-03 01:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0040_material_piece_count'),
]
operations = [
migrations.AlterField(
model_name='material',
name='type',
field=models.PositiveSmallIntegerField(choices=[(1, '成品'), (2, '半成品'), (3, '主要原料'), (4, '辅助材料'), (5, '加工工具'), (6, '辅助工装')], default=1, verbose_name='物料类型'),
),
]

View File

@ -36,7 +36,7 @@ class Material(CommonAModel):
name = models.CharField('物料名称', max_length=100)
number = models.CharField('编号', max_length=100, unique=True)
specification = models.CharField('型号', max_length=100, null=True, blank=True)
type = models.CharField('物料类型', choices= type_choices, max_length=20, default=1)
type = models.PositiveSmallIntegerField('物料类型', choices= type_choices, default=1)
sort_str = models.CharField('排序字符', max_length=100, null=True, blank=True)
unit = models.CharField('基准计量单位', choices=unit_choices, default='', max_length=10)
count = models.IntegerField('物料总数', default=0)

View File

@ -0,0 +1,30 @@
# Generated by Django 3.2.9 on 2021-12-02 08:20
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0040_material_piece_count'),
('qm', '0012_alter_testrecorditem_field_type'),
]
operations = [
migrations.AddField(
model_name='testrecord',
name='step',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='关联的工序步骤'),
),
migrations.AddField(
model_name='testrecord',
name='test_record',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord', verbose_name='关联检验记录'),
),
migrations.AddField(
model_name='testrecord',
name='type',
field=models.PositiveSmallIntegerField(choices=[(10, '子工序检验'), (20, '工序检验'), (30, '工序复检'), (40, '成品检验')], default=20),
),
]

View File

@ -47,14 +47,27 @@ class TestRecord(CommonAModel):
"""
检验记录
"""
TEST_STEP = 10
TEST_PROCESS = 20
TEST_PROCESS_RE = 30
TEST_FINAL = 40
type_choice = (
(TEST_STEP, '子工序检验'),
(TEST_PROCESS, '工序检验'),
(TEST_PROCESS_RE, '工序复检'),
(TEST_FINAL, '成品检验')
)
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
type = models.PositiveSmallIntegerField(choices=type_choice, default=TEST_PROCESS)
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)
material = models.ForeignKey('mtm.material', verbose_name='关联的物料状态', on_delete=models.CASCADE, null=True, blank=True)
step = models.ForeignKey('mtm.step', verbose_name='关联的工序步骤', on_delete=models.CASCADE, null=True, blank=True)
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)
test_record = models.ForeignKey('self', verbose_name='关联检验记录', on_delete=models.CASCADE, null=True, blank=True)
remark = models.TextField('备注', default='')

View File

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

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-12-02 08:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0028_auto_20211202_1620'),
]
operations = [
migrations.RemoveField(
model_name='wproduct',
name='is_executed',
),
migrations.AlterField(
model_name='wproduct',
name='operation',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wp_operation', to='wpm.operation', verbose_name='关联操作'),
),
]

View File

@ -25,6 +25,7 @@ class WProduct(CommonAModel):
动态半成品/成品表
"""
WPR_ACT_STATE_TORETEST = 6
WPR_ACT_STATE_DOWAIT = 8
WPR_ACT_STATE_DOING = 10
WPR_ACT_STATE_TOTEST = 20
WPR_ACT_STATE_OK = 30
@ -33,7 +34,8 @@ class WProduct(CommonAModel):
WPR_ACT_STATE_TOFINALTEST = 60
act_state_choices=(
(WPR_ACT_STATE_TORETEST, '待复检'),
(WPR_ACT_STATE_DOING, '生产中'),
(WPR_ACT_STATE_DOWAIT, '操作准备中'),
(WPR_ACT_STATE_DOING, '操作进行中'),
(WPR_ACT_STATE_TOTEST, '待检验'),
(WPR_ACT_STATE_OK, '已合格'),
(WPR_ACT_STATE_INM, '库存中'),
@ -45,14 +47,13 @@ class WProduct(CommonAModel):
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_step')
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)
is_executed = models.BooleanField('子工序是否已执行', default=False)
is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
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')
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')
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
class Pick(CommonADModel):

View File

@ -100,7 +100,7 @@ class PickSerializer(serializers.Serializer):
wids = IProduct.objects.filter(pk__in=[x.id for x in iproducts]).values_list('wproduct', flat=True)
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,
wproducts.update(step=first_step,
act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None,
subproduction_plan=sp)
sp.is_picked=True
@ -187,10 +187,10 @@ class OperationCreateSerializer(serializers.Serializer):
if step.type == Step.STEP_TYPE_DIV:
raise exceptions.APIException(_('不可进行此操作'))
for i in data['wproducts']:
if i.act_state != WProduct.WPR_ACT_STATE_DOING:
raise exceptions.APIException('半成品不在生产状态')
if i.is_executed:
raise exceptions.APIException('不可进行操作')
if i.act_state != WProduct.WPR_ACT_STATE_DOWAIT:
raise exceptions.APIException('半成品不在待操作状态')
# if i.is_executed:
# raise exceptions.APIException('不可进行操作')
# if i.subproduction_plan != subproduction_plan:
# raise exceptions.APIException('半成品所属子计划不一致')
if i.step != step:
@ -224,8 +224,8 @@ class OperationInitSerializer(serializers.Serializer):
if step.type == Step.STEP_TYPE_DIV:
raise exceptions.APIException(_('不可进行此操作'))
for i in data['wproducts']:
if i.is_executed:
raise exceptions.APIException('不可进行操作')
if i.act_state != WProduct.WPR_ACT_STATE_DOWAIT:
raise exceptions.APIException('半成品不在待操作状态')
# if i.subproduction_plan != subproduction_plan:
# raise exceptions.APIException('半成品所属子计划不一致')
if i.step != step:

View File

@ -11,7 +11,7 @@ from apps.mtm.models import Material, RecordForm, RecordFormField, Step, Subprod
from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from apps.qm.models import TestRecordItem
from apps.qm.models import TestRecord, TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
@ -73,7 +73,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
# raise exceptions.APIException('超过计划数')
spp.save()
wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']], act_state=WProduct.WPR_ACT_STATE_OK)
wps.update(step=first_step, is_executed=False,
wps.update(step=first_step,
act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None,
subproduction_plan=sp, update_by=request.user, update_time=timezone.now())
for i in wps:
@ -177,9 +177,9 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
半成品
"""
perms_map={'*':'*'}
queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False, operation=None)
queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False)
serializer_class = WProductListSerializer
filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state']
filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state', 'material__type']
search_fields = ['number']
ordering_fields = ['id']
ordering = ['id']
@ -195,13 +195,19 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
vdata = serializer.validated_data
record_data = vdata.pop('record_data')
wproduct = vdata['wproduct']
if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST, WProduct.WPR_ACT_STATE_TORETEST]:
if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST,
WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST]:
raise exceptions.APIException('该产品当前状态不可检验')
if 'is_testok' not in vdata:
raise exceptions.APIException('未填写检测结论')
obj = serializer.save(create_by = self.request.user,
material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan)
savedict = dict(create_by = self.request.user,
material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan, step=wproduct.step)
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST:
savedict['type'] = TestRecord.TEST_PROCESS_RE
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST:
savedict['type'] = TestRecord.TEST_FINAL
obj = serializer.save(**savedict)
tris = []
for m in record_data: # 保存记录详情
form_field = m['form_field']
@ -219,7 +225,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
# 如果检测合格, 变更动态产品进行状态
if obj.is_testok:
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
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 wproduct.material.type == Material.MA_TYPE_GOOD:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST # 成品检验
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
if wproduct.number is None: # 产生半成品编号
wproduct.number = 'WP'+ranstr(7)
wproduct.save()
@ -235,47 +246,47 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
return Response()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer)
@transaction.atomic
def retest(self, request, pk=None):
"""
复检
"""
serializer = WpmTestRecordCreateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
record_data = vdata.pop('record_data')
wproduct = vdata['wproduct']
if wproduct.act_state != WProduct.WPR_ACT_STATE_TORETEST:
raise exceptions.APIException('该产品当前状态不可检验')
if 'is_testok' not in vdata:
raise exceptions.APIException('未填写检测结论')
# @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer)
# @transaction.atomic
# def retest(self, request, pk=None):
# """
# 复检
# """
# serializer = WpmTestRecordCreateSerializer(data=request.data)
# serializer.is_valid(raise_exception=True)
# vdata = serializer.validated_data
# record_data = vdata.pop('record_data')
# wproduct = vdata['wproduct']
# if wproduct.act_state != WProduct.WPR_ACT_STATE_TORETEST:
# raise exceptions.APIException('该产品当前状态不可检验')
# if 'is_testok' not in vdata:
# raise exceptions.APIException('未填写检测结论')
obj = serializer.save(create_by = self.request.user,
material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan)
tris = []
for m in 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['need_judge'] = form_field.need_judge
m['is_testok'] = m['is_testok'] if 'is_testok' in m else None
m['test_record'] = obj
tris.append(TestRecordItem(**m))
TestRecordItem.objects.bulk_create(tris)
# obj = serializer.save(create_by = self.request.user,
# material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan)
# tris = []
# for m in 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['need_judge'] = form_field.need_judge
# m['is_testok'] = m['is_testok'] if 'is_testok' in m else None
# m['test_record'] = obj
# tris.append(TestRecordItem(**m))
# TestRecordItem.objects.bulk_create(tris)
# 如果检测合格, 变更动态产品进行状态
# # 如果检测合格, 变更动态产品进行状态
if obj.is_testok:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOING
wproduct.save()
else:# 如果不合格
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
wproduct.save()
return Response()
# if obj.is_testok:
# wproduct.act_state = WProduct.WProduct.WPR_ACT_STATE_DOWAIT
# wproduct.save()
# else:# 如果不合格
# wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
# wproduct.save()
# return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
@transaction.atomic
@ -357,6 +368,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
instance = self.get_object()
if instance.is_submited:
raise exceptions.APIException('该操作已提交')
# 恢复半成品可操作
instance.wp_operation.all().update(act_state=WProduct.WPR_ACT_STATE_DOWAIT)
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
@ -376,7 +389,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 创建操作所用半成品关联记录
if 'wproducts' in vdata:
owps = []
WProduct.objects.filter(pk__in=[x.id for x in vdata['wproducts']]).update(operation=op)
WProduct.objects.filter(pk__in=[x.id for x in vdata['wproducts']]).update(operation=op, act_state=WProduct.WPR_ACT_STATE_DOING)
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts'])
for wpd in vdata['wproducts']:
owp = {}
@ -456,9 +469,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
wp.step = newstep
wp.pre_step = step
if hasNext:
wp.is_executed= False
wp.act_state= WProduct.WPR_ACT_STATE_DOWAIT
else:
wp.is_executed = True
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material = wsp.main_product
# 更新子计划进度
@ -474,7 +486,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
if i.subproduction_progress.is_main:
newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step)
wpr = dict(material=i.material, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i.subproduction_plan)
for x in range(i.count):
WProduct.objects.create(**wpr)
@ -486,11 +498,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
wproduct.step = newstep
wproduct.subproduction_plan = i.subproduction_plan
if hasNext:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOING
wproduct.is_executed = False
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.is_executed = True
# 更新子计划进度
instance = SubProductionProgress.objects.get(subproduction_plan=i.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
@ -799,7 +809,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
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_DOING, is_executed=False, remark='',
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i['subproduction_plan'])
for x in range(i['count_output']):
WProduct.objects.create(**wpr)
@ -831,11 +841,9 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproduct.subproduction_plan=vdata['subproduction_plan']
wproduct.parent = data['wproducts']
if hasNext:
wproduct.act_state=WProduct.WPR_ACT_STATE_DOING
wproduct.is_executed=False
wproduct.act_state=WProduct.WPR_ACT_STATE_DOWAIT
else:
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
wproduct.is_executed=True
wproduct.save()
else:
raise exceptions.APIException('请指定子计划')
@ -846,9 +854,8 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproduct.step = newstep
wproduct.pre_step=vdata['step']
if hasNext:
wproduct.is_executed= False
wproduct.act_state=WProduct.WPR_ACT_STATE_DOWAIT
else:
wproduct.is_executed= True
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
wproduct.material=wproduct.subproduction_plan.main_product
wproduct.save()