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)
production_dept = models.ForeignKey('system.dept', verbose_name='生产车间', on_delete=models.CASCADE, 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:
unique_together = ('material', 'batch', 'warehouse')

View File

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

View File

@ -90,7 +90,7 @@ class InmService:
material=material,
warehouse=warehouse,
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:
mb.count = mb.count + getattr(i, field)

View File

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

View File

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

View File

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

View File

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