返工返修执行操作决定
This commit is contained in:
parent
6682d43022
commit
811fe24fc7
|
@ -14,6 +14,8 @@ from rest_framework.decorators import action
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from apps.wf.models import Workflow
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
|
@ -168,6 +170,10 @@ class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, C
|
||||||
FIFOItemProduct.objects.bulk_create(ipxs)
|
FIFOItemProduct.objects.bulk_create(ipxs)
|
||||||
# 更新成品库情况
|
# 更新成品库情况
|
||||||
ips.update(is_saled=True)
|
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)
|
update_inm(fifo)
|
||||||
# 变更审核状态
|
# 变更审核状态
|
||||||
|
|
|
@ -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='占位符'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -174,8 +174,8 @@ class CustomField(CommonAModel):
|
||||||
help_text='选项值,格式为list, 例["id":1, "name":"张三"]')
|
help_text='选项值,格式为list, 例["id":1, "name":"张三"]')
|
||||||
|
|
||||||
label = models.CharField('标签', max_length=1000, default='', help_text='处理特殊逻辑使用')
|
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='可用于携带不需要用户查看的信息')
|
is_hidden = models.BooleanField('是否隐藏', default=False, help_text='可用于携带不需要用户查看的字段信息')
|
||||||
|
|
||||||
class Ticket(CommonBModel):
|
class Ticket(CommonBModel):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -36,6 +36,7 @@ class WProduct(CommonAModel):
|
||||||
WPR_ACT_STATE_NOTOK = 50
|
WPR_ACT_STATE_NOTOK = 50
|
||||||
WPR_ACT_STATE_TOFINALTEST = 60
|
WPR_ACT_STATE_TOFINALTEST = 60
|
||||||
WPR_ACT_STATE_SCRAP = 70
|
WPR_ACT_STATE_SCRAP = 70
|
||||||
|
WPR_ACT_STATE_SELLED = 80
|
||||||
act_state_choices=(
|
act_state_choices=(
|
||||||
(WPR_ACT_STATE_TORETEST, '待复检'),
|
(WPR_ACT_STATE_TORETEST, '待复检'),
|
||||||
(WPR_ACT_STATE_DOWAIT, '操作准备中'),
|
(WPR_ACT_STATE_DOWAIT, '操作准备中'),
|
||||||
|
@ -46,7 +47,8 @@ class WProduct(CommonAModel):
|
||||||
(WPR_ACT_STATE_INM, '已入库'),
|
(WPR_ACT_STATE_INM, '已入库'),
|
||||||
(WPR_ACT_STATE_NOTOK, '不合格'),
|
(WPR_ACT_STATE_NOTOK, '不合格'),
|
||||||
(WPR_ACT_STATE_TOFINALTEST, '待成品检验'),
|
(WPR_ACT_STATE_TOFINALTEST, '待成品检验'),
|
||||||
(WPR_ACT_STATE_SCRAP, '已报废')
|
(WPR_ACT_STATE_SCRAP, '已报废'),
|
||||||
|
(WPR_ACT_STATE_SELLED, '已售出'),
|
||||||
)
|
)
|
||||||
SCRAP_REASON_QIPAO = 10
|
SCRAP_REASON_QIPAO = 10
|
||||||
SCRAP_REASON_PODIAN = 20
|
SCRAP_REASON_PODIAN = 20
|
||||||
|
@ -58,6 +60,26 @@ class WProduct(CommonAModel):
|
||||||
(30, '划伤'),
|
(30, '划伤'),
|
||||||
(40, '其他')
|
(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)
|
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
|
||||||
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
material = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
||||||
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_step')
|
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')
|
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)
|
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)
|
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
|
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
|
||||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
|
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
|
||||||
|
@ -89,6 +114,7 @@ class WprouctTicket(CommonAModel):
|
||||||
"""
|
"""
|
||||||
玻璃审批工单
|
玻璃审批工单
|
||||||
"""
|
"""
|
||||||
|
|
||||||
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
|
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
|
||||||
wproduct = models.ForeignKey(WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
|
wproduct = models.ForeignKey(WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
|
||||||
material = models.ForeignKey(Material, 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)
|
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')
|
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):
|
class Pick(CommonADModel):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -46,17 +46,18 @@ class WpmServies(object):
|
||||||
if is_testok:
|
if is_testok:
|
||||||
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检
|
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检
|
||||||
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
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: # 成品检验
|
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
|
wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST
|
||||||
else:
|
else:
|
||||||
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)
|
||||||
# 更新子计划状态
|
|
||||||
# 更新子计划主产品数
|
# 更新子计划合格进度
|
||||||
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
|
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
|
||||||
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
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()
|
instance.save()
|
||||||
else:# 如果不合格
|
else:# 如果不合格
|
||||||
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
|
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
from django.db.models.signals import post_save
|
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.qm.models import TestRecord
|
||||||
from apps.wf.models import Ticket
|
from apps.wf.models import Ticket
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
from rest_framework import exceptions
|
||||||
from apps.wpm.models import WProduct, WprouctTicket
|
from apps.wpm.models import WProduct, WprouctTicket
|
||||||
|
from apps.wpm.models import OperationWproduct
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Ticket)
|
@receiver(post_save, sender=Ticket)
|
||||||
|
@ -43,18 +46,41 @@ def handleTicket(sender, instance, created, **kwargs):
|
||||||
ticket_data = instance.ticket_data
|
ticket_data = instance.ticket_data
|
||||||
wt = instance.wt_ticket
|
wt = instance.wt_ticket
|
||||||
wp = wt.wproduct
|
wp = wt.wproduct
|
||||||
|
decision = WProduct.NG_BACK_WORK
|
||||||
|
|
||||||
if 'decision_1' in ticket_data and ticket_data['decision_1']:
|
if 'decision_1' in ticket_data and ticket_data['decision_1']:
|
||||||
wt.decision = ticket_data['decision_1']
|
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
|
|
||||||
elif 'decision_2' in ticket_data and ticket_data['decision_2']:
|
elif 'decision_2' in ticket_data and ticket_data['decision_2']:
|
||||||
wp.decision = ticket_data['decision_2']
|
decision = ticket_data['decision_2']
|
||||||
if ticket_data['decision_2'] in ['返工', '返修']:
|
|
||||||
pass
|
|
||||||
elif ticket_data['decision_2'] in ['让步接收']:
|
wp.ng_sign = decision
|
||||||
wp.act_state = WProduct.WPR_ACT_STATE_OK
|
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()
|
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()
|
wp.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -370,8 +370,8 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
发起不合格审理单
|
发起不合格审理单
|
||||||
"""
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK:
|
if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK or obj.ng_sign is not None:
|
||||||
raise exceptions.APIException('非检验不合格产品不可发起不合格审理')
|
raise exceptions.APIException('该产品不可发起不合格审理')
|
||||||
workflow = Workflow.objects.filter(name='不合格品审理单', is_deleted=False).first()
|
workflow = Workflow.objects.filter(name='不合格品审理单', is_deleted=False).first()
|
||||||
if workflow:
|
if workflow:
|
||||||
exist_data = {
|
exist_data = {
|
||||||
|
@ -539,7 +539,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
||||||
else:
|
else:
|
||||||
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
|
||||||
wp.material = wsp.main_product
|
wp.material = wsp.main_product
|
||||||
# 更新子计划进度
|
# 更新子计划生产进度
|
||||||
|
# 如果产品有返工标记不做计算
|
||||||
|
if wp.ng_sign not in [WProduct.NG_BACK_FIX, WProduct.NG_BACK_WORK]:
|
||||||
instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
|
instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
|
||||||
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
||||||
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
|
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
|
||||||
|
|
Loading…
Reference in New Issue