返工返修执行操作决定

This commit is contained in:
caoqianming 2021-12-27 09:45:23 +08:00
parent 6682d43022
commit 811fe24fc7
7 changed files with 121 additions and 27 deletions

View File

@ -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)
# 变更审核状态 # 变更审核状态

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

@ -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):
""" """

View File

@ -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):
""" """

View File

@ -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

View File

@ -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
if 'decision_1' in ticket_data and ticket_data['decision_1']: decision = WProduct.NG_BACK_WORK
wt.decision = ticket_data['decision_1']
if ticket_data['decision_1'] in ['返工', '返修']: if 'decision_1' in ticket_data and ticket_data['decision_1']:
pass decision = ticket_data['decision_1']
elif ticket_data['decision_1'] in ['让步接收']: elif 'decision_2' in ticket_data and ticket_data['decision_2']:
wp.act_state = WProduct.WPR_ACT_STATE_OK decision = ticket_data['decision_2']
elif 'decision_2' in ticket_data and ticket_data['decision_2']:
wp.decision = ticket_data['decision_2']
if ticket_data['decision_2'] in ['返工', '返修']: wp.ng_sign = decision
pass if decision in [WProduct.NG_BACK_WORK, WProduct.NG_BACK_FIX]:
elif ticket_data['decision_2'] in ['让步接收']: step = ticket_data['back_step']
wp.act_state = WProduct.WPR_ACT_STATE_OK wp.step = step
wt.save() # 找到当时所属的计划
wp.save() 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

@ -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,11 +539,13 @@ 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
# 更新子计划进度 # 更新子计划生产进度
instance = SubProductionProgress.objects.get(subproduction_plan=wsp, # 如果产品有返工标记不做计算
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) if wp.ng_sign not in [WProduct.NG_BACK_FIX, WProduct.NG_BACK_WORK]:
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
instance.save() is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save()
wp.operation = None wp.operation = None
wp.update_by = request.user wp.update_by = request.user
wp.save() wp.save()