Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
04f1521939
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-27 05:18
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pm', '0017_auto_20211213_1401'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='productionplan',
|
||||||
|
name='process_json',
|
||||||
|
field=models.JSONField(blank=True, default=list, null=True, verbose_name='按工序的统计数'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -29,6 +29,7 @@ class ProductionPlan(CommonAModel):
|
||||||
count_ok = models.PositiveIntegerField('合格数', default=0)
|
count_ok = models.PositiveIntegerField('合格数', default=0)
|
||||||
start_date = models.DateField('计划开工日期')
|
start_date = models.DateField('计划开工日期')
|
||||||
end_date = models.DateField('计划完工日期')
|
end_date = models.DateField('计划完工日期')
|
||||||
|
process_json = models.JSONField('按工序的统计数', default=dict, null=True, blank=True)
|
||||||
is_planed = models.BooleanField('是否已排产', default=False)
|
is_planed = models.BooleanField('是否已排产', default=False)
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '生产计划'
|
verbose_name = '生产计划'
|
||||||
|
|
|
@ -48,11 +48,7 @@ class SubProductionPlanUpdateSerializer(serializers.ModelSerializer):
|
||||||
class GenSubPlanSerializer(serializers.Serializer):
|
class GenSubPlanSerializer(serializers.Serializer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class SubProductionProgressSerializer(serializers.ModelSerializer):
|
|
||||||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
|
||||||
class Meta:
|
|
||||||
model = SubProductionProgress
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
class PickNeedSerializer(serializers.Serializer):
|
class PickNeedSerializer(serializers.Serializer):
|
||||||
warehouse = serializers.IntegerField(label="仓库ID")
|
warehouse = serializers.IntegerField(label="仓库ID")
|
||||||
|
@ -64,3 +60,10 @@ class SubproductionPlanSimpleSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SubProductionPlan
|
model = SubProductionPlan
|
||||||
fields = ['id', 'number']
|
fields = ['id', 'number']
|
||||||
|
|
||||||
|
class SubProductionProgressSerializer(serializers.ModelSerializer):
|
||||||
|
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||||
|
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = SubProductionProgress
|
||||||
|
fields = '__all__'
|
|
@ -0,0 +1,27 @@
|
||||||
|
from django.db.models.aggregates import Sum
|
||||||
|
from apps.pm.models import ProductionPlan, SubProductionPlan
|
||||||
|
|
||||||
|
class PmService:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_plan_process_json(cls, plan:ProductionPlan):
|
||||||
|
"""
|
||||||
|
更新计划按工序统计字段
|
||||||
|
"""
|
||||||
|
ret = {}
|
||||||
|
subplans = SubProductionPlan.objects.filter(production_plan=plan, is_deleted=False)
|
||||||
|
qs = subplans.values('process', 'process__name', 'process__number').annotate(count=Sum('main_count'),
|
||||||
|
count_real=Sum('main_count_real'), count_ok=Sum('main_count_ok'))
|
||||||
|
qs_list = list(qs)
|
||||||
|
for i in qs_list:
|
||||||
|
ret[i['process__number']] = {
|
||||||
|
'count':i['count'],
|
||||||
|
'count_real':i['count_real'],
|
||||||
|
'count_ok':i['count_ok'],
|
||||||
|
'rate': round((i['count_ok']/i['count_real'])*100,2) if i['count_real'] > 0 else 0
|
||||||
|
}
|
||||||
|
plan.process_json = ret
|
||||||
|
plan.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from apps.mtm.models import Material
|
from apps.mtm.models import Material
|
||||||
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
||||||
|
from apps.pm.services import PmService
|
||||||
|
|
||||||
@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,6 +14,7 @@ def update_subplan_main(sender, instance, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
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
|
||||||
subplan.main_count_ok = instance.count_ok
|
subplan.main_count_ok = instance.count_ok
|
||||||
if instance.count_ok >= instance.count and instance.count_ok > 0:
|
if instance.count_ok >= instance.count and instance.count_ok > 0:
|
||||||
|
@ -26,6 +28,10 @@ def update_subplan_main(sender, instance, created, **kwargs):
|
||||||
plan.count_real = subplan.main_count_real
|
plan.count_real = subplan.main_count_real
|
||||||
plan.count_ok = subplan.main_count_ok
|
plan.count_ok = subplan.main_count_ok
|
||||||
plan.save()
|
plan.save()
|
||||||
|
# 更新计划工序统计字段
|
||||||
|
PmService.update_plan_process_json(subplan.production_plan)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-27 05:18
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wf', '0022_alter_customfield_is_hidden'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
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, select_dg, select_dgs,textarea, file', max_length=50, verbose_name='类型'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='customfield',
|
||||||
|
name='label',
|
||||||
|
field=models.CharField(default='', help_text='处理特殊逻辑使用,比如sys_user用于获取用户作为选项', max_length=1000, verbose_name='标签'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -159,7 +159,7 @@ class CustomField(CommonAModel):
|
||||||
)
|
)
|
||||||
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
|
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, verbose_name='所属工作流')
|
||||||
field_type = models.CharField('类型', max_length=50, choices=field_type_choices,
|
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')
|
help_text='string, int, float, date, datetime, radio, checkbox, select, selects, cascader, cascaders, select_dg, select_dgs,textarea, file')
|
||||||
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
|
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
|
||||||
field_name = models.CharField('字段名称', max_length=50)
|
field_name = models.CharField('字段名称', max_length=50)
|
||||||
sort = models.IntegerField('排序', default=0, help_text='工单基础字段在表单中排序为:流水号0,标题20,状态id40,状态名41,创建人80,创建时间100,更新时间120.前端展示工单信息的表单可以根据这个id顺序排列')
|
sort = models.IntegerField('排序', default=0, help_text='工单基础字段在表单中排序为:流水号0,标题20,状态id40,状态名41,创建人80,创建时间100,更新时间120.前端展示工单信息的表单可以根据这个id顺序排列')
|
||||||
|
@ -173,7 +173,7 @@ class CustomField(CommonAModel):
|
||||||
field_choice = models.JSONField('选项值', default=list, blank=True,
|
field_choice = models.JSONField('选项值', default=list, blank=True,
|
||||||
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='处理特殊逻辑使用,比如sys_user用于获取用户作为选项')
|
||||||
# hook = models.CharField('hook', 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='可用于携带不需要用户查看的字段信息')
|
||||||
|
|
||||||
|
|
|
@ -129,21 +129,22 @@ class TicketDetailSerializer(serializers.ModelSerializer):
|
||||||
i['field_state'] = state_fields.get(key, 1)
|
i['field_state'] = state_fields.get(key, 1)
|
||||||
i['field_value'] = ticket_data.get(key, None)
|
i['field_value'] = ticket_data.get(key, None)
|
||||||
i['field_display'] = i['field_value'] # 该字段是用于查看详情直接展示
|
i['field_display'] = i['field_value'] # 该字段是用于查看详情直接展示
|
||||||
if 'sys_user' in i['label']:
|
if i['field_value']:
|
||||||
if isinstance(i['field_value'], list):
|
if 'sys_user' in i['label']:
|
||||||
i['field_display'] = ','.join(list(User.objects.filter(id__in=i['field_value']).values_list('name', flat=True)))
|
if isinstance(i['field_value'], list):
|
||||||
else:
|
i['field_display'] = ','.join(list(User.objects.filter(id__in=i['field_value']).values_list('name', flat=True)))
|
||||||
i['field_display'] = User.objects.get(id=i['field_value']).name
|
else:
|
||||||
elif i['field_type'] in ['radio', 'select']:
|
i['field_display'] = User.objects.get(id=i['field_value']).name
|
||||||
for m in i['field_choice']:
|
elif i['field_type'] in ['radio', 'select']:
|
||||||
if m['id'] == i['field_value']:
|
for m in i['field_choice']:
|
||||||
i['field_display'] = m['name']
|
if m['id'] == i['field_value']:
|
||||||
elif i['field_type'] in ['checkbox', 'selects']:
|
i['field_display'] = m['name']
|
||||||
d_list = []
|
elif i['field_type'] in ['checkbox', 'selects']:
|
||||||
for m in i['field_choice']:
|
d_list = []
|
||||||
if m['id'] in i['field_value']:
|
for m in i['field_choice']:
|
||||||
d_list.append(m['name'])
|
if m['id'] in i['field_value']:
|
||||||
i['field_display'] = ','.join(d_list)
|
d_list.append(m['name'])
|
||||||
|
i['field_display'] = ','.join(d_list)
|
||||||
return all_fields_l
|
return all_fields_l
|
||||||
|
|
||||||
def filter_display(self, item, field_value):
|
def filter_display(self, item, field_value):
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from django.db.models.expressions import F
|
||||||
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
||||||
from apps.mtm.models import Material, Step, SubprodctionMaterial
|
from apps.mtm.models import Material, Step, SubprodctionMaterial
|
||||||
from apps.qm.models import TestRecord
|
from apps.qm.models import TestRecord
|
||||||
|
@ -55,13 +57,13 @@ class WpmServies(object):
|
||||||
wproduct.number = 'WP'+ranstr(7)
|
wproduct.number = 'WP'+ranstr(7)
|
||||||
|
|
||||||
# 更新子计划合格进度
|
# 更新子计划合格进度
|
||||||
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
|
ins = 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
|
ins.count_ok = ins.count_ok + 1
|
||||||
instance.save()
|
ins.save()
|
||||||
else:# 如果不合格
|
else:# 如果不合格
|
||||||
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
|
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
|
||||||
# 需要走不合格品审理的工单
|
# 需要走不合格品审理的工单
|
||||||
wproduct.update_by = user
|
wproduct.update_by = user
|
||||||
wproduct.test = None
|
wproduct.test = None
|
||||||
wproduct.save()
|
wproduct.save()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
from django.db.models.expressions import F
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from apps.mtm.models import SubprodctionMaterial
|
from apps.mtm.models import Step, SubprodctionMaterial
|
||||||
from apps.pm.models import SubProductionProgress
|
from apps.pm.models import SubProductionPlan, 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
|
||||||
|
@ -56,10 +57,11 @@ def handleTicket(sender, instance, created, **kwargs):
|
||||||
|
|
||||||
wp.ng_sign = decision
|
wp.ng_sign = decision
|
||||||
if decision in [WProduct.NG_BACK_WORK, WProduct.NG_BACK_FIX]:
|
if decision in [WProduct.NG_BACK_WORK, WProduct.NG_BACK_FIX]:
|
||||||
step = ticket_data['back_step']
|
step = Step.objects.get(id=ticket_data['back_step'])
|
||||||
wp.step = step
|
wp.step = step
|
||||||
# 找到当时所属的计划
|
# 找到当时所属的计划
|
||||||
sp = OperationWproduct.objects.filter(operation__is_submited=True, operation__step=step).first()
|
sp = SubProductionPlan.objects.filter(ow_subplan__wproduct=wp,
|
||||||
|
ow_subplan__operation__is_submited=True, ow_subplan__step=step).first()
|
||||||
if sp:
|
if sp:
|
||||||
wp.subproduction_plan = sp
|
wp.subproduction_plan = sp
|
||||||
wt.save()
|
wt.save()
|
||||||
|
@ -67,10 +69,11 @@ def handleTicket(sender, instance, created, **kwargs):
|
||||||
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
|
||||||
wp.save()
|
wp.save()
|
||||||
# 更新子计划合格进度
|
# 更新子计划合格进度
|
||||||
instance = SubProductionProgress.objects.get(subproduction_plan=sp,
|
if sp != wt.subproduction_plan:
|
||||||
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
ins = SubProductionProgress.objects.filter(subproduction_plan=sp,
|
||||||
instance.count_ok = instance.count_ok - 1 #进度计算这里该怎么处理呢
|
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
||||||
instance.save()
|
ins.count_ok = ins.count_ok - 1
|
||||||
|
ins.save()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise exceptions.APIException('返回步骤点错误')
|
raise exceptions.APIException('返回步骤点错误')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.db.models.expressions import F
|
||||||
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 CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
||||||
|
@ -370,7 +371,8 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
发起不合格审理单
|
发起不合格审理单
|
||||||
"""
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK or obj.ng_sign is not None:
|
if obj.act_state != WProduct.WPR_ACT_STATE_NOTOK or obj.ng_sign is not None\
|
||||||
|
or obj.ticket 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:
|
||||||
|
@ -542,10 +544,10 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
||||||
# 更新子计划生产进度
|
# 更新子计划生产进度
|
||||||
# 如果产品有返工标记不做计算
|
# 如果产品有返工标记不做计算
|
||||||
if wp.ng_sign not in [WProduct.NG_BACK_FIX, WProduct.NG_BACK_WORK]:
|
if wp.ng_sign not in [WProduct.NG_BACK_FIX, WProduct.NG_BACK_WORK]:
|
||||||
instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
|
ins = 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 # 这个地方可能会有问题,不够严谨
|
ins.count_real = ins.count_real + 1
|
||||||
instance.save()
|
ins.save()
|
||||||
wp.operation = None
|
wp.operation = None
|
||||||
wp.update_by = request.user
|
wp.update_by = request.user
|
||||||
wp.save()
|
wp.save()
|
||||||
|
|
Loading…
Reference in New Issue