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

This commit is contained in:
shijing 2021-12-27 10:11:22 +08:00
commit ce635ff949
16 changed files with 302 additions and 48 deletions

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.9 on 2021-12-27 01:48
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0038_auto_20211227_0948'),
('inm', '0023_auto_20211216_0945'),
]
operations = [
migrations.AlterField(
model_name='fifoitemproduct',
name='wproduct',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fifoitem_wproduct', to='wpm.wproduct', verbose_name='关联的动态产品'),
),
migrations.AlterField(
model_name='iproduct',
name='wproduct',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='iproduct_wproduct', to='wpm.wproduct', verbose_name='关联的动态产品'),
),
]

View File

@ -92,7 +92,8 @@ class IProduct(BaseModel):
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, default='')
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False,
null=True, blank=True, related_name='iproduct_wproduct')
is_mtested = models.BooleanField('是否军检', default=False)
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
remark_mtest = models.TextField('军检备注', null=True, blank=True)
@ -103,7 +104,8 @@ class FIFOItemProduct(BaseModel):
出入库产品
"""
fifoitem = models.ForeignKey(FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True,
related_name='fifoitem_wproduct')
number = models.CharField('物品编号', max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
iproduct = models.ForeignKey(IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL)

View File

@ -74,7 +74,7 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'*': '*'}
queryset = FIFOItem.objects.select_related('material', 'fifo').all()
serializer_class = FIFOItemSerializer
filterset_fields = ['material', 'fifo']
filterset_fields = ['material', 'fifo', 'fifo__type', 'is_tested', 'is_testok']
search_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
@ -99,13 +99,7 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
obj = serializer.save(create_by = self.request.user)
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 True
m['test_record'] = obj
tris.append(TestRecordItem(**m))

View File

@ -14,6 +14,8 @@ from rest_framework.decorators import action
from django.db.models import F
from rest_framework.response import Response
from django.utils import timezone
from apps.wf.models import Workflow
# Create your views here.
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
"""
@ -168,6 +170,10 @@ class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, C
FIFOItemProduct.objects.bulk_create(ipxs)
# 更新成品库情况
ips.update(is_saled=True)
# 更新动态产品表情况
from apps.wpm.models import WProduct
WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
act_state=WProduct.WPR_ACT_STATE_SELLED)
# 更新库存
update_inm(fifo)
# 变更审核状态

View File

@ -0,0 +1,38 @@
# Generated by Django 3.2.9 on 2021-12-23 02:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wf', '0019_auto_20211221_0923'),
]
operations = [
migrations.AddField(
model_name='customfield',
name='is_hidden',
field=models.BooleanField(default=False, help_text='可用于携带不需要用户查看的信息', verbose_name='是否隐藏'),
),
migrations.AlterField(
model_name='customfield',
name='field_choice',
field=models.JSONField(blank=True, default=list, help_text='选项值格式为list, 例["id":1, "name":"张三"]', verbose_name='选项值'),
),
migrations.AlterField(
model_name='customfield',
name='field_type',
field=models.CharField(choices=[('string', '字符串'), ('int', '整型'), ('float', '浮点'), ('boolean', '布尔'), ('date', '日期'), ('datetime', '日期时间'), ('radio', '单选'), ('checkbox', '多选'), ('select', '单选下拉'), ('selects', '多选下拉'), ('cascader', '单选级联'), ('cascaders', '多选级联'), ('select_dg', '弹框单选'), ('select_dgs', '弹框多选'), ('textarea', '文本域'), ('file', '附件')], help_text='5.字符串10.整形15.浮点型20.布尔25.日期30.日期时间35.单选框40.多选框45.下拉列表50.多选下拉列表55.文本域60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)', max_length=50, verbose_name='类型'),
),
migrations.AlterField(
model_name='customfield',
name='label',
field=models.CharField(default='', help_text='处理特殊逻辑使用', max_length=1000, verbose_name='标签'),
),
migrations.AlterField(
model_name='workflow',
name='title_template',
field=models.CharField(blank=True, default='{title}', help_text='工单字段的值可以作为参数写到模板中,格式如:你有一个待办工单:{title}', max_length=50, null=True, verbose_name='标题模板'),
),
]

View File

@ -0,0 +1,33 @@
# Generated by Django 3.2.9 on 2021-12-24 06:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wf', '0020_auto_20211223_1006'),
]
operations = [
migrations.AlterField(
model_name='customfield',
name='description',
field=models.CharField(blank=True, help_text='字段的描述信息,可用于显示在字段的下方对该字段的详细描述', max_length=100, null=True, verbose_name='描述'),
),
migrations.AlterField(
model_name='customfield',
name='field_template',
field=models.TextField(blank=True, help_text='文本域类型字段前端显示时可以将此内容作为字段的placeholder', null=True, verbose_name='文本域模板'),
),
migrations.AlterField(
model_name='customfield',
name='field_type',
field=models.CharField(choices=[('string', '字符串'), ('int', '整型'), ('float', '浮点'), ('boolean', '布尔'), ('date', '日期'), ('datetime', '日期时间'), ('radio', '单选'), ('checkbox', '多选'), ('select', '单选下拉'), ('selects', '多选下拉'), ('cascader', '单选级联'), ('cascaders', '多选级联'), ('select_dg', '弹框单选'), ('select_dgs', '弹框多选'), ('textarea', '文本域'), ('file', '附件')], help_text='string, int, float, date, datetime, radio, checkbox, select, selects, cascader, cascaders, cascader, cascaders,textarea, file', max_length=50, verbose_name='类型'),
),
migrations.AlterField(
model_name='customfield',
name='placeholder',
field=models.CharField(blank=True, help_text='用户工单详情表单中作为字段的占位符显示', max_length=100, null=True, verbose_name='占位符'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-27 01:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wf', '0021_auto_20211224_1426'),
]
operations = [
migrations.AlterField(
model_name='customfield',
name='is_hidden',
field=models.BooleanField(default=False, help_text='可用于携带不需要用户查看的字段信息', verbose_name='是否隐藏'),
),
]

View File

@ -150,26 +150,32 @@ class CustomField(CommonAModel):
('checkbox', '多选'),
('select', '单选下拉'),
('selects', '多选下拉'),
('cascader', '单选级联'),
('cascaders', '多选级联'),
('select_dg', '弹框单选'),
('select_dgs', '弹框多选'),
('textarea', '文本域'),
('selectuser', '单选用户'),
('selectusers', '多选用户'),
('file', '附件'),
('draw', '绘图')
('file', '附件')
)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
field_type = models.CharField('类型', max_length=50, choices=field_type_choices, help_text='5.字符串10.整形15.浮点型20.布尔25.日期30.日期时间35.单选框40.多选框45.下拉列表50.多选下拉列表55.文本域60.用户名, 70.多选的用户名, 80.附件(只保存路径,多个使用逗号隔开)')
field_type = models.CharField('类型', max_length=50, choices=field_type_choices,
help_text='string, int, float, date, datetime, radio, checkbox, select, selects, cascader, cascaders, cascader, cascaders,textarea, file')
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
field_name = models.CharField('字段名称', max_length=50)
sort = models.IntegerField('排序', default=0, help_text='工单基础字段在表单中排序为:流水号0,标题20,状态id40,状态名41,创建人80,创建时间100,更新时间120.前端展示工单信息的表单可以根据这个id顺序排列')
default_value = models.CharField('默认值', null=True, blank=True, max_length=100, help_text='前端展示时,可以将此内容作为表单中的该字段的默认值')
description = models.CharField('描述', max_length=100, blank=True, default='', help_text='字段的描述信息,可用于显示在字段的下方对该字段的详细描述')
placeholder = models.CharField('占位符', max_length=100, blank=True, default='', help_text='用户工单详情表单中作为字段的占位符显示')
field_template = models.TextField('文本域模板', default='', blank=True, help_text='文本域类型字段前端显示时可以将此内容作为字段的placeholder')
description = models.CharField('描述', max_length=100, blank=True, null=True, help_text='字段的描述信息,可用于显示在字段的下方对该字段的详细描述')
placeholder = models.CharField('占位符', max_length=100, blank=True, null=True, help_text='用户工单详情表单中作为字段的占位符显示')
field_template = models.TextField('文本域模板', null=True, blank=True, help_text='文本域类型字段前端显示时可以将此内容作为字段的placeholder')
boolean_field_display = models.JSONField('布尔类型显示名', default=dict, blank=True,
help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"","0":""}或{"1":"需要","0":"不需要"},注意数字也需要引号')
field_choice = models.JSONField('radio、checkbox、select的选项', default=dict, blank=True,
help_text='radio,checkbox,select,multiselect类型可供选择的选项格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
label = models.JSONField('标签', blank=True, default=dict, help_text='自定义标签json格式调用方可根据标签自行处理特殊场景逻辑loonflow只保存文本内容')
field_choice = models.JSONField('选项值', default=list, blank=True,
help_text='选项值格式为list, 例["id":1, "name":"张三"]')
label = models.CharField('标签', max_length=1000, default='', help_text='处理特殊逻辑使用')
# hook = models.CharField('hook', max_length=1000, default='', help_text='获取下拉选项用于动态选项值')
is_hidden = models.BooleanField('是否隐藏', default=False, help_text='可用于携带不需要用户查看的字段信息')
class Ticket(CommonBModel):
"""

View File

@ -38,12 +38,33 @@ class TransitionSerializer(serializers.ModelSerializer):
queryset = queryset.select_related('source_state','destination_state')
return queryset
class AllField(serializers.Field):
def to_representation(self, value):
return value
def to_internal_value(self, data):
return data
class FieldChoiceSerializer(serializers.Serializer):
id = AllField(label='ID')
name = serializers.CharField(label='名称')
class CustomFieldSerializer(serializers.ModelSerializer):
class Meta:
model = CustomField
fields = '__all__'
class CustomFieldCreateUpdateSerializer(serializers.ModelSerializer):
field_choice = FieldChoiceSerializer(label='选项列表', many=True, required=False)
class Meta:
model = CustomField
fields = ['workflow', 'field_type', 'field_key', 'field_name',
'sort', 'default_value', 'description', 'placeholder', 'field_template',
'boolean_field_display', 'field_choice', 'label', 'is_hidden']
class TicketSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Ticket
@ -107,8 +128,28 @@ class TicketDetailSerializer(serializers.ModelSerializer):
key = i['field_key']
i['field_state'] = state_fields.get(key, 1)
i['field_value'] = ticket_data.get(key, None)
i['field_display'] = i['field_value'] # 该字段是用于查看详情直接展示
if 'sys_user' in i['label']:
if isinstance(i['field_value'], list):
i['field_display'] = ','.join(list(User.objects.filter(id__in=i['field_value']).values_list('name', flat=True)))
else:
i['field_display'] = User.objects.get(id=i['field_value']).name
elif i['field_type'] in ['radio', 'select']:
for m in i['field_choice']:
if m['id'] == i['field_value']:
i['field_display'] = m['name']
elif i['field_type'] in ['checkbox', 'selects']:
d_list = []
for m in i['field_choice']:
if m['id'] in i['field_value']:
d_list.append(m['name'])
i['field_display'] = ','.join(d_list)
return all_fields_l
def filter_display(self, item, field_value):
if item['id'] == field_value:
return
class TicketFlowSerializer(serializers.ModelSerializer):
participant_ = UserSimpleSerializer(source='participant', read_only=True)
state_ = StateSimpleSerializer(source='state', read_only=True)

View File

@ -9,7 +9,7 @@ from django.core.exceptions import AppRegistryNotReady
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from apps.wf.serializers import CustomFieldSerializer, StateSerializer, TicketAddNodeEndSerializer, TicketAddNodeSerializer, TicketCloseSerializer, TicketCreateSerializer, TicketDestorySerializer, TicketFlowSerializer, TicketFlowSimpleSerializer, TicketHandleSerializer, TicketRetreatSerializer, TicketSerializer, TransitionSerializer, WorkflowSerializer, TicketListSerializer, TicketDetailSerializer
from apps.wf.serializers import CustomFieldCreateUpdateSerializer, CustomFieldSerializer, StateSerializer, TicketAddNodeEndSerializer, TicketAddNodeSerializer, TicketCloseSerializer, TicketCreateSerializer, TicketDestorySerializer, TicketFlowSerializer, TicketFlowSimpleSerializer, TicketHandleSerializer, TicketRetreatSerializer, TicketSerializer, TransitionSerializer, WorkflowSerializer, TicketListSerializer, TicketDetailSerializer
from django.shortcuts import get_object_or_404, render
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.decorators import action, api_view
@ -111,6 +111,11 @@ class CustomFieldViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin,
filterset_fields = ['workflow', 'field_type']
ordering = ['sort']
def get_serializer_class(self):
if self.action in ['create', 'update']:
return CustomFieldCreateUpdateSerializer
return super().get_serializer_class()
class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, RetrieveModelMixin, GenericViewSet):
perms_map = {'*':'*'}
queryset = Ticket.objects.all()
@ -133,7 +138,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
return super().get_serializer_class()
def filter_queryset(self, queryset):
if not self.request.query_params.get('category', None):
if not self.detail and not self.request.query_params.get('category', None):
raise APIException('请指定查询分类')
return super().filter_queryset(queryset)

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.9 on 2021-12-27 01:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0037_wproduct_scrap_reason'),
]
operations = [
migrations.AddField(
model_name='wproduct',
name='ng_sign',
field=models.PositiveSmallIntegerField(blank=True, choices=[(10, '返工'), (20, '返修'), (30, '报废'), (40, '让步接收'), (50, '偏离许可'), (60, '降级使用'), (70, '退回供方'), (80, '召回')], null=True, verbose_name='不合格标记'),
),
migrations.AlterField(
model_name='wproduct',
name='act_state',
field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '已入库'), (50, '不合格'), (60, '待成品检验'), (70, '已报废'), (80, '已售出')], default=0, verbose_name='进行状态'),
),
migrations.AlterField(
model_name='wprouctticket',
name='decision',
field=models.PositiveSmallIntegerField(blank=True, choices=[(10, '返工'), (20, '返修'), (30, '报废'), (40, '让步接收'), (50, '偏离许可'), (60, '降级使用'), (70, '退回供方'), (80, '召回')], null=True, verbose_name='最终决定'),
),
]

View File

@ -36,6 +36,7 @@ class WProduct(CommonAModel):
WPR_ACT_STATE_NOTOK = 50
WPR_ACT_STATE_TOFINALTEST = 60
WPR_ACT_STATE_SCRAP = 70
WPR_ACT_STATE_SELLED = 80
act_state_choices=(
(WPR_ACT_STATE_TORETEST, '待复检'),
(WPR_ACT_STATE_DOWAIT, '操作准备中'),
@ -46,7 +47,8 @@ class WProduct(CommonAModel):
(WPR_ACT_STATE_INM, '已入库'),
(WPR_ACT_STATE_NOTOK, '不合格'),
(WPR_ACT_STATE_TOFINALTEST, '待成品检验'),
(WPR_ACT_STATE_SCRAP, '已报废')
(WPR_ACT_STATE_SCRAP, '已报废'),
(WPR_ACT_STATE_SELLED, '已售出'),
)
SCRAP_REASON_QIPAO = 10
SCRAP_REASON_PODIAN = 20
@ -58,6 +60,26 @@ class WProduct(CommonAModel):
(30, '划伤'),
(40, '其他')
)
NG_BACK_WORK = 10
NG_BACK_FIX = 20
NG_SCRAP = 30
NG_ACCEPT = 40
NG_PERMIT = 50
NG_DOWN = 60
NG_BACK_FROM = 70
NG_RECALL = 80
ng_choices = (
(NG_BACK_WORK, '返工'),
(NG_BACK_FIX, '返修'),
(NG_SCRAP, '报废'),
(NG_ACCEPT, '让步接收'),
(NG_PERMIT, '偏离许可'),
(NG_DOWN, '降级使用'),
(NG_BACK_FROM, '退回供方'),
(NG_RECALL, '召回')
)
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_step')
@ -69,6 +91,9 @@ class WProduct(CommonAModel):
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan')
scrap_reason = models.IntegerField('报废原因', choices=scrap_reason_choices, null=True, blank=True)
ng_sign = models.PositiveSmallIntegerField('不合格标记', choices=ng_choices, 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='wp_operation')
@ -89,6 +114,7 @@ class WprouctTicket(CommonAModel):
"""
玻璃审批工单
"""
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
wproduct = models.ForeignKey(WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
material = models.ForeignKey(Material, verbose_name='所在物料状态', on_delete=models.CASCADE)
@ -96,7 +122,7 @@ class WprouctTicket(CommonAModel):
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE)
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='wt_ticket')
decision = models.CharField('最终决定', null=True, blank=True, max_length=100)
decision = models.PositiveSmallIntegerField('最终决定', choices=WProduct.ng_choices, null=True, blank=True)
class Pick(CommonADModel):
"""

View File

@ -382,6 +382,7 @@ class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
class OperationMaterialCreate2ListSerailizer(serializers.ListSerializer):
child=OperationMaterialCreate2Serailizer()
class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all())
class Meta:

View File

@ -46,17 +46,18 @@ class WpmServies(object):
if is_testok:
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
wproduct.ng_sign = None # 把不合格标记去除
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)
# 更新子计划状态
# 更新子计划主产品数
# 更新子计划合格进度
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_ok = instance.count_ok + 1 # 这个地方可能会有问题
instance.count_ok = instance.count_ok + 1
instance.save()
else:# 如果不合格
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK

View File

@ -1,9 +1,12 @@
from django.db.models.signals import post_save
from apps.mtm.models import SubprodctionMaterial
from apps.pm.models import SubProductionProgress
from apps.qm.models import TestRecord
from apps.wf.models import Ticket
from django.dispatch import receiver
from rest_framework import exceptions
from apps.wpm.models import WProduct, WprouctTicket
from apps.wpm.models import OperationWproduct
@receiver(post_save, sender=Ticket)
@ -43,18 +46,41 @@ def handleTicket(sender, instance, created, **kwargs):
ticket_data = instance.ticket_data
wt = instance.wt_ticket
wp = wt.wproduct
decision = WProduct.NG_BACK_WORK
if 'decision_1' in ticket_data and ticket_data['decision_1']:
wt.decision = ticket_data['decision_1']
if ticket_data['decision_1'] in ['返工', '返修']:
pass
elif ticket_data['decision_1'] in ['让步接收']:
wp.act_state = WProduct.WPR_ACT_STATE_OK
decision = ticket_data['decision_1']
elif 'decision_2' in ticket_data and ticket_data['decision_2']:
wp.decision = ticket_data['decision_2']
if ticket_data['decision_2'] in ['返工', '返修']:
pass
elif ticket_data['decision_2'] in ['让步接收']:
wp.act_state = WProduct.WPR_ACT_STATE_OK
wt.save()
wp.save()
decision = ticket_data['decision_2']
wp.ng_sign = decision
if decision in [WProduct.NG_BACK_WORK, WProduct.NG_BACK_FIX]:
step = ticket_data['back_step']
wp.step = step
# 找到当时所属的计划
sp = OperationWproduct.objects.filter(operation__is_submited=True, operation__step=step).first()
if sp:
wp.subproduction_plan = sp
wt.save()
wp.ticket = None # 解除当前工单
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
wp.save()
# 更新子计划合格进度
instance = SubProductionProgress.objects.get(subproduction_plan=sp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_ok = instance.count_ok - 1 #进度计算这里该怎么处理呢
instance.save()
else:
raise exceptions.APIException('返回步骤点错误')
elif decision in [WProduct.NG_ACCEPT, WProduct.NG_PERMIT]:
wp.act_state = WProduct.WPR_ACT_STATE_OK
wp.ng_sign = decision
wt.save()
wp.ticket = None # 解除当前工单
wp.save()

View File

@ -343,7 +343,8 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
vdata = serializer.validated_data
if obj.act_state == WProduct.WPR_ACT_STATE_NOTOK:
pass
elif obj.step.process.id == 1: # 如果是冷加工可直接报废
elif obj.step.process.id == 1 and \
obj.act_state in [WProduct.WPR_ACT_STATE_DOWAIT, WProduct.WPR_ACT_STATE_TOTEST]: # 如果是冷加工可直接报废
if vdata.get('scrap_reason', None):
obj.scrap_reason = vdata['scrap_reason']
else:
@ -369,12 +370,13 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
发起不合格审理单
"""
obj = self.get_object()
if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK:
raise exceptions.APIException('非检验不合格产品不可发起不合格审理')
if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK or obj.ng_sign is not None:
raise exceptions.APIException('产品不可发起不合格审理')
workflow = Workflow.objects.filter(name='不合格品审理单', is_deleted=False).first()
if workflow:
exist_data = {
'wproduct':obj.id,
'wproduct_number':obj.number,
'wproduct_name':obj.material.name,
'wproduct_specification':obj.material.specification,
'finder':request.user.id,
@ -537,11 +539,13 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
else:
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material = wsp.main_product
# 更新子计划进度
instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save()
# 更新子计划生产进度
# 如果产品有返工标记不做计算
if wp.ng_sign not in [WProduct.NG_BACK_FIX, WProduct.NG_BACK_WORK]:
instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save()
wp.operation = None
wp.update_by = request.user
wp.save()