Support manual route output materials
This commit is contained in:
parent
d5d940c5e4
commit
bcbb27374f
|
|
@ -3,11 +3,12 @@ from apps.mtm.models import (Shift, Material, Mgroup, Team, Goal,
|
|||
Process, Route, TeamMember, RoutePack, Srule, RouteMat)
|
||||
from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS_DEPT
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError, ParseError
|
||||
from rest_framework.exceptions import ValidationError, ParseError, PermissionDenied
|
||||
from apps.system.models import Dept, UserPost
|
||||
from django.db import transaction
|
||||
from apps.wf.serializers import TicketSimpleSerializer
|
||||
from apps.system.serializers import FileSerializer
|
||||
from apps.utils.permission import has_perm
|
||||
|
||||
|
||||
class ShiftSerializer(CustomModelSerializer):
|
||||
|
|
@ -177,6 +178,23 @@ class RoutePackCopySerializer(serializers.Serializer):
|
|||
material_in = serializers.CharField(label='原料ID')
|
||||
material_out = serializers.CharField(label='产品ID')
|
||||
|
||||
|
||||
class RouteMaterialOutCreateSerializer(serializers.Serializer):
|
||||
"""工艺路线内快捷新建半成品时允许录入的物料字段。"""
|
||||
name = serializers.CharField(label='名称', max_length=50)
|
||||
number = serializers.CharField(label='编号', max_length=100, required=False, allow_blank=True, allow_null=True)
|
||||
cate = serializers.CharField(label='大类', max_length=20, required=False, allow_blank=True)
|
||||
model = serializers.CharField(label='型号', max_length=100, required=False, allow_blank=True, allow_null=True)
|
||||
specification = serializers.CharField(label='规格', max_length=100, required=False, allow_blank=True, allow_null=True)
|
||||
unit = serializers.CharField(label='基准计量单位', max_length=10, required=False, default='个')
|
||||
test_mode_in = serializers.ChoiceField(
|
||||
label='入库检验方式',
|
||||
choices=(Material.MA_TEST_EXEMPT, Material.MA_TEST_REQUIRED),
|
||||
required=False,
|
||||
default=Material.MA_TEST_REQUIRED,
|
||||
)
|
||||
|
||||
|
||||
class RouteSerializer(CustomModelSerializer):
|
||||
name = serializers.CharField(source='__str__', read_only=True)
|
||||
material_ = MaterialSerializer(source='material', read_only=True)
|
||||
|
|
@ -194,6 +212,7 @@ class RouteSerializer(CustomModelSerializer):
|
|||
material_out_is_hidden = serializers.BooleanField(
|
||||
source='material_out.is_hidden', read_only=True)
|
||||
material_out_tracking = serializers.IntegerField(write_only=True, required=False, allow_null=True)
|
||||
material_out_create = RouteMaterialOutCreateSerializer(write_only=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Route
|
||||
|
|
@ -201,6 +220,8 @@ class RouteSerializer(CustomModelSerializer):
|
|||
read_only_fields = EXCLUDE_FIELDS
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs.get('material_out') and attrs.get('material_out_create'):
|
||||
raise ParseError('选择已有输出物料和新建半成品不可同时提交')
|
||||
if attrs.get('routepack', None):
|
||||
attrs['material'] = attrs['routepack'].material
|
||||
if 'mgroup' in attrs and attrs['mgroup']:
|
||||
|
|
@ -262,12 +283,30 @@ class RouteSerializer(CustomModelSerializer):
|
|||
})
|
||||
return material_out
|
||||
|
||||
def create_material_out(self, material_data, process, tracking):
|
||||
if self.request and not has_perm(self.request.user, ['material.create']):
|
||||
raise PermissionDenied('无新建物料权限')
|
||||
material_data.update({
|
||||
'type': Material.MA_TYPE_HALFGOOD,
|
||||
'process': process.id,
|
||||
'tracking': tracking,
|
||||
'is_hidden': False,
|
||||
})
|
||||
serializer = MaterialSerializer(data=material_data, context=self.context)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
return serializer.save()
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
process = validated_data['process']
|
||||
routepack = validated_data.get('routepack', None)
|
||||
material_out_create = validated_data.pop('material_out_create', None)
|
||||
material_out_tracking = validated_data.pop("material_out_tracking", Material.MA_TRACKING_BATCH)
|
||||
if material_out_tracking is None:
|
||||
material_out_tracking = Material.MA_TRACKING_BATCH
|
||||
if material_out_create:
|
||||
validated_data['material_out'] = self.create_material_out(
|
||||
material_out_create, process, material_out_tracking)
|
||||
if routepack:
|
||||
pass
|
||||
# if Route.objects.filter(routepack=routepack, process=process).exists():
|
||||
|
|
@ -308,12 +347,17 @@ class RouteSerializer(CustomModelSerializer):
|
|||
# raise ParseError(f"该工艺步骤已存在-{msg}")
|
||||
return instance
|
||||
|
||||
@transaction.atomic
|
||||
def update(self, instance, validated_data):
|
||||
validated_data.pop('material', None)
|
||||
process = validated_data.pop('process', None)
|
||||
process = validated_data.pop('process', None) or instance.process
|
||||
material_out_create = validated_data.pop('material_out_create', None)
|
||||
material_out_tracking = validated_data.pop("material_out_tracking", Material.MA_TRACKING_BATCH)
|
||||
if material_out_tracking is None:
|
||||
material_out_tracking = Material.MA_TRACKING_BATCH
|
||||
if material_out_create:
|
||||
validated_data['material_out'] = self.create_material_out(
|
||||
material_out_create, process, material_out_tracking)
|
||||
|
||||
if not validated_data.get('material_out', instance.material_out) and not instance.material:
|
||||
raise ParseError('未指定输出物料,且工艺包未设置产品无法自动生成;请指定输出物料,或先在工艺包基本信息中选择产品')
|
||||
|
|
|
|||
|
|
@ -1,3 +1,69 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
from apps.mtm.models import Material, Process, Route, RoutePack
|
||||
from apps.mtm.serializers import RouteSerializer
|
||||
|
||||
|
||||
class RouteMaterialOutCreateSerializerTests(TestCase):
|
||||
def setUp(self):
|
||||
self.process = Process.objects.create(name='切割')
|
||||
self.product = Material.objects.create(
|
||||
name='产品A',
|
||||
number='CP-A',
|
||||
type=Material.MA_TYPE_GOOD,
|
||||
process=self.process,
|
||||
)
|
||||
self.material_in = Material.objects.create(
|
||||
name='原料A',
|
||||
number='YL-A',
|
||||
type=Material.MA_TYPE_MAINSO,
|
||||
)
|
||||
self.routepack = RoutePack.objects.create(name='产品A工艺', material=self.product)
|
||||
|
||||
def test_create_route_and_visible_halfgood_in_one_serializer_save(self):
|
||||
serializer = RouteSerializer(data={
|
||||
'routepack': self.routepack.id,
|
||||
'process': self.process.id,
|
||||
'material_in': self.material_in.id,
|
||||
'material_out_tracking': Material.MA_TRACKING_SINGLE,
|
||||
'material_out_create': {
|
||||
'name': '分支半成品A',
|
||||
'number': 'BCP-A',
|
||||
'specification': 'S1',
|
||||
'model': 'M1',
|
||||
'unit': '件',
|
||||
},
|
||||
})
|
||||
|
||||
serializer.is_valid(raise_exception=True)
|
||||
route = serializer.save()
|
||||
|
||||
material_out = route.material_out
|
||||
self.assertEqual(material_out.type, Material.MA_TYPE_HALFGOOD)
|
||||
self.assertEqual(material_out.process, self.process)
|
||||
self.assertEqual(material_out.tracking, Material.MA_TRACKING_SINGLE)
|
||||
self.assertFalse(material_out.is_hidden)
|
||||
self.assertEqual(material_out.name, '分支半成品A')
|
||||
self.assertEqual(material_out.unit, '件')
|
||||
self.assertTrue(Route.objects.filter(pk=route.pk, material_out=material_out).exists())
|
||||
|
||||
def test_existing_and_new_material_out_are_mutually_exclusive(self):
|
||||
existing = Material.objects.create(
|
||||
name='已有半成品',
|
||||
number='BCP-OLD',
|
||||
type=Material.MA_TYPE_HALFGOOD,
|
||||
process=self.process,
|
||||
)
|
||||
serializer = RouteSerializer(data={
|
||||
'routepack': self.routepack.id,
|
||||
'process': self.process.id,
|
||||
'material_in': self.material_in.id,
|
||||
'material_out': existing.id,
|
||||
'material_out_create': {
|
||||
'name': '新半成品',
|
||||
'number': 'BCP-NEW',
|
||||
},
|
||||
})
|
||||
|
||||
self.assertFalse(serializer.is_valid())
|
||||
self.assertIn('non_field_errors', serializer.errors)
|
||||
|
|
|
|||
Loading…
Reference in New Issue