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

This commit is contained in:
shijing 2021-12-28 17:07:22 +08:00
commit 95a9fa86dc
13 changed files with 209 additions and 30 deletions

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class DevelopConfig(AppConfig):
name = 'apps.develop'
verbose_name = '开发调试接口'

View File

@ -0,0 +1,12 @@
from django.shortcuts import render
from rest_framework.exceptions import APIException
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers, status
from rest_framework.response import Response
class CleanData(APIView):
pass

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-28 06:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pm', '0018_productionplan_process_json'),
]
operations = [
migrations.AlterField(
model_name='productionplan',
name='process_json',
field=models.JSONField(blank=True, default=dict, null=True, verbose_name='按工序的统计数'),
),
]

View File

@ -11,7 +11,7 @@ from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
from apps.pm.filters import SubproductionProgressFilterSet
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from django.shortcuts import render
@ -34,7 +34,7 @@ def updateOrderPlanedCount(order):
order.planed_count = planed_count
order.save()
class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModelMixin, GenericViewSet):
class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModelMixin, RetrieveModelMixin, GenericViewSet):
"""
生产计划
"""

View File

@ -25,6 +25,7 @@ class WMaterialFilterSet(filters.FilterSet):
class WProductFilterSet(filters.FilterSet):
tag = filters.CharFilter(method='filter_tag')
production_plan = filters.NumberFilter(field_name='subproduction_plan__production_plan')
class Meta:
model = WProduct
fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state', 'material__type']

View File

@ -0,0 +1,58 @@
# Generated by Django 3.2.9 on 2021-12-28 06:17
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('inm', '0024_auto_20211227_0948'),
('qm', '0022_auto_20211216_1401'),
('mtm', '0042_alter_recordformfield_field_type'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('pm', '0019_alter_productionplan_process_json'),
('wf', '0023_auto_20211227_1318'),
('wpm', '0038_auto_20211227_0948'),
]
operations = [
migrations.AlterField(
model_name='wprouctticket',
name='step',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='所在步骤/发现步骤'),
),
migrations.CreateModel(
name='WproductFlow',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('number', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='物品编号')),
('act_state', models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '已入库'), (50, '不合格'), (60, '待成品检验'), (70, '已报废'), (80, '已售出')], default=0, verbose_name='进行状态')),
('is_hidden', models.BooleanField(default=False, verbose_name='是否隐藏')),
('remark', models.CharField(blank=True, max_length=200, null=True, verbose_name='备注')),
('scrap_reason', models.IntegerField(blank=True, choices=[(10, '气泡'), (20, '破点'), (30, '划伤'), (40, '其他')], null=True, verbose_name='报废原因')),
('ng_sign', models.PositiveSmallIntegerField(blank=True, choices=[(10, '返工'), (20, '返修'), (30, '报废'), (40, '让步接收'), (50, '偏离许可'), (60, '降级使用'), (70, '退回供方'), (80, '召回')], null=True, verbose_name='不合格标记')),
('is_lastlog', models.BooleanField(default=True, verbose_name='是否该子计划下的最后一条日志')),
('child', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproductflow')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductflow_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所属物料状态')),
('operation', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wpm.operation', verbose_name='当前操作')),
('pre_step', models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wl_pre_step', to='mtm.step', verbose_name='已执行到')),
('step', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wl_step', to='mtm.step', verbose_name='所在步骤')),
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='当前子生产计划')),
('test', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='qm.testrecord', verbose_name='当前检验')),
('ticket', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wf.ticket', verbose_name='当前工单')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductflow_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
('warehouse', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='inm.warehouse', verbose_name='所在仓库')),
('wproduct', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联产品')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-28 07:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0039_auto_20211228_1417'),
]
operations = [
migrations.AlterField(
model_name='wproductflow',
name='number',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='物品编号'),
),
]

View File

@ -118,12 +118,40 @@ 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)
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE)
step = models.ForeignKey(Step, 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')
decision = models.PositiveSmallIntegerField('最终决定', choices=WProduct.ng_choices, null=True, blank=True)
class WproductFlow(CommonAModel):
"""
动态产品表日志
"""
wproduct = models.ForeignKey(WProduct, on_delete=models.CASCADE, verbose_name='关联产品', null=True, blank=True)
number = models.CharField('物品编号', 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='wl_pre_step')
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='wl_step')
act_state = models.IntegerField('进行状态', default=0, choices=WProduct.act_state_choices)
is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
scrap_reason = models.IntegerField('报废原因', choices= WProduct.scrap_reason_choices, null=True, blank=True)
ng_sign = models.PositiveSmallIntegerField('不合格标记', choices= WProduct.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)
test = models.ForeignKey('qm.testrecord', verbose_name='当前检验',
on_delete=models.SET_NULL, null=True, blank=True)
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
on_delete=models.SET_NULL, null=True, blank=True)
is_lastlog = models.BooleanField('是否该子计划下的最后一条日志', default=True)
class Pick(CommonADModel):
"""
领料记录

View File

@ -5,7 +5,7 @@ from apps.pm.models import SubProductionPlan, SubProductionProgress
from apps.mtm.models import Material, Step, SubprodctionMaterial
from apps.qm.models import TestRecord
from apps.system.models import User
from apps.wpm.models import WProduct
from apps.wpm.models import WProduct, WproductFlow, WprouctTicket
from utils.tools import ranstr
class WpmServies(object):
@ -48,7 +48,7 @@ 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:
@ -56,14 +56,32 @@ class WpmServies(object):
if wproduct.number is None: # 产生半成品编号
wproduct.number = 'WP'+ranstr(7)
# 更新子计划合格进度
ins = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
ins.count_ok = ins.count_ok + 1
ins.save()
# 去除ng_sign
if wproduct.ng_sign:
wt = WprouctTicket.objects.order_by('id').last() #取最后的工单
if wt.step.process == test.step.process:
wproduct.ng_sign = None
# 更新子计划相关进度
cls.update_subproduction_progress_main(sp=wproduct.subproduction_plan)
else:# 如果不合格
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK
# 需要走不合格品审理的工单
wproduct.update_by = user
wproduct.test = None
wproduct.save()
@classmethod
def update_subproduction_progress_main(cls, sp:SubProductionPlan):
"""
根据产品变动日志更新生产进度
"""
objs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True)
count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM,
WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).count()
count_real = objs.exclude(act_state__in=[WProduct.WPR_ACT_STATE_TORETEST,
WProduct.WPR_ACT_STATE_DOWAIT, WProduct.WPR_ACT_STATE_DOING])
ins = SubProductionProgress.objects.get(subproduction_plan=sp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
ins.count_ok = count_ok
ins.count_real = count_real
ins.save()

View File

@ -6,8 +6,9 @@ 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 WProduct, WproductFlow, WprouctTicket
from apps.wpm.models import OperationWproduct
from apps.wpm.services import WpmServies
@receiver(post_save, sender=Ticket)
@ -45,7 +46,7 @@ def handleTicket(sender, instance, created, **kwargs):
执行操作决定
"""
ticket_data = instance.ticket_data
wt = instance.wt_ticket
wt = WprouctTicket.objects.get(ticket=instance)
wp = wt.wproduct
decision = WProduct.NG_BACK_WORK
@ -61,7 +62,7 @@ def handleTicket(sender, instance, created, **kwargs):
wp.step = step
# 找到当时所属的计划
sp = SubProductionPlan.objects.filter(ow_subplan__wproduct=wp,
ow_subplan__operation__is_submited=True, ow_subplan__step=step).first()
ow_subplan__operation__is_submited=True, ow_subplan__operation__step=step).first()
if sp:
wp.subproduction_plan = sp
wt.save()
@ -69,11 +70,7 @@ def handleTicket(sender, instance, created, **kwargs):
wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT
wp.save()
# 更新子计划合格进度
if sp != wt.subproduction_plan:
ins = SubProductionProgress.objects.filter(subproduction_plan=sp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
ins.count_ok = ins.count_ok - 1
ins.save()
WpmServies.update_subproduction_progress_main(sp=sp)
else:
raise exceptions.APIException('返回步骤点错误')
@ -85,5 +82,16 @@ def handleTicket(sender, instance, created, **kwargs):
wp.ticket = None # 解除当前工单
wp.save()
@receiver(post_save, sender=WProduct)
def update_wproduct_log(sender, instance, created, **kwargs):
"""
更新产品变动日志
"""
WproductFlow.objects.filter(wproduct=instance, subproduction_plan=instance.subproduction_plan).update(is_lastlog=False)
ins = WproductFlow()
ins.wproduct = instance
for f in WproductFlow._meta.fields:
if f.name not in ['id', 'create_time', 'update_time', 'wproduct', 'is_lastlog']:
setattr(ins, f.name, getattr(instance, f.name, None))
ins.save()

View File

@ -180,14 +180,21 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
半成品
"""
perms_map={'*':'*'}
queryset = WProduct.objects.select_related('step', 'material', 'subproduction_plan').filter(is_hidden=False)
queryset = WProduct.objects.select_related('step', 'material', 'subproduction_plan')
serializer_class = WProductListSerializer
filterset_class = WProductFilterSet
search_fields = ['number']
ordering_fields = ['id']
ordering = ['id']
def get_queryset(self):
queryset = self.queryset
if self.request.query_params.get('tag', None) != 'show_hidden':
queryset = queryset.filter(is_hidden=False)
return queryset
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestFormInitSerializer)
@transaction.atomic
def test_init(self, request, pk=None):
"""
检验记录创建及初始化
@ -283,7 +290,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态
update_inm(fifo)
wproducts.update(act_state=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now())
for i in wproducts:
i.act_state = WProduct.WPR_ACT_STATE_INM
i.warehouse = warehouse
i.update_by = request.user
i.update_time = timezone.now()
i.save()
return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
@ -544,10 +556,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 更新子计划生产进度
# 如果产品有返工标记不做计算
if wp.ng_sign not in [WProduct.NG_BACK_FIX, WProduct.NG_BACK_WORK]:
ins = SubProductionProgress.objects.get(subproduction_plan=wsp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
ins.count_real = ins.count_real + 1
ins.save()
WpmServies.update_subproduction_progress_main(sp=wsp)
wp.operation = None
wp.update_by = request.user
wp.save()
@ -560,7 +569,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i.subproduction_plan)
for x in range(i.count):
WProduct.objects.create(**wpr)
WProduct.objects.create(**wpr)
WpmServies.update_subproduction_progress_main(sp=i.subproduction_plan)
elif step.type == Step.STEP_TYPE_COMB:
oms_w = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT,
subproduction_progress__is_main=True)
@ -577,9 +587,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
# 更新子计划进度
instance = oms_w.subproduction_progress
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save()
WpmServies.update_subproduction_progress_main(sp=oms_w.subproduction_plan)
wproduct.create_by = request.user
wproduct.save()
# 隐藏原半成品