This commit is contained in:
TianyangZhang 2025-11-07 09:23:34 +08:00
commit 3ca7a2b539
13 changed files with 108 additions and 139 deletions

View File

@ -1,45 +0,0 @@
from .models import MaterialBatch, MIOItem
from apps.mtm.models import Material, Mgroup
from apps.system.models import Dept
from rest_framework.exceptions import ParseError
from django.db.models import F, Sum
from django.db import transaction
from .services import InmService
def correct_material_batch():
"""矫正物料批次
"""
mgroups = Mgroup.objects.all()
p_dict = {}
for mgroup in mgroups:
if mgroup.process:
processId = mgroup.process.id
dept: Dept = mgroup.belong_dept
if processId not in p_dict:
p_dict[processId] = dept
else:
raise ParseError('存在多个同工序的工段:{}'.format(mgroup.name))
mbs = MaterialBatch.objects.filter(material__type__in=[Material.MA_TYPE_GOOD, Material.MA_TYPE_HALFGOOD],
production_dept=None)
for mb in mbs:
if mb.material.process:
processId = mb.material.process.id
mb.production_dept = p_dict[processId]
mb.save()
def correct_mb_count_notok():
"""矫正因count_notok未记录导致的错误数据
"""
mis = MIOItem.objects.filter(mio__state=20, count_notok=0).exclude(
test_date=None,
count_notok=F('count_n_zw') + F('count_n_tw') + F('count_n_qp') + F('count_n_wq') + F('count_n_dl') + F('count_n_pb') + F('count_n_dxt') + F('count_n_js') + F('count_n_qx') + F('count_n_zz') + F('count_n_ysq') + F('count_n_hs') + F('count_n_b') + F('count_n_qt')
)
for mi in mis:
count_notok = mi.count_n_zw + mi.count_n_tw + mi.count_n_qp + mi.count_n_wq + mi.count_n_dl + mi.count_n_pb + mi.count_n_dxt + mi.count_n_js + mi.count_n_qx + mi.count_n_zz + mi.count_n_ysq + mi.count_n_hs + mi.count_n_b + mi.count_n_qt
# 先处理库存
try:
MIOItem.objects.filter(id=mi.id).update(count_notok=count_notok)
InmService.update_mb_after_test(mi)
except ParseError as e:
MIOItem.objects.filter(id=mi.id).update(test_date=None)

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.12 on 2025-11-06 15:38
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0062_auto_20250902_1122'),
('inm', '0036_mioitem_pack_index'),
]
operations = [
migrations.AlterField(
model_name='materialbatch',
name='material',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mb_m', to='mtm.material', verbose_name='物料'),
),
]

View File

@ -25,7 +25,7 @@ class MaterialBatch(BaseModel):
batch = models.TextField('批次号', db_index=True)
state = models.PositiveSmallIntegerField('状态', default=10, choices=((10, '合格'), (20, '不合格'), (30, '返修'), (40, '检验'), (50, '报废')))
material = models.ForeignKey(
Material, on_delete=models.CASCADE, verbose_name='物料')
Material, on_delete=models.CASCADE, verbose_name='物料', related_name="mb_m")
warehouse = models.ForeignKey(
WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
count = models.DecimalField('存量', max_digits=12, decimal_places=3, default=0)

View File

@ -3,7 +3,6 @@ from apps.inm.models import (MIO, MIOItem,
MIOItemA, MIOItemw)
from rest_framework.exceptions import ParseError
from apps.mtm.models import Material
from apps.mtm.services_2 import cal_material_count
from apps.wpm.models import WMaterial, BatchSt, BatchLog
from apps.wpm.services_2 import ana_batch_thread
from apps.wpmw.models import Wpr
@ -268,16 +267,6 @@ def do_in(item: MIOItem):
class InmService:
@classmethod
def update_material_count(cls, instance: MIO):
"""
更新物料数量
"""
# 统计物料数量
m_ids = list(MIOItem.objects.filter(mio=instance).values_list('material_id', flat=True))
m_ids2 = list(MIOItemA.objects.filter(mioitem__mio=instance).values_list('material_id', flat=True))
cal_material_count(m_ids+m_ids2)
@classmethod
def update_inm(cls, instance: MIO, is_reverse: bool = False):
"""
@ -484,3 +473,4 @@ class InmService:
mioitem.delete()
else:
raise ParseError("不支持该出入库单明细撤销")

View File

@ -2,7 +2,6 @@ from rest_framework.exceptions import ParseError
from apps.mtm.models import Process, Material
from apps.inm.models import WareHouse, MaterialBatch, MIOItem, MIOItemw, MIO
from apps.utils.tools import ranstr
from apps.mtm.services_2 import cal_material_count
def daoru_mb(path: str):
"""
@ -59,7 +58,6 @@ def daoru_mb(path: str):
MaterialBatch.objects.get_or_create(
material=material, batch=batch, warehouse=warehouse, defaults={"material": material, "batch": batch, "warehouse": warehouse, "count": count, "id": idWorker.get_id()}
)
cal_material_count([material.id])
i = i + 1
def daoru_mioitem_test(path:str, mioitem:MIOItem):

View File

@ -223,7 +223,6 @@ class MIOViewSet(CustomModelViewSet):
ins.state = MIO.MIO_SUBMITED
ins.save()
InmService.update_inm(ins)
InmService.update_material_count(ins)
return Response(MIOListSerializer(instance=ins).data)
@action(methods=['post'], detail=True, perms_map={'post': 'mio.submit'}, serializer_class=serializers.Serializer)
@ -245,7 +244,6 @@ class MIOViewSet(CustomModelViewSet):
ins.submit_time = None
ins.save()
InmService.update_inm(ins, is_reverse=True)
InmService.update_material_count(ins)
return Response()
@ -408,7 +406,6 @@ class MIOItemViewSet(CustomListModelMixin, BulkCreateModelMixin, BulkDestroyMode
sr.save()
# 开始变动库存
InmService.update_mb_item(ins, -1, 'count_notok')
InmService.update_material_count(ins.mio)
return Response()
@action(methods=['post'], detail=True, perms_map={'post': 'mioitem.test'}, serializer_class=serializers.Serializer)
@ -426,7 +423,6 @@ class MIOItemViewSet(CustomListModelMixin, BulkCreateModelMixin, BulkDestroyMode
pass
ins.test_date = None
ins.save()
InmService.update_material_count(ins.mio)
return Response()
@action(methods=['post'], detail=True, perms_map={'post': 'mioitem.test'}, serializer_class=MIOItemPurInTestSerializer)
@ -444,7 +440,6 @@ class MIOItemViewSet(CustomListModelMixin, BulkCreateModelMixin, BulkDestroyMode
sr = MIOItemPurInTestSerializer(instance=ins, data=request.data)
sr.is_valid(raise_exception=True)
sr.save()
InmService.update_material_count(ins.mio)
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MioItemAnaSerializer)

View File

@ -22,7 +22,6 @@ class MaterialFilter(filters.FilterSet):
"orderitem_material__order": ['exact'],
"pu_orderitem_material__pu_order": ["exact"],
"route_material_out__mgroup": ["exact"],
"count": ["gte", "lte", "exact", "gt", "lt"],
"count_safe": ["gte", "lte", "exact", "gt", "lt"]
}

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.12 on 2025-11-06 15:39
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('mtm', '0062_auto_20250902_1122'),
]
operations = [
migrations.RemoveField(
model_name='material',
name='count',
),
migrations.RemoveField(
model_name='material',
name='count_mb',
),
migrations.RemoveField(
model_name='material',
name='count_wm',
),
]

View File

@ -93,9 +93,9 @@ class Material(CommonAModel):
tracking = models.PositiveSmallIntegerField("追踪方式", default=10,
choices=((MA_TRACKING_BATCH, '批次'),
(MA_TRACKING_SINGLE, '单件')))
count = models.DecimalField('总库存', max_digits=14, decimal_places=3, default=0)
count_mb = models.DecimalField('仓库库存', max_digits=14, decimal_places=3, default=0)
count_wm = models.DecimalField('车间库存', max_digits=14, decimal_places=3, default=0)
# count = models.DecimalField('总库存', max_digits=14, decimal_places=3, default=0)
# count_mb = models.DecimalField('仓库库存', max_digits=14, decimal_places=3, default=0)
# count_wm = models.DecimalField('车间库存', max_digits=14, decimal_places=3, default=0)
count_safe = models.DecimalField('安全库存数', max_digits=14, decimal_places=3, null=True, blank=True)
week_esitimate_consume = models.DecimalField('周消耗预估', max_digits=14, decimal_places=3, null=True, blank=True)
process = models.ForeignKey(

View File

@ -33,6 +33,18 @@ class MaterialSimpleSerializer(CustomModelSerializer):
class MaterialSerializer(CustomModelSerializer):
process_name = serializers.CharField(source='process.name', read_only=True)
full_name = serializers.SerializerMethodField()
count_mb = serializers.SerializerMethodField()
count_wm = serializers.SerializerMethodField()
count = serializers.SerializerMethodField()
def get_count_mb(self, obj):
return getattr(obj, 'count_mb', 0)
def get_count_wm(self, obj):
return getattr(obj, 'count_wm', 0)
def get_count(self, obj):
return getattr(obj, 'count_mb', 0) + getattr(obj, 'count_wm', 0)
class Meta:
model = Material

View File

@ -4,24 +4,24 @@ from django.db.models import Sum
from apps.inm.models import MaterialBatch
from apps.wpm.models import WMaterial
def cal_material_count(materialId_list: List[str]=None):
"""
计算物料总数量
"""
if materialId_list is None:
materialId_list = []
if materialId_list:
objs = Material.objects.filter(id__in=set(materialId_list))
else:
objs = Material.objects.all()
for material in objs:
mb_count = MaterialBatch.objects.filter(material=material, state=10).aggregate(total=Sum("count"))["total"] or 0
wm_count = WMaterial.objects.filter(material=material, state=10).aggregate(total=Sum("count"))["total"] or 0
if mb_count is None:
mb_count = 0
if wm_count is None:
wm_count = 0
Material.objects.filter(id=material.id).update(
count_wm=wm_count,
count_mb=mb_count,
count=mb_count + wm_count)
# def cal_material_count(materialId_list: List[str]=None):
# """
# 计算物料总数量
# """
# if materialId_list is None:
# materialId_list = []
# if materialId_list:
# objs = Material.objects.filter(id__in=set(materialId_list))
# else:
# objs = Material.objects.all()
# for material in objs:
# mb_count = MaterialBatch.objects.filter(material=material, state=10).aggregate(total=Sum("count"))["total"] or 0
# wm_count = WMaterial.objects.filter(material=material, state=10).aggregate(total=Sum("count"))["total"] or 0
# if mb_count is None:
# mb_count = 0
# if wm_count is None:
# wm_count = 0
# Material.objects.filter(id=material.id).update(
# count_wm=wm_count,
# count_mb=mb_count,
# count=mb_count + wm_count)

View File

@ -17,12 +17,13 @@ from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin
from rest_framework.serializers import Serializer
from django.db import transaction
from django.db.models import Q
from apps.wf.models import Ticket
from django.utils import timezone
from rest_framework.permissions import IsAdminUser
from apps.utils.export import export_excel
from operator import itemgetter
from django.db.models import Sum, Q, Value, F, ExpressionWrapper, DecimalField
from django.db.models.functions import Coalesce
# Create your views here.
class MaterialViewSet(CustomModelViewSet):
@ -41,6 +42,28 @@ class MaterialViewSet(CustomModelViewSet):
ordering_fields = ['name', 'model', 'specification',
'type', 'process', 'process__sort', 'sort', 'id', 'number', 'create_time']
def get_queryset(self):
qs = super().get_queryset()
if self.action in ["list", "retrieve"]:
return qs.annotate(
count_wm=Coalesce(
Sum('mb_m__count', filter=Q(mb_m__state=10)),
Value(0),
output_field=DecimalField()
),
count_mb=Coalesce(
Sum('wm_m__count', filter=Q(wm_m__state=10)),
Value(0),
output_field=DecimalField()
)
).annotate(
count=ExpressionWrapper(
F('count_wm') + F('count_mb'),
output_field=DecimalField()
)
)
def perform_destroy(self, instance):
from apps.inm.models import MaterialBatch
if MaterialBatch.objects.filter(material=instance).exists():
@ -60,18 +83,6 @@ class MaterialViewSet(CustomModelViewSet):
daoru_material(settings.BASE_DIR + request.data.get('path', ''))
return Response()
@action(methods=['post'], detail=True, serializer_class=Serializer, perms_map={'post': 'material.create'})
@transaction.atomic
def cal_count(self, request, *args, **kwargs):
"""统计数量
统计数量
"""
ins = self.get_object()
from apps.mtm.services_2 import cal_material_count
cal_material_count([ins.id])
return Response()
@action(methods=['put'], detail=True, serializer_class=Serializer, perms_map={'put': '*'})
@transaction.atomic
def set_week_esitimate_consume(self, request, *args, **kwargs):

View File

@ -12,7 +12,6 @@ from apps.pm.models import Mtask
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw, MlogbDefect, BatchLog, BatchSt, MlogUser
from apps.mtm.services_2 import cal_material_count
from apps.wf.models import Ticket
from apps.wf.services import WfService
import logging
@ -23,7 +22,6 @@ from ..qm.models import Defect, Ftest
from django.db.models import Count, Q
from apps.utils.tasks import ctask_run
from apps.mtm.models import Process
from apps.mtm.services_2 import cal_material_count
from apps.utils.lock import lock_model_record_d_func
myLogger = logging.getLogger('log')
@ -399,9 +397,6 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
# 更新任务进度
cal_mtask_progress_from_mlog(mlog)
# 更新物料数量
cal_material_count_from_mlog(mlog)
# 触发批次统计分析
xbatches = list(Mlogb.objects.filter(mlog=mlog).values_list('batch', flat=True))
ana_batch_thread(xbatchs=xbatches, mgroup=mlog.mgroup)
@ -618,9 +613,6 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
# 更新任务进度
cal_mtask_progress_from_mlog(mlog)
# 更新物料数量
cal_material_count_from_mlog(mlog)
# 清除关系链
BatchLog.clear(mlog=mlog)
@ -651,24 +643,6 @@ def cal_mtask_progress_from_mlog(mlog:Mlog):
update_mtask(mtask, fill_way=mlog.fill_way)
caled_mtask.append(mtask)
def cal_material_count_from_mlog(mlog: Mlog):
"""
更新mlog关联的物料数量(可单独执行)
"""
matid_list = []
if mlog.material_in:
matid_list.append(mlog.material_in.id)
if mlog.material_out:
matid_list.append(mlog.material_out.id)
matid_list2 = Mlogb.objects.filter(mlog=mlog).values_list('material_in__id', 'material_out__id').distinct()
for matid in matid_list2:
if matid[0]:
matid_list.append(matid[0])
if matid[1]:
matid_list.append(matid[1])
matid_list = list(set(matid_list))
cal_material_count(matid_list)
def update_mtask(mtask: Mtask, fill_way: int = 10):
mtask = Mtask.objects.get(id=mtask.id) # 防止并发修改获取最新的mtask
@ -954,11 +928,6 @@ def handover_submit(handover:Handover, user: User, now: Union[datetime.datetime,
handover.recive_user = user
handover.save()
# 如果是改版交接需要触发统计数量
if handover.type == Handover.H_CHANGE:
mids.append(handover.material_changed.id)
cal_material_count(mids)
ana_batch_thread(xbatchs=batches)
@lock_model_record_d_func(Handover)
@ -1014,11 +983,6 @@ def handover_revert(handover:Handover, handler:User=None):
# 删除追踪链
BatchLog.clear(handover=handover)
# 如果是改版交接需要触发统计数量
if handover.type == Handover.H_CHANGE:
mids.append(handover.material_changed.id)
cal_material_count(mids)
ana_batch_thread(xbatchs=xbatchs)
def mlog_submit_validate(ins: Mlog):