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

This commit is contained in:
shijing 2021-12-27 17:10:06 +08:00
commit 04f1521939
11 changed files with 124 additions and 38 deletions

View File

@ -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='按工序的统计数'),
),
]

View File

@ -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 = '生产计划'

View File

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

View File

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

View File

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

View File

@ -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='标签'),
),
]

View File

@ -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='可用于携带不需要用户查看的字段信息')

View File

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

View File

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

View File

@ -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('返回步骤点错误')

View File

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