This commit is contained in:
zty 2024-10-15 09:54:54 +08:00
commit 46dd264dba
18 changed files with 197 additions and 3 deletions

0
apps/cm/__init__.py Normal file
View File

3
apps/cm/admin.py Normal file
View File

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

6
apps/cm/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class CmConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.cm'

View File

@ -0,0 +1,36 @@
# Generated by Django 3.2.12 on 2024-10-11 07:17
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('pum', '0008_auto_20240731_1829'),
('mtm', '0042_auto_20241010_1140'),
]
operations = [
migrations.CreateModel(
name='LableMat',
fields=[
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, 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='删除标记')),
('state', models.PositiveSmallIntegerField(choices=[(10, '合格'), (20, '不合格'), (30, '返修'), (40, '检验'), (50, '报废')], default=10, verbose_name='状态')),
('batch', models.CharField(max_length=100, verbose_name='批次号')),
('notok_sign', models.CharField(blank=True, max_length=10, null=True, verbose_name='不合格标记')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material')),
('material_origin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='lm_mo', to='mtm.material', verbose_name='原始物料')),
('supplier', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pum.supplier', verbose_name='外协供应商')),
],
options={
'abstract': False,
},
),
]

View File

13
apps/cm/models.py Normal file
View File

@ -0,0 +1,13 @@
from django.db import models
from apps.utils.models import BaseModel
from apps.mtm.models import Material
from apps.pum.models import Supplier
# Create your models here.
class LableMat(BaseModel):
state = models.PositiveSmallIntegerField('状态', default=10, choices=((10, '合格'), (20, '不合格'), (30, '返修'), (40, '检验'), (50, '报废')))
material = models.ForeignKey(Material, on_delete=models.CASCADE)
batch = models.CharField('批次号', max_length=100)
supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True)
notok_sign = models.CharField('不合格标记', max_length=10, null=True, blank=True)
material_origin = models.ForeignKey(Material, verbose_name='原始物料', on_delete=models.SET_NULL, null=True, blank=True, related_name='lm_mo')

25
apps/cm/serializers.py Normal file
View File

@ -0,0 +1,25 @@
from rest_framework import serializers
from .models import LableMat
from apps.qm.models import NotOkOption
from apps.wpm.models import WmStateOption
class TidSerializer(serializers.Serializer):
tid = serializers.CharField(label='表ID')
class LabelMatSerializer(serializers.ModelSerializer):
material_name = serializers.StringRelatedField(source='material', read_only=True)
material_origin_name = serializers.StringRelatedField(source='material_origin', read_only=True)
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
notok_sign_name = serializers.SerializerMethodField()
state_name = serializers.SerializerMethodField()
class Meta:
model = LableMat
fields = '__all__'
def get_notok_sign_name(self, obj):
return getattr(NotOkOption, obj.notok_sign, NotOkOption.qt).label if obj.notok_sign else None
def get_state_name(self, obj):
return getattr(WmStateOption, str(obj.state), WmStateOption.OK).label if obj.state else None

3
apps/cm/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

12
apps/cm/urls.py Normal file
View File

@ -0,0 +1,12 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.cm.views import LableMatViewSet
API_BASE_URL = 'api/cm/'
HTML_BASE_URL = 'cm/'
router = DefaultRouter()
router.register('labelmat', LableMatViewSet, basename='labelmat')
urlpatterns = [
path(API_BASE_URL, include(router.urls)),
]

61
apps/cm/views.py Normal file
View File

@ -0,0 +1,61 @@
from apps.cm.models import LableMat
from rest_framework.decorators import action
from apps.cm.serializers import TidSerializer, LabelMatSerializer
from apps.inm.models import MaterialBatch
from apps.wpm.models import WMaterial
from rest_framework.exceptions import ParseError, NotFound
from rest_framework.response import Response
from apps.utils.viewsets import CustomGenericViewSet, RetrieveModelMixin, CustomListModelMixin
# Create your views here.
class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
perms_map = {"post": "*", "get": "*"}
serializer_class = LabelMatSerializer
queryset = LableMat.objects.all()
select_related_fields = ["material", "material_origin", "supplier"]
@action(methods=['post'], detail=False, serializer_class=TidSerializer)
def get_from_mb(self, request, pk=None):
"""
从仓库明细获取物料标签
从仓库明细获取物料标签
"""
tid = request.data.get('tid')
try:
mb = MaterialBatch.objects.get(id=tid)
except MaterialBatch.DoesNotExist:
raise NotFound('仓库明细不存在')
obj, _ = LableMat.objects.get_or_create(
state=10,
material=mb.material,
batch=mb.batch,
defaults={
"supplier": mb.supplier
}
)
rdata = LabelMatSerializer(obj).data
rdata["code_label"] = f"mat:{obj.id}"
return Response(rdata)
@action(methods=['post'], detail=False, serializer_class=TidSerializer)
def get_from_wm(self, request, pk=None):
"""
从车间库存明细获取物料标签
从车间库存明细获取物料标签
"""
tid = request.data.get('tid')
try:
wm = WMaterial.objects.get(id=tid)
except WMaterial.DoesNotExist:
raise NotFound('车间库存不存在')
obj, _ = LableMat.objects.get_or_create(
state=wm.state,
material=wm.material,
batch=wm.batch,
notok_sign=wm.notok_sign,
material_origin=wm.material_origin)
rdata = LabelMatSerializer(obj).data
rdata["code_label"] = f"mat:{obj.id}"
return Response(rdata)

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.12 on 2024-10-11 04:38
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pum', '0008_auto_20240731_1829'),
('inm', '0019_mio_mgroup'),
]
operations = [
migrations.AddField(
model_name='materialbatch',
name='supplier',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pum.supplier', verbose_name='供应商'),
),
]

View File

@ -28,6 +28,8 @@ class MaterialBatch(BaseModel):
count = models.DecimalField('存量', max_digits=12, decimal_places=3, default=0) count = models.DecimalField('存量', max_digits=12, decimal_places=3, default=0)
production_dept = models.ForeignKey('system.dept', verbose_name='生产车间', on_delete=models.CASCADE, null=True, blank=True) production_dept = models.ForeignKey('system.dept', verbose_name='生产车间', on_delete=models.CASCADE, null=True, blank=True)
expiration_date = models.DateField('有效期', null=True, blank=True) expiration_date = models.DateField('有效期', null=True, blank=True)
supplier = models.ForeignKey(
Supplier, verbose_name='供应商', on_delete=models.SET_NULL, null=True, blank=True)
class Meta: class Meta:
unique_together = ('material', 'batch', 'warehouse') unique_together = ('material', 'batch', 'warehouse')

View File

@ -33,6 +33,8 @@ class MaterialBatchSerializer(CustomModelSerializer):
source='warehouse.name', read_only=True) source='warehouse.name', read_only=True)
material_name = serializers.StringRelatedField( material_name = serializers.StringRelatedField(
source='material', read_only=True) source='material', read_only=True)
supplier_name = serializers.StringRelatedField(
source='supplier', read_only=True)
material_ = MaterialSerializer(source='material', read_only=True) material_ = MaterialSerializer(source='material', read_only=True)
class Meta: class Meta:
@ -49,6 +51,8 @@ class MaterialBatchDetailSerializer(CustomModelSerializer):
material_ = MaterialSerializer(source='material', read_only=True) material_ = MaterialSerializer(source='material', read_only=True)
assemb = MaterialBatchAListSerializer( assemb = MaterialBatchAListSerializer(
source='a_mb', read_only=True, many=True) source='a_mb', read_only=True, many=True)
supplier_name = serializers.StringRelatedField(
source='supplier', read_only=True)
class Meta: class Meta:
model = MaterialBatch model = MaterialBatch

View File

@ -90,7 +90,7 @@ class InmService:
material=material, material=material,
warehouse=warehouse, warehouse=warehouse,
batch=i.batch, batch=i.batch,
defaults={"material": material, "warehouse": warehouse, "count": 0, "batch": i.batch} defaults={"count": 0, "supplier": i.mio.supplier}
) )
if in_or_out == 1: if in_or_out == 1:
mb.count = mb.count + getattr(i, field) mb.count = mb.count + getattr(i, field)

View File

@ -48,7 +48,7 @@ class MaterialBatchViewSet(ListModelMixin, CustomGenericViewSet):
queryset = MaterialBatch.objects.filter(count__gt=0) queryset = MaterialBatch.objects.filter(count__gt=0)
serializer_class = MaterialBatchSerializer serializer_class = MaterialBatchSerializer
retrieve_serializer_class = MaterialBatchDetailSerializer retrieve_serializer_class = MaterialBatchDetailSerializer
select_related_fields = ['warehouse', 'material'] select_related_fields = ['warehouse', 'material', 'supplier']
filterset_class = MaterialBatchFilter filterset_class = MaterialBatchFilter
search_fields = ['material__name', 'material__number', search_fields = ['material__name', 'material__number',
'material__model', 'material__specification', 'batch'] 'material__model', 'material__specification', 'batch']

View File

@ -9,6 +9,7 @@ from apps.system.models import Dept
from datetime import timedelta from datetime import timedelta
from apps.pum.models import Supplier from apps.pum.models import Supplier
from django.db.models import Sum from django.db.models import Sum
from django.utils.translation import gettext_lazy as _
# Create your models here. # Create your models here.
@ -86,6 +87,12 @@ class SfLogExp(CommonADModel):
class Meta: class Meta:
unique_together = ('sflog', 'stlog') unique_together = ('sflog', 'stlog')
class WmStateOption(models.IntegerChoices):
OK = 10, _("合格")
NOTOK = 20, _("不合格")
REPAIR = 30, _("返修")
TEST = 40, _("检验")
SCRAP = 50, _("报废")
class WMaterial(CommonBDModel): class WMaterial(CommonBDModel):
""" """
belong_dept是所在车间 belong_dept是所在车间

View File

@ -78,7 +78,8 @@ INSTALLED_APPS = [
'apps.pm', 'apps.pm',
'apps.enp', 'apps.enp',
'apps.edu', 'apps.edu',
'apps.dpm' 'apps.dpm',
'apps.cm'
] ]
MIDDLEWARE = [ MIDDLEWARE = [

View File

@ -68,6 +68,7 @@ urlpatterns = [
path('', include('apps.enp.urls')), path('', include('apps.enp.urls')),
path('', include('apps.edu.urls')), path('', include('apps.edu.urls')),
path('', include('apps.dpm.urls')), path('', include('apps.dpm.urls')),
path('', include('apps.cm.urls')),
# 前端页面入口 # 前端页面入口
path('', TemplateView.as_view(template_name="index.html")), path('', TemplateView.as_view(template_name="index.html")),